"use strict";
/*
- * The CLI object should *not* call process.exit() directly. It should only return
+ * NOTE: The CLI object should *not* call process.exit() directly. It should only return
* exit codes. This allows other programs to use the CLI object and still control
* when the program exits.
*/
path = require("path"),
{ promisify } = require("util"),
{ ESLint } = require("./eslint"),
- CLIOptions = require("./options"),
+ { FlatESLint } = require("./eslint/flat-eslint"),
+ createCLIOptions = require("./options"),
log = require("./shared/logging"),
RuntimeInfo = require("./shared/runtime-info");
+const { Legacy: { naming } } = require("@eslint/eslintrc");
+const { findFlatConfigFile } = require("./eslint/flat-eslint");
+const { gitignoreToMinimatch } = require("@humanwhocodes/gitignore-to-minimatch");
+const { ModuleImporter } = require("@humanwhocodes/module-importer");
const debug = require("debug")("eslint:cli");
}
/**
- * Translates the CLI options into the options expected by the CLIEngine.
+ * Translates the CLI options into the options expected by the ESLint constructor.
* @param {ParsedCLIOptions} cliOptions The CLI options to translate.
- * @returns {ESLintOptions} The options object for the CLIEngine.
+ * @param {"flat"|"eslintrc"} [configType="eslintrc"] The format of the
+ * config to generate.
+ * @returns {Promise<ESLintOptions>} The options object for the ESLint constructor.
* @private
*/
-function translateOptions({
+async function translateOptions({
cache,
cacheFile,
cacheLocation,
cacheStrategy,
config,
+ configLookup,
env,
errorOnUnmatchedPattern,
eslintrc,
resolvePluginsRelativeTo,
rule,
rulesdir
-}) {
- return {
- allowInlineConfig: inlineConfig,
- cache,
- cacheLocation: cacheLocation || cacheFile,
- cacheStrategy,
- errorOnUnmatchedPattern,
- extensions: ext,
- fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
- fixTypes: fixType,
- ignore,
- ignorePath,
- overrideConfig: {
+}, configType) {
+
+ let overrideConfig, overrideConfigFile;
+ const importer = new ModuleImporter();
+
+ if (configType === "flat") {
+ overrideConfigFile = (typeof config === "string") ? config : !configLookup;
+ if (overrideConfigFile === false) {
+ overrideConfigFile = void 0;
+ }
+
+ let globals = {};
+
+ if (global) {
+ globals = global.reduce((obj, name) => {
+ if (name.endsWith(":true")) {
+ obj[name.slice(0, -5)] = "writable";
+ } else {
+ obj[name] = "readonly";
+ }
+ return obj;
+ }, globals);
+ }
+
+ overrideConfig = [{
+ languageOptions: {
+ globals,
+ parserOptions: parserOptions || {}
+ },
+ rules: rule ? rule : {}
+ }];
+
+ if (parser) {
+ overrideConfig[0].languageOptions.parser = await importer.import(parser);
+ }
+
+ if (plugin) {
+ const plugins = {};
+
+ for (const pluginName of plugin) {
+
+ const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
+ const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
+
+ plugins[shortName] = await importer.import(longName);
+ }
+
+ overrideConfig[0].plugins = plugins;
+ }
+
+ if (ignorePattern) {
+ overrideConfig.push({
+ ignores: ignorePattern.map(gitignoreToMinimatch)
+ });
+ }
+
+ } else {
+ overrideConfigFile = config;
+
+ overrideConfig = {
env: env && env.reduce((obj, name) => {
obj[name] = true;
return obj;
parserOptions,
plugins: plugin,
rules: rule
- },
- overrideConfigFile: config,
- reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0,
- resolvePluginsRelativeTo,
- rulePaths: rulesdir,
- useEslintrc: eslintrc
+ };
+ }
+
+ const options = {
+ allowInlineConfig: inlineConfig,
+ cache,
+ cacheLocation: cacheLocation || cacheFile,
+ cacheStrategy,
+ errorOnUnmatchedPattern,
+ fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
+ fixTypes: fixType,
+ ignore,
+ ignorePath,
+ overrideConfig,
+ overrideConfigFile,
+ reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0
};
+
+ if (configType !== "flat") {
+ options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
+ options.rulePaths = rulesdir;
+ options.useEslintrc = eslintrc;
+ options.extensions = ext;
+ }
+
+ return options;
}
/**
* Executes the CLI based on an array of arguments that is passed in.
* @param {string|Array|Object} args The arguments to process.
* @param {string} [text] The text to lint (used for TTY).
+ * @param {boolean} [allowFlatConfig] Whether or not to allow flat config.
* @returns {Promise<number>} The exit code for the operation.
*/
- async execute(args, text) {
+ async execute(args, text, allowFlatConfig) {
if (Array.isArray(args)) {
debug("CLI args: %o", args.slice(2));
}
+ /*
+ * Before doing anything, we need to see if we are using a
+ * flat config file. If so, then we need to change the way command
+ * line args are parsed. This is temporary, and when we fully
+ * switch to flat config we can remove this logic.
+ */
+
+ const usingFlatConfig = allowFlatConfig && !!(await findFlatConfigFile(process.cwd()));
+
+ debug("Using flat config?", usingFlatConfig);
+
+ const CLIOptions = createCLIOptions(usingFlatConfig);
+
/** @type {ParsedCLIOptions} */
let options;
try {
options = CLIOptions.parse(args);
} catch (error) {
+ debug("Error parsing CLI options:", error.message);
log.error(error.message);
return 2;
}
log.info(RuntimeInfo.environment());
return 0;
} catch (err) {
+ debug("Error retrieving environment info");
log.error(err.message);
return 2;
}
return 2;
}
- const engine = new ESLint(translateOptions(options));
+ const engine = usingFlatConfig
+ ? new FlatESLint(await translateOptions(options, "flat"))
+ : new ESLint(await translateOptions(options));
const fileConfig =
await engine.calculateConfigForFile(options.printConfig);
return 2;
}
- const engine = new ESLint(translateOptions(options));
+ const ActiveESLint = usingFlatConfig ? FlatESLint : ESLint;
+
+ const engine = new ActiveESLint(await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc"));
let results;
if (useStdin) {
if (options.fix) {
debug("Fix mode enabled - applying fixes");
- await ESLint.outputFixes(results);
+ await ActiveESLint.outputFixes(results);
}
let resultsToPrint = results;
if (options.quiet) {
debug("Quiet mode enabled - filtering out warnings");
- resultsToPrint = ESLint.getErrorResults(resultsToPrint);
+ resultsToPrint = ActiveESLint.getErrorResults(resultsToPrint);
}
if (await printResults(engine, resultsToPrint, options.format, options.outputFile)) {