Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: use async reading of stdin in bin/eslint.js #12230

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 33 additions & 5 deletions bin/eslint.js
Expand Up @@ -60,13 +60,41 @@ process.once("uncaughtException", err => {
if (useStdIn) {

/*
* Note: `process.stdin.fd` is not used here due to https://github.com/nodejs/node/issues/7439.
* Accessing the `process.stdin` property seems to modify the behavior of file descriptor 0, resulting
* in an error when stdin is piped in asynchronously.
* Note: See
* - https://github.com/nodejs/node/blob/master/doc/api/process.md#processstdin
* - https://github.com/nodejs/node/blob/master/doc/api/process.md#a-note-on-process-io
* - https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-01/msg00419.html
* - https://github.com/nodejs/node/issues/7439 (historical)
*
* On Windows using `fs.readFileSync(STDIN_FILE_DESCRIPTOR, "utf8")` seems
* to read 4096 bytes before blocking and never drains to read further data.
*
* The investigation on the Emacs thread indicates:
*
* > Emacs on MS-Windows uses pipes to communicate with subprocesses; a
* > pipe on Windows has a 4K buffer. So as soon as Emacs writes more than
* > 4096 bytes to the pipe, the pipe becomes full, and Emacs then waits for
* > the subprocess to read its end of the pipe, at which time Emacs will
* > write the rest of the stuff.
*
* Using the nodejs code example for reading from stdin.
*/
const STDIN_FILE_DESCRIPTOR = 0;
const input = [];

process.exitCode = cli.execute(process.argv, fs.readFileSync(STDIN_FILE_DESCRIPTOR, "utf8"));
process.stdin.on("readable", () => {
kaicataldo marked this conversation as resolved.
Show resolved Hide resolved
let chunk;

// Use a loop to make sure we read all available data.
while ((chunk = process.stdin.read()) !== null) {
input.push(chunk);
}
});

process.stdin.on("end", () => {
const contents = input.join("");
kaicataldo marked this conversation as resolved.
Show resolved Hide resolved

process.exitCode = cli.execute(process.argv, contents, "utf8");
});
} else if (init) {
const configInit = require("../lib/init/config-initializer");

Expand Down
9 changes: 9 additions & 0 deletions tests/bin/eslint.js
Expand Up @@ -163,6 +163,15 @@ describe("bin/eslint.js", () => {
return assertExitCode(child, 0);
});
});

it("successfully handles more than 4k data via stdin", () => {
const child = runESLint(["--stdin", "--no-eslintrc"]);
const large = fs.createReadStream(`${__dirname}/../bench/large.js`, "utf8");

large.pipe(child.stdin);

return assertExitCode(child, 0);
});
});

describe("running on files", () => {
Expand Down