]> git.proxmox.com Git - pve-eslint.git/blobdiff - eslint/lib/eslint/eslint.js
import 8.4.0 source
[pve-eslint.git] / eslint / lib / eslint / eslint.js
index d195aab09f1918256e744832361d7f541620678a..6274772ad856a4adb4c7046212b01abe0ddfc622 100644 (file)
@@ -15,7 +15,13 @@ const fs = require("fs");
 const { promisify } = require("util");
 const { CLIEngine, getCLIEngineInternalSlots } = require("../cli-engine/cli-engine");
 const BuiltinRules = require("../rules");
-const { getRuleSeverity } = require("../shared/config-ops");
+const {
+    Legacy: {
+        ConfigOps: {
+            getRuleSeverity
+        }
+    }
+} = require("@eslint/eslintrc");
 const { version } = require("../../package.json");
 
 //------------------------------------------------------------------------------
@@ -28,7 +34,12 @@ const { version } = require("../../package.json");
 /** @typedef {import("../shared/types").LintMessage} LintMessage */
 /** @typedef {import("../shared/types").Plugin} Plugin */
 /** @typedef {import("../shared/types").Rule} Rule */
-/** @typedef {import("./load-formatter").Formatter} Formatter */
+
+/**
+ * The main formatter object.
+ * @typedef Formatter
+ * @property {function(LintResult[]): string | Promise<string>} format format function.
+ */
 
 /**
  * The options with which to configure the ESLint instance.
@@ -37,6 +48,7 @@ const { version } = require("../../package.json");
  * @property {ConfigData} [baseConfig] Base config object, extended by all configs used with this instance
  * @property {boolean} [cache] Enable result caching.
  * @property {string} [cacheLocation] The cache file to use instead of .eslintcache.
+ * @property {"metadata" | "content"} [cacheStrategy] The strategy used to detect changed files.
  * @property {string} [cwd] The value to use for the current working directory.
  * @property {boolean} [errorOnUnmatchedPattern] If `false` then `ESLint#lintFiles()` doesn't throw even if no target files found. Defaults to `true`.
  * @property {string[]} [extensions] An array of file extensions to check.
@@ -47,7 +59,7 @@ const { version } = require("../../package.json");
  * @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
  * @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
  * @property {string} [overrideConfigFile] The configuration file to use.
- * @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
+ * @property {Record<string,Plugin>|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation.
  * @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
  * @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD.
  * @property {string[]} [rulePaths] An array of directories to load custom rules from.
@@ -118,7 +130,7 @@ function isArrayOfNonEmptyString(x) {
  * @returns {boolean} `true` if `x` is valid fix type.
  */
 function isFixType(x) {
-    return x === "problem" || x === "suggestion" || x === "layout";
+    return x === "directive" || x === "problem" || x === "suggestion" || x === "layout";
 }
 
 /**
@@ -144,6 +156,7 @@ class ESLintInvalidOptionsError extends Error {
 /**
  * Validates and normalizes options for the wrapped CLIEngine instance.
  * @param {ESLintOptions} options The options to process.
+ * @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
  * @returns {ESLintOptions} The normalized options.
  */
 function processOptions({
@@ -151,6 +164,7 @@ function processOptions({
     baseConfig = null,
     cache = false,
     cacheLocation = ".eslintcache",
+    cacheStrategy = "metadata",
     cwd = process.cwd(),
     errorOnUnmatchedPattern = true,
     extensions = null, // ← should be null by default because if it's an array then it suppresses RFC20 feature.
@@ -210,6 +224,12 @@ function processOptions({
     if (!isNonEmptyString(cacheLocation)) {
         errors.push("'cacheLocation' must be a non-empty string.");
     }
+    if (
+        cacheStrategy !== "metadata" &&
+        cacheStrategy !== "content"
+    ) {
+        errors.push("'cacheStrategy' must be any of \"metadata\", \"content\".");
+    }
     if (!isNonEmptyString(cwd) || !path.isAbsolute(cwd)) {
         errors.push("'cwd' must be an absolute path.");
     }
@@ -223,7 +243,7 @@ function processOptions({
         errors.push("'fix' must be a boolean or a function.");
     }
     if (fixTypes !== null && !isFixTypeArray(fixTypes)) {
-        errors.push("'fixTypes' must be an array of any of \"problem\", \"suggestion\", and \"layout\".");
+        errors.push("'fixTypes' must be an array of any of \"directive\", \"problem\", \"suggestion\", and \"layout\".");
     }
     if (typeof globInputPaths !== "boolean") {
         errors.push("'globInputPaths' must be a boolean.");
@@ -266,7 +286,7 @@ function processOptions({
         errors.push("'rulePaths' must be an array of non-empty strings.");
     }
     if (typeof useEslintrc !== "boolean") {
-        errors.push("'useElintrc' must be a boolean.");
+        errors.push("'useEslintrc' must be a boolean.");
     }
 
     if (errors.length > 0) {
@@ -278,6 +298,7 @@ function processOptions({
         baseConfig,
         cache,
         cacheLocation,
+        cacheStrategy,
         configFile: overrideConfigFile,
         cwd,
         errorOnUnmatchedPattern,
@@ -406,6 +427,9 @@ function compareResultsByFilePath(a, b) {
     return 0;
 }
 
+/**
+ * Main API.
+ */
 class ESLint {
 
     /**
@@ -414,26 +438,13 @@ class ESLint {
      */
     constructor(options = {}) {
         const processedOptions = processOptions(options);
-        const cliEngine = new CLIEngine(processedOptions);
+        const cliEngine = new CLIEngine(processedOptions, { preloadedPlugins: options.plugins });
         const {
-            additionalPluginPool,
             configArrayFactory,
             lastConfigArrays
         } = getCLIEngineInternalSlots(cliEngine);
         let updated = false;
 
-        /*
-         * Address `plugins` to add plugin implementations.
-         * Operate the `additionalPluginPool` internal slot directly to avoid
-         * using `addPlugin(id, plugin)` method that resets cache everytime.
-         */
-        if (options.plugins) {
-            for (const [id, plugin] of Object.entries(options.plugins)) {
-                additionalPluginPool.set(id, plugin);
-                updated = true;
-            }
-        }
-
         /*
          * Address `overrideConfig` to set override config.
          * Operate the `configArrayFactory` internal slot directly because this
@@ -499,6 +510,39 @@ class ESLint {
         return CLIEngine.getErrorResults(results);
     }
 
+    /**
+     * Returns meta objects for each rule represented in the lint results.
+     * @param {LintResult[]} results The results to fetch rules meta for.
+     * @returns {Object} A mapping of ruleIds to rule meta objects.
+     */
+    getRulesMetaForResults(results) {
+
+        const resultRuleIds = new Set();
+
+        // first gather all ruleIds from all results
+
+        for (const result of results) {
+            for (const { ruleId } of result.messages) {
+                resultRuleIds.add(ruleId);
+            }
+        }
+
+        // create a map of all rules in the results
+
+        const { cliEngine } = privateMembersMap.get(this);
+        const rules = cliEngine.getRules();
+        const resultRules = new Map();
+
+        for (const [ruleId, rule] of rules) {
+            if (resultRuleIds.has(ruleId)) {
+                resultRules.set(ruleId, rule);
+            }
+        }
+
+        return createRulesMeta(resultRules);
+
+    }
+
     /**
      * Executes the current configuration on an array of file and directory names.
      * @param {string[]} patterns An array of file and directory names.
@@ -537,9 +581,12 @@ class ESLint {
             ...unknownOptions
         } = options || {};
 
-        for (const key of Object.keys(unknownOptions)) {
-            throw new Error(`'options' must not include the unknown option '${key}'`);
+        const unknownOptionKeys = Object.keys(unknownOptions);
+
+        if (unknownOptionKeys.length > 0) {
+            throw new Error(`'options' must not include the unknown option(s): ${unknownOptionKeys.join(", ")}`);
         }
+
         if (filePath !== void 0 && !isNonEmptyString(filePath)) {
             throw new Error("'options.filePath' must be a non-empty string or undefined");
         }
@@ -557,7 +604,7 @@ class ESLint {
 
     /**
      * Returns the formatter representing the given formatter name.
-     * @param {string} [name] The name of the formattter to load.
+     * @param {string} [name] The name of the formatter to load.
      * The following values are allowed:
      * - `undefined` ... Load `stylish` builtin formatter.
      * - A builtin formatter name ... Load the builtin formatter.
@@ -575,7 +622,7 @@ class ESLint {
             throw new Error("'name' must be a string");
         }
 
-        const { cliEngine } = privateMembersMap.get(this);
+        const { cliEngine, options } = privateMembersMap.get(this);
         const formatter = cliEngine.getFormatter(name);
 
         if (typeof formatter !== "function") {
@@ -587,7 +634,7 @@ class ESLint {
             /**
              * The main formatter method.
              * @param {LintResults[]} results The lint results to format.
-             * @returns {string} The formatted lint results.
+             * @returns {string | Promise<string>} The formatted lint results.
              */
             format(results) {
                 let rulesMeta = null;
@@ -595,6 +642,9 @@ class ESLint {
                 results.sort(compareResultsByFilePath);
 
                 return formatter(results, {
+                    get cwd() {
+                        return options.cwd;
+                    },
                     get rulesMeta() {
                         if (!rulesMeta) {
                             rulesMeta = createRulesMeta(cliEngine.getRules());