-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Comments
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:
We don't use the At this moment, not all plugins export metadata (e.g., |
thanks for the explanation, i will then fix it for all our plugins which haven't adopted yet. |
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:
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
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.
The text was updated successfully, but these errors were encountered: