eslint 8.57.1 → 9.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -115
- package/bin/eslint.js +112 -89
- package/conf/default-cli-options.js +22 -22
- package/conf/ecma-version.js +16 -0
- package/conf/globals.js +109 -94
- package/conf/replacements.json +24 -20
- package/conf/rule-type-list.json +89 -26
- package/lib/api.js +16 -20
- package/lib/cli-engine/cli-engine.js +841 -810
- package/lib/cli-engine/file-enumerator.js +384 -390
- package/lib/cli-engine/formatters/formatters-meta.json +17 -45
- package/lib/cli-engine/formatters/html.js +110 -102
- package/lib/cli-engine/formatters/json-with-metadata.js +5 -5
- package/lib/cli-engine/formatters/json.js +2 -2
- package/lib/cli-engine/formatters/stylish.js +97 -76
- package/lib/cli-engine/hash.js +1 -1
- package/lib/cli-engine/index.js +1 -1
- package/lib/cli-engine/lint-result-cache.js +165 -148
- package/lib/cli-engine/load-rules.js +17 -17
- package/lib/cli.js +481 -399
- package/lib/config/config-loader.js +816 -0
- package/lib/config/config.js +674 -0
- package/lib/config/default-config.js +57 -46
- package/lib/config/flat-config-array.js +170 -333
- package/lib/config/flat-config-schema.js +389 -389
- package/lib/config-api.js +12 -0
- package/lib/eslint/eslint-helpers.js +1196 -663
- package/lib/eslint/eslint.js +1262 -607
- package/lib/eslint/index.js +3 -3
- package/lib/eslint/legacy-eslint.js +786 -0
- package/lib/eslint/worker.js +173 -0
- package/lib/languages/js/index.js +336 -0
- package/lib/languages/js/source-code/index.js +7 -0
- package/lib/languages/js/source-code/source-code.js +1364 -0
- package/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js +61 -0
- package/lib/languages/js/source-code/token-store/backward-token-cursor.js +57 -0
- package/lib/{source-code → languages/js/source-code}/token-store/cursor.js +36 -36
- package/lib/languages/js/source-code/token-store/cursors.js +120 -0
- package/lib/{source-code → languages/js/source-code}/token-store/decorative-cursor.js +17 -18
- package/lib/{source-code → languages/js/source-code}/token-store/filter-cursor.js +19 -20
- package/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js +65 -0
- package/lib/languages/js/source-code/token-store/forward-token-cursor.js +62 -0
- package/lib/languages/js/source-code/token-store/index.js +721 -0
- package/lib/{source-code → languages/js/source-code}/token-store/limit-cursor.js +17 -18
- package/lib/languages/js/source-code/token-store/padded-token-cursor.js +45 -0
- package/lib/{source-code → languages/js/source-code}/token-store/skip-cursor.js +19 -20
- package/lib/languages/js/source-code/token-store/utils.js +110 -0
- package/lib/languages/js/validate-language-options.js +196 -0
- package/lib/linter/apply-disable-directives.js +490 -371
- package/lib/linter/code-path-analysis/code-path-analyzer.js +650 -674
- package/lib/linter/code-path-analysis/code-path-segment.js +215 -216
- package/lib/linter/code-path-analysis/code-path-state.js +2118 -2096
- package/lib/linter/code-path-analysis/code-path.js +307 -317
- package/lib/linter/code-path-analysis/debug-helpers.js +183 -163
- package/lib/linter/code-path-analysis/fork-context.js +297 -272
- package/lib/linter/code-path-analysis/id-generator.js +22 -23
- package/lib/linter/esquery.js +332 -0
- package/lib/linter/file-context.js +144 -0
- package/lib/linter/file-report.js +608 -0
- package/lib/linter/index.js +3 -5
- package/lib/linter/interpolate.js +38 -16
- package/lib/linter/linter.js +2328 -1785
- package/lib/linter/rule-fixer.js +136 -107
- package/lib/linter/rules.js +37 -46
- package/lib/linter/source-code-fixer.js +96 -94
- package/lib/linter/source-code-traverser.js +333 -0
- package/lib/linter/source-code-visitor.js +81 -0
- package/lib/linter/timing.js +145 -97
- package/lib/linter/vfile.js +115 -0
- package/lib/options.js +464 -326
- package/lib/rule-tester/index.js +3 -1
- package/lib/rule-tester/rule-tester.js +1371 -998
- package/lib/rules/accessor-pairs.js +333 -259
- package/lib/rules/array-bracket-newline.js +250 -220
- package/lib/rules/array-bracket-spacing.js +286 -229
- package/lib/rules/array-callback-return.js +401 -354
- package/lib/rules/array-element-newline.js +358 -295
- package/lib/rules/arrow-body-style.js +400 -278
- package/lib/rules/arrow-parens.js +206 -155
- package/lib/rules/arrow-spacing.js +169 -145
- package/lib/rules/block-scoped-var.js +125 -123
- package/lib/rules/block-spacing.js +186 -158
- package/lib/rules/brace-style.js +262 -181
- package/lib/rules/callback-return.js +203 -174
- package/lib/rules/camelcase.js +403 -380
- package/lib/rules/capitalized-comments.js +253 -228
- package/lib/rules/class-methods-use-this.js +231 -168
- package/lib/rules/comma-dangle.js +379 -328
- package/lib/rules/comma-spacing.js +193 -177
- package/lib/rules/comma-style.js +375 -298
- package/lib/rules/complexity.js +180 -144
- package/lib/rules/computed-property-spacing.js +236 -193
- package/lib/rules/consistent-return.js +181 -170
- package/lib/rules/consistent-this.js +167 -141
- package/lib/rules/constructor-super.js +418 -411
- package/lib/rules/curly.js +407 -468
- package/lib/rules/default-case-last.js +39 -32
- package/lib/rules/default-case.js +89 -83
- package/lib/rules/default-param-last.js +69 -53
- package/lib/rules/dot-location.js +122 -92
- package/lib/rules/dot-notation.js +193 -153
- package/lib/rules/eol-last.js +122 -102
- package/lib/rules/eqeqeq.js +191 -155
- package/lib/rules/for-direction.js +150 -122
- package/lib/rules/func-call-spacing.js +261 -213
- package/lib/rules/func-name-matching.js +294 -209
- package/lib/rules/func-names.js +165 -164
- package/lib/rules/func-style.js +209 -86
- package/lib/rules/function-call-argument-newline.js +152 -111
- package/lib/rules/function-paren-newline.js +349 -273
- package/lib/rules/generator-star-spacing.js +229 -192
- package/lib/rules/getter-return.js +208 -170
- package/lib/rules/global-require.js +85 -58
- package/lib/rules/grouped-accessor-pairs.js +201 -148
- package/lib/rules/guard-for-in.js +72 -63
- package/lib/rules/handle-callback-err.js +108 -87
- package/lib/rules/id-blacklist.js +182 -187
- package/lib/rules/id-denylist.js +174 -179
- package/lib/rules/id-length.js +197 -157
- package/lib/rules/id-match.js +350 -286
- package/lib/rules/implicit-arrow-linebreak.js +102 -61
- package/lib/rules/indent-legacy.js +1345 -1102
- package/lib/rules/indent.js +2272 -1741
- package/lib/rules/index.js +320 -294
- package/lib/rules/init-declarations.js +139 -106
- package/lib/rules/jsx-quotes.js +94 -64
- package/lib/rules/key-spacing.js +750 -615
- package/lib/rules/keyword-spacing.js +648 -587
- package/lib/rules/line-comment-position.js +143 -108
- package/lib/rules/linebreak-style.js +115 -88
- package/lib/rules/lines-around-comment.js +540 -430
- package/lib/rules/lines-around-directive.js +233 -185
- package/lib/rules/lines-between-class-members.js +305 -216
- package/lib/rules/logical-assignment-operators.js +582 -398
- package/lib/rules/max-classes-per-file.js +69 -68
- package/lib/rules/max-depth.js +146 -143
- package/lib/rules/max-len.js +473 -416
- package/lib/rules/max-lines-per-function.js +201 -176
- package/lib/rules/max-lines.js +158 -162
- package/lib/rules/max-nested-callbacks.js +102 -104
- package/lib/rules/max-params.js +102 -75
- package/lib/rules/max-statements-per-line.js +205 -180
- package/lib/rules/max-statements.js +168 -164
- package/lib/rules/multiline-comment-style.js +638 -460
- package/lib/rules/multiline-ternary.js +241 -158
- package/lib/rules/new-cap.js +233 -232
- package/lib/rules/new-parens.js +88 -61
- package/lib/rules/newline-after-var.js +287 -233
- package/lib/rules/newline-before-return.js +229 -204
- package/lib/rules/newline-per-chained-call.js +142 -109
- package/lib/rules/no-alert.js +90 -79
- package/lib/rules/no-array-constructor.js +175 -113
- package/lib/rules/no-async-promise-executor.js +30 -24
- package/lib/rules/no-await-in-loop.js +79 -70
- package/lib/rules/no-bitwise.js +113 -87
- package/lib/rules/no-buffer-constructor.js +61 -37
- package/lib/rules/no-caller.js +39 -33
- package/lib/rules/no-case-declarations.js +61 -45
- package/lib/rules/no-catch-shadow.js +76 -62
- package/lib/rules/no-class-assign.js +51 -48
- package/lib/rules/no-compare-neg-zero.js +62 -48
- package/lib/rules/no-cond-assign.js +148 -132
- package/lib/rules/no-confusing-arrow.js +98 -63
- package/lib/rules/no-console.js +202 -188
- package/lib/rules/no-const-assign.js +58 -41
- package/lib/rules/no-constant-binary-expression.js +501 -407
- package/lib/rules/no-constant-condition.js +158 -131
- package/lib/rules/no-constructor-return.js +49 -49
- package/lib/rules/no-continue.js +25 -26
- package/lib/rules/no-control-regex.js +125 -121
- package/lib/rules/no-debugger.js +28 -30
- package/lib/rules/no-delete-var.js +29 -29
- package/lib/rules/no-div-regex.js +47 -40
- package/lib/rules/no-dupe-args.js +79 -69
- package/lib/rules/no-dupe-class-members.js +102 -89
- package/lib/rules/no-dupe-else-if.js +100 -77
- package/lib/rules/no-dupe-keys.js +133 -110
- package/lib/rules/no-duplicate-case.js +50 -43
- package/lib/rules/no-duplicate-imports.js +266 -188
- package/lib/rules/no-else-return.js +430 -385
- package/lib/rules/no-empty-character-class.js +57 -50
- package/lib/rules/no-empty-function.js +197 -128
- package/lib/rules/no-empty-pattern.js +63 -56
- package/lib/rules/no-empty-static-block.js +61 -35
- package/lib/rules/no-empty.js +135 -85
- package/lib/rules/no-eq-null.js +37 -32
- package/lib/rules/no-eval.js +258 -249
- package/lib/rules/no-ex-assign.js +42 -39
- package/lib/rules/no-extend-native.js +161 -160
- package/lib/rules/no-extra-bind.js +201 -190
- package/lib/rules/no-extra-boolean-cast.js +398 -295
- package/lib/rules/no-extra-label.js +150 -130
- package/lib/rules/no-extra-parens.js +1654 -1307
- package/lib/rules/no-extra-semi.js +146 -126
- package/lib/rules/no-fallthrough.js +200 -136
- package/lib/rules/no-floating-decimal.js +74 -48
- package/lib/rules/no-func-assign.js +54 -55
- package/lib/rules/no-global-assign.js +78 -72
- package/lib/rules/no-implicit-coercion.js +350 -262
- package/lib/rules/no-implicit-globals.js +174 -133
- package/lib/rules/no-implied-eval.js +150 -112
- package/lib/rules/no-import-assign.js +145 -159
- package/lib/rules/no-inline-comments.js +101 -96
- package/lib/rules/no-inner-declarations.js +115 -78
- package/lib/rules/no-invalid-regexp.js +223 -174
- package/lib/rules/no-invalid-this.js +145 -117
- package/lib/rules/no-irregular-whitespace.js +266 -250
- package/lib/rules/no-iterator.js +29 -33
- package/lib/rules/no-label-var.js +59 -61
- package/lib/rules/no-labels.js +138 -131
- package/lib/rules/no-lone-blocks.js +127 -123
- package/lib/rules/no-lonely-if.js +105 -67
- package/lib/rules/no-loop-func.js +245 -184
- package/lib/rules/no-loss-of-precision.js +236 -201
- package/lib/rules/no-magic-numbers.js +339 -217
- package/lib/rules/no-misleading-character-class.js +548 -253
- package/lib/rules/no-mixed-operators.js +188 -164
- package/lib/rules/no-mixed-requires.js +253 -224
- package/lib/rules/no-mixed-spaces-and-tabs.js +135 -103
- package/lib/rules/no-multi-assign.js +46 -47
- package/lib/rules/no-multi-spaces.js +163 -125
- package/lib/rules/no-multi-str.js +42 -40
- package/lib/rules/no-multiple-empty-lines.js +196 -140
- package/lib/rules/no-native-reassign.js +90 -74
- package/lib/rules/no-negated-condition.js +79 -74
- package/lib/rules/no-negated-in-lhs.js +45 -32
- package/lib/rules/no-nested-ternary.js +33 -31
- package/lib/rules/no-new-func.js +71 -62
- package/lib/rules/no-new-native-nonconstructor.js +43 -39
- package/lib/rules/no-new-object.js +48 -39
- package/lib/rules/no-new-require.js +48 -31
- package/lib/rules/no-new-symbol.js +61 -43
- package/lib/rules/no-new-wrappers.js +43 -41
- package/lib/rules/no-new.js +28 -29
- package/lib/rules/no-nonoctal-decimal-escape.js +149 -121
- package/lib/rules/no-obj-calls.js +66 -53
- package/lib/rules/no-object-constructor.js +104 -97
- package/lib/rules/no-octal-escape.js +40 -43
- package/lib/rules/no-octal.js +29 -32
- package/lib/rules/no-param-reassign.js +236 -218
- package/lib/rules/no-path-concat.js +66 -51
- package/lib/rules/no-plusplus.js +60 -63
- package/lib/rules/no-process-env.js +49 -32
- package/lib/rules/no-process-exit.js +48 -28
- package/lib/rules/no-promise-executor-return.js +205 -204
- package/lib/rules/no-proto.js +26 -29
- package/lib/rules/no-prototype-builtins.js +146 -124
- package/lib/rules/no-redeclare.js +154 -155
- package/lib/rules/no-regex-spaces.js +183 -161
- package/lib/rules/no-restricted-exports.js +208 -174
- package/lib/rules/no-restricted-globals.js +254 -112
- package/lib/rules/no-restricted-imports.js +824 -384
- package/lib/rules/no-restricted-modules.js +222 -186
- package/lib/rules/no-restricted-properties.js +218 -153
- package/lib/rules/no-restricted-syntax.js +56 -52
- package/lib/rules/no-return-assign.js +56 -49
- package/lib/rules/no-return-await.js +147 -120
- package/lib/rules/no-script-url.js +53 -46
- package/lib/rules/no-self-assign.js +148 -145
- package/lib/rules/no-self-compare.js +63 -46
- package/lib/rules/no-sequences.js +135 -115
- package/lib/rules/no-setter-return.js +176 -178
- package/lib/rules/no-shadow-restricted-names.js +84 -36
- package/lib/rules/no-shadow.js +598 -310
- package/lib/rules/no-spaced-func.js +82 -60
- package/lib/rules/no-sparse-arrays.js +46 -28
- package/lib/rules/no-sync.js +61 -44
- package/lib/rules/no-tabs.js +83 -54
- package/lib/rules/no-template-curly-in-string.js +33 -32
- package/lib/rules/no-ternary.js +25 -28
- package/lib/rules/no-this-before-super.js +332 -298
- package/lib/rules/no-throw-literal.js +31 -36
- package/lib/rules/no-trailing-spaces.js +208 -174
- package/lib/rules/no-unassigned-vars.js +80 -0
- package/lib/rules/no-undef-init.js +86 -60
- package/lib/rules/no-undef.js +52 -47
- package/lib/rules/no-undefined.js +73 -74
- package/lib/rules/no-underscore-dangle.js +370 -322
- package/lib/rules/no-unexpected-multiline.js +112 -102
- package/lib/rules/no-unmodified-loop-condition.js +254 -254
- package/lib/rules/no-unneeded-ternary.js +212 -146
- package/lib/rules/no-unreachable-loop.js +145 -140
- package/lib/rules/no-unreachable.js +255 -248
- package/lib/rules/no-unsafe-finally.js +93 -85
- package/lib/rules/no-unsafe-negation.js +105 -81
- package/lib/rules/no-unsafe-optional-chaining.js +193 -177
- package/lib/rules/no-unused-expressions.js +199 -158
- package/lib/rules/no-unused-labels.js +139 -124
- package/lib/rules/no-unused-private-class-members.js +206 -182
- package/lib/rules/no-unused-vars.js +1708 -687
- package/lib/rules/no-use-before-define.js +327 -229
- package/lib/rules/no-useless-assignment.js +654 -0
- package/lib/rules/no-useless-backreference.js +212 -143
- package/lib/rules/no-useless-call.js +58 -53
- package/lib/rules/no-useless-catch.js +40 -40
- package/lib/rules/no-useless-computed-key.js +144 -108
- package/lib/rules/no-useless-concat.js +65 -59
- package/lib/rules/no-useless-constructor.js +160 -97
- package/lib/rules/no-useless-escape.js +364 -291
- package/lib/rules/no-useless-rename.js +183 -153
- package/lib/rules/no-useless-return.js +344 -307
- package/lib/rules/no-var.js +245 -212
- package/lib/rules/no-void.js +51 -46
- package/lib/rules/no-warning-comments.js +191 -183
- package/lib/rules/no-whitespace-before-property.js +131 -97
- package/lib/rules/no-with.js +24 -26
- package/lib/rules/nonblock-statement-body-position.js +149 -112
- package/lib/rules/object-curly-newline.js +306 -247
- package/lib/rules/object-curly-spacing.js +360 -296
- package/lib/rules/object-property-newline.js +137 -88
- package/lib/rules/object-shorthand.js +632 -500
- package/lib/rules/one-var-declaration-per-line.js +104 -82
- package/lib/rules/one-var.js +686 -536
- package/lib/rules/operator-assignment.js +219 -158
- package/lib/rules/operator-linebreak.js +295 -233
- package/lib/rules/padded-blocks.js +346 -290
- package/lib/rules/padding-line-between-statements.js +443 -421
- package/lib/rules/prefer-arrow-callback.js +371 -315
- package/lib/rules/prefer-const.js +418 -373
- package/lib/rules/prefer-destructuring.js +309 -278
- package/lib/rules/prefer-exponentiation-operator.js +176 -132
- package/lib/rules/prefer-named-capture-group.js +160 -141
- package/lib/rules/prefer-numeric-literals.js +121 -112
- package/lib/rules/prefer-object-has-own.js +116 -82
- package/lib/rules/prefer-object-spread.js +214 -193
- package/lib/rules/prefer-promise-reject-errors.js +140 -118
- package/lib/rules/prefer-reflect.js +126 -103
- package/lib/rules/prefer-regex-literals.js +561 -463
- package/lib/rules/prefer-rest-params.js +79 -80
- package/lib/rules/prefer-spread.js +47 -43
- package/lib/rules/prefer-template.js +266 -194
- package/lib/rules/preserve-caught-error.js +535 -0
- package/lib/rules/quote-props.js +373 -289
- package/lib/rules/quotes.js +374 -308
- package/lib/rules/radix.js +152 -134
- package/lib/rules/require-atomic-updates.js +316 -282
- package/lib/rules/require-await.js +153 -82
- package/lib/rules/require-unicode-regexp.js +296 -108
- package/lib/rules/require-yield.js +53 -54
- package/lib/rules/rest-spread-spacing.js +128 -98
- package/lib/rules/semi-spacing.js +281 -232
- package/lib/rules/semi-style.js +176 -116
- package/lib/rules/semi.js +456 -418
- package/lib/rules/sort-imports.js +307 -229
- package/lib/rules/sort-keys.js +219 -181
- package/lib/rules/sort-vars.js +127 -91
- package/lib/rules/space-before-blocks.js +199 -171
- package/lib/rules/space-before-function-paren.js +186 -148
- package/lib/rules/space-in-parens.js +359 -270
- package/lib/rules/space-infix-ops.js +237 -183
- package/lib/rules/space-unary-ops.js +356 -280
- package/lib/rules/spaced-comment.js +363 -301
- package/lib/rules/strict.js +266 -229
- package/lib/rules/switch-colon-spacing.js +130 -104
- package/lib/rules/symbol-description.js +45 -48
- package/lib/rules/template-curly-spacing.js +148 -124
- package/lib/rules/template-tag-spacing.js +98 -70
- package/lib/rules/unicode-bom.js +54 -54
- package/lib/rules/use-isnan.js +237 -110
- package/lib/rules/utils/ast-utils.js +2139 -1688
- package/lib/rules/utils/char-source.js +247 -0
- package/lib/rules/utils/fix-tracker.js +99 -88
- package/lib/rules/utils/keywords.js +59 -59
- package/lib/rules/utils/lazy-loading-rule-map.js +81 -78
- package/lib/rules/utils/regular-expressions.js +35 -19
- package/lib/rules/utils/unicode/index.js +9 -4
- package/lib/rules/utils/unicode/is-combining-character.js +1 -1
- package/lib/rules/utils/unicode/is-emoji-modifier.js +1 -1
- package/lib/rules/utils/unicode/is-regional-indicator-symbol.js +1 -1
- package/lib/rules/utils/unicode/is-surrogate-pair.js +1 -1
- package/lib/rules/valid-typeof.js +153 -109
- package/lib/rules/vars-on-top.js +152 -144
- package/lib/rules/wrap-iife.js +204 -173
- package/lib/rules/wrap-regex.js +77 -47
- package/lib/rules/yield-star-spacing.js +145 -116
- package/lib/rules/yoda.js +283 -274
- package/lib/services/parser-service.js +65 -0
- package/lib/services/processor-service.js +101 -0
- package/lib/services/suppressions-service.js +302 -0
- package/lib/services/warning-service.js +98 -0
- package/lib/shared/ajv.js +14 -14
- package/lib/shared/assert.js +21 -0
- package/lib/shared/ast-utils.js +7 -6
- package/lib/shared/deep-merge-arrays.js +62 -0
- package/lib/shared/directives.js +3 -2
- package/lib/shared/flags.js +108 -0
- package/lib/shared/logging.js +24 -16
- package/lib/shared/naming.js +109 -0
- package/lib/shared/option-utils.js +63 -0
- package/lib/shared/relative-module-resolver.js +18 -40
- package/lib/shared/runtime-info.js +138 -128
- package/lib/shared/serialization.js +78 -0
- package/lib/shared/severity.js +22 -22
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +19 -21
- package/lib/shared/text-table.js +68 -0
- package/lib/shared/translate-cli-options.js +281 -0
- package/lib/shared/traverser.js +153 -146
- package/lib/types/config-api.d.ts +12 -0
- package/lib/types/index.d.ts +1473 -0
- package/lib/types/rules.d.ts +5589 -0
- package/lib/types/universal.d.ts +6 -0
- package/lib/types/use-at-your-own-risk.d.ts +87 -0
- package/lib/universal.js +10 -0
- package/lib/unsupported-api.js +8 -9
- package/messages/all-files-ignored.js +3 -3
- package/messages/all-matched-files-ignored.js +21 -0
- package/messages/config-file-missing.js +16 -0
- package/messages/config-plugin-missing.js +14 -0
- package/messages/config-serialize-function.js +30 -0
- package/messages/eslintrc-incompat.js +35 -16
- package/messages/eslintrc-plugins.js +8 -5
- package/messages/extend-config-missing.js +3 -3
- package/messages/failed-to-read-json.js +3 -3
- package/messages/file-not-found.js +3 -3
- package/messages/invalid-rule-options.js +2 -2
- package/messages/invalid-rule-severity.js +2 -2
- package/messages/no-config-found.js +4 -4
- package/messages/plugin-conflict.js +9 -9
- package/messages/plugin-invalid.js +4 -4
- package/messages/plugin-missing.js +4 -4
- package/messages/print-config-with-directory-path.js +2 -2
- package/messages/shared.js +6 -1
- package/messages/whitespace-found.js +3 -3
- package/package.json +105 -60
- package/conf/config-schema.js +0 -93
- package/lib/cli-engine/formatters/checkstyle.js +0 -60
- package/lib/cli-engine/formatters/compact.js +0 -60
- package/lib/cli-engine/formatters/jslint-xml.js +0 -41
- package/lib/cli-engine/formatters/junit.js +0 -82
- package/lib/cli-engine/formatters/tap.js +0 -95
- package/lib/cli-engine/formatters/unix.js +0 -58
- package/lib/cli-engine/formatters/visualstudio.js +0 -63
- package/lib/cli-engine/xml-escape.js +0 -34
- package/lib/config/flat-config-helpers.js +0 -111
- package/lib/config/rule-validator.js +0 -158
- package/lib/eslint/flat-eslint.js +0 -1159
- package/lib/linter/config-comment-parser.js +0 -185
- package/lib/linter/node-event-generator.js +0 -354
- package/lib/linter/report-translator.js +0 -369
- package/lib/linter/safe-emitter.js +0 -52
- package/lib/rule-tester/flat-rule-tester.js +0 -1131
- package/lib/rules/require-jsdoc.js +0 -122
- package/lib/rules/utils/patterns/letters.js +0 -36
- package/lib/rules/valid-jsdoc.js +0 -516
- package/lib/shared/config-validator.js +0 -347
- package/lib/shared/deprecation-warnings.js +0 -58
- package/lib/shared/types.js +0 -216
- package/lib/source-code/index.js +0 -5
- package/lib/source-code/source-code.js +0 -1055
- package/lib/source-code/token-store/backward-token-comment-cursor.js +0 -57
- package/lib/source-code/token-store/backward-token-cursor.js +0 -58
- package/lib/source-code/token-store/cursors.js +0 -90
- package/lib/source-code/token-store/forward-token-comment-cursor.js +0 -57
- package/lib/source-code/token-store/forward-token-cursor.js +0 -63
- package/lib/source-code/token-store/index.js +0 -627
- package/lib/source-code/token-store/padded-token-cursor.js +0 -38
- package/lib/source-code/token-store/utils.js +0 -107
package/lib/linter/linter.js
CHANGED
|
@@ -10,64 +10,77 @@
|
|
|
10
10
|
// Requirements
|
|
11
11
|
//------------------------------------------------------------------------------
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
applyDisableDirectives = require("./apply-disable-directives"),
|
|
35
|
-
ConfigCommentParser = require("./config-comment-parser"),
|
|
36
|
-
NodeEventGenerator = require("./node-event-generator"),
|
|
37
|
-
createReportTranslator = require("./report-translator"),
|
|
38
|
-
Rules = require("./rules"),
|
|
39
|
-
createEmitter = require("./safe-emitter"),
|
|
40
|
-
SourceCodeFixer = require("./source-code-fixer"),
|
|
41
|
-
timing = require("./timing"),
|
|
42
|
-
ruleReplacements = require("../../conf/replacements.json");
|
|
43
|
-
const { getRuleFromConfig } = require("../config/flat-config-helpers");
|
|
13
|
+
const path = require("node:path"),
|
|
14
|
+
eslintScope = require("eslint-scope"),
|
|
15
|
+
evk = require("eslint-visitor-keys"),
|
|
16
|
+
espree = require("espree"),
|
|
17
|
+
merge = require("lodash.merge"),
|
|
18
|
+
pkg = require("../../package.json"),
|
|
19
|
+
{
|
|
20
|
+
Legacy: {
|
|
21
|
+
ConfigOps,
|
|
22
|
+
ConfigValidator,
|
|
23
|
+
environments: BuiltInEnvironments,
|
|
24
|
+
},
|
|
25
|
+
} = require("@eslint/eslintrc/universal"),
|
|
26
|
+
Traverser = require("../shared/traverser"),
|
|
27
|
+
{ SourceCode } = require("../languages/js/source-code"),
|
|
28
|
+
applyDisableDirectives = require("./apply-disable-directives"),
|
|
29
|
+
{ ConfigCommentParser } = require("@eslint/plugin-kit"),
|
|
30
|
+
Rules = require("./rules"),
|
|
31
|
+
SourceCodeFixer = require("./source-code-fixer"),
|
|
32
|
+
{ SourceCodeVisitor } = require("./source-code-visitor"),
|
|
33
|
+
timing = require("./timing");
|
|
44
34
|
const { FlatConfigArray } = require("../config/flat-config-array");
|
|
45
|
-
const {
|
|
46
|
-
const {
|
|
47
|
-
const {
|
|
35
|
+
const { startTime, endTime } = require("../shared/stats");
|
|
36
|
+
const { assertIsRuleSeverity } = require("../config/flat-config-schema");
|
|
37
|
+
const {
|
|
38
|
+
normalizeSeverityToString,
|
|
39
|
+
normalizeSeverityToNumber,
|
|
40
|
+
} = require("../shared/severity");
|
|
41
|
+
const { deepMergeArrays } = require("../shared/deep-merge-arrays");
|
|
42
|
+
const jslang = require("../languages/js");
|
|
43
|
+
const {
|
|
44
|
+
activeFlags,
|
|
45
|
+
inactiveFlags,
|
|
46
|
+
getInactivityReasonMessage,
|
|
47
|
+
} = require("../shared/flags");
|
|
48
48
|
const debug = require("debug")("eslint:linter");
|
|
49
49
|
const MAX_AUTOFIX_PASSES = 10;
|
|
50
50
|
const DEFAULT_PARSER_NAME = "espree";
|
|
51
51
|
const DEFAULT_ECMA_VERSION = 5;
|
|
52
52
|
const commentParser = new ConfigCommentParser();
|
|
53
|
-
const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };
|
|
54
53
|
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
54
|
+
const { LATEST_ECMA_VERSION } = require("../../conf/ecma-version");
|
|
55
|
+
const { VFile } = require("./vfile");
|
|
56
|
+
const { ParserService } = require("../services/parser-service");
|
|
57
|
+
const { FileContext } = require("./file-context");
|
|
58
|
+
const { ProcessorService } = require("../services/processor-service");
|
|
59
|
+
const { containsDifferentProperty } = require("../shared/option-utils");
|
|
60
|
+
const { Config } = require("../config/config");
|
|
61
|
+
const { WarningService } = require("../services/warning-service");
|
|
62
|
+
const { SourceCodeTraverser } = require("./source-code-traverser");
|
|
63
|
+
const { FileReport, updateLocationInformation } = require("./file-report");
|
|
55
64
|
|
|
56
65
|
//------------------------------------------------------------------------------
|
|
57
66
|
// Typedefs
|
|
58
67
|
//------------------------------------------------------------------------------
|
|
59
68
|
|
|
60
|
-
/** @
|
|
61
|
-
|
|
62
|
-
/** @typedef {import("../
|
|
63
|
-
/** @typedef {import("../
|
|
64
|
-
/** @typedef {import("../
|
|
65
|
-
/** @typedef {import("../
|
|
66
|
-
/** @typedef {import("../
|
|
67
|
-
/** @typedef {import("../
|
|
68
|
-
/** @typedef {import("../
|
|
69
|
-
/** @typedef {import("../
|
|
70
|
-
/** @typedef {import("../
|
|
69
|
+
/** @import { Language, LanguageOptions, RuleConfig, RuleDefinition, RuleSeverity } from "@eslint/core" */
|
|
70
|
+
|
|
71
|
+
/** @typedef {import("../types").Linter.Config} Config */
|
|
72
|
+
/** @typedef {import("../types").ESLint.ConfigData} ConfigData */
|
|
73
|
+
/** @typedef {import("../types").ESLint.Environment} Environment */
|
|
74
|
+
/** @typedef {import("../types").Linter.GlobalConf} GlobalConf */
|
|
75
|
+
/** @typedef {import("../types").Linter.LanguageOptions} JSLanguageOptions */
|
|
76
|
+
/** @typedef {import("../types").Linter.LintMessage} LintMessage */
|
|
77
|
+
/** @typedef {import("../types").Linter.Parser} Parser */
|
|
78
|
+
/** @typedef {import("../types").Linter.ParserOptions} ParserOptions */
|
|
79
|
+
/** @typedef {import("../types").Linter.Processor} Processor */
|
|
80
|
+
/** @typedef {import("../types").Rule.RuleModule} Rule */
|
|
81
|
+
/** @typedef {import("../types").Linter.StringSeverity} StringSeverity */
|
|
82
|
+
/** @typedef {import("../types").Linter.SuppressedLintMessage} SuppressedLintMessage */
|
|
83
|
+
/** @typedef {import("../types").Linter.TimePass} TimePass */
|
|
71
84
|
|
|
72
85
|
/* eslint-disable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
|
|
73
86
|
/**
|
|
@@ -92,7 +105,9 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
|
92
105
|
* @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
|
|
93
106
|
* @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
|
|
94
107
|
* @property {Map<string, Parser>} parserMap The loaded parsers.
|
|
108
|
+
* @property {{ passes: TimePass[]; }} times The times spent on applying a rule to a file (see `stats` option).
|
|
95
109
|
* @property {Rules} ruleMap The loaded rules.
|
|
110
|
+
* @property {WarningService} warningService The warning service.
|
|
96
111
|
*/
|
|
97
112
|
|
|
98
113
|
/**
|
|
@@ -105,6 +120,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
|
105
120
|
* @property {string} [filename] the filename of the source code.
|
|
106
121
|
* @property {boolean | "off" | "warn" | "error"} [reportUnusedDisableDirectives] Adds reported errors for
|
|
107
122
|
* unused `eslint-disable` directives.
|
|
123
|
+
* @property {Function} [ruleFilter] A predicate function that determines whether a given rule should run.
|
|
108
124
|
*/
|
|
109
125
|
|
|
110
126
|
/**
|
|
@@ -130,7 +146,8 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
|
130
146
|
/**
|
|
131
147
|
* @typedef {Object} InternalOptions
|
|
132
148
|
* @property {string | null} warnInlineConfig The config name what `noInlineConfig` setting came from. If `noInlineConfig` setting didn't exist, this is null. If this is a config name, then the linter warns directive comments.
|
|
133
|
-
* @property {
|
|
149
|
+
* @property {StringSeverity} reportUnusedDisableDirectives Severity to report unused disable directives, if not "off" (boolean values were normalized).
|
|
150
|
+
* @property {StringSeverity} reportUnusedInlineConfigs Severity to report unused inline configs, if not "off".
|
|
134
151
|
*/
|
|
135
152
|
|
|
136
153
|
//------------------------------------------------------------------------------
|
|
@@ -143,7 +160,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
|
143
160
|
* @returns {boolean} True if the parser is Espree or false if not.
|
|
144
161
|
*/
|
|
145
162
|
function isEspree(parser) {
|
|
146
|
-
|
|
163
|
+
return !!(parser === espree || parser[parserSymbol] === espree);
|
|
147
164
|
}
|
|
148
165
|
|
|
149
166
|
/**
|
|
@@ -155,166 +172,227 @@ function isEspree(parser) {
|
|
|
155
172
|
* @param {{exportedVariables: Object, enabledGlobals: Object}} commentDirectives Directives from comment configuration
|
|
156
173
|
* @returns {void}
|
|
157
174
|
*/
|
|
158
|
-
function addDeclaredGlobals(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
175
|
+
function addDeclaredGlobals(
|
|
176
|
+
globalScope,
|
|
177
|
+
configGlobals,
|
|
178
|
+
{ exportedVariables, enabledGlobals },
|
|
179
|
+
) {
|
|
180
|
+
// Define configured global variables.
|
|
181
|
+
for (const id of new Set([
|
|
182
|
+
...Object.keys(configGlobals),
|
|
183
|
+
...Object.keys(enabledGlobals),
|
|
184
|
+
])) {
|
|
185
|
+
/*
|
|
186
|
+
* `ConfigOps.normalizeConfigGlobal` will throw an error if a configured global value is invalid. However, these errors would
|
|
187
|
+
* typically be caught when validating a config anyway (validity for inline global comments is checked separately).
|
|
188
|
+
*/
|
|
189
|
+
const configValue =
|
|
190
|
+
configGlobals[id] === void 0
|
|
191
|
+
? void 0
|
|
192
|
+
: ConfigOps.normalizeConfigGlobal(configGlobals[id]);
|
|
193
|
+
const commentValue = enabledGlobals[id] && enabledGlobals[id].value;
|
|
194
|
+
const value = commentValue || configValue;
|
|
195
|
+
const sourceComments =
|
|
196
|
+
enabledGlobals[id] && enabledGlobals[id].comments;
|
|
197
|
+
|
|
198
|
+
if (value === "off") {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let variable = globalScope.set.get(id);
|
|
203
|
+
|
|
204
|
+
if (!variable) {
|
|
205
|
+
variable = new eslintScope.Variable(id, globalScope);
|
|
206
|
+
|
|
207
|
+
globalScope.variables.push(variable);
|
|
208
|
+
globalScope.set.set(id, variable);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
variable.eslintImplicitGlobalSetting = configValue;
|
|
212
|
+
variable.eslintExplicitGlobal = sourceComments !== void 0;
|
|
213
|
+
variable.eslintExplicitGlobalComments = sourceComments;
|
|
214
|
+
variable.writeable = value === "writable";
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// mark all exported variables as such
|
|
218
|
+
Object.keys(exportedVariables).forEach(name => {
|
|
219
|
+
const variable = globalScope.set.get(name);
|
|
220
|
+
|
|
221
|
+
if (variable) {
|
|
222
|
+
variable.eslintUsed = true;
|
|
223
|
+
variable.eslintExported = true;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
* "through" contains all references which definitions cannot be found.
|
|
229
|
+
* Since we augment the global scope using configuration, we need to update
|
|
230
|
+
* references and remove the ones that were added by configuration.
|
|
231
|
+
*/
|
|
232
|
+
globalScope.through = globalScope.through.filter(reference => {
|
|
233
|
+
const name = reference.identifier.name;
|
|
234
|
+
const variable = globalScope.set.get(name);
|
|
235
|
+
|
|
236
|
+
if (variable) {
|
|
237
|
+
/*
|
|
238
|
+
* Links the variable and the reference.
|
|
239
|
+
* And this reference is removed from `Scope#through`.
|
|
240
|
+
*/
|
|
241
|
+
reference.resolved = variable;
|
|
242
|
+
variable.references.push(reference);
|
|
243
|
+
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return true;
|
|
248
|
+
});
|
|
224
249
|
}
|
|
225
250
|
|
|
226
251
|
/**
|
|
227
|
-
*
|
|
228
|
-
* @
|
|
229
|
-
* @
|
|
230
|
-
* @
|
|
252
|
+
* Wraps the value in an Array if it isn't already one.
|
|
253
|
+
* @template T
|
|
254
|
+
* @param {T|T[]} value Value to be wrapped.
|
|
255
|
+
* @returns {Array} The value as an array.
|
|
231
256
|
*/
|
|
232
|
-
function
|
|
233
|
-
|
|
234
|
-
? `Rule '${ruleId}' was removed and replaced by: ${ruleReplacements.rules[ruleId].join(", ")}`
|
|
235
|
-
: `Definition for rule '${ruleId}' was not found.`;
|
|
257
|
+
function asArray(value) {
|
|
258
|
+
return Array.isArray(value) ? value : [value];
|
|
236
259
|
}
|
|
237
260
|
|
|
238
261
|
/**
|
|
239
|
-
*
|
|
240
|
-
* @param {
|
|
241
|
-
* @param {
|
|
242
|
-
* @param {
|
|
243
|
-
* @param {string}
|
|
244
|
-
* @param {
|
|
245
|
-
* @
|
|
246
|
-
* @
|
|
262
|
+
* Pushes a problem to inlineConfigProblems if ruleOptions are redundant.
|
|
263
|
+
* @param {Config} config Provided config.
|
|
264
|
+
* @param {Object} loc A line/column location
|
|
265
|
+
* @param {FileReport} report Report that may be added to.
|
|
266
|
+
* @param {string} ruleId The rule ID.
|
|
267
|
+
* @param {Array} ruleOptions The rule options, merged with the config's.
|
|
268
|
+
* @param {Array} ruleOptionsInline The rule options from the comment.
|
|
269
|
+
* @param {"error"|"warn"} severity The severity to report.
|
|
270
|
+
* @returns {void}
|
|
247
271
|
*/
|
|
248
|
-
function
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
272
|
+
function addProblemIfSameSeverityAndOptions(
|
|
273
|
+
config,
|
|
274
|
+
loc,
|
|
275
|
+
report,
|
|
276
|
+
ruleId,
|
|
277
|
+
ruleOptions,
|
|
278
|
+
ruleOptionsInline,
|
|
279
|
+
severity,
|
|
280
|
+
) {
|
|
281
|
+
const existingConfigRaw = config.rules?.[ruleId];
|
|
282
|
+
const existingConfig = existingConfigRaw
|
|
283
|
+
? asArray(existingConfigRaw)
|
|
284
|
+
: ["off"];
|
|
285
|
+
const existingSeverity = normalizeSeverityToString(existingConfig[0]);
|
|
286
|
+
const inlineSeverity = normalizeSeverityToString(ruleOptions[0]);
|
|
287
|
+
const sameSeverity = existingSeverity === inlineSeverity;
|
|
288
|
+
|
|
289
|
+
if (!sameSeverity) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const alreadyConfigured = existingConfigRaw
|
|
294
|
+
? `is already configured to '${existingSeverity}'`
|
|
295
|
+
: "is not enabled so can't be turned off";
|
|
296
|
+
let message;
|
|
297
|
+
|
|
298
|
+
if (
|
|
299
|
+
(existingConfig.length === 1 && ruleOptions.length === 1) ||
|
|
300
|
+
existingSeverity === "off"
|
|
301
|
+
) {
|
|
302
|
+
message = `Unused inline config ('${ruleId}' ${alreadyConfigured}).`;
|
|
303
|
+
} else if (
|
|
304
|
+
!containsDifferentProperty(
|
|
305
|
+
ruleOptions.slice(1),
|
|
306
|
+
existingConfig.slice(1),
|
|
307
|
+
)
|
|
308
|
+
) {
|
|
309
|
+
message =
|
|
310
|
+
ruleOptionsInline.length === 1
|
|
311
|
+
? `Unused inline config ('${ruleId}' ${alreadyConfigured}).`
|
|
312
|
+
: `Unused inline config ('${ruleId}' ${alreadyConfigured} with the same options).`;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (message) {
|
|
316
|
+
const numericSeverity = normalizeSeverityToNumber(severity);
|
|
317
|
+
const descriptor = {
|
|
318
|
+
message,
|
|
319
|
+
loc,
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
if (numericSeverity === 1) {
|
|
323
|
+
report.addWarning(descriptor);
|
|
324
|
+
} else if (numericSeverity === 2) {
|
|
325
|
+
report.addError(descriptor);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
266
328
|
}
|
|
267
329
|
|
|
268
330
|
/**
|
|
269
331
|
* Creates a collection of disable directives from a comment
|
|
270
332
|
* @param {Object} options to create disable directives
|
|
271
333
|
* @param {("disable"|"enable"|"disable-line"|"disable-next-line")} options.type The type of directive comment
|
|
272
|
-
* @param {token} options.commentToken The Comment token
|
|
273
334
|
* @param {string} options.value The value after the directive in the comment
|
|
274
335
|
* comment specified no specific rules, so it applies to all rules (e.g. `eslint-disable`)
|
|
275
336
|
* @param {string} options.justification The justification of the directive
|
|
276
|
-
* @param {
|
|
277
|
-
* @
|
|
337
|
+
* @param {ASTNode|token} options.node The Comment node/token.
|
|
338
|
+
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
|
339
|
+
* @param {Language} language The language to use to adjust the location information.
|
|
340
|
+
* @param {SourceCode} sourceCode The SourceCode object to get comments from.
|
|
341
|
+
* @param {FileReport} report The report to add problems to.
|
|
342
|
+
* @returns {Object[]} Directives from the comment
|
|
278
343
|
*/
|
|
279
|
-
function createDisableDirectives(
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
344
|
+
function createDisableDirectives(
|
|
345
|
+
{ type, value, justification, node },
|
|
346
|
+
ruleMapper,
|
|
347
|
+
language,
|
|
348
|
+
sourceCode,
|
|
349
|
+
report,
|
|
350
|
+
) {
|
|
351
|
+
const ruleIds = Object.keys(commentParser.parseListConfig(value));
|
|
352
|
+
const directiveRules = ruleIds.length ? ruleIds : [null];
|
|
353
|
+
const directives = []; // valid disable directives
|
|
354
|
+
const parentDirective = { node, value, ruleIds };
|
|
355
|
+
|
|
356
|
+
for (const ruleId of directiveRules) {
|
|
357
|
+
const loc = sourceCode.getLoc(node);
|
|
358
|
+
|
|
359
|
+
// push to directives, if the rule is defined(including null, e.g. /*eslint enable*/)
|
|
360
|
+
if (ruleId === null || !!ruleMapper(ruleId)) {
|
|
361
|
+
if (type === "disable-next-line") {
|
|
362
|
+
const { line, column } = updateLocationInformation(
|
|
363
|
+
loc.end,
|
|
364
|
+
language,
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
directives.push({
|
|
368
|
+
parentDirective,
|
|
369
|
+
type,
|
|
370
|
+
line,
|
|
371
|
+
column,
|
|
372
|
+
ruleId,
|
|
373
|
+
justification,
|
|
374
|
+
});
|
|
375
|
+
} else {
|
|
376
|
+
const { line, column } = updateLocationInformation(
|
|
377
|
+
loc.start,
|
|
378
|
+
language,
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
directives.push({
|
|
382
|
+
parentDirective,
|
|
383
|
+
type,
|
|
384
|
+
line,
|
|
385
|
+
column,
|
|
386
|
+
ruleId,
|
|
387
|
+
justification,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
report.addError({ ruleId, loc });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return directives;
|
|
318
396
|
}
|
|
319
397
|
|
|
320
398
|
/**
|
|
@@ -324,214 +402,289 @@ function createDisableDirectives(options) {
|
|
|
324
402
|
* @param {SourceCode} sourceCode The SourceCode object to get comments from.
|
|
325
403
|
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
|
326
404
|
* @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
|
|
327
|
-
* @
|
|
405
|
+
* @param {ConfigData} config Provided config.
|
|
406
|
+
* @param {FileReport} report The report to add problems to.
|
|
407
|
+
* @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, disableDirectives: DisableDirective[]}}
|
|
328
408
|
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
|
329
409
|
*/
|
|
330
|
-
function getDirectiveComments(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
410
|
+
function getDirectiveComments(
|
|
411
|
+
sourceCode,
|
|
412
|
+
ruleMapper,
|
|
413
|
+
warnInlineConfig,
|
|
414
|
+
config,
|
|
415
|
+
report,
|
|
416
|
+
) {
|
|
417
|
+
const configuredRules = {};
|
|
418
|
+
const enabledGlobals = Object.create(null);
|
|
419
|
+
const exportedVariables = {};
|
|
420
|
+
const disableDirectives = [];
|
|
421
|
+
const validator = new ConfigValidator({
|
|
422
|
+
builtInRules: Rules,
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
sourceCode
|
|
426
|
+
.getInlineConfigNodes()
|
|
427
|
+
.filter(token => token.type !== "Shebang")
|
|
428
|
+
.forEach(comment => {
|
|
429
|
+
const directive = commentParser.parseDirective(comment.value);
|
|
430
|
+
|
|
431
|
+
if (!directive) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const {
|
|
436
|
+
label,
|
|
437
|
+
value,
|
|
438
|
+
justification: justificationPart,
|
|
439
|
+
} = directive;
|
|
440
|
+
|
|
441
|
+
const lineCommentSupported =
|
|
442
|
+
/^eslint-disable-(?:next-)?line$/u.test(label);
|
|
443
|
+
|
|
444
|
+
if (comment.type === "Line" && !lineCommentSupported) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const loc = sourceCode.getLoc(comment);
|
|
449
|
+
|
|
450
|
+
if (warnInlineConfig) {
|
|
451
|
+
const kind =
|
|
452
|
+
comment.type === "Block" ? `/*${label}*/` : `//${label}`;
|
|
453
|
+
|
|
454
|
+
report.addWarning({
|
|
455
|
+
ruleId: null,
|
|
456
|
+
message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`,
|
|
457
|
+
loc,
|
|
458
|
+
});
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (
|
|
463
|
+
label === "eslint-disable-line" &&
|
|
464
|
+
loc.start.line !== loc.end.line
|
|
465
|
+
) {
|
|
466
|
+
const message = `${label} comment should not span multiple lines.`;
|
|
467
|
+
|
|
468
|
+
report.addError({
|
|
469
|
+
message,
|
|
470
|
+
loc,
|
|
471
|
+
});
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
switch (label) {
|
|
476
|
+
case "eslint-disable":
|
|
477
|
+
case "eslint-enable":
|
|
478
|
+
case "eslint-disable-next-line":
|
|
479
|
+
case "eslint-disable-line": {
|
|
480
|
+
const directiveType = label.slice("eslint-".length);
|
|
481
|
+
const directives = createDisableDirectives(
|
|
482
|
+
{
|
|
483
|
+
type: directiveType,
|
|
484
|
+
value,
|
|
485
|
+
justification: justificationPart,
|
|
486
|
+
node: comment,
|
|
487
|
+
},
|
|
488
|
+
ruleMapper,
|
|
489
|
+
jslang,
|
|
490
|
+
sourceCode,
|
|
491
|
+
report,
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
disableDirectives.push(...directives);
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
case "exported":
|
|
499
|
+
Object.assign(
|
|
500
|
+
exportedVariables,
|
|
501
|
+
commentParser.parseListConfig(value),
|
|
502
|
+
);
|
|
503
|
+
break;
|
|
504
|
+
|
|
505
|
+
case "globals":
|
|
506
|
+
case "global":
|
|
507
|
+
for (const [id, idSetting] of Object.entries(
|
|
508
|
+
commentParser.parseStringConfig(value),
|
|
509
|
+
)) {
|
|
510
|
+
let normalizedValue;
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
normalizedValue =
|
|
514
|
+
ConfigOps.normalizeConfigGlobal(idSetting);
|
|
515
|
+
} catch (err) {
|
|
516
|
+
report.addError({
|
|
517
|
+
loc,
|
|
518
|
+
message: err.message,
|
|
519
|
+
});
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (enabledGlobals[id]) {
|
|
524
|
+
enabledGlobals[id].comments.push(comment);
|
|
525
|
+
enabledGlobals[id].value = normalizedValue;
|
|
526
|
+
} else {
|
|
527
|
+
enabledGlobals[id] = {
|
|
528
|
+
comments: [comment],
|
|
529
|
+
value: normalizedValue,
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
break;
|
|
534
|
+
|
|
535
|
+
case "eslint": {
|
|
536
|
+
const parseResult =
|
|
537
|
+
commentParser.parseJSONLikeConfig(value);
|
|
538
|
+
|
|
539
|
+
if (parseResult.ok) {
|
|
540
|
+
Object.keys(parseResult.config).forEach(name => {
|
|
541
|
+
const rule = ruleMapper(name);
|
|
542
|
+
const ruleValue = parseResult.config[name];
|
|
543
|
+
|
|
544
|
+
if (!rule) {
|
|
545
|
+
report.addError({ ruleId: name, loc });
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (Object.hasOwn(configuredRules, name)) {
|
|
550
|
+
report.addError({
|
|
551
|
+
message: `Rule "${name}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
|
|
552
|
+
loc,
|
|
553
|
+
});
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
let ruleOptions = asArray(ruleValue);
|
|
558
|
+
|
|
559
|
+
/*
|
|
560
|
+
* If the rule was already configured, inline rule configuration that
|
|
561
|
+
* only has severity should retain options from the config and just override the severity.
|
|
562
|
+
*
|
|
563
|
+
* Example:
|
|
564
|
+
*
|
|
565
|
+
* {
|
|
566
|
+
* rules: {
|
|
567
|
+
* curly: ["error", "multi"]
|
|
568
|
+
* }
|
|
569
|
+
* }
|
|
570
|
+
*
|
|
571
|
+
* /* eslint curly: ["warn"] * /
|
|
572
|
+
*
|
|
573
|
+
* Results in:
|
|
574
|
+
*
|
|
575
|
+
* curly: ["warn", "multi"]
|
|
576
|
+
*/
|
|
577
|
+
if (
|
|
578
|
+
/*
|
|
579
|
+
* If inline config for the rule has only severity
|
|
580
|
+
*/
|
|
581
|
+
ruleOptions.length === 1 &&
|
|
582
|
+
/*
|
|
583
|
+
* And the rule was already configured
|
|
584
|
+
*/
|
|
585
|
+
config.rules &&
|
|
586
|
+
Object.hasOwn(config.rules, name)
|
|
587
|
+
) {
|
|
588
|
+
/*
|
|
589
|
+
* Then use severity from the inline config and options from the provided config
|
|
590
|
+
*/
|
|
591
|
+
ruleOptions = [
|
|
592
|
+
ruleOptions[0], // severity from the inline config
|
|
593
|
+
...asArray(config.rules[name]).slice(1), // options from the provided config
|
|
594
|
+
];
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
try {
|
|
598
|
+
validator.validateRuleOptions(
|
|
599
|
+
rule,
|
|
600
|
+
name,
|
|
601
|
+
ruleOptions,
|
|
602
|
+
);
|
|
603
|
+
} catch (err) {
|
|
604
|
+
/*
|
|
605
|
+
* If the rule has invalid `meta.schema`, throw the error because
|
|
606
|
+
* this is not an invalid inline configuration but an invalid rule.
|
|
607
|
+
*/
|
|
608
|
+
if (
|
|
609
|
+
err.code ===
|
|
610
|
+
"ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
|
|
611
|
+
) {
|
|
612
|
+
throw err;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
report.addError({
|
|
616
|
+
ruleId: name,
|
|
617
|
+
message: err.message,
|
|
618
|
+
loc,
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// do not apply the config, if found invalid options.
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
configuredRules[name] = ruleOptions;
|
|
626
|
+
});
|
|
627
|
+
} else {
|
|
628
|
+
report.addFatal({
|
|
629
|
+
loc,
|
|
630
|
+
message: parseResult.error.message,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// no default
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
return {
|
|
642
|
+
configuredRules,
|
|
643
|
+
enabledGlobals,
|
|
644
|
+
exportedVariables,
|
|
645
|
+
disableDirectives,
|
|
646
|
+
};
|
|
472
647
|
}
|
|
473
648
|
|
|
474
649
|
/**
|
|
475
650
|
* Parses comments in file to extract disable directives.
|
|
476
651
|
* @param {SourceCode} sourceCode The SourceCode object to get comments from.
|
|
477
652
|
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
|
478
|
-
* @
|
|
653
|
+
* @param {Language} language The language to use to adjust the location information
|
|
654
|
+
* @param {FileReport} report The report to add problems to.
|
|
655
|
+
* @returns {DisableDirective[]}
|
|
479
656
|
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
|
480
657
|
*/
|
|
481
|
-
function getDirectiveCommentsForFlatConfig(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const directiveValue = directivePart.slice(match.index + directiveText.length);
|
|
512
|
-
|
|
513
|
-
switch (directiveText) {
|
|
514
|
-
case "eslint-disable":
|
|
515
|
-
case "eslint-enable":
|
|
516
|
-
case "eslint-disable-next-line":
|
|
517
|
-
case "eslint-disable-line": {
|
|
518
|
-
const directiveType = directiveText.slice("eslint-".length);
|
|
519
|
-
const options = { commentToken: comment, type: directiveType, value: directiveValue, justification: justificationPart, ruleMapper };
|
|
520
|
-
const { directives, directiveProblems } = createDisableDirectives(options);
|
|
521
|
-
|
|
522
|
-
disableDirectives.push(...directives);
|
|
523
|
-
problems.push(...directiveProblems);
|
|
524
|
-
break;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// no default
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
return {
|
|
532
|
-
problems,
|
|
533
|
-
disableDirectives
|
|
534
|
-
};
|
|
658
|
+
function getDirectiveCommentsForFlatConfig(
|
|
659
|
+
sourceCode,
|
|
660
|
+
ruleMapper,
|
|
661
|
+
language,
|
|
662
|
+
report,
|
|
663
|
+
) {
|
|
664
|
+
const disableDirectives = [];
|
|
665
|
+
|
|
666
|
+
if (sourceCode.getDisableDirectives) {
|
|
667
|
+
const { directives: directivesSources, problems: directivesProblems } =
|
|
668
|
+
sourceCode.getDisableDirectives();
|
|
669
|
+
|
|
670
|
+
if (Array.isArray(directivesProblems)) {
|
|
671
|
+
directivesProblems.forEach(problem => report.addError(problem));
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
directivesSources.forEach(directive => {
|
|
675
|
+
const directives = createDisableDirectives(
|
|
676
|
+
directive,
|
|
677
|
+
ruleMapper,
|
|
678
|
+
language,
|
|
679
|
+
sourceCode,
|
|
680
|
+
report,
|
|
681
|
+
);
|
|
682
|
+
|
|
683
|
+
disableDirectives.push(...directives);
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return disableDirectives;
|
|
535
688
|
}
|
|
536
689
|
|
|
537
690
|
/**
|
|
@@ -541,18 +694,17 @@ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
|
|
|
541
694
|
* @returns {number} normalized ECMAScript version
|
|
542
695
|
*/
|
|
543
696
|
function normalizeEcmaVersion(parser, ecmaVersion) {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
|
|
697
|
+
if (isEspree(parser)) {
|
|
698
|
+
if (ecmaVersion === "latest") {
|
|
699
|
+
return espree.latestEcmaVersion;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/*
|
|
704
|
+
* Calculate ECMAScript edition number from official year version starting with
|
|
705
|
+
* ES2015, which corresponds with ES6 (or a difference of 2009).
|
|
706
|
+
*/
|
|
707
|
+
return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
|
|
556
708
|
}
|
|
557
709
|
|
|
558
710
|
/**
|
|
@@ -562,32 +714,31 @@ function normalizeEcmaVersion(parser, ecmaVersion) {
|
|
|
562
714
|
* @returns {number} normalized ECMAScript version
|
|
563
715
|
*/
|
|
564
716
|
function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
return espree.latestEcmaVersion + 2009;
|
|
717
|
+
switch (ecmaVersion) {
|
|
718
|
+
case 3:
|
|
719
|
+
return 3;
|
|
720
|
+
|
|
721
|
+
// void 0 = no ecmaVersion specified so use the default
|
|
722
|
+
case 5:
|
|
723
|
+
case void 0:
|
|
724
|
+
return 5;
|
|
725
|
+
|
|
726
|
+
default:
|
|
727
|
+
if (typeof ecmaVersion === "number") {
|
|
728
|
+
return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/*
|
|
733
|
+
* We default to the latest supported ecmaVersion for everything else.
|
|
734
|
+
* Remember, this is for languageOptions.ecmaVersion, which sets the version
|
|
735
|
+
* that is used for a number of processes inside of ESLint. It's normally
|
|
736
|
+
* safe to assume people want the latest unless otherwise specified.
|
|
737
|
+
*/
|
|
738
|
+
return LATEST_ECMA_VERSION;
|
|
588
739
|
}
|
|
589
740
|
|
|
590
|
-
const eslintEnvPattern = /\/\*\s*eslint-env\s
|
|
741
|
+
const eslintEnvPattern = /\/\*\s*eslint-env\s.+?(?:\*\/|$)/gsu;
|
|
591
742
|
|
|
592
743
|
/**
|
|
593
744
|
* Checks whether or not there is a comment which has "eslint-env *" in a given text.
|
|
@@ -595,20 +746,22 @@ const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)(?:\*\/|$)/gsu;
|
|
|
595
746
|
* @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment.
|
|
596
747
|
*/
|
|
597
748
|
function findEslintEnv(text) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
749
|
+
let match, retv;
|
|
750
|
+
|
|
751
|
+
eslintEnvPattern.lastIndex = 0;
|
|
752
|
+
|
|
753
|
+
while ((match = eslintEnvPattern.exec(text)) !== null) {
|
|
754
|
+
if (match[0].endsWith("*/")) {
|
|
755
|
+
retv = Object.assign(
|
|
756
|
+
retv || {},
|
|
757
|
+
commentParser.parseListConfig(
|
|
758
|
+
commentParser.parseDirective(match[0].slice(2, -2)).value,
|
|
759
|
+
),
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
return retv;
|
|
612
765
|
}
|
|
613
766
|
|
|
614
767
|
/**
|
|
@@ -624,52 +777,77 @@ function findEslintEnv(text) {
|
|
|
624
777
|
* @returns {string} The normalized filename.
|
|
625
778
|
*/
|
|
626
779
|
function normalizeFilename(filename) {
|
|
627
|
-
|
|
628
|
-
|
|
780
|
+
const parts = filename.split(path.sep);
|
|
781
|
+
const index = parts.lastIndexOf("<text>");
|
|
629
782
|
|
|
630
|
-
|
|
783
|
+
return index === -1 ? filename : parts.slice(index).join(path.sep);
|
|
631
784
|
}
|
|
632
785
|
|
|
633
786
|
/**
|
|
634
787
|
* Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
|
|
635
788
|
* consistent shape.
|
|
636
789
|
* @param {VerifyOptions} providedOptions Options
|
|
637
|
-
* @param {ConfigData} config Config.
|
|
790
|
+
* @param {Config|ConfigData} config Config.
|
|
638
791
|
* @returns {Required<VerifyOptions> & InternalOptions} Normalized options
|
|
639
792
|
*/
|
|
640
793
|
function normalizeVerifyOptions(providedOptions, config) {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
794
|
+
const linterOptions = config.linterOptions || config;
|
|
795
|
+
|
|
796
|
+
// .noInlineConfig for eslintrc, .linterOptions.noInlineConfig for flat
|
|
797
|
+
const disableInlineConfig = linterOptions.noInlineConfig === true;
|
|
798
|
+
const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
|
|
799
|
+
const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
|
|
800
|
+
? ` (${config.configNameOfNoInlineConfig})`
|
|
801
|
+
: "";
|
|
802
|
+
|
|
803
|
+
let reportUnusedDisableDirectives =
|
|
804
|
+
providedOptions.reportUnusedDisableDirectives;
|
|
805
|
+
|
|
806
|
+
if (typeof reportUnusedDisableDirectives === "boolean") {
|
|
807
|
+
reportUnusedDisableDirectives = reportUnusedDisableDirectives
|
|
808
|
+
? "error"
|
|
809
|
+
: "off";
|
|
810
|
+
}
|
|
811
|
+
if (typeof reportUnusedDisableDirectives !== "string") {
|
|
812
|
+
if (typeof linterOptions.reportUnusedDisableDirectives === "boolean") {
|
|
813
|
+
reportUnusedDisableDirectives =
|
|
814
|
+
linterOptions.reportUnusedDisableDirectives ? "warn" : "off";
|
|
815
|
+
} else {
|
|
816
|
+
reportUnusedDisableDirectives =
|
|
817
|
+
linterOptions.reportUnusedDisableDirectives === void 0
|
|
818
|
+
? "off"
|
|
819
|
+
: normalizeSeverityToString(
|
|
820
|
+
linterOptions.reportUnusedDisableDirectives,
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const reportUnusedInlineConfigs =
|
|
826
|
+
linterOptions.reportUnusedInlineConfigs === void 0
|
|
827
|
+
? "off"
|
|
828
|
+
: normalizeSeverityToString(
|
|
829
|
+
linterOptions.reportUnusedInlineConfigs,
|
|
830
|
+
);
|
|
831
|
+
|
|
832
|
+
let ruleFilter = providedOptions.ruleFilter;
|
|
833
|
+
|
|
834
|
+
if (typeof ruleFilter !== "function") {
|
|
835
|
+
ruleFilter = () => true;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return {
|
|
839
|
+
filename: normalizeFilename(providedOptions.filename || "<input>"),
|
|
840
|
+
allowInlineConfig: !ignoreInlineConfig,
|
|
841
|
+
warnInlineConfig:
|
|
842
|
+
disableInlineConfig && !ignoreInlineConfig
|
|
843
|
+
? `your config${configNameOfNoInlineConfig}`
|
|
844
|
+
: null,
|
|
845
|
+
reportUnusedDisableDirectives,
|
|
846
|
+
reportUnusedInlineConfigs,
|
|
847
|
+
disableFixes: Boolean(providedOptions.disableFixes),
|
|
848
|
+
stats: providedOptions.stats,
|
|
849
|
+
ruleFilter,
|
|
850
|
+
};
|
|
673
851
|
}
|
|
674
852
|
|
|
675
853
|
/**
|
|
@@ -680,25 +858,36 @@ function normalizeVerifyOptions(providedOptions, config) {
|
|
|
680
858
|
* @returns {ParserOptions} Resulting parser options after merge
|
|
681
859
|
*/
|
|
682
860
|
function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
861
|
+
const parserOptionsFromEnv = enabledEnvironments
|
|
862
|
+
.filter(env => env.parserOptions)
|
|
863
|
+
.reduce(
|
|
864
|
+
(parserOptions, env) => merge(parserOptions, env.parserOptions),
|
|
865
|
+
{},
|
|
866
|
+
);
|
|
867
|
+
const mergedParserOptions = merge(
|
|
868
|
+
parserOptionsFromEnv,
|
|
869
|
+
providedOptions || {},
|
|
870
|
+
);
|
|
871
|
+
const isModule = mergedParserOptions.sourceType === "module";
|
|
872
|
+
|
|
873
|
+
if (isModule) {
|
|
874
|
+
/*
|
|
875
|
+
* can't have global return inside of modules
|
|
876
|
+
* TODO: espree validate parserOptions.globalReturn when sourceType is setting to module.(@aladdin-add)
|
|
877
|
+
*/
|
|
878
|
+
mergedParserOptions.ecmaFeatures = Object.assign(
|
|
879
|
+
{},
|
|
880
|
+
mergedParserOptions.ecmaFeatures,
|
|
881
|
+
{ globalReturn: false },
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
mergedParserOptions.ecmaVersion = normalizeEcmaVersion(
|
|
886
|
+
parser,
|
|
887
|
+
mergedParserOptions.ecmaVersion,
|
|
888
|
+
);
|
|
889
|
+
|
|
890
|
+
return mergedParserOptions;
|
|
702
891
|
}
|
|
703
892
|
|
|
704
893
|
/**
|
|
@@ -707,22 +896,22 @@ function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
|
|
|
707
896
|
* @param {Object} config.globals Global variable definitions.
|
|
708
897
|
* @param {Parser} config.parser The parser to use.
|
|
709
898
|
* @param {ParserOptions} config.parserOptions The parserOptions to use.
|
|
710
|
-
* @returns {
|
|
899
|
+
* @returns {JSLanguageOptions} The languageOptions equivalent.
|
|
711
900
|
*/
|
|
712
|
-
function createLanguageOptions({
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
901
|
+
function createLanguageOptions({
|
|
902
|
+
globals: configuredGlobals,
|
|
903
|
+
parser,
|
|
904
|
+
parserOptions,
|
|
905
|
+
}) {
|
|
906
|
+
const { ecmaVersion, sourceType } = parserOptions;
|
|
907
|
+
|
|
908
|
+
return {
|
|
909
|
+
globals: configuredGlobals,
|
|
910
|
+
ecmaVersion: normalizeEcmaVersionForLanguageOptions(ecmaVersion),
|
|
911
|
+
sourceType,
|
|
912
|
+
parser,
|
|
913
|
+
parserOptions,
|
|
914
|
+
};
|
|
726
915
|
}
|
|
727
916
|
|
|
728
917
|
/**
|
|
@@ -732,393 +921,299 @@ function createLanguageOptions({ globals: configuredGlobals, parser, parserOptio
|
|
|
732
921
|
* @returns {Record<string, GlobalConf>} The resolved globals object
|
|
733
922
|
*/
|
|
734
923
|
function resolveGlobals(providedGlobals, enabledEnvironments) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
924
|
+
return Object.assign(
|
|
925
|
+
Object.create(null),
|
|
926
|
+
...enabledEnvironments
|
|
927
|
+
.filter(env => env.globals)
|
|
928
|
+
.map(env => env.globals),
|
|
929
|
+
providedGlobals,
|
|
930
|
+
);
|
|
740
931
|
}
|
|
741
932
|
|
|
742
933
|
/**
|
|
743
|
-
*
|
|
744
|
-
* @param {
|
|
745
|
-
* @
|
|
934
|
+
* Store time measurements in map
|
|
935
|
+
* @param {number} time Time measurement
|
|
936
|
+
* @param {Object} timeOpts Options relating which time was measured
|
|
937
|
+
* @param {WeakMap<Linter, LinterInternalSlots>} slots Linter internal slots map
|
|
938
|
+
* @returns {void}
|
|
746
939
|
*/
|
|
747
|
-
function
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
940
|
+
function storeTime(time, timeOpts, slots) {
|
|
941
|
+
const { type, key } = timeOpts;
|
|
942
|
+
|
|
943
|
+
if (!slots.times) {
|
|
944
|
+
slots.times = { passes: [{}] };
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const passIndex = slots.fixPasses;
|
|
948
|
+
|
|
949
|
+
if (passIndex > slots.times.passes.length - 1) {
|
|
950
|
+
slots.times.passes.push({});
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (key) {
|
|
954
|
+
slots.times.passes[passIndex][type] ??= {};
|
|
955
|
+
slots.times.passes[passIndex][type][key] ??= { total: 0 };
|
|
956
|
+
slots.times.passes[passIndex][type][key].total += time;
|
|
957
|
+
} else {
|
|
958
|
+
slots.times.passes[passIndex][type] ??= { total: 0 };
|
|
959
|
+
slots.times.passes[passIndex][type].total += time;
|
|
960
|
+
}
|
|
758
961
|
}
|
|
759
962
|
|
|
760
963
|
/**
|
|
761
964
|
* Get the options for a rule (not including severity), if any
|
|
762
|
-
* @param {
|
|
965
|
+
* @param {RuleConfig} ruleConfig rule configuration
|
|
966
|
+
* @param {Object|undefined} defaultOptions rule.meta.defaultOptions
|
|
763
967
|
* @returns {Array} of rule options, empty Array if none
|
|
764
968
|
*/
|
|
765
|
-
function getRuleOptions(ruleConfig) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
969
|
+
function getRuleOptions(ruleConfig, defaultOptions) {
|
|
970
|
+
if (Array.isArray(ruleConfig)) {
|
|
971
|
+
return deepMergeArrays(defaultOptions, ruleConfig.slice(1));
|
|
972
|
+
}
|
|
973
|
+
return defaultOptions ?? [];
|
|
771
974
|
}
|
|
772
975
|
|
|
773
976
|
/**
|
|
774
977
|
* Analyze scope of the given AST.
|
|
775
978
|
* @param {ASTNode} ast The `Program` node to analyze.
|
|
776
|
-
* @param {
|
|
979
|
+
* @param {JSLanguageOptions} languageOptions The language options.
|
|
777
980
|
* @param {Record<string, string[]>} visitorKeys The visitor keys.
|
|
778
981
|
* @returns {ScopeManager} The analysis result.
|
|
779
982
|
*/
|
|
780
983
|
function analyzeScope(ast, languageOptions, visitorKeys) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
/**
|
|
797
|
-
* Parses text into an AST. Moved out here because the try-catch prevents
|
|
798
|
-
* optimization of functions, so it's best to keep the try-catch as isolated
|
|
799
|
-
* as possible
|
|
800
|
-
* @param {string} text The text to parse.
|
|
801
|
-
* @param {LanguageOptions} languageOptions Options to pass to the parser
|
|
802
|
-
* @param {string} filePath The path to the file being parsed.
|
|
803
|
-
* @returns {{success: false, error: LintMessage}|{success: true, sourceCode: SourceCode}}
|
|
804
|
-
* An object containing the AST and parser services if parsing was successful, or the error if parsing failed
|
|
805
|
-
* @private
|
|
806
|
-
*/
|
|
807
|
-
function parse(text, languageOptions, filePath) {
|
|
808
|
-
const textToParse = stripUnicodeBOM(text).replace(astUtils.shebangPattern, (match, captured) => `//${captured}`);
|
|
809
|
-
const { ecmaVersion, sourceType, parser } = languageOptions;
|
|
810
|
-
const parserOptions = Object.assign(
|
|
811
|
-
{ ecmaVersion, sourceType },
|
|
812
|
-
languageOptions.parserOptions,
|
|
813
|
-
{
|
|
814
|
-
loc: true,
|
|
815
|
-
range: true,
|
|
816
|
-
raw: true,
|
|
817
|
-
tokens: true,
|
|
818
|
-
comment: true,
|
|
819
|
-
eslintVisitorKeys: true,
|
|
820
|
-
eslintScopeManager: true,
|
|
821
|
-
filePath
|
|
822
|
-
}
|
|
823
|
-
);
|
|
824
|
-
|
|
825
|
-
/*
|
|
826
|
-
* Check for parsing errors first. If there's a parsing error, nothing
|
|
827
|
-
* else can happen. However, a parsing error does not throw an error
|
|
828
|
-
* from this method - it's just considered a fatal error message, a
|
|
829
|
-
* problem that ESLint identified just like any other.
|
|
830
|
-
*/
|
|
831
|
-
try {
|
|
832
|
-
debug("Parsing:", filePath);
|
|
833
|
-
const parseResult = (typeof parser.parseForESLint === "function")
|
|
834
|
-
? parser.parseForESLint(textToParse, parserOptions)
|
|
835
|
-
: { ast: parser.parse(textToParse, parserOptions) };
|
|
836
|
-
|
|
837
|
-
debug("Parsing successful:", filePath);
|
|
838
|
-
const ast = parseResult.ast;
|
|
839
|
-
const parserServices = parseResult.services || {};
|
|
840
|
-
const visitorKeys = parseResult.visitorKeys || evk.KEYS;
|
|
841
|
-
|
|
842
|
-
debug("Scope analysis:", filePath);
|
|
843
|
-
const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
|
|
844
|
-
|
|
845
|
-
debug("Scope analysis successful:", filePath);
|
|
846
|
-
|
|
847
|
-
return {
|
|
848
|
-
success: true,
|
|
849
|
-
|
|
850
|
-
/*
|
|
851
|
-
* Save all values that `parseForESLint()` returned.
|
|
852
|
-
* If a `SourceCode` object is given as the first parameter instead of source code text,
|
|
853
|
-
* linter skips the parsing process and reuses the source code object.
|
|
854
|
-
* In that case, linter needs all the values that `parseForESLint()` returned.
|
|
855
|
-
*/
|
|
856
|
-
sourceCode: new SourceCode({
|
|
857
|
-
text,
|
|
858
|
-
ast,
|
|
859
|
-
parserServices,
|
|
860
|
-
scopeManager,
|
|
861
|
-
visitorKeys
|
|
862
|
-
})
|
|
863
|
-
};
|
|
864
|
-
} catch (ex) {
|
|
865
|
-
|
|
866
|
-
// If the message includes a leading line number, strip it:
|
|
867
|
-
const message = `Parsing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
|
|
868
|
-
|
|
869
|
-
debug("%s\n%s", message, ex.stack);
|
|
870
|
-
|
|
871
|
-
return {
|
|
872
|
-
success: false,
|
|
873
|
-
error: {
|
|
874
|
-
ruleId: null,
|
|
875
|
-
fatal: true,
|
|
876
|
-
severity: 2,
|
|
877
|
-
message,
|
|
878
|
-
line: ex.lineNumber,
|
|
879
|
-
column: ex.column,
|
|
880
|
-
nodeType: null
|
|
881
|
-
}
|
|
882
|
-
};
|
|
883
|
-
}
|
|
984
|
+
const parserOptions = languageOptions.parserOptions;
|
|
985
|
+
const ecmaFeatures = parserOptions.ecmaFeatures || {};
|
|
986
|
+
const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
|
|
987
|
+
|
|
988
|
+
return eslintScope.analyze(ast, {
|
|
989
|
+
ignoreEval: true,
|
|
990
|
+
nodejsScope: ecmaFeatures.globalReturn,
|
|
991
|
+
impliedStrict: ecmaFeatures.impliedStrict,
|
|
992
|
+
ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
|
|
993
|
+
sourceType: languageOptions.sourceType || "script",
|
|
994
|
+
childVisitorKeys: visitorKeys || evk.KEYS,
|
|
995
|
+
fallback: Traverser.getKeys,
|
|
996
|
+
});
|
|
884
997
|
}
|
|
885
998
|
|
|
886
999
|
/**
|
|
887
1000
|
* Runs a rule, and gets its listeners
|
|
888
|
-
* @param {
|
|
1001
|
+
* @param {RuleDefinition} rule A rule object
|
|
889
1002
|
* @param {Context} ruleContext The context that should be passed to the rule
|
|
1003
|
+
* @throws {TypeError} If `rule` is not an object with a `create` method
|
|
890
1004
|
* @throws {any} Any error during the rule's `create`
|
|
891
1005
|
* @returns {Object} A map of selector listeners provided by the rule
|
|
892
1006
|
*/
|
|
893
1007
|
function createRuleListeners(rule, ruleContext) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1008
|
+
if (
|
|
1009
|
+
!rule ||
|
|
1010
|
+
typeof rule !== "object" ||
|
|
1011
|
+
typeof rule.create !== "function"
|
|
1012
|
+
) {
|
|
1013
|
+
throw new TypeError(
|
|
1014
|
+
`Error while loading rule '${ruleContext.id}': Rule must be an object with a \`create\` method`,
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
try {
|
|
1019
|
+
return rule.create(ruleContext);
|
|
1020
|
+
} catch (ex) {
|
|
1021
|
+
ex.message = `Error while loading rule '${ruleContext.id}': ${ex.message}`;
|
|
1022
|
+
throw ex;
|
|
1023
|
+
}
|
|
900
1024
|
}
|
|
901
1025
|
|
|
902
|
-
// methods that exist on SourceCode object
|
|
903
|
-
const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
|
|
904
|
-
getSource: "getText",
|
|
905
|
-
getSourceLines: "getLines",
|
|
906
|
-
getAllComments: "getAllComments",
|
|
907
|
-
getNodeByRangeIndex: "getNodeByRangeIndex",
|
|
908
|
-
getComments: "getComments",
|
|
909
|
-
getCommentsBefore: "getCommentsBefore",
|
|
910
|
-
getCommentsAfter: "getCommentsAfter",
|
|
911
|
-
getCommentsInside: "getCommentsInside",
|
|
912
|
-
getJSDocComment: "getJSDocComment",
|
|
913
|
-
getFirstToken: "getFirstToken",
|
|
914
|
-
getFirstTokens: "getFirstTokens",
|
|
915
|
-
getLastToken: "getLastToken",
|
|
916
|
-
getLastTokens: "getLastTokens",
|
|
917
|
-
getTokenAfter: "getTokenAfter",
|
|
918
|
-
getTokenBefore: "getTokenBefore",
|
|
919
|
-
getTokenByRangeStart: "getTokenByRangeStart",
|
|
920
|
-
getTokens: "getTokens",
|
|
921
|
-
getTokensAfter: "getTokensAfter",
|
|
922
|
-
getTokensBefore: "getTokensBefore",
|
|
923
|
-
getTokensBetween: "getTokensBetween"
|
|
924
|
-
};
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
928
|
-
Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).reduce(
|
|
929
|
-
(contextInfo, methodName) =>
|
|
930
|
-
Object.assign(contextInfo, {
|
|
931
|
-
[methodName](...args) {
|
|
932
|
-
return this.sourceCode[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
|
|
933
|
-
}
|
|
934
|
-
}),
|
|
935
|
-
{}
|
|
936
|
-
)
|
|
937
|
-
);
|
|
938
|
-
|
|
939
1026
|
/**
|
|
940
1027
|
* Runs the given rules on the given SourceCode object
|
|
941
1028
|
* @param {SourceCode} sourceCode A SourceCode object for the given text
|
|
942
1029
|
* @param {Object} configuredRules The rules configuration
|
|
943
|
-
* @param {function(string):
|
|
1030
|
+
* @param {function(string): RuleDefinition} ruleMapper A mapper function from rule names to rules
|
|
944
1031
|
* @param {string | undefined} parserName The name of the parser in the config
|
|
1032
|
+
* @param {Language} language The language object used for parsing.
|
|
945
1033
|
* @param {LanguageOptions} languageOptions The options for parsing the code.
|
|
946
1034
|
* @param {Object} settings The settings that were enabled in the config
|
|
947
1035
|
* @param {string} filename The reported filename of the code
|
|
948
|
-
* @param {boolean}
|
|
1036
|
+
* @param {boolean} applyDefaultOptions If true, apply rules' meta.defaultOptions in computing their config options.
|
|
949
1037
|
* @param {string | undefined} cwd cwd of the cli
|
|
950
1038
|
* @param {string} physicalFilename The full path of the file on disk without any code block information
|
|
951
|
-
* @
|
|
1039
|
+
* @param {Function} ruleFilter A predicate function to filter which rules should be executed.
|
|
1040
|
+
* @param {boolean} stats If true, stats are collected appended to the result
|
|
1041
|
+
* @param {WeakMap<Linter, LinterInternalSlots>} slots InternalSlotsMap of linter
|
|
1042
|
+
* @param {FileReport} report The report to add problems to
|
|
1043
|
+
* @returns {FileReport} report The report with added problems
|
|
1044
|
+
* @throws {Error} If traversal into a node fails.
|
|
952
1045
|
*/
|
|
953
|
-
function runRules(
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1046
|
+
function runRules(
|
|
1047
|
+
sourceCode,
|
|
1048
|
+
configuredRules,
|
|
1049
|
+
ruleMapper,
|
|
1050
|
+
parserName,
|
|
1051
|
+
language,
|
|
1052
|
+
languageOptions,
|
|
1053
|
+
settings,
|
|
1054
|
+
filename,
|
|
1055
|
+
applyDefaultOptions,
|
|
1056
|
+
cwd,
|
|
1057
|
+
physicalFilename,
|
|
1058
|
+
ruleFilter,
|
|
1059
|
+
stats,
|
|
1060
|
+
slots,
|
|
1061
|
+
report,
|
|
1062
|
+
) {
|
|
1063
|
+
const visitor = new SourceCodeVisitor();
|
|
1064
|
+
|
|
1065
|
+
/*
|
|
1066
|
+
* Create a frozen object with the ruleContext properties and methods that are shared by all rules.
|
|
1067
|
+
* All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
|
|
1068
|
+
* properties once for each rule.
|
|
1069
|
+
*/
|
|
1070
|
+
const fileContext = new FileContext({
|
|
1071
|
+
cwd,
|
|
1072
|
+
filename,
|
|
1073
|
+
physicalFilename: physicalFilename || filename,
|
|
1074
|
+
sourceCode,
|
|
1075
|
+
parserOptions: {
|
|
1076
|
+
...languageOptions.parserOptions,
|
|
1077
|
+
},
|
|
1078
|
+
parserPath: parserName,
|
|
1079
|
+
languageOptions,
|
|
1080
|
+
settings,
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
const steps = sourceCode.traverse();
|
|
1084
|
+
|
|
1085
|
+
Object.keys(configuredRules).forEach(ruleId => {
|
|
1086
|
+
const severity = Config.getRuleNumericSeverity(configuredRules[ruleId]);
|
|
1087
|
+
|
|
1088
|
+
// not load disabled rules
|
|
1089
|
+
if (severity === 0) {
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
if (ruleFilter && !ruleFilter({ ruleId, severity })) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
const rule = ruleMapper(ruleId);
|
|
1098
|
+
|
|
1099
|
+
if (!rule) {
|
|
1100
|
+
report.addError({ ruleId });
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const ruleContext = fileContext.extend({
|
|
1105
|
+
id: ruleId,
|
|
1106
|
+
options: getRuleOptions(
|
|
1107
|
+
configuredRules[ruleId],
|
|
1108
|
+
applyDefaultOptions ? rule.meta?.defaultOptions : void 0,
|
|
1109
|
+
),
|
|
1110
|
+
report(...args) {
|
|
1111
|
+
const problem = report.addRuleMessage(
|
|
1112
|
+
ruleId,
|
|
1113
|
+
severity,
|
|
1114
|
+
...args,
|
|
1115
|
+
);
|
|
1116
|
+
|
|
1117
|
+
if (problem.fix && !(rule.meta && rule.meta.fixable)) {
|
|
1118
|
+
throw new Error(
|
|
1119
|
+
'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".',
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
if (
|
|
1124
|
+
problem.suggestions &&
|
|
1125
|
+
!(rule.meta && rule.meta.hasSuggestions === true)
|
|
1126
|
+
) {
|
|
1127
|
+
if (
|
|
1128
|
+
rule.meta &&
|
|
1129
|
+
rule.meta.docs &&
|
|
1130
|
+
typeof rule.meta.docs.suggestion !== "undefined"
|
|
1131
|
+
) {
|
|
1132
|
+
// Encourage migration from the former property name.
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
"Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
throw new Error(
|
|
1138
|
+
"Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
},
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
const ruleListenersReturn =
|
|
1145
|
+
timing.enabled || stats
|
|
1146
|
+
? timing.time(
|
|
1147
|
+
ruleId,
|
|
1148
|
+
createRuleListeners,
|
|
1149
|
+
stats,
|
|
1150
|
+
)(rule, ruleContext)
|
|
1151
|
+
: createRuleListeners(rule, ruleContext);
|
|
1152
|
+
|
|
1153
|
+
const ruleListeners = stats
|
|
1154
|
+
? ruleListenersReturn.result
|
|
1155
|
+
: ruleListenersReturn;
|
|
1156
|
+
|
|
1157
|
+
if (stats) {
|
|
1158
|
+
storeTime(
|
|
1159
|
+
ruleListenersReturn.tdiff,
|
|
1160
|
+
{ type: "rules", key: ruleId },
|
|
1161
|
+
slots,
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Include `ruleId` in error logs
|
|
1167
|
+
* @param {Function} ruleListener A rule method that listens for a node.
|
|
1168
|
+
* @returns {Function} ruleListener wrapped in error handler
|
|
1169
|
+
*/
|
|
1170
|
+
function addRuleErrorHandler(ruleListener) {
|
|
1171
|
+
return function ruleErrorHandler(...listenerArgs) {
|
|
1172
|
+
try {
|
|
1173
|
+
const ruleListenerReturn = ruleListener(...listenerArgs);
|
|
1174
|
+
|
|
1175
|
+
const ruleListenerResult = stats
|
|
1176
|
+
? ruleListenerReturn.result
|
|
1177
|
+
: ruleListenerReturn;
|
|
1178
|
+
|
|
1179
|
+
if (stats) {
|
|
1180
|
+
storeTime(
|
|
1181
|
+
ruleListenerReturn.tdiff,
|
|
1182
|
+
{ type: "rules", key: ruleId },
|
|
1183
|
+
slots,
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
return ruleListenerResult;
|
|
1188
|
+
} catch (e) {
|
|
1189
|
+
e.ruleId = ruleId;
|
|
1190
|
+
throw e;
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
if (typeof ruleListeners === "undefined" || ruleListeners === null) {
|
|
1196
|
+
throw new Error(
|
|
1197
|
+
`The create() function for rule '${ruleId}' did not return an object.`,
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// add all the selectors from the rule as listeners
|
|
1202
|
+
Object.keys(ruleListeners).forEach(selector => {
|
|
1203
|
+
const ruleListener =
|
|
1204
|
+
timing.enabled || stats
|
|
1205
|
+
? timing.time(ruleId, ruleListeners[selector], stats)
|
|
1206
|
+
: ruleListeners[selector];
|
|
1207
|
+
|
|
1208
|
+
visitor.add(selector, addRuleErrorHandler(ruleListener));
|
|
1209
|
+
});
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1212
|
+
const traverser = SourceCodeTraverser.getInstance(language);
|
|
1213
|
+
|
|
1214
|
+
traverser.traverseSync(sourceCode, visitor, { steps });
|
|
1215
|
+
|
|
1216
|
+
return report;
|
|
1122
1217
|
}
|
|
1123
1218
|
|
|
1124
1219
|
/**
|
|
@@ -1127,14 +1222,14 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
|
1127
1222
|
* @returns {string} The source code text.
|
|
1128
1223
|
*/
|
|
1129
1224
|
function ensureText(textOrSourceCode) {
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1225
|
+
if (typeof textOrSourceCode === "object") {
|
|
1226
|
+
const { hasBOM, text } = textOrSourceCode;
|
|
1227
|
+
const bom = hasBOM ? "\uFEFF" : "";
|
|
1133
1228
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1229
|
+
return bom + text;
|
|
1230
|
+
}
|
|
1136
1231
|
|
|
1137
|
-
|
|
1232
|
+
return String(textOrSourceCode);
|
|
1138
1233
|
}
|
|
1139
1234
|
|
|
1140
1235
|
/**
|
|
@@ -1144,11 +1239,12 @@ function ensureText(textOrSourceCode) {
|
|
|
1144
1239
|
* @returns {Environment|null} The environment.
|
|
1145
1240
|
*/
|
|
1146
1241
|
function getEnv(slots, envId) {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1242
|
+
return (
|
|
1243
|
+
(slots.lastConfigArray &&
|
|
1244
|
+
slots.lastConfigArray.pluginEnvironments.get(envId)) ||
|
|
1245
|
+
BuiltInEnvironments.get(envId) ||
|
|
1246
|
+
null
|
|
1247
|
+
);
|
|
1152
1248
|
}
|
|
1153
1249
|
|
|
1154
1250
|
/**
|
|
@@ -1158,10 +1254,11 @@ function getEnv(slots, envId) {
|
|
|
1158
1254
|
* @returns {Rule|null} The rule.
|
|
1159
1255
|
*/
|
|
1160
1256
|
function getRule(slots, ruleId) {
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1257
|
+
return (
|
|
1258
|
+
(slots.lastConfigArray &&
|
|
1259
|
+
slots.lastConfigArray.pluginRules.get(ruleId)) ||
|
|
1260
|
+
slots.ruleMap.get(ruleId)
|
|
1261
|
+
);
|
|
1165
1262
|
}
|
|
1166
1263
|
|
|
1167
1264
|
/**
|
|
@@ -1170,16 +1267,16 @@ function getRule(slots, ruleId) {
|
|
|
1170
1267
|
* @returns {string | undefined} normalized cwd
|
|
1171
1268
|
*/
|
|
1172
1269
|
function normalizeCwd(cwd) {
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1270
|
+
if (cwd) {
|
|
1271
|
+
return cwd;
|
|
1272
|
+
}
|
|
1273
|
+
if (typeof process === "object") {
|
|
1274
|
+
return process.cwd();
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
// It's more explicit to assign the undefined
|
|
1278
|
+
// eslint-disable-next-line no-undefined -- Consistently returning a value
|
|
1279
|
+
return undefined;
|
|
1183
1280
|
}
|
|
1184
1281
|
|
|
1185
1282
|
/**
|
|
@@ -1195,14 +1292,15 @@ const internalSlotsMap = new WeakMap();
|
|
|
1195
1292
|
* @throws {Error} If the linter is in flat config mode.
|
|
1196
1293
|
*/
|
|
1197
1294
|
function assertEslintrcConfig(linter) {
|
|
1198
|
-
|
|
1295
|
+
const { configType } = internalSlotsMap.get(linter);
|
|
1199
1296
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1297
|
+
if (configType === "flat") {
|
|
1298
|
+
throw new Error(
|
|
1299
|
+
"This method cannot be used with flat config. Add your entries directly into the config array.",
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1203
1302
|
}
|
|
1204
1303
|
|
|
1205
|
-
|
|
1206
1304
|
//------------------------------------------------------------------------------
|
|
1207
1305
|
// Public Interface
|
|
1208
1306
|
//------------------------------------------------------------------------------
|
|
@@ -1212,908 +1310,1353 @@ function assertEslintrcConfig(linter) {
|
|
|
1212
1310
|
* @name Linter
|
|
1213
1311
|
*/
|
|
1214
1312
|
class Linter {
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
1313
|
+
/**
|
|
1314
|
+
* Initialize the Linter.
|
|
1315
|
+
* @param {Object} [config] the config object
|
|
1316
|
+
* @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
|
|
1317
|
+
* @param {Array<string>} [config.flags] the feature flags to enable.
|
|
1318
|
+
* @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
|
|
1319
|
+
* @param {WarningService} [config.warningService] The warning service to use.
|
|
1320
|
+
*/
|
|
1321
|
+
constructor({
|
|
1322
|
+
cwd,
|
|
1323
|
+
configType = "flat",
|
|
1324
|
+
flags = [],
|
|
1325
|
+
warningService = new WarningService(),
|
|
1326
|
+
} = {}) {
|
|
1327
|
+
const processedFlags = [];
|
|
1328
|
+
|
|
1329
|
+
flags.forEach(flag => {
|
|
1330
|
+
if (inactiveFlags.has(flag)) {
|
|
1331
|
+
const inactiveFlagData = inactiveFlags.get(flag);
|
|
1332
|
+
const inactivityReason =
|
|
1333
|
+
getInactivityReasonMessage(inactiveFlagData);
|
|
1334
|
+
const message = `The flag '${flag}' is inactive: ${inactivityReason}`;
|
|
1335
|
+
|
|
1336
|
+
if (typeof inactiveFlagData.replacedBy === "undefined") {
|
|
1337
|
+
throw new Error(message);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// if there's a replacement, enable it instead of original
|
|
1341
|
+
if (typeof inactiveFlagData.replacedBy === "string") {
|
|
1342
|
+
processedFlags.push(inactiveFlagData.replacedBy);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
warningService.emitInactiveFlagWarning(flag, message);
|
|
1346
|
+
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
if (!activeFlags.has(flag)) {
|
|
1351
|
+
throw new Error(`Unknown flag '${flag}'.`);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
processedFlags.push(flag);
|
|
1355
|
+
});
|
|
1356
|
+
|
|
1357
|
+
internalSlotsMap.set(this, {
|
|
1358
|
+
cwd: normalizeCwd(cwd),
|
|
1359
|
+
flags: processedFlags,
|
|
1360
|
+
lastConfigArray: null,
|
|
1361
|
+
lastSourceCode: null,
|
|
1362
|
+
lastSuppressedMessages: [],
|
|
1363
|
+
configType, // TODO: Remove after flat config conversion
|
|
1364
|
+
parserMap: new Map([["espree", espree]]),
|
|
1365
|
+
ruleMap: new Rules(),
|
|
1366
|
+
warningService,
|
|
1367
|
+
});
|
|
1368
|
+
|
|
1369
|
+
this.version = pkg.version;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* Getter for package version.
|
|
1374
|
+
* @static
|
|
1375
|
+
* @returns {string} The version from package.json.
|
|
1376
|
+
*/
|
|
1377
|
+
static get version() {
|
|
1378
|
+
return pkg.version;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* Indicates if the given feature flag is enabled for this instance.
|
|
1383
|
+
* @param {string} flag The feature flag to check.
|
|
1384
|
+
* @returns {boolean} `true` if the feature flag is enabled, `false` if not.
|
|
1385
|
+
*/
|
|
1386
|
+
hasFlag(flag) {
|
|
1387
|
+
return internalSlotsMap.get(this).flags.includes(flag);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/**
|
|
1391
|
+
* Lint using eslintrc and without processors.
|
|
1392
|
+
* @param {VFile} file The file to lint.
|
|
1393
|
+
* @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
|
|
1394
|
+
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
|
1395
|
+
* @throws {Error} If during rule execution.
|
|
1396
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
|
1397
|
+
*/
|
|
1398
|
+
#eslintrcVerifyWithoutProcessors(file, providedConfig, providedOptions) {
|
|
1399
|
+
const slots = internalSlotsMap.get(this);
|
|
1400
|
+
const config = providedConfig || {};
|
|
1401
|
+
const options = normalizeVerifyOptions(providedOptions, config);
|
|
1402
|
+
|
|
1403
|
+
// Resolve parser.
|
|
1404
|
+
let parserName = DEFAULT_PARSER_NAME;
|
|
1405
|
+
let parser = espree;
|
|
1406
|
+
|
|
1407
|
+
if (typeof config.parser === "object" && config.parser !== null) {
|
|
1408
|
+
parserName = config.parser.filePath;
|
|
1409
|
+
parser = config.parser.definition;
|
|
1410
|
+
} else if (typeof config.parser === "string") {
|
|
1411
|
+
if (!slots.parserMap.has(config.parser)) {
|
|
1412
|
+
return [
|
|
1413
|
+
{
|
|
1414
|
+
ruleId: null,
|
|
1415
|
+
fatal: true,
|
|
1416
|
+
severity: 2,
|
|
1417
|
+
message: `Configured parser '${config.parser}' was not found.`,
|
|
1418
|
+
line: 0,
|
|
1419
|
+
column: 0,
|
|
1420
|
+
nodeType: null,
|
|
1421
|
+
},
|
|
1422
|
+
];
|
|
1423
|
+
}
|
|
1424
|
+
parserName = config.parser;
|
|
1425
|
+
parser = slots.parserMap.get(config.parser);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// search and apply "eslint-env *".
|
|
1429
|
+
const envInFile =
|
|
1430
|
+
options.allowInlineConfig && !options.warnInlineConfig
|
|
1431
|
+
? findEslintEnv(file.body)
|
|
1432
|
+
: {};
|
|
1433
|
+
const resolvedEnvConfig = Object.assign(
|
|
1434
|
+
{ builtin: true },
|
|
1435
|
+
config.env,
|
|
1436
|
+
envInFile,
|
|
1437
|
+
);
|
|
1438
|
+
const enabledEnvs = Object.keys(resolvedEnvConfig)
|
|
1439
|
+
.filter(envName => resolvedEnvConfig[envName])
|
|
1440
|
+
.map(envName => getEnv(slots, envName))
|
|
1441
|
+
.filter(env => env);
|
|
1442
|
+
|
|
1443
|
+
const parserOptions = resolveParserOptions(
|
|
1444
|
+
parser,
|
|
1445
|
+
config.parserOptions || {},
|
|
1446
|
+
enabledEnvs,
|
|
1447
|
+
);
|
|
1448
|
+
const configuredGlobals = resolveGlobals(
|
|
1449
|
+
config.globals || {},
|
|
1450
|
+
enabledEnvs,
|
|
1451
|
+
);
|
|
1452
|
+
const settings = config.settings || {};
|
|
1453
|
+
const languageOptions = createLanguageOptions({
|
|
1454
|
+
globals: config.globals,
|
|
1455
|
+
parser,
|
|
1456
|
+
parserOptions,
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
if (!slots.lastSourceCode) {
|
|
1460
|
+
let t;
|
|
1461
|
+
|
|
1462
|
+
if (options.stats) {
|
|
1463
|
+
t = startTime();
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
const parserService = new ParserService();
|
|
1467
|
+
const parseResult = parserService.parseSync(file, {
|
|
1468
|
+
language: jslang,
|
|
1469
|
+
languageOptions,
|
|
1470
|
+
});
|
|
1471
|
+
|
|
1472
|
+
if (options.stats) {
|
|
1473
|
+
const time = endTime(t);
|
|
1474
|
+
const timeOpts = { type: "parse" };
|
|
1475
|
+
|
|
1476
|
+
storeTime(time, timeOpts, slots);
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
if (!parseResult.ok) {
|
|
1480
|
+
return parseResult.errors;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
slots.lastSourceCode = parseResult.sourceCode;
|
|
1484
|
+
} else {
|
|
1485
|
+
/*
|
|
1486
|
+
* If the given source code object as the first argument does not have scopeManager, analyze the scope.
|
|
1487
|
+
* This is for backward compatibility (SourceCode is frozen so it cannot rebind).
|
|
1488
|
+
*/
|
|
1489
|
+
if (!slots.lastSourceCode.scopeManager) {
|
|
1490
|
+
slots.lastSourceCode = new SourceCode({
|
|
1491
|
+
text: slots.lastSourceCode.text,
|
|
1492
|
+
ast: slots.lastSourceCode.ast,
|
|
1493
|
+
hasBOM: slots.lastSourceCode.hasBOM,
|
|
1494
|
+
parserServices: slots.lastSourceCode.parserServices,
|
|
1495
|
+
visitorKeys: slots.lastSourceCode.visitorKeys,
|
|
1496
|
+
scopeManager: analyzeScope(
|
|
1497
|
+
slots.lastSourceCode.ast,
|
|
1498
|
+
languageOptions,
|
|
1499
|
+
),
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
const sourceCode = slots.lastSourceCode;
|
|
1505
|
+
const report = new FileReport({
|
|
1506
|
+
ruleMapper: ruleId => getRule(slots, ruleId),
|
|
1507
|
+
language: jslang,
|
|
1508
|
+
sourceCode,
|
|
1509
|
+
disableFixes: options.disableFixes,
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
const commentDirectives = options.allowInlineConfig
|
|
1513
|
+
? getDirectiveComments(
|
|
1514
|
+
sourceCode,
|
|
1515
|
+
ruleId => getRule(slots, ruleId),
|
|
1516
|
+
options.warnInlineConfig,
|
|
1517
|
+
config,
|
|
1518
|
+
report,
|
|
1519
|
+
)
|
|
1520
|
+
: {
|
|
1521
|
+
configuredRules: {},
|
|
1522
|
+
enabledGlobals: {},
|
|
1523
|
+
exportedVariables: {},
|
|
1524
|
+
disableDirectives: [],
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1527
|
+
addDeclaredGlobals(
|
|
1528
|
+
sourceCode.scopeManager.scopes[0],
|
|
1529
|
+
configuredGlobals,
|
|
1530
|
+
{
|
|
1531
|
+
exportedVariables: commentDirectives.exportedVariables,
|
|
1532
|
+
enabledGlobals: commentDirectives.enabledGlobals,
|
|
1533
|
+
},
|
|
1534
|
+
);
|
|
1535
|
+
|
|
1536
|
+
const configuredRules = Object.assign(
|
|
1537
|
+
{},
|
|
1538
|
+
config.rules,
|
|
1539
|
+
commentDirectives.configuredRules,
|
|
1540
|
+
);
|
|
1541
|
+
|
|
1542
|
+
try {
|
|
1543
|
+
runRules(
|
|
1544
|
+
sourceCode,
|
|
1545
|
+
configuredRules,
|
|
1546
|
+
ruleId => getRule(slots, ruleId),
|
|
1547
|
+
parserName,
|
|
1548
|
+
jslang,
|
|
1549
|
+
languageOptions,
|
|
1550
|
+
settings,
|
|
1551
|
+
options.filename,
|
|
1552
|
+
true,
|
|
1553
|
+
slots.cwd,
|
|
1554
|
+
providedOptions.physicalFilename,
|
|
1555
|
+
null,
|
|
1556
|
+
options.stats,
|
|
1557
|
+
slots,
|
|
1558
|
+
report,
|
|
1559
|
+
);
|
|
1560
|
+
} catch (err) {
|
|
1561
|
+
err.message += `\nOccurred while linting ${options.filename}`;
|
|
1562
|
+
debug("An error occurred while traversing");
|
|
1563
|
+
debug("Filename:", options.filename);
|
|
1564
|
+
if (err.currentNode) {
|
|
1565
|
+
const { line } = sourceCode.getLoc(err.currentNode).start;
|
|
1566
|
+
|
|
1567
|
+
debug("Line:", line);
|
|
1568
|
+
err.message += `:${line}`;
|
|
1569
|
+
}
|
|
1570
|
+
debug("Parser Options:", parserOptions);
|
|
1571
|
+
debug("Parser Path:", parserName);
|
|
1572
|
+
debug("Settings:", settings);
|
|
1573
|
+
|
|
1574
|
+
if (err.ruleId) {
|
|
1575
|
+
err.message += `\nRule: "${err.ruleId}"`;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
throw err;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
return applyDisableDirectives({
|
|
1582
|
+
language: jslang,
|
|
1583
|
+
sourceCode,
|
|
1584
|
+
directives: commentDirectives.disableDirectives,
|
|
1585
|
+
disableFixes: options.disableFixes,
|
|
1586
|
+
problems: report.messages.sort(
|
|
1587
|
+
(problemA, problemB) =>
|
|
1588
|
+
problemA.line - problemB.line ||
|
|
1589
|
+
problemA.column - problemB.column,
|
|
1590
|
+
),
|
|
1591
|
+
reportUnusedDisableDirectives:
|
|
1592
|
+
options.reportUnusedDisableDirectives,
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* Same as linter.verify, except without support for processors.
|
|
1598
|
+
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
|
1599
|
+
* @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
|
|
1600
|
+
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
|
1601
|
+
* @throws {Error} If during rule execution.
|
|
1602
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
|
1603
|
+
*/
|
|
1604
|
+
_verifyWithoutProcessors(
|
|
1605
|
+
textOrSourceCode,
|
|
1606
|
+
providedConfig,
|
|
1607
|
+
providedOptions,
|
|
1608
|
+
) {
|
|
1609
|
+
const slots = internalSlotsMap.get(this);
|
|
1610
|
+
const filename = normalizeFilename(
|
|
1611
|
+
providedOptions.filename || "<input>",
|
|
1612
|
+
);
|
|
1613
|
+
let text;
|
|
1614
|
+
|
|
1615
|
+
// evaluate arguments
|
|
1616
|
+
if (typeof textOrSourceCode === "string") {
|
|
1617
|
+
slots.lastSourceCode = null;
|
|
1618
|
+
text = textOrSourceCode;
|
|
1619
|
+
} else {
|
|
1620
|
+
slots.lastSourceCode = textOrSourceCode;
|
|
1621
|
+
text = textOrSourceCode.text;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
const file = new VFile(filename, text, {
|
|
1625
|
+
physicalPath: providedOptions.physicalFilename,
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1628
|
+
return this.#eslintrcVerifyWithoutProcessors(
|
|
1629
|
+
file,
|
|
1630
|
+
providedConfig,
|
|
1631
|
+
providedOptions,
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Verifies the text against the rules specified by the second argument.
|
|
1637
|
+
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
|
1638
|
+
* @param {ConfigData|ConfigArray} config An ESLintConfig instance to configure everything.
|
|
1639
|
+
* @param {(string|(VerifyOptions&ProcessorOptions))} [filenameOrOptions] The optional filename of the file being checked.
|
|
1640
|
+
* If this is not set, the filename will default to '<input>' in the rule context. If
|
|
1641
|
+
* an object, then it has "filename", "allowInlineConfig", and some properties.
|
|
1642
|
+
* @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
|
|
1643
|
+
*/
|
|
1644
|
+
verify(textOrSourceCode, config, filenameOrOptions) {
|
|
1645
|
+
debug("Verify");
|
|
1646
|
+
|
|
1647
|
+
const { configType, cwd } = internalSlotsMap.get(this);
|
|
1648
|
+
|
|
1649
|
+
const options =
|
|
1650
|
+
typeof filenameOrOptions === "string"
|
|
1651
|
+
? { filename: filenameOrOptions }
|
|
1652
|
+
: filenameOrOptions || {};
|
|
1653
|
+
|
|
1654
|
+
const configToUse = config ?? {};
|
|
1655
|
+
|
|
1656
|
+
if (configType !== "eslintrc") {
|
|
1657
|
+
/*
|
|
1658
|
+
* Because of how Webpack packages up the files, we can't
|
|
1659
|
+
* compare directly to `FlatConfigArray` using `instanceof`
|
|
1660
|
+
* because it's not the same `FlatConfigArray` as in the tests.
|
|
1661
|
+
* So, we work around it by assuming an array is, in fact, a
|
|
1662
|
+
* `FlatConfigArray` if it has a `getConfig()` method.
|
|
1663
|
+
*/
|
|
1664
|
+
let configArray = configToUse;
|
|
1665
|
+
|
|
1666
|
+
if (
|
|
1667
|
+
!Array.isArray(configToUse) ||
|
|
1668
|
+
typeof configToUse.getConfig !== "function"
|
|
1669
|
+
) {
|
|
1670
|
+
configArray = new FlatConfigArray(configToUse, {
|
|
1671
|
+
basePath: cwd,
|
|
1672
|
+
});
|
|
1673
|
+
configArray.normalizeSync();
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
return this._distinguishSuppressedMessages(
|
|
1677
|
+
this._verifyWithFlatConfigArray(
|
|
1678
|
+
textOrSourceCode,
|
|
1679
|
+
configArray,
|
|
1680
|
+
options,
|
|
1681
|
+
true,
|
|
1682
|
+
),
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
if (typeof configToUse.extractConfig === "function") {
|
|
1687
|
+
return this._distinguishSuppressedMessages(
|
|
1688
|
+
this._verifyWithConfigArray(
|
|
1689
|
+
textOrSourceCode,
|
|
1690
|
+
configToUse,
|
|
1691
|
+
options,
|
|
1692
|
+
),
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
/*
|
|
1697
|
+
* If we get to here, it means `config` is just an object rather
|
|
1698
|
+
* than a config array so we can go right into linting.
|
|
1699
|
+
*/
|
|
1700
|
+
|
|
1701
|
+
/*
|
|
1702
|
+
* `Linter` doesn't support `overrides` property in configuration.
|
|
1703
|
+
* So we cannot apply multiple processors.
|
|
1704
|
+
*/
|
|
1705
|
+
if (options.preprocess || options.postprocess) {
|
|
1706
|
+
return this._distinguishSuppressedMessages(
|
|
1707
|
+
this._verifyWithProcessor(
|
|
1708
|
+
textOrSourceCode,
|
|
1709
|
+
configToUse,
|
|
1710
|
+
options,
|
|
1711
|
+
),
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
return this._distinguishSuppressedMessages(
|
|
1715
|
+
this._verifyWithoutProcessors(
|
|
1716
|
+
textOrSourceCode,
|
|
1717
|
+
configToUse,
|
|
1718
|
+
options,
|
|
1719
|
+
),
|
|
1720
|
+
);
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Verify with a processor.
|
|
1725
|
+
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
1726
|
+
* @param {Config} config The config array.
|
|
1727
|
+
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
1728
|
+
* @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
|
|
1729
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
1730
|
+
*/
|
|
1731
|
+
_verifyWithFlatConfigArrayAndProcessor(
|
|
1732
|
+
textOrSourceCode,
|
|
1733
|
+
config,
|
|
1734
|
+
options,
|
|
1735
|
+
configForRecursive,
|
|
1736
|
+
) {
|
|
1737
|
+
const slots = internalSlotsMap.get(this);
|
|
1738
|
+
const filename = options.filename || "<input>";
|
|
1739
|
+
const filenameToExpose = normalizeFilename(filename);
|
|
1740
|
+
const physicalFilename = options.physicalFilename || filenameToExpose;
|
|
1741
|
+
const text = ensureText(textOrSourceCode);
|
|
1742
|
+
const file = new VFile(filenameToExpose, text, {
|
|
1743
|
+
physicalPath: physicalFilename,
|
|
1744
|
+
});
|
|
1745
|
+
|
|
1746
|
+
const preprocess = options.preprocess || (rawText => [rawText]);
|
|
1747
|
+
const postprocess =
|
|
1748
|
+
options.postprocess || (messagesList => messagesList.flat());
|
|
1749
|
+
|
|
1750
|
+
const processorService = new ProcessorService();
|
|
1751
|
+
const preprocessResult = processorService.preprocessSync(file, {
|
|
1752
|
+
processor: {
|
|
1753
|
+
preprocess,
|
|
1754
|
+
postprocess,
|
|
1755
|
+
},
|
|
1756
|
+
});
|
|
1757
|
+
|
|
1758
|
+
if (!preprocessResult.ok) {
|
|
1759
|
+
return preprocessResult.errors;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
const filterCodeBlock =
|
|
1763
|
+
options.filterCodeBlock ||
|
|
1764
|
+
(blockFilename => blockFilename.endsWith(".js"));
|
|
1765
|
+
const originalExtname = path.extname(filename);
|
|
1766
|
+
const { files } = preprocessResult;
|
|
1767
|
+
|
|
1768
|
+
const messageLists = files.map(block => {
|
|
1769
|
+
debug("A code block was found: %o", block.path || "(unnamed)");
|
|
1770
|
+
|
|
1771
|
+
// Keep the legacy behavior.
|
|
1772
|
+
if (typeof block === "string") {
|
|
1773
|
+
return this._verifyWithFlatConfigArrayAndWithoutProcessors(
|
|
1774
|
+
block,
|
|
1775
|
+
config,
|
|
1776
|
+
options,
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
// Skip this block if filtered.
|
|
1781
|
+
if (!filterCodeBlock(block.path, block.body)) {
|
|
1782
|
+
debug("This code block was skipped.");
|
|
1783
|
+
return [];
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// Resolve configuration again if the file content or extension was changed.
|
|
1787
|
+
if (
|
|
1788
|
+
configForRecursive &&
|
|
1789
|
+
(text !== block.rawBody ||
|
|
1790
|
+
path.extname(block.path) !== originalExtname)
|
|
1791
|
+
) {
|
|
1792
|
+
debug(
|
|
1793
|
+
"Resolving configuration again because the file content or extension was changed.",
|
|
1794
|
+
);
|
|
1795
|
+
return this._verifyWithFlatConfigArray(
|
|
1796
|
+
block.rawBody,
|
|
1797
|
+
configForRecursive,
|
|
1798
|
+
{
|
|
1799
|
+
...options,
|
|
1800
|
+
filename: block.path,
|
|
1801
|
+
physicalFilename: block.physicalPath,
|
|
1802
|
+
},
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
slots.lastSourceCode = null;
|
|
1807
|
+
|
|
1808
|
+
// Does lint.
|
|
1809
|
+
return this.#flatVerifyWithoutProcessors(block, config, {
|
|
1810
|
+
...options,
|
|
1811
|
+
filename: block.path,
|
|
1812
|
+
physicalFilename: block.physicalPath,
|
|
1813
|
+
});
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
return processorService.postprocessSync(file, messageLists, {
|
|
1817
|
+
processor: {
|
|
1818
|
+
preprocess,
|
|
1819
|
+
postprocess,
|
|
1820
|
+
},
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* Verify using flat config and without any processors.
|
|
1826
|
+
* @param {VFile} file The file to lint.
|
|
1827
|
+
* @param {Config} providedConfig An ESLintConfig instance to configure everything.
|
|
1828
|
+
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
|
1829
|
+
* @throws {Error} If during rule execution.
|
|
1830
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
|
1831
|
+
*/
|
|
1832
|
+
#flatVerifyWithoutProcessors(file, providedConfig, providedOptions) {
|
|
1833
|
+
const slots = internalSlotsMap.get(this);
|
|
1834
|
+
const config = providedConfig || {};
|
|
1835
|
+
const { settings = {}, languageOptions } = config;
|
|
1836
|
+
const options = normalizeVerifyOptions(providedOptions, config);
|
|
1837
|
+
|
|
1838
|
+
if (!slots.lastSourceCode) {
|
|
1839
|
+
let t;
|
|
1840
|
+
|
|
1841
|
+
if (options.stats) {
|
|
1842
|
+
t = startTime();
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
const parserService = new ParserService();
|
|
1846
|
+
const parseResult = parserService.parseSync(file, config);
|
|
1847
|
+
|
|
1848
|
+
if (options.stats) {
|
|
1849
|
+
const time = endTime(t);
|
|
1850
|
+
|
|
1851
|
+
storeTime(time, { type: "parse" }, slots);
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
if (!parseResult.ok) {
|
|
1855
|
+
return parseResult.errors;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
slots.lastSourceCode = parseResult.sourceCode;
|
|
1859
|
+
} else {
|
|
1860
|
+
/*
|
|
1861
|
+
* If the given source code object as the first argument does not have scopeManager, analyze the scope.
|
|
1862
|
+
* This is for backward compatibility (SourceCode is frozen so it cannot rebind).
|
|
1863
|
+
*
|
|
1864
|
+
* We check explicitly for `null` to ensure that this is a JS-flavored language.
|
|
1865
|
+
* For non-JS languages we don't want to do this.
|
|
1866
|
+
*
|
|
1867
|
+
* TODO: Remove this check when we stop exporting the `SourceCode` object.
|
|
1868
|
+
*/
|
|
1869
|
+
if (slots.lastSourceCode.scopeManager === null) {
|
|
1870
|
+
slots.lastSourceCode = new SourceCode({
|
|
1871
|
+
text: slots.lastSourceCode.text,
|
|
1872
|
+
ast: slots.lastSourceCode.ast,
|
|
1873
|
+
hasBOM: slots.lastSourceCode.hasBOM,
|
|
1874
|
+
parserServices: slots.lastSourceCode.parserServices,
|
|
1875
|
+
visitorKeys: slots.lastSourceCode.visitorKeys,
|
|
1876
|
+
scopeManager: analyzeScope(
|
|
1877
|
+
slots.lastSourceCode.ast,
|
|
1878
|
+
languageOptions,
|
|
1879
|
+
),
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
const sourceCode = slots.lastSourceCode;
|
|
1885
|
+
const report = new FileReport({
|
|
1886
|
+
ruleMapper: ruleId => config.getRuleDefinition(ruleId),
|
|
1887
|
+
language: config.language,
|
|
1888
|
+
sourceCode,
|
|
1889
|
+
disableFixes: options.disableFixes,
|
|
1890
|
+
});
|
|
1891
|
+
|
|
1892
|
+
/*
|
|
1893
|
+
* Make adjustments based on the language options. For JavaScript,
|
|
1894
|
+
* this is primarily about adding variables into the global scope
|
|
1895
|
+
* to account for ecmaVersion and configured globals.
|
|
1896
|
+
*/
|
|
1897
|
+
sourceCode.applyLanguageOptions?.(languageOptions);
|
|
1898
|
+
|
|
1899
|
+
const mergedInlineConfig = {
|
|
1900
|
+
rules: {},
|
|
1901
|
+
};
|
|
1902
|
+
|
|
1903
|
+
/*
|
|
1904
|
+
* Inline config can be either enabled or disabled. If disabled, it's possible
|
|
1905
|
+
* to detect the inline config and emit a warning (though this is not required).
|
|
1906
|
+
* So we first check to see if inline config is allowed at all, and if so, we
|
|
1907
|
+
* need to check if it's a warning or not.
|
|
1908
|
+
*/
|
|
1909
|
+
if (options.allowInlineConfig) {
|
|
1910
|
+
// if inline config should warn then add the warnings
|
|
1911
|
+
if (options.warnInlineConfig) {
|
|
1912
|
+
if (sourceCode.getInlineConfigNodes) {
|
|
1913
|
+
sourceCode.getInlineConfigNodes().forEach(node => {
|
|
1914
|
+
const loc = sourceCode.getLoc(node);
|
|
1915
|
+
const range = sourceCode.getRange(node);
|
|
1916
|
+
|
|
1917
|
+
report.addWarning({
|
|
1918
|
+
message: `'${sourceCode.text.slice(range[0], range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`,
|
|
1919
|
+
loc,
|
|
1920
|
+
});
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
} else {
|
|
1924
|
+
const inlineConfigResult = sourceCode.applyInlineConfig?.();
|
|
1925
|
+
|
|
1926
|
+
if (inlineConfigResult) {
|
|
1927
|
+
inlineConfigResult.problems.forEach(problem => {
|
|
1928
|
+
report.addFatal(problem);
|
|
1929
|
+
});
|
|
1930
|
+
|
|
1931
|
+
for (const {
|
|
1932
|
+
config: inlineConfig,
|
|
1933
|
+
loc,
|
|
1934
|
+
} of inlineConfigResult.configs) {
|
|
1935
|
+
Object.keys(inlineConfig.rules).forEach(ruleId => {
|
|
1936
|
+
const rule = config.getRuleDefinition(ruleId);
|
|
1937
|
+
const ruleValue = inlineConfig.rules[ruleId];
|
|
1938
|
+
|
|
1939
|
+
if (!rule) {
|
|
1940
|
+
report.addError({
|
|
1941
|
+
ruleId,
|
|
1942
|
+
loc,
|
|
1943
|
+
});
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
if (
|
|
1948
|
+
Object.hasOwn(mergedInlineConfig.rules, ruleId)
|
|
1949
|
+
) {
|
|
1950
|
+
report.addError({
|
|
1951
|
+
message: `Rule "${ruleId}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
|
|
1952
|
+
loc,
|
|
1953
|
+
});
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
try {
|
|
1958
|
+
const ruleOptionsInline = asArray(ruleValue);
|
|
1959
|
+
let ruleOptions = ruleOptionsInline;
|
|
1960
|
+
|
|
1961
|
+
assertIsRuleSeverity(ruleId, ruleOptions[0]);
|
|
1962
|
+
|
|
1963
|
+
/*
|
|
1964
|
+
* If the rule was already configured, inline rule configuration that
|
|
1965
|
+
* only has severity should retain options from the config and just override the severity.
|
|
1966
|
+
*
|
|
1967
|
+
* Example:
|
|
1968
|
+
*
|
|
1969
|
+
* {
|
|
1970
|
+
* rules: {
|
|
1971
|
+
* curly: ["error", "multi"]
|
|
1972
|
+
* }
|
|
1973
|
+
* }
|
|
1974
|
+
*
|
|
1975
|
+
* /* eslint curly: ["warn"] * /
|
|
1976
|
+
*
|
|
1977
|
+
* Results in:
|
|
1978
|
+
*
|
|
1979
|
+
* curly: ["warn", "multi"]
|
|
1980
|
+
*/
|
|
1981
|
+
|
|
1982
|
+
let shouldValidateOptions = true;
|
|
1983
|
+
|
|
1984
|
+
if (
|
|
1985
|
+
/*
|
|
1986
|
+
* If inline config for the rule has only severity
|
|
1987
|
+
*/
|
|
1988
|
+
ruleOptions.length === 1 &&
|
|
1989
|
+
/*
|
|
1990
|
+
* And the rule was already configured
|
|
1991
|
+
*/
|
|
1992
|
+
config.rules &&
|
|
1993
|
+
Object.hasOwn(config.rules, ruleId)
|
|
1994
|
+
) {
|
|
1995
|
+
/*
|
|
1996
|
+
* Then use severity from the inline config and options from the provided config
|
|
1997
|
+
*/
|
|
1998
|
+
ruleOptions = [
|
|
1999
|
+
ruleOptions[0], // severity from the inline config
|
|
2000
|
+
...config.rules[ruleId].slice(1), // options from the provided config
|
|
2001
|
+
];
|
|
2002
|
+
|
|
2003
|
+
// if the rule was enabled, the options have already been validated
|
|
2004
|
+
if (config.rules[ruleId][0] > 0) {
|
|
2005
|
+
shouldValidateOptions = false;
|
|
2006
|
+
}
|
|
2007
|
+
} else {
|
|
2008
|
+
/**
|
|
2009
|
+
* Since we know the user provided options, apply defaults on top of them
|
|
2010
|
+
*/
|
|
2011
|
+
const slicedOptions = ruleOptions.slice(1);
|
|
2012
|
+
const mergedOptions = deepMergeArrays(
|
|
2013
|
+
rule.meta?.defaultOptions,
|
|
2014
|
+
slicedOptions,
|
|
2015
|
+
);
|
|
2016
|
+
|
|
2017
|
+
if (mergedOptions.length) {
|
|
2018
|
+
ruleOptions = [
|
|
2019
|
+
ruleOptions[0],
|
|
2020
|
+
...mergedOptions,
|
|
2021
|
+
];
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
if (
|
|
2026
|
+
options.reportUnusedInlineConfigs !== "off"
|
|
2027
|
+
) {
|
|
2028
|
+
addProblemIfSameSeverityAndOptions(
|
|
2029
|
+
config,
|
|
2030
|
+
loc,
|
|
2031
|
+
report,
|
|
2032
|
+
ruleId,
|
|
2033
|
+
ruleOptions,
|
|
2034
|
+
ruleOptionsInline,
|
|
2035
|
+
options.reportUnusedInlineConfigs,
|
|
2036
|
+
);
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
if (shouldValidateOptions) {
|
|
2040
|
+
config.validateRulesConfig({
|
|
2041
|
+
[ruleId]: ruleOptions,
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
mergedInlineConfig.rules[ruleId] = ruleOptions;
|
|
2046
|
+
} catch (err) {
|
|
2047
|
+
/*
|
|
2048
|
+
* If the rule has invalid `meta.schema`, throw the error because
|
|
2049
|
+
* this is not an invalid inline configuration but an invalid rule.
|
|
2050
|
+
*/
|
|
2051
|
+
if (
|
|
2052
|
+
err.code ===
|
|
2053
|
+
"ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
|
|
2054
|
+
) {
|
|
2055
|
+
throw err;
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
let baseMessage = err.message
|
|
2059
|
+
.slice(
|
|
2060
|
+
err.message.startsWith('Key "rules":')
|
|
2061
|
+
? err.message.indexOf(":", 12) + 1
|
|
2062
|
+
: err.message.indexOf(":") + 1,
|
|
2063
|
+
)
|
|
2064
|
+
.trim();
|
|
2065
|
+
|
|
2066
|
+
if (err.messageTemplate) {
|
|
2067
|
+
baseMessage += ` You passed "${ruleValue}".`;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
report.addError({
|
|
2071
|
+
ruleId,
|
|
2072
|
+
message: `Inline configuration for rule "${ruleId}" is invalid:\n\t${baseMessage}\n`,
|
|
2073
|
+
loc,
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
const commentDirectives =
|
|
2083
|
+
options.allowInlineConfig && !options.warnInlineConfig
|
|
2084
|
+
? getDirectiveCommentsForFlatConfig(
|
|
2085
|
+
sourceCode,
|
|
2086
|
+
ruleId => config.getRuleDefinition(ruleId),
|
|
2087
|
+
config.language,
|
|
2088
|
+
report,
|
|
2089
|
+
)
|
|
2090
|
+
: [];
|
|
2091
|
+
|
|
2092
|
+
const configuredRules = Object.assign(
|
|
2093
|
+
{},
|
|
2094
|
+
config.rules,
|
|
2095
|
+
mergedInlineConfig.rules,
|
|
2096
|
+
);
|
|
2097
|
+
|
|
2098
|
+
sourceCode.finalize?.();
|
|
2099
|
+
|
|
2100
|
+
try {
|
|
2101
|
+
runRules(
|
|
2102
|
+
sourceCode,
|
|
2103
|
+
configuredRules,
|
|
2104
|
+
ruleId => config.getRuleDefinition(ruleId),
|
|
2105
|
+
void 0,
|
|
2106
|
+
config.language,
|
|
2107
|
+
languageOptions,
|
|
2108
|
+
settings,
|
|
2109
|
+
options.filename,
|
|
2110
|
+
false,
|
|
2111
|
+
slots.cwd,
|
|
2112
|
+
providedOptions.physicalFilename,
|
|
2113
|
+
options.ruleFilter,
|
|
2114
|
+
options.stats,
|
|
2115
|
+
slots,
|
|
2116
|
+
report,
|
|
2117
|
+
);
|
|
2118
|
+
} catch (err) {
|
|
2119
|
+
err.message += `\nOccurred while linting ${options.filename}`;
|
|
2120
|
+
debug("An error occurred while traversing");
|
|
2121
|
+
debug("Filename:", options.filename);
|
|
2122
|
+
if (err.currentNode) {
|
|
2123
|
+
const { line } = sourceCode.getLoc(err.currentNode).start;
|
|
2124
|
+
|
|
2125
|
+
debug("Line:", line);
|
|
2126
|
+
err.message += `:${line}`;
|
|
2127
|
+
}
|
|
2128
|
+
debug("Parser Options:", languageOptions.parserOptions);
|
|
2129
|
+
|
|
2130
|
+
// debug("Parser Path:", parserName);
|
|
2131
|
+
debug("Settings:", settings);
|
|
2132
|
+
|
|
2133
|
+
if (err.ruleId) {
|
|
2134
|
+
err.message += `\nRule: "${err.ruleId}"`;
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
throw err;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
return applyDisableDirectives({
|
|
2141
|
+
language: config.language,
|
|
2142
|
+
sourceCode,
|
|
2143
|
+
directives: commentDirectives,
|
|
2144
|
+
disableFixes: options.disableFixes,
|
|
2145
|
+
problems: report.messages.sort(
|
|
2146
|
+
(problemA, problemB) =>
|
|
2147
|
+
problemA.line - problemB.line ||
|
|
2148
|
+
problemA.column - problemB.column,
|
|
2149
|
+
),
|
|
2150
|
+
reportUnusedDisableDirectives:
|
|
2151
|
+
options.reportUnusedDisableDirectives,
|
|
2152
|
+
ruleFilter: options.ruleFilter,
|
|
2153
|
+
configuredRules,
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
/**
|
|
2158
|
+
* Same as linter.verify, except without support for processors.
|
|
2159
|
+
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
|
2160
|
+
* @param {Config} providedConfig An ESLintConfig instance to configure everything.
|
|
2161
|
+
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
|
2162
|
+
* @throws {Error} If during rule execution.
|
|
2163
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
|
2164
|
+
*/
|
|
2165
|
+
_verifyWithFlatConfigArrayAndWithoutProcessors(
|
|
2166
|
+
textOrSourceCode,
|
|
2167
|
+
providedConfig,
|
|
2168
|
+
providedOptions,
|
|
2169
|
+
) {
|
|
2170
|
+
const slots = internalSlotsMap.get(this);
|
|
2171
|
+
const filename = normalizeFilename(
|
|
2172
|
+
providedOptions.filename || "<input>",
|
|
2173
|
+
);
|
|
2174
|
+
let text;
|
|
2175
|
+
|
|
2176
|
+
// evaluate arguments
|
|
2177
|
+
if (typeof textOrSourceCode === "string") {
|
|
2178
|
+
slots.lastSourceCode = null;
|
|
2179
|
+
text = textOrSourceCode;
|
|
2180
|
+
} else {
|
|
2181
|
+
slots.lastSourceCode = textOrSourceCode;
|
|
2182
|
+
text = textOrSourceCode.text;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
const file = new VFile(filename, text, {
|
|
2186
|
+
physicalPath: providedOptions.physicalFilename,
|
|
2187
|
+
});
|
|
2188
|
+
|
|
2189
|
+
return this.#flatVerifyWithoutProcessors(
|
|
2190
|
+
file,
|
|
2191
|
+
providedConfig,
|
|
2192
|
+
providedOptions,
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
/**
|
|
2197
|
+
* Verify a given code with `ConfigArray`.
|
|
2198
|
+
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
2199
|
+
* @param {ConfigArray} configArray The config array.
|
|
2200
|
+
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
2201
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
2202
|
+
*/
|
|
2203
|
+
_verifyWithConfigArray(textOrSourceCode, configArray, options) {
|
|
2204
|
+
debug("With ConfigArray: %s", options.filename);
|
|
2205
|
+
|
|
2206
|
+
// Store the config array in order to get plugin envs and rules later.
|
|
2207
|
+
internalSlotsMap.get(this).lastConfigArray = configArray;
|
|
2208
|
+
|
|
2209
|
+
// Extract the final config for this file.
|
|
2210
|
+
const config = configArray.extractConfig(options.filename);
|
|
2211
|
+
const processor =
|
|
2212
|
+
config.processor &&
|
|
2213
|
+
configArray.pluginProcessors.get(config.processor);
|
|
2214
|
+
|
|
2215
|
+
// Verify.
|
|
2216
|
+
if (processor) {
|
|
2217
|
+
debug("Apply the processor: %o", config.processor);
|
|
2218
|
+
const { preprocess, postprocess, supportsAutofix } = processor;
|
|
2219
|
+
const disableFixes = options.disableFixes || !supportsAutofix;
|
|
2220
|
+
|
|
2221
|
+
return this._verifyWithProcessor(
|
|
2222
|
+
textOrSourceCode,
|
|
2223
|
+
config,
|
|
2224
|
+
{ ...options, disableFixes, postprocess, preprocess },
|
|
2225
|
+
configArray,
|
|
2226
|
+
);
|
|
2227
|
+
}
|
|
2228
|
+
return this._verifyWithoutProcessors(textOrSourceCode, config, options);
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
/**
|
|
2232
|
+
* Verify a given code with a flat config.
|
|
2233
|
+
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
2234
|
+
* @param {FlatConfigArray} configArray The config array.
|
|
2235
|
+
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
2236
|
+
* @param {boolean} [firstCall=false] Indicates if this is being called directly
|
|
2237
|
+
* from verify(). (TODO: Remove once eslintrc is removed.)
|
|
2238
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
2239
|
+
*/
|
|
2240
|
+
_verifyWithFlatConfigArray(
|
|
2241
|
+
textOrSourceCode,
|
|
2242
|
+
configArray,
|
|
2243
|
+
options,
|
|
2244
|
+
firstCall = false,
|
|
2245
|
+
) {
|
|
2246
|
+
debug("With flat config: %s", options.filename);
|
|
2247
|
+
|
|
2248
|
+
// we need a filename to match configs against
|
|
2249
|
+
const filename = options.filename || "__placeholder__.js";
|
|
2250
|
+
|
|
2251
|
+
// Store the config array in order to get plugin envs and rules later.
|
|
2252
|
+
internalSlotsMap.get(this).lastConfigArray = configArray;
|
|
2253
|
+
const config = configArray.getConfig(filename);
|
|
2254
|
+
|
|
2255
|
+
if (!config) {
|
|
2256
|
+
return [
|
|
2257
|
+
{
|
|
2258
|
+
ruleId: null,
|
|
2259
|
+
severity: 1,
|
|
2260
|
+
message: `No matching configuration found for ${filename}.`,
|
|
2261
|
+
line: 0,
|
|
2262
|
+
column: 0,
|
|
2263
|
+
nodeType: null,
|
|
2264
|
+
},
|
|
2265
|
+
];
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
// Verify.
|
|
2269
|
+
if (config.processor) {
|
|
2270
|
+
debug("Apply the processor: %o", config.processor);
|
|
2271
|
+
const { preprocess, postprocess, supportsAutofix } =
|
|
2272
|
+
config.processor;
|
|
2273
|
+
const disableFixes = options.disableFixes || !supportsAutofix;
|
|
2274
|
+
|
|
2275
|
+
return this._verifyWithFlatConfigArrayAndProcessor(
|
|
2276
|
+
textOrSourceCode,
|
|
2277
|
+
config,
|
|
2278
|
+
{ ...options, filename, disableFixes, postprocess, preprocess },
|
|
2279
|
+
configArray,
|
|
2280
|
+
);
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
// check for options-based processing
|
|
2284
|
+
if (firstCall && (options.preprocess || options.postprocess)) {
|
|
2285
|
+
return this._verifyWithFlatConfigArrayAndProcessor(
|
|
2286
|
+
textOrSourceCode,
|
|
2287
|
+
config,
|
|
2288
|
+
options,
|
|
2289
|
+
);
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
return this._verifyWithFlatConfigArrayAndWithoutProcessors(
|
|
2293
|
+
textOrSourceCode,
|
|
2294
|
+
config,
|
|
2295
|
+
options,
|
|
2296
|
+
);
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
/**
|
|
2300
|
+
* Verify with a processor.
|
|
2301
|
+
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
2302
|
+
* @param {ConfigData|ExtractedConfig} config The config array.
|
|
2303
|
+
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
2304
|
+
* @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
|
|
2305
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
2306
|
+
*/
|
|
2307
|
+
_verifyWithProcessor(
|
|
2308
|
+
textOrSourceCode,
|
|
2309
|
+
config,
|
|
2310
|
+
options,
|
|
2311
|
+
configForRecursive,
|
|
2312
|
+
) {
|
|
2313
|
+
const slots = internalSlotsMap.get(this);
|
|
2314
|
+
const filename = options.filename || "<input>";
|
|
2315
|
+
const filenameToExpose = normalizeFilename(filename);
|
|
2316
|
+
const physicalFilename = options.physicalFilename || filenameToExpose;
|
|
2317
|
+
const text = ensureText(textOrSourceCode);
|
|
2318
|
+
const file = new VFile(filenameToExpose, text, {
|
|
2319
|
+
physicalPath: physicalFilename,
|
|
2320
|
+
});
|
|
2321
|
+
|
|
2322
|
+
const preprocess = options.preprocess || (rawText => [rawText]);
|
|
2323
|
+
const postprocess =
|
|
2324
|
+
options.postprocess || (messagesList => messagesList.flat());
|
|
2325
|
+
|
|
2326
|
+
const processorService = new ProcessorService();
|
|
2327
|
+
const preprocessResult = processorService.preprocessSync(file, {
|
|
2328
|
+
processor: {
|
|
2329
|
+
preprocess,
|
|
2330
|
+
postprocess,
|
|
2331
|
+
},
|
|
2332
|
+
});
|
|
2333
|
+
|
|
2334
|
+
if (!preprocessResult.ok) {
|
|
2335
|
+
return preprocessResult.errors;
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
const filterCodeBlock =
|
|
2339
|
+
options.filterCodeBlock ||
|
|
2340
|
+
(blockFilePath => blockFilePath.endsWith(".js"));
|
|
2341
|
+
const originalExtname = path.extname(filename);
|
|
2342
|
+
|
|
2343
|
+
const { files } = preprocessResult;
|
|
2344
|
+
|
|
2345
|
+
const messageLists = files.map(block => {
|
|
2346
|
+
debug("A code block was found: %o", block.path ?? "(unnamed)");
|
|
2347
|
+
|
|
2348
|
+
// Keep the legacy behavior.
|
|
2349
|
+
if (typeof block === "string") {
|
|
2350
|
+
return this._verifyWithoutProcessors(block, config, options);
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
// Skip this block if filtered.
|
|
2354
|
+
if (!filterCodeBlock(block.path, block.body)) {
|
|
2355
|
+
debug("This code block was skipped.");
|
|
2356
|
+
return [];
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// Resolve configuration again if the file content or extension was changed.
|
|
2360
|
+
if (
|
|
2361
|
+
configForRecursive &&
|
|
2362
|
+
(text !== block.rawBody ||
|
|
2363
|
+
path.extname(block.path) !== originalExtname)
|
|
2364
|
+
) {
|
|
2365
|
+
debug(
|
|
2366
|
+
"Resolving configuration again because the file content or extension was changed.",
|
|
2367
|
+
);
|
|
2368
|
+
return this._verifyWithConfigArray(
|
|
2369
|
+
block.rawBody,
|
|
2370
|
+
configForRecursive,
|
|
2371
|
+
{
|
|
2372
|
+
...options,
|
|
2373
|
+
filename: block.path,
|
|
2374
|
+
physicalFilename: block.physicalPath,
|
|
2375
|
+
},
|
|
2376
|
+
);
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
slots.lastSourceCode = null;
|
|
2380
|
+
|
|
2381
|
+
// Does lint.
|
|
2382
|
+
return this.#eslintrcVerifyWithoutProcessors(block, config, {
|
|
2383
|
+
...options,
|
|
2384
|
+
filename: block.path,
|
|
2385
|
+
physicalFilename: block.physicalPath,
|
|
2386
|
+
});
|
|
2387
|
+
});
|
|
2388
|
+
|
|
2389
|
+
return processorService.postprocessSync(file, messageLists, {
|
|
2390
|
+
processor: {
|
|
2391
|
+
preprocess,
|
|
2392
|
+
postprocess,
|
|
2393
|
+
},
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
/**
|
|
2398
|
+
* Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
|
|
2399
|
+
* The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
|
|
2400
|
+
* @param {Array<LintMessage|SuppressedLintMessage>} problems A list of reported problems.
|
|
2401
|
+
* @returns {LintMessage[]} A list of LintMessage.
|
|
2402
|
+
*/
|
|
2403
|
+
_distinguishSuppressedMessages(problems) {
|
|
2404
|
+
const messages = [];
|
|
2405
|
+
const suppressedMessages = [];
|
|
2406
|
+
const slots = internalSlotsMap.get(this);
|
|
2407
|
+
|
|
2408
|
+
for (const problem of problems) {
|
|
2409
|
+
if (problem.suppressions) {
|
|
2410
|
+
suppressedMessages.push(problem);
|
|
2411
|
+
} else {
|
|
2412
|
+
messages.push(problem);
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
slots.lastSuppressedMessages = suppressedMessages;
|
|
2417
|
+
|
|
2418
|
+
return messages;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
/**
|
|
2422
|
+
* Gets the SourceCode object representing the parsed source.
|
|
2423
|
+
* @returns {SourceCode} The SourceCode object.
|
|
2424
|
+
*/
|
|
2425
|
+
getSourceCode() {
|
|
2426
|
+
return internalSlotsMap.get(this).lastSourceCode;
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
/**
|
|
2430
|
+
* Gets the times spent on (parsing, fixing, linting) a file.
|
|
2431
|
+
* @returns {{ passes: TimePass[]; }} The times.
|
|
2432
|
+
*/
|
|
2433
|
+
getTimes() {
|
|
2434
|
+
return internalSlotsMap.get(this).times ?? { passes: [] };
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
/**
|
|
2438
|
+
* Gets the number of autofix passes that were made in the last run.
|
|
2439
|
+
* @returns {number} The number of autofix passes.
|
|
2440
|
+
*/
|
|
2441
|
+
getFixPassCount() {
|
|
2442
|
+
return internalSlotsMap.get(this).fixPasses ?? 0;
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
/**
|
|
2446
|
+
* Gets the list of SuppressedLintMessage produced in the last running.
|
|
2447
|
+
* @returns {SuppressedLintMessage[]} The list of SuppressedLintMessage
|
|
2448
|
+
*/
|
|
2449
|
+
getSuppressedMessages() {
|
|
2450
|
+
return internalSlotsMap.get(this).lastSuppressedMessages;
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
/**
|
|
2454
|
+
* Defines a new linting rule.
|
|
2455
|
+
* @param {string} ruleId A unique rule identifier
|
|
2456
|
+
* @param {Rule} rule A rule object
|
|
2457
|
+
* @returns {void}
|
|
2458
|
+
*/
|
|
2459
|
+
defineRule(ruleId, rule) {
|
|
2460
|
+
assertEslintrcConfig(this);
|
|
2461
|
+
internalSlotsMap.get(this).ruleMap.define(ruleId, rule);
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
/**
|
|
2465
|
+
* Defines many new linting rules.
|
|
2466
|
+
* @param {Record<string, Rule>} rulesToDefine map from unique rule identifier to rule
|
|
2467
|
+
* @returns {void}
|
|
2468
|
+
*/
|
|
2469
|
+
defineRules(rulesToDefine) {
|
|
2470
|
+
assertEslintrcConfig(this);
|
|
2471
|
+
Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => {
|
|
2472
|
+
this.defineRule(ruleId, rulesToDefine[ruleId]);
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
/**
|
|
2477
|
+
* Gets an object with all loaded rules.
|
|
2478
|
+
* @returns {Map<string, Rule>} All loaded rules
|
|
2479
|
+
*/
|
|
2480
|
+
getRules() {
|
|
2481
|
+
assertEslintrcConfig(this);
|
|
2482
|
+
const { lastConfigArray, ruleMap } = internalSlotsMap.get(this);
|
|
2483
|
+
|
|
2484
|
+
return new Map(
|
|
2485
|
+
(function* () {
|
|
2486
|
+
yield* ruleMap;
|
|
2487
|
+
|
|
2488
|
+
if (lastConfigArray) {
|
|
2489
|
+
yield* lastConfigArray.pluginRules;
|
|
2490
|
+
}
|
|
2491
|
+
})(),
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
/**
|
|
2496
|
+
* Define a new parser module
|
|
2497
|
+
* @param {string} parserId Name of the parser
|
|
2498
|
+
* @param {Parser} parserModule The parser object
|
|
2499
|
+
* @returns {void}
|
|
2500
|
+
*/
|
|
2501
|
+
defineParser(parserId, parserModule) {
|
|
2502
|
+
assertEslintrcConfig(this);
|
|
2503
|
+
internalSlotsMap.get(this).parserMap.set(parserId, parserModule);
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
/**
|
|
2507
|
+
* Performs multiple autofix passes over the text until as many fixes as possible
|
|
2508
|
+
* have been applied.
|
|
2509
|
+
* @param {string} text The source text to apply fixes to.
|
|
2510
|
+
* @param {ConfigData|ConfigArray|FlatConfigArray} config The ESLint config object to use.
|
|
2511
|
+
* @param {VerifyOptions&ProcessorOptions&FixOptions} options The ESLint options object to use.
|
|
2512
|
+
* @returns {{fixed:boolean,messages:LintMessage[],output:string}} The result of the fix operation as returned from the
|
|
2513
|
+
* SourceCodeFixer.
|
|
2514
|
+
*/
|
|
2515
|
+
verifyAndFix(text, config, options) {
|
|
2516
|
+
let messages,
|
|
2517
|
+
fixedResult,
|
|
2518
|
+
fixed = false,
|
|
2519
|
+
passNumber = 0,
|
|
2520
|
+
currentText = text,
|
|
2521
|
+
secondPreviousText,
|
|
2522
|
+
previousText;
|
|
2523
|
+
const debugTextDescription =
|
|
2524
|
+
(options && options.filename) || `${text.slice(0, 10)}...`;
|
|
2525
|
+
const shouldFix =
|
|
2526
|
+
options && typeof options.fix !== "undefined" ? options.fix : true;
|
|
2527
|
+
const stats = options?.stats;
|
|
2528
|
+
|
|
2529
|
+
const slots = internalSlotsMap.get(this);
|
|
2530
|
+
|
|
2531
|
+
// Remove lint times from the last run.
|
|
2532
|
+
if (stats) {
|
|
2533
|
+
delete slots.times;
|
|
2534
|
+
slots.fixPasses = 0;
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
/**
|
|
2538
|
+
* This loop continues until one of the following is true:
|
|
2539
|
+
*
|
|
2540
|
+
* 1. No more fixes have been applied.
|
|
2541
|
+
* 2. Ten passes have been made.
|
|
2542
|
+
*
|
|
2543
|
+
* That means anytime a fix is successfully applied, there will be another pass.
|
|
2544
|
+
* Essentially, guaranteeing a minimum of two passes.
|
|
2545
|
+
*/
|
|
2546
|
+
do {
|
|
2547
|
+
passNumber++;
|
|
2548
|
+
let tTotal;
|
|
2549
|
+
|
|
2550
|
+
if (stats) {
|
|
2551
|
+
tTotal = startTime();
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
debug(
|
|
2555
|
+
`Linting code for ${debugTextDescription} (pass ${passNumber})`,
|
|
2556
|
+
);
|
|
2557
|
+
messages = this.verify(currentText, config, options);
|
|
2558
|
+
|
|
2559
|
+
debug(
|
|
2560
|
+
`Generating fixed text for ${debugTextDescription} (pass ${passNumber})`,
|
|
2561
|
+
);
|
|
2562
|
+
let t;
|
|
2563
|
+
|
|
2564
|
+
if (stats) {
|
|
2565
|
+
t = startTime();
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
fixedResult = SourceCodeFixer.applyFixes(
|
|
2569
|
+
currentText,
|
|
2570
|
+
messages,
|
|
2571
|
+
shouldFix,
|
|
2572
|
+
);
|
|
2573
|
+
|
|
2574
|
+
if (stats) {
|
|
2575
|
+
if (fixedResult.fixed) {
|
|
2576
|
+
const time = endTime(t);
|
|
2577
|
+
|
|
2578
|
+
storeTime(time, { type: "fix" }, slots);
|
|
2579
|
+
slots.fixPasses++;
|
|
2580
|
+
} else {
|
|
2581
|
+
storeTime(0, { type: "fix" }, slots);
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
/*
|
|
2586
|
+
* stop if there are any syntax errors.
|
|
2587
|
+
* 'fixedResult.output' is a empty string.
|
|
2588
|
+
*/
|
|
2589
|
+
if (messages.length === 1 && messages[0].fatal) {
|
|
2590
|
+
break;
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
// keep track if any fixes were ever applied - important for return value
|
|
2594
|
+
fixed = fixed || fixedResult.fixed;
|
|
2595
|
+
|
|
2596
|
+
// update to use the fixed output instead of the original text
|
|
2597
|
+
secondPreviousText = previousText;
|
|
2598
|
+
previousText = currentText;
|
|
2599
|
+
currentText = fixedResult.output;
|
|
2600
|
+
|
|
2601
|
+
if (stats) {
|
|
2602
|
+
tTotal = endTime(tTotal);
|
|
2603
|
+
const passIndex = slots.times.passes.length - 1;
|
|
2604
|
+
|
|
2605
|
+
slots.times.passes[passIndex].total = tTotal;
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
// Stop if we've made a circular fix
|
|
2609
|
+
if (
|
|
2610
|
+
passNumber > 1 &&
|
|
2611
|
+
currentText.length === secondPreviousText.length &&
|
|
2612
|
+
currentText === secondPreviousText
|
|
2613
|
+
) {
|
|
2614
|
+
debug(
|
|
2615
|
+
`Circular fixes detected after pass ${passNumber}. Exiting fix loop.`,
|
|
2616
|
+
);
|
|
2617
|
+
slots.warningService.emitCircularFixesWarning(
|
|
2618
|
+
options?.filename ?? "text",
|
|
2619
|
+
);
|
|
2620
|
+
break;
|
|
2621
|
+
}
|
|
2622
|
+
} while (fixedResult.fixed && passNumber < MAX_AUTOFIX_PASSES);
|
|
2623
|
+
|
|
2624
|
+
/*
|
|
2625
|
+
* If the last result had fixes, we need to lint again to be sure we have
|
|
2626
|
+
* the most up-to-date information.
|
|
2627
|
+
*/
|
|
2628
|
+
if (fixedResult.fixed) {
|
|
2629
|
+
let tTotal;
|
|
2630
|
+
|
|
2631
|
+
if (stats) {
|
|
2632
|
+
tTotal = startTime();
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
fixedResult.messages = this.verify(currentText, config, options);
|
|
2636
|
+
|
|
2637
|
+
if (stats) {
|
|
2638
|
+
storeTime(0, { type: "fix" }, slots);
|
|
2639
|
+
slots.times.passes.at(-1).total = endTime(tTotal);
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// ensure the last result properly reflects if fixes were done
|
|
2644
|
+
fixedResult.fixed = fixed;
|
|
2645
|
+
fixedResult.output = currentText;
|
|
2646
|
+
|
|
2647
|
+
return fixedResult;
|
|
2648
|
+
}
|
|
2106
2649
|
}
|
|
2107
2650
|
|
|
2108
2651
|
module.exports = {
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2652
|
+
Linter,
|
|
2653
|
+
|
|
2654
|
+
/**
|
|
2655
|
+
* Get the internal slots of a given Linter instance for tests.
|
|
2656
|
+
* @param {Linter} instance The Linter instance to get.
|
|
2657
|
+
* @returns {LinterInternalSlots} The internal slots.
|
|
2658
|
+
*/
|
|
2659
|
+
getLinterInternalSlots(instance) {
|
|
2660
|
+
return internalSlotsMap.get(instance);
|
|
2661
|
+
},
|
|
2119
2662
|
};
|