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

Change Request: track dependencies of eslint.config.js to invalidate cache & typescript support #18337

Closed
1 task done
netconomy-stephan-dum opened this issue Apr 14, 2024 · 2 comments
Labels
core Relates to ESLint's core APIs and features enhancement This change enhances an existing feature of ESLint

Comments

@netconomy-stephan-dum
Copy link

ESLint version

9.0.0

What problem do you want to solve?

The current implementation uses json-stable-stringify-without-jsonify to hash the config which is not appropriate for all given options (ie plugins, parsers, custom rules...) basically everything that is a function.

This behavior forces developers to execute eslint without the --cache flag once to clean it up after the config has been updated. (It was mentioned at some point in the docs but got removed!)

For small teams this might be okay but on lager projects this can be problematic and could prevent developer from using the cache at all because of the noise it produces when ever an update happens.

Over the years i have also seen some custom CLI implementation which create a hash of the package.json file to detect if a version change happend but obviously this is a thing eslint should handle internally.

What do you think is the correct solution?

A more sophisticated solution would be to use a build tool like webpack to generate the hash.

A nice side effect would be that typescript can be used for eslint.config then as well. At the moment IDEs do not support it out of the box, but i guess if you guys make a move now into this direction vendors will follow ;).

In my tests with bigger composed flat configs (airBnB + ts + js + react + jest+ cypress) the approach added around 500ms for compiling.
Importing the final config took around 2.3s but this is needed anyways so i wouldn't count that to the increased runtime.

The following quick and dirty code snipped should illustrate the idea behind this:

import { readFile, access, writeFile } from 'node:fs/promises';
import { dirname, basename } from 'node:path';
import nodeExternals from 'webpack-node-externals';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'node:module';
import { createHash } from 'node:crypto';
import webpack from 'webpack';
import stringify from 'json-stable-stringify-without-jsonify';

const fileExists = (filePath) =>
  access(filePath).then(
    () => true,
    () => false,
  );

