You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
#!/usr/bin/env node
/** * @fileoverview Main CLI that is run via the eslint command. * @author Nicholas C. Zakas */
/* eslint no-console:off */
"use strict";
// to use V8's code cache to speed up instantiation time
require("v8-compile-cache");
// must do this initialization *before* other requires in order to work
if (process.argv.includes("--debug")) { require("debug").enable("eslint:*,-eslint:code-path"); }
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/** * Read data from stdin til the end. * * 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. * @returns {Promise<string>} The read text. */ function readStdin() { return new Promise((resolve, reject) => { let content = ""; let chunk = "";
process.stdin .setEncoding("utf8") .on("readable", () => { while ((chunk = process.stdin.read()) !== null) { content += chunk; } }) .on("end", () => resolve(content)) .on("error", reject); }); }
/** * Get the error message of a given value. * @param {any} error The value to get. * @returns {string} The error message. */ function getErrorMessage(error) {
// Lazy loading because those are used only if error happened.
const fs = require("fs"); const path = require("path"); const util = require("util"); const lodash = require("lodash");
// Foolproof -- thirdparty module might throw non-object.
if (typeof error !== "object" || error === null) { return String(error); }
// Use templates if `error.messageTemplate` is present.
if (typeof error.messageTemplate === "string") { try { const templateFilePath = path.resolve( __dirname, `../messages/${error.messageTemplate}.txt` );
// Use sync API because Node.js should exit at this tick.
const templateText = fs.readFileSync(templateFilePath, "utf-8"); const template = lodash.template(templateText);
return template(error.messageData || {}); } catch {
// Ignore template error then fallback to use `error.stack`.
} }
// Use the stacktrace if it's an error object.
if (typeof error.stack === "string") { return error.stack; }
// Otherwise, dump the object.
return util.format("%o", error); }
/** * Catch and report unexpected error. * @param {any} error The thrown error object. * @returns {void} */ function onFatalError(error) { process.exitCode = 2;
const { version } = require("../package.json"); const message = getErrorMessage(error);
console.error(`
Oops! Something went wrong! :(
ESLint: ${version}
${message}`);
}
//------------------------------------------------------------------------------
// Execution
//------------------------------------------------------------------------------
(async function main() { process.on("uncaughtException", onFatalError); process.on("unhandledRejection", onFatalError);
// Call the config initializer if `--init` is present.
if (process.argv.includes("--init")) { await require("../lib/init/config-initializer").initializeConfig(); return; }
// Otherwise, call the CLI.
process.exitCode = await require("../lib/cli").execute( process.argv, process.argv.includes("--stdin") ? await readStdin() : null ); }()).catch(onFatalError);
|