123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- "use strict";
- const fs = require("node:fs"),
- path = require("node:path"),
- { promisify } = require("node:util"),
- { LegacyESLint } = require("./eslint"),
- { ESLint, shouldUseFlatConfig, locateConfigFileToUse } = require("./eslint/eslint"),
- createCLIOptions = require("./options"),
- log = require("./shared/logging"),
- RuntimeInfo = require("./shared/runtime-info"),
- { normalizeSeverityToString } = require("./shared/severity");
- const { Legacy: { naming } } = require("@eslint/eslintrc");
- const { ModuleImporter } = require("@humanwhocodes/module-importer");
- const debug = require("debug")("eslint:cli");
- const mkdir = promisify(fs.mkdir);
- const stat = promisify(fs.stat);
- const writeFile = promisify(fs.writeFile);
- async function loadPlugins(importer, pluginNames) {
- const plugins = {};
- await Promise.all(pluginNames.map(async pluginName => {
- const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
- const module = await importer.import(longName);
- if (!("default" in module)) {
- throw new Error(`"${longName}" cannot be used with the \`--plugin\` option because its default module does not provide a \`default\` export`);
- }
- const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
- plugins[shortName] = module.default;
- }));
- return plugins;
- }
- function quietFixPredicate(message) {
- return message.severity === 2;
- }
- function quietRuleFilter(rule) {
- return rule.severity === 2;
- }
- async function translateOptions({
- cache,
- cacheFile,
- cacheLocation,
- cacheStrategy,
- config,
- configLookup,
- env,
- errorOnUnmatchedPattern,
- eslintrc,
- ext,
- fix,
- fixDryRun,
- fixType,
- flag,
- global,
- ignore,
- ignorePath,
- ignorePattern,
- inlineConfig,
- parser,
- parserOptions,
- plugin,
- quiet,
- reportUnusedDisableDirectives,
- reportUnusedDisableDirectivesSeverity,
- resolvePluginsRelativeTo,
- rule,
- rulesdir,
- stats,
- warnIgnored,
- passOnNoPatterns,
- maxWarnings
- }, configType) {
- let overrideConfig, overrideConfigFile;
- const importer = new ModuleImporter();
- if (configType === "flat") {
- overrideConfigFile = (typeof config === "string") ? config : !configLookup;
- if (overrideConfigFile === false) {
- overrideConfigFile = void 0;
- }
- const languageOptions = {};
- if (global) {
- languageOptions.globals = global.reduce((obj, name) => {
- if (name.endsWith(":true")) {
- obj[name.slice(0, -5)] = "writable";
- } else {
- obj[name] = "readonly";
- }
- return obj;
- }, {});
- }
- if (parserOptions) {
- languageOptions.parserOptions = parserOptions;
- }
- if (parser) {
- languageOptions.parser = await importer.import(parser);
- }
- overrideConfig = [{
- ...Object.keys(languageOptions).length > 0 ? { languageOptions } : {},
- rules: rule ? rule : {}
- }];
- if (reportUnusedDisableDirectives || reportUnusedDisableDirectivesSeverity !== void 0) {
- overrideConfig[0].linterOptions = {
- reportUnusedDisableDirectives: reportUnusedDisableDirectives
- ? "error"
- : normalizeSeverityToString(reportUnusedDisableDirectivesSeverity)
- };
- }
- if (plugin) {
- overrideConfig[0].plugins = await loadPlugins(importer, plugin);
- }
- } else {
- overrideConfigFile = config;
- overrideConfig = {
- env: env && env.reduce((obj, name) => {
- obj[name] = true;
- return obj;
- }, {}),
- globals: global && global.reduce((obj, name) => {
- if (name.endsWith(":true")) {
- obj[name.slice(0, -5)] = "writable";
- } else {
- obj[name] = "readonly";
- }
- return obj;
- }, {}),
- ignorePatterns: ignorePattern,
- parser,
- parserOptions,
- plugins: plugin,
- rules: rule
- };
- }
- const options = {
- allowInlineConfig: inlineConfig,
- cache,
- cacheLocation: cacheLocation || cacheFile,
- cacheStrategy,
- errorOnUnmatchedPattern,
- fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
- fixTypes: fixType,
- ignore,
- overrideConfig,
- overrideConfigFile,
- passOnNoPatterns
- };
- if (configType === "flat") {
- options.ignorePatterns = ignorePattern;
- options.stats = stats;
- options.warnIgnored = warnIgnored;
- options.flags = flag;
-
- options.ruleFilter = quiet && maxWarnings === -1 ? quietRuleFilter : () => true;
- } else {
- options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
- options.rulePaths = rulesdir;
- options.useEslintrc = eslintrc;
- options.extensions = ext;
- options.ignorePath = ignorePath;
- if (reportUnusedDisableDirectives || reportUnusedDisableDirectivesSeverity !== void 0) {
- options.reportUnusedDisableDirectives = reportUnusedDisableDirectives
- ? "error"
- : normalizeSeverityToString(reportUnusedDisableDirectivesSeverity);
- }
- }
- return options;
- }
- function countErrors(results) {
- let errorCount = 0;
- let fatalErrorCount = 0;
- let warningCount = 0;
- for (const result of results) {
- errorCount += result.errorCount;
- fatalErrorCount += result.fatalErrorCount;
- warningCount += result.warningCount;
- }
- return { errorCount, fatalErrorCount, warningCount };
- }
- async function isDirectory(filePath) {
- try {
- return (await stat(filePath)).isDirectory();
- } catch (error) {
- if (error.code === "ENOENT" || error.code === "ENOTDIR") {
- return false;
- }
- throw error;
- }
- }
- async function printResults(engine, results, format, outputFile, resultsMeta) {
- let formatter;
- try {
- formatter = await engine.loadFormatter(format);
- } catch (e) {
- log.error(e.message);
- return false;
- }
- const output = await formatter.format(results, resultsMeta);
- if (outputFile) {
- const filePath = path.resolve(process.cwd(), outputFile);
- if (await isDirectory(filePath)) {
- log.error("Cannot write to output file path, it is a directory: %s", outputFile);
- return false;
- }
- try {
- await mkdir(path.dirname(filePath), { recursive: true });
- await writeFile(filePath, output);
- } catch (ex) {
- log.error("There was a problem writing the output file:\n%s", ex);
- return false;
- }
- } else if (output) {
- log.info(output);
- }
- return true;
- }
- const cli = {
-
- async calculateInspectConfigFlags(configFile, hasUnstableTSConfigFlag) {
-
- const {
- configFilePath,
- basePath
- } = await locateConfigFileToUse({ cwd: process.cwd(), configFile }, hasUnstableTSConfigFlag);
- return ["--config", configFilePath, "--basePath", basePath];
- },
-
- async execute(args, text, allowFlatConfig = true) {
- if (Array.isArray(args)) {
- debug("CLI args: %o", args.slice(2));
- }
-
- const usingFlatConfig = allowFlatConfig && await shouldUseFlatConfig();
- debug("Using flat config?", usingFlatConfig);
- if (allowFlatConfig && !usingFlatConfig) {
- process.emitWarning("You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.", "ESLintRCWarning");
- }
- const CLIOptions = createCLIOptions(usingFlatConfig);
-
- let options;
- try {
- options = CLIOptions.parse(args);
- } catch (error) {
- debug("Error parsing CLI options:", error.message);
- let errorMessage = error.message;
- if (usingFlatConfig) {
- errorMessage += "\nYou're using eslint.config.js, some command line flags are no longer available. Please see https://eslint.org/docs/latest/use/command-line-interface for details.";
- }
- log.error(errorMessage);
- return 2;
- }
- const files = options._;
- const useStdin = typeof text === "string";
- if (options.help) {
- log.info(CLIOptions.generateHelp());
- return 0;
- }
- if (options.version) {
- log.info(RuntimeInfo.version());
- return 0;
- }
- if (options.envInfo) {
- try {
- log.info(RuntimeInfo.environment());
- return 0;
- } catch (err) {
- debug("Error retrieving environment info");
- log.error(err.message);
- return 2;
- }
- }
- if (options.printConfig) {
- if (files.length) {
- log.error("The --print-config option must be used with exactly one file name.");
- return 2;
- }
- if (useStdin) {
- log.error("The --print-config option is not available for piped-in code.");
- return 2;
- }
- const engine = usingFlatConfig
- ? new ESLint(await translateOptions(options, "flat"))
- : new LegacyESLint(await translateOptions(options));
- const fileConfig =
- await engine.calculateConfigForFile(options.printConfig);
- log.info(JSON.stringify(fileConfig, null, " "));
- return 0;
- }
- if (options.inspectConfig) {
- log.info("You can also run this command directly using 'npx @eslint/config-inspector@latest' in the same directory as your configuration file.");
- try {
- const flatOptions = await translateOptions(options, "flat");
- const spawn = require("cross-spawn");
- const flags = await cli.calculateInspectConfigFlags(flatOptions.overrideConfigFile, flatOptions.flags ? flatOptions.flags.includes("unstable_ts_config") : false);
- spawn.sync("npx", ["@eslint/config-inspector@latest", ...flags], { encoding: "utf8", stdio: "inherit" });
- } catch (error) {
- log.error(error);
- return 2;
- }
- return 0;
- }
- debug(`Running on ${useStdin ? "text" : "files"}`);
- if (options.fix && options.fixDryRun) {
- log.error("The --fix option and the --fix-dry-run option cannot be used together.");
- return 2;
- }
- if (useStdin && options.fix) {
- log.error("The --fix option is not available for piped-in code; use --fix-dry-run instead.");
- return 2;
- }
- if (options.fixType && !options.fix && !options.fixDryRun) {
- log.error("The --fix-type option requires either --fix or --fix-dry-run.");
- return 2;
- }
- if (options.reportUnusedDisableDirectives && options.reportUnusedDisableDirectivesSeverity !== void 0) {
- log.error("The --report-unused-disable-directives option and the --report-unused-disable-directives-severity option cannot be used together.");
- return 2;
- }
- const ActiveESLint = usingFlatConfig ? ESLint : LegacyESLint;
- const eslintOptions = await translateOptions(options, usingFlatConfig ? "flat" : "eslintrc");
- const engine = new ActiveESLint(eslintOptions);
- let results;
- if (useStdin) {
- results = await engine.lintText(text, {
- filePath: options.stdinFilename,
-
- warnIgnored: usingFlatConfig ? void 0 : true
- });
- } else {
- results = await engine.lintFiles(files);
- }
- if (options.fix) {
- debug("Fix mode enabled - applying fixes");
- await ActiveESLint.outputFixes(results);
- }
- let resultsToPrint = results;
- if (options.quiet) {
- debug("Quiet mode enabled - filtering out warnings");
- resultsToPrint = ActiveESLint.getErrorResults(resultsToPrint);
- }
- const resultCounts = countErrors(results);
- const tooManyWarnings = options.maxWarnings >= 0 && resultCounts.warningCount > options.maxWarnings;
- const resultsMeta = tooManyWarnings
- ? {
- maxWarningsExceeded: {
- maxWarnings: options.maxWarnings,
- foundWarnings: resultCounts.warningCount
- }
- }
- : {};
- if (await printResults(engine, resultsToPrint, options.format, options.outputFile, resultsMeta)) {
-
- const shouldExitForFatalErrors =
- options.exitOnFatalError && resultCounts.fatalErrorCount > 0;
- if (!resultCounts.errorCount && tooManyWarnings) {
- log.error(
- "ESLint found too many warnings (maximum: %s).",
- options.maxWarnings
- );
- }
- if (shouldExitForFatalErrors) {
- return 2;
- }
- return (resultCounts.errorCount || tooManyWarnings) ? 1 : 0;
- }
- return 2;
- }
- };
- module.exports = cli;
|