const logger = console;
const require = createRequire(import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const cachePath = `${__dirname}/.tmp/.cache.txt`;
const output = `${__dirname}/.tmp/config.cjs`;

logger.time('runtime');
(async () => {
  const oldHash = (await fileExists(cachePath))
    ? await readFile(cachePath, { encoding: 'utf8' })
    : '';

  const packageJSONPath = `${process.cwd()}/package.json`;
  const packageJSON = require(packageJSONPath);
  const nodExternalsHandler = nodeExternals({
    modulesFromFile: packageJSONPath,
  });
  const externalsMap = new Map();

  logger.time('compiling');
  const compiler = webpack({
    mode: 'production',
    entry: './eslint.config.ts',
    target: 'node',
    output: {
      filename: basename(output),
      path: dirname(output),
      library: {
        type: 'commonjs2',
        export: 'default',
      },
    },
    optimization: {
      minimize: false,
    },
    externals: (options, callback) => {
      nodExternalsHandler(options, (error, resolved) => {
        // instead the package.json could be hashed but then unrelated version bumps will also invalidate the cache
        if (resolved) {
          const [, modulePath] = resolved.split(' ');
          const modulePathSegments = modulePath.split('/', 2);
          const moduleName = modulePath.startsWith('@')
            ? modulePathSegments.join('/')
            : modulePathSegments[0];

          externalsMap.set(
            moduleName,
            packageJSON.dependencies[moduleName] ||
              packageJSON.devDependencies[moduleName],
          );
        }

        return callback(error, resolved);
      });
    },
    externalsPresets: {
      node: true,
    },
    module: {
      rules: [
        {
          test: /.[mc]?js|ts/,
          loader: require.resolve('swc-loader'),
          options: {},
        },
      ],
    },
  });

  return new Promise((resolve, reject) => {
    compiler.run((error, stats) => {
      if (error) {
        logger.error(error);
        return reject();
      }

      const info = stats.toJson({
        hash: true,
        errors: true,
        warnings: true,
      });

      if (info.warnings.length) {
        info.warnings.forEach((warning) => {
          logger.warn(warning.message, warning.details);
        });
      }

      if (info.errors.length) {
        info.errors.forEach((error) => {
          logger.error(error.message, error.details);
        });
        return reject();
      }

      return resolve(info.hash);
    });
  }).then(
    async (buildHash) => {
      logger.timeEnd('compiling');

      logger.time('importing');
      const config = (await import(`file://${output}`)).default;
      logger.timeEnd('importing');
      logger.log('config', config);

      const newHash = createHash('sha256')
        .update(
          stringify({ cycles: true }, config) +
            JSON.stringify(Array.from(externalsMap)) +
            buildHash,
        )
        .digest('hex');

      await writeFile(cachePath, newHash);

      const configChanged = oldHash !== newHash;
      logger.log('config or its dependencies changed', configChanged);
      logger.timeEnd('runtime');
    },
    () => {
      process.exit(1);
    },
  );
})();

Drawback

In this example code webpack-node-externals is used which will prevent importing source of node_modules.
Therefor changes inside npm linked packages or mono repo packages will not be recognized.
IMHO this is something we could make developers aware of and it will only affect the developer actually working on the eslint config and as soon as a new version of that package is release all others will receive a different hash dues the cache will be invalidated.

I also added json-stable-stringify-without-jsonify to the hash mainly to show that it is possible but as mentioned in the problem statement this will not track all changes and it might even give the developer a wrong impression that everything is fine till the cache is cleaned...

Participation

  • I am willing to submit a pull request for this change.

Additional comments

Let me know what you think about this idea and if i should invest more time into forming an actual PR out of this.

@netconomy-stephan-dum netconomy-stephan-dum added core Relates to ESLint's core APIs and features enhancement This change enhances an existing feature of ESLint labels Apr 14, 2024
@mdjermanovic
Copy link
Member

mdjermanovic commented Apr 14, 2024

The current implementation uses json-stable-stringify-without-jsonify to hash the config which is not appropriate for all given options (ie plugins, parsers, custom rules...) basically everything that is a function.

This problem is already solved by including metadata (name + version) of plugins and parsers in serialized configs (#16284).

https://eslint.org/docs/latest/extend/plugins#meta-data-in-plugins

https://eslint.org/docs/latest/extend/custom-parsers#meta-data-in-custom-parsers

For example, this is a serialized config for the eslint/eslint project:

{
  "settings": {
    "jsdoc": {
      "mode": "typescript",
      "tagNamePreference": {
        "file": "fileoverview",
        "augments": "extends",
        "class": "constructor"
      },
      "preferredTypes": {
        "*": {
          "message": "Use a more precise type or if necessary use `any` or `ArbitraryCallbackResult`",
          "replacement": "any"
        },
        "Any": {
          "message": "Use a more precise type or if necessary use `any` or `ArbitraryCallbackResult`",
          "replacement": "any"
        },
        "function": {
          "message": "Point to a `@callback` namepath or `Function` if truly arbitrary in form",
          "replacement": "Function"
        },
        "Promise": {
          "message": "Specify the specific Promise type, including, if necessary, the type `any`"
        },
        ".<>": {
          "message": "Prefer type form without dot",
          "replacement": "<>"
        },
        "object": {
          "message": "Use the specific object type or `Object` if truly arbitrary",
          "replacement": "Object"
        },
        "array": "Array"
      }
    }
  },
  "linterOptions": {
    "reportUnusedDisableDirectives": 2
  },
  "languageOptions": {
    "ecmaVersion": "latest",
    "sourceType": "commonjs",
    "globals": {
      "__dirname": "readonly",
      "__filename": "readonly",
      "AbortController": false,
      "AbortSignal": false,
      "atob": false,
      "Blob": false,
      "BroadcastChannel": false,
      "btoa": false,
      "Buffer": false,
      "ByteLengthQueuingStrategy": false,
      "clearImmediate": false,
      "clearInterval": false,
      "clearTimeout": false,
      "CompressionStream": false,
      "console": false,
      "CountQueuingStrategy": false,
      "crypto": false,
      "Crypto": false,
      "CryptoKey": false,
      "CustomEvent": false,
      "DecompressionStream": false,
      "DOMException": false,
      "Event": false,
      "EventTarget": false,
      "exports": "writable",
      "fetch": false,
      "File": false,
      "FormData": false,
      "global": false,
      "Headers": false,
      "Intl": false,
      "MessageChannel": false,
      "MessageEvent": false,
      "MessagePort": false,
      "module": "readonly",
      "performance": false,
      "PerformanceEntry": false,
      "PerformanceMark": false,
      "PerformanceMeasure": false,
      "PerformanceObserver": false,
      "PerformanceObserverEntryList": false,
      "PerformanceResourceTiming": false,
      "process": false,
      "queueMicrotask": false,
      "ReadableByteStreamController": false,
      "ReadableStream": false,
      "ReadableStreamBYOBReader": false,
      "ReadableStreamBYOBRequest": false,
      "ReadableStreamDefaultController": false,
      "ReadableStreamDefaultReader": false,
      "Request": false,
      "require": "readonly",
      "Response": false,
      "setImmediate": false,
      "setInterval": false,
      "setTimeout": false,
      "structuredClone": false,
      "SubtleCrypto": false,
      "TextDecoder": false,
      "TextDecoderStream": false,
      "TextEncoder": false,
      "TextEncoderStream": false,
      "TransformStream": false,
      "TransformStreamDefaultController": false,
      "URL": false,
      "URLSearchParams": false,
      "WebAssembly": false,
      "WritableStream": false,
      "WritableStreamDefaultController": false,
      "WritableStreamDefaultWriter": false,
      "AggregateError": false,
      "Array": false,
      "ArrayBuffer": false,
      "Atomics": false,
      "BigInt": false,
      "BigInt64Array": false,
      "BigUint64Array": false,
      "Boolean": false,
      "constructor": false,
      "DataView": false,
      "Date": false,
      "decodeURI": false,
      "decodeURIComponent": false,
      "encodeURI": false,
      "encodeURIComponent": false,
      "Error": false,
      "escape": false,
      "eval": false,
      "EvalError": false,
      "FinalizationRegistry": false,
      "Float32Array": false,
      "Float64Array": false,
      "Function": false,
      "globalThis": false,
      "hasOwnProperty": false,
      "Infinity": false,
      "Int16Array": false,
      "Int32Array": false,
      "Int8Array": false,
      "isFinite": false,
      "isNaN": false,
      "isPrototypeOf": false,
      "JSON": false,
      "Map": false,
      "Math": false,
      "NaN": false,
      "Number": false,
      "Object": false,
      "parseFloat": false,
      "parseInt": false,
      "Promise": false,
      "propertyIsEnumerable": false,
      "Proxy": false,
      "RangeError": false,
      "ReferenceError": false,
      "Reflect": false,
      "RegExp": false,
      "Set": false,
      "SharedArrayBuffer": false,
      "String": false,
      "Symbol": false,
      "SyntaxError": false,
      "toLocaleString": false,
      "toString": false,
      "TypeError": false,
      "Uint16Array": false,
      "Uint32Array": false,
      "Uint8Array": false,
      "Uint8ClampedArray": false,
      "undefined": false,
      "unescape": false,
      "URIError": false,
      "valueOf": false,
      "WeakMap": false,
      "WeakRef": false,
      "WeakSet": false
    },
    "parser": "espree@10.0.1",
    "parserOptions": {}
  },
  "plugins": [
    "@",
    "unicorn:eslint-plugin-unicorn@52.0.0",
    "jsdoc",
    "@eslint-community/eslint-comments:@eslint-community/eslint-plugin-eslint-comments@4.3.0",
    "n:eslint-plugin-n@17.2.0",
    "internal-rules"
  ],
  "rules": {
    "constructor-super": [
      2
    ],
    "for-direction": [
      2
    ],
    "getter-return": [
      2
    ],
    "no-async-promise-executor": [
      2
    ],
    "no-case-declarations": [
      2
    ],
    "no-class-assign": [
      2
    ],
    "no-compare-neg-zero": [
      2
    ],
    "no-cond-assign": [
      2
    ],
    "no-const-assign": [
      2
    ],
    "no-constant-binary-expression": [
      2
    ],
    "no-constant-condition": [
      2
    ],
    "no-control-regex": [
      2
    ],
    "no-debugger": [
      2
    ],
    "no-delete-var": [
      2
    ],
    "no-dupe-args": [
      2
    ],
    "no-dupe-class-members": [
      2
    ],
    "no-dupe-else-if": [
      2
    ],
    "no-dupe-keys": [
      2
    ],
    "no-duplicate-case": [
      2
    ],
    "no-empty": [
      2
    ],
    "no-empty-character-class": [
      2
    ],
    "no-empty-pattern": [
      2
    ],
    "no-empty-static-block": [
      2
    ],
    "no-ex-assign": [
      2
    ],
    "no-extra-boolean-cast": [
      2
    ],
    "no-fallthrough": [
      2
    ],
    "no-func-assign": [
      2
    ],
    "no-global-assign": [
      2
    ],
    "no-import-assign": [
      2
    ],
    "no-invalid-regexp": [
      2
    ],
    "no-irregular-whitespace": [
      2
    ],
    "no-loss-of-precision": [
      2
    ],
    "no-misleading-character-class": [
      2
    ],
    "no-new-native-nonconstructor": [
      2
    ],
    "no-nonoctal-decimal-escape": [
      2
    ],
    "no-obj-calls": [
      2
    ],
    "no-octal": [
      2
    ],
    "no-prototype-builtins": [
      2
    ],
    "no-redeclare": [
      2
    ],
    "no-regex-spaces": [
      2
    ],
    "no-self-assign": [
      2
    ],
    "no-setter-return": [
      2
    ],
    "no-shadow-restricted-names": [
      2
    ],
    "no-sparse-arrays": [
      2
    ],
    "no-this-before-super": [
      2
    ],
    "no-undef": [
      2,
      {
        "typeof": true
      }
    ],
    "no-unexpected-multiline": [
      2
    ],
    "no-unreachable": [
      2
    ],
    "no-unsafe-finally": [
      2
    ],
    "no-unsafe-negation": [
      2
    ],
    "no-unsafe-optional-chaining": [
      2
    ],
    "no-unused-labels": [
      2
    ],
    "no-unused-private-class-members": [
      2
    ],
    "no-unused-vars": [
      2,
      {
        "vars": "all",
        "args": "after-used",
        "caughtErrors": "all"
      }
    ],
    "no-useless-backreference": [
      2
    ],
    "no-useless-catch": [
      2
    ],
    "no-useless-escape": [
      2
    ],
    "no-with": [
      2
    ],
    "require-yield": [
      2
    ],
    "use-isnan": [
      2
    ],
    "valid-typeof": [
      2
    ],
    "array-bracket-spacing": [
      2
    ],
    "array-callback-return": [
      2
    ],
    "arrow-body-style": [
      2,
      "as-needed"
    ],
    "arrow-parens": [
      2,
      "as-needed"
    ],
    "arrow-spacing": [
      2
    ],
    "indent": [
      2,
      4,
      {
        "SwitchCase": 1,
        "flatTernaryExpressions": false,
        "offsetTernaryExpressions": false,
        "ignoreComments": false
      }
    ],
    "block-spacing": [
      2
    ],
    "brace-style": [
      2,
      "1tbs"
    ],
    "camelcase": [
      2
    ],
    "class-methods-use-this": [
      2
    ],
    "comma-dangle": [
      2
    ],
    "comma-spacing": [
      2
    ],
    "comma-style": [
      2,
      "last"
    ],
    "computed-property-spacing": [
      2
    ],
    "consistent-return": [
      2
    ],
    "curly": [
      2,
      "all"
    ],
    "default-case": [
      2
    ],
    "default-case-last": [
      2
    ],
    "default-param-last": [
      2
    ],
    "dot-location": [
      2,
      "property"
    ],
    "dot-notation": [
      2,
      {
        "allowKeywords": true,
        "allowPattern": ""
      }
    ],
    "eol-last": [
      2
    ],
    "eqeqeq": [
      2
    ],
    "func-call-spacing": [
      2
    ],
    "func-style": [
      2,
      "declaration"
    ],
    "function-call-argument-newline": [
      2,
      "consistent"
    ],
    "function-paren-newline": [
      2,
      "consistent"
    ],
    "generator-star-spacing": [
      2
    ],
    "grouped-accessor-pairs": [
      2
    ],
    "guard-for-in": [
      2
    ],
    "key-spacing": [
      2,
      {
        "beforeColon": false,
        "afterColon": true
      }
    ],
    "keyword-spacing": [
      2
    ],
    "lines-around-comment": [
      2,
      {
        "beforeBlockComment": true,
        "afterBlockComment": false,
        "beforeLineComment": true,
        "afterLineComment": false,
        "allowBlockStart": false,
        "allowBlockEnd": false,
        "afterHashbangComment": false
      }
    ],
    "max-len": [
      2,
      160,
      {
        "ignoreComments": true,
        "ignoreUrls": true,
        "ignoreStrings": true,
        "ignoreTemplateLiterals": true,
        "ignoreRegExpLiterals": true
      }
    ],
    "max-statements-per-line": [
      2
    ],
    "new-cap": [
      2
    ],
    "new-parens": [
      2
    ],
    "no-alert": [
      2
    ],
    "no-array-constructor": [
      2
    ],
    "no-caller": [
      2
    ],
    "no-confusing-arrow": [
      2
    ],
    "no-console": [
      2
    ],
    "no-constructor-return": [
      2
    ],
    "no-else-return": [
      2,
      {
        "allowElseIf": false
      }
    ],
    "no-eval": [
      2
    ],
    "no-extend-native": [
      2
    ],
    "no-extra-bind": [
      2
    ],
    "no-extra-semi": [
      2
    ],
    "no-floating-decimal": [
      2
    ],
    "no-implied-eval": [
      2
    ],
    "no-inner-declarations": [
      2
    ],
    "no-invalid-this": [
      2
    ],
    "no-iterator": [
      2
    ],
    "no-label-var": [
      2
    ],
    "no-labels": [
      2
    ],
    "no-lone-blocks": [
      2
    ],
    "no-loop-func": [
      2
    ],
    "no-mixed-spaces-and-tabs": [
      2,
      false
    ],
    "no-multi-spaces": [
      2
    ],
    "no-multi-str": [
      2
    ],
    "no-multiple-empty-lines": [
      2,
      {
        "max": 2,
        "maxBOF": 0,
        "maxEOF": 0
      }
    ],
    "no-nested-ternary": [
      2
    ],
    "no-new": [
      2
    ],
    "no-new-func": [
      2
    ],
    "no-new-wrappers": [
      2
    ],
    "no-object-constructor": [
      2
    ],
    "no-octal-escape": [
      2
    ],
    "no-param-reassign": [
      2
    ],
    "no-proto": [
      2
    ],
    "no-process-exit": [
      0
    ],
    "no-restricted-properties": [
      2,
      {
        "property": "substring",
        "message": "Use .slice instead of .substring."
      },
      {
        "property": "substr",
        "message": "Use .slice instead of .substr."
      },
      {
        "object": "assert",
        "property": "equal",
        "message": "Use assert.strictEqual instead of assert.equal."
      },
      {
        "object": "assert",
        "property": "notEqual",
        "message": "Use assert.notStrictEqual instead of assert.notEqual."
      },
      {
        "object": "assert",
        "property": "deepEqual",
        "message": "Use assert.deepStrictEqual instead of assert.deepEqual."
      },
      {
        "object": "assert",
        "property": "notDeepEqual",
        "message": "Use assert.notDeepStrictEqual instead of assert.notDeepEqual."
      }
    ],
    "no-return-assign": [
      2
    ],
    "no-script-url": [
      2
    ],
    "no-self-compare": [
      2
    ],
    "no-sequences": [
      2
    ],
    "no-shadow": [
      2
    ],
    "no-tabs": [
      2
    ],
    "no-throw-literal": [
      2
    ],
    "no-trailing-spaces": [
      2
    ],
    "no-undef-init": [
      2
    ],
    "no-undefined": [
      2
    ],
    "no-underscore-dangle": [
      2,
      {
        "allowAfterThis": true,
        "allowAfterSuper": false,
        "allowAfterThisConstructor": false,
        "enforceInMethodNames": false,
        "allowFunctionParams": true,
        "enforceInClassFields": false,
        "allowInArrayDestructuring": true,
        "allowInObjectDestructuring": true
      }
    ],
    "no-unmodified-loop-condition": [
      2
    ],
    "no-unneeded-ternary": [
      2
    ],
    "no-unreachable-loop": [
      2
    ],
    "no-unused-expressions": [
      2
    ],
    "no-use-before-define": [
      2
    ],
    "no-useless-assignment": [
      2
    ],
    "no-useless-call": [
      2
    ],
    "no-useless-computed-key": [
      2
    ],
    "no-useless-concat": [
      2
    ],
    "no-useless-constructor": [
      2
    ],
    "no-useless-rename": [
      2
    ],
    "no-useless-return": [
      2
    ],
    "no-whitespace-before-property": [
      2
    ],
    "no-var": [
      2
    ],
    "object-curly-newline": [
      2,
      {
        "consistent": true,
        "multiline": true
      }
    ],
    "object-curly-spacing": [
      2,
      "always"
    ],
    "object-property-newline": [
      2,
      {
        "allowAllPropertiesOnSameLine": true,
        "allowMultiplePropertiesPerLine": false
      }
    ],
    "object-shorthand": [
      2,
      "always",
      {
        "avoidExplicitReturnArrows": true
      }
    ],
    "one-var-declaration-per-line": [
      2
    ],
    "operator-assignment": [
      2
    ],
    "operator-linebreak": [
      2
    ],
    "padding-line-between-statements": [
      2,
      {
        "blankLine": "always",
        "prev": [
          "const",
          "let",
          "var"
        ],
        "next": "*"
      },
      {
        "blankLine": "any",
        "prev": [
          "const",
          "let",
          "var"
        ],
        "next": [
          "const",
          "let",
          "var"
        ]
      }
    ],
    "prefer-arrow-callback": [
      2
    ],
    "prefer-const": [
      2
    ],
    "prefer-exponentiation-operator": [
      2
    ],
    "prefer-numeric-literals": [
      2
    ],
    "prefer-object-has-own": [
      2
    ],
    "prefer-promise-reject-errors": [
      2
    ],
    "prefer-regex-literals": [
      2
    ],
    "prefer-rest-params": [
      2
    ],
    "prefer-spread": [
      2
    ],
    "prefer-template": [
      2
    ],
    "quotes": [
      2,
      "double",
      {
        "avoidEscape": true
      }
    ],
    "quote-props": [
      2,
      "as-needed"
    ],
    "radix": [
      2
    ],
    "require-unicode-regexp": [
      2
    ],
    "rest-spread-spacing": [
      2
    ],
    "semi": [
      2
    ],
    "semi-spacing": [
      2,
      {
        "before": false,
        "after": true
      }
    ],
    "semi-style": [
      2
    ],
    "space-before-blocks": [
      2
    ],
    "space-before-function-paren": [
      2,
      {
        "anonymous": "never",
        "named": "never",
        "asyncArrow": "always"
      }
    ],
    "space-in-parens": [
      2
    ],
    "space-infix-ops": [
      2
    ],
    "space-unary-ops": [
      2,
      {
        "words": true,
        "nonwords": false
      }
    ],
    "spaced-comment": [
      2,
      "always",
      {
        "exceptions": [
          "-"
        ]
      }
    ],
    "strict": [
      2,
      "global"
    ],
    "switch-colon-spacing": [
      2
    ],
    "symbol-description": [
      2
    ],
    "template-curly-spacing": [
      2,
      "never"
    ],
    "template-tag-spacing": [
      2
    ],
    "unicode-bom": [
      2
    ],
    "wrap-iife": [
      2
    ],
    "yield-star-spacing": [
      2
    ],
    "yoda": [
      2,
      "never",
      {
        "exceptRange": true,
        "onlyEquality": false
      }
    ],
    "unicorn/prefer-array-find": [
      2
    ],
    "unicorn/prefer-array-flat-map": [
      2
    ],
    "unicorn/prefer-array-flat": [
      2
    ],
    "unicorn/prefer-array-index-of": [
      2
    ],
    "unicorn/prefer-array-some": [
      2
    ],
    "unicorn/prefer-at": [
      2
    ],
    "unicorn/prefer-includes": [
      2
    ],
    "unicorn/prefer-set-has": [
      2
    ],
    "unicorn/prefer-string-slice": [
      2
    ],
    "unicorn/prefer-string-starts-ends-with": [
      2
    ],
    "unicorn/prefer-string-trim-start-end": [
      2
    ],
    "jsdoc/check-access": [
      2
    ],
    "jsdoc/check-alignment": [
      2
    ],
    "jsdoc/check-examples": [
      0
    ],
    "jsdoc/check-indentation": [
      0
    ],
    "jsdoc/check-line-alignment": [
      0
    ],
    "jsdoc/check-param-names": [
      2
    ],
    "jsdoc/check-property-names": [
      2
    ],
    "jsdoc/check-syntax": [
      2
    ],
    "jsdoc/check-tag-names": [
      2
    ],
    "jsdoc/check-types": [
      2
    ],
    "jsdoc/check-values": [
      2,
      {
        "allowedLicenses": true
      }
    ],
    "jsdoc/empty-tags": [
      2
    ],
    "jsdoc/implements-on-classes": [
      2
    ],
    "jsdoc/imports-as-dependencies": [
      0
    ],
    "jsdoc/informative-docs": [
      0
    ],
    "jsdoc/match-description": [
      0
    ],
    "jsdoc/match-name": [
      0
    ],
    "jsdoc/multiline-blocks": [
      2
    ],
    "jsdoc/no-bad-blocks": [
      2
    ],
    "jsdoc/no-blank-block-descriptions": [
      0
    ],
    "jsdoc/no-blank-blocks": [
      0
    ],
    "jsdoc/no-defaults": [
      0
    ],
    "jsdoc/no-missing-syntax": [
      0
    ],
    "jsdoc/no-multi-asterisks": [
      2,
      {
        "allowWhitespace": true
      }
    ],
    "jsdoc/no-restricted-syntax": [
      0
    ],
    "jsdoc/no-types": [
      0
    ],
    "jsdoc/no-undefined-types": [
      0
    ],
    "jsdoc/require-asterisk-prefix": [
      2
    ],
    "jsdoc/require-description": [
      2,
      {
        "checkConstructors": false,
        "checkGetters": true,
        "checkSetters": true
      }
    ],
    "jsdoc/require-description-complete-sentence": [
      0
    ],
    "jsdoc/require-example": [
      0
    ],
    "jsdoc/require-file-overview": [
      0
    ],
    "jsdoc/require-hyphen-before-param-description": [
      2,
      "never"
    ],
    "jsdoc/require-jsdoc": [
      2,
      {
        "require": {
          "ClassDeclaration": true,
          "ArrowFunctionExpression": false,
          "ClassExpression": false,
          "FunctionDeclaration": true,
          "FunctionExpression": false,
          "MethodDefinition": false
        },
        "checkConstructors": true,
        "checkGetters": true,
        "checkSetters": true,
        "enableFixer": true,
        "exemptEmptyConstructors": false,
        "exemptEmptyFunctions": false,
        "fixerMessage": ""
      }
    ],
    "jsdoc/require-param": [
      2
    ],
    "jsdoc/require-param-description": [
      2
    ],
    "jsdoc/require-param-name": [
      2
    ],
    "jsdoc/require-param-type": [
      2
    ],
    "jsdoc/require-property": [
      2
    ],
    "jsdoc/require-property-description": [
      2
    ],
    "jsdoc/require-property-name": [
      2
    ],
    "jsdoc/require-property-type": [
      2
    ],
    "jsdoc/require-returns": [
      2,
      {
        "forceRequireReturn": true,
        "forceReturnsWithAsync": true,
        "checkConstructors": false,
        "checkGetters": true
      }
    ],
    "jsdoc/require-returns-check": [
      2
    ],
    "jsdoc/require-returns-description": [
      2
    ],
    "jsdoc/require-returns-type": [
      2
    ],
    "jsdoc/require-throws": [
      2
    ],
    "jsdoc/require-yields": [
      0
    ],
    "jsdoc/require-yields-check": [
      2
    ],
    "jsdoc/sort-tags": [
      0
    ],
    "jsdoc/tag-lines": [
      2,
      "never",
      {
        "tags": {
          "example": {
            "lines": "always"
          },
          "fileoverview": {
            "lines": "any"
          }
        },
        "startLines": 0
      }
    ],
    "jsdoc/text-escaping": [
      0
    ],
    "jsdoc/valid-types": [
      2
    ],
    "@eslint-community/eslint-comments/disable-enable-pair": [
      2
    ],
    "@eslint-community/eslint-comments/no-aggregating-enable": [
      2
    ],
    "@eslint-community/eslint-comments/no-duplicate-disable": [
      2
    ],
    "@eslint-community/eslint-comments/no-unlimited-disable": [
      2
    ],
    "@eslint-community/eslint-comments/no-unused-enable": [
      2
    ],
    "@eslint-community/eslint-comments/no-unused-disable": [
      2
    ],
    "@eslint-community/eslint-comments/require-description": [
      2
    ],
    "n/no-deprecated-api": [
      2
    ],
    "n/no-extraneous-import": [
      2
    ],
    "n/no-extraneous-require": [
      2
    ],
    "n/no-exports-assign": [
      2
    ],
    "n/no-missing-import": [
      2
    ],
    "n/no-missing-require": [
      2
    ],
    "n/no-process-exit": [
      2
    ],
    "n/no-unpublished-bin": [
      2
    ],
    "n/no-unpublished-import": [
      2
    ],
    "n/no-unpublished-require": [
      2
    ],
    "n/no-unsupported-features/es-builtins": [
      2
    ],
    "n/no-unsupported-features/es-syntax": [
      2,
      {
        "ignores": []
      }
    ],
    "n/no-unsupported-features/node-builtins": [
      2
    ],
    "n/process-exit-as-throw": [
      2
    ],
    "n/hashbang": [
      2
    ],
    "n/callback-return": [
      2,
      [
        "cb",
        "callback",
        "next"
      ]
    ],
    "n/handle-callback-err": [
      2,
      "err"
    ],
    "n/no-mixed-requires": [
      2
    ],
    "n/no-new-require": [
      2
    ],
    "n/no-path-concat": [
      2
    ],
    "internal-rules/multiline-comment-style": [
      2
    ]
  }
}

Relevant part:

    "parser": "espree@10.0.1",
    "parserOptions": {}
  },
  "plugins": [
    "@",
    "unicorn:eslint-plugin-unicorn@52.0.0",
    "jsdoc",
    "@eslint-community/eslint-comments:@eslint-community/eslint-plugin-eslint-comments@4.3.0",
    "n:eslint-plugin-n@17.2.0",
    "internal-rules"
  ],

We don't use the --cache flag, but if we did, every time a new version of e.g. espree or eslint-plugin-unicorn is used, the serialized configuration would change (for example, "parser": "espree@10.0.1" would become "parser": "espree@10.0.2") and thus invalidate the cache. We'd also add and maintain metadata for internal-rules (our internal plugin with custom rules).

At this moment, not all plugins export metadata (e.g., eslint-plugin-jsdoc, as can be seen in the serialized config above), but we expect that most plugins will soon.

@mdjermanovic mdjermanovic closed this as not planned Won't fix, can't repro, duplicate, stale Apr 14, 2024
@netconomy-stephan-dum
Copy link
Author

thanks for the explanation, i will then fix it for all our plugins which haven't adopted yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Relates to ESLint's core APIs and features enhancement This change enhances an existing feature of ESLint
Projects
Archived in project
Development

No branches or pull requests

2 participants