bahlint 28.58.6934
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/LICENSE +19 -0
- package/README.md +370 -0
- package/bin/eslint.js +195 -0
- package/conf/ecma-version.js +16 -0
- package/conf/globals.js +169 -0
- package/conf/replacements.json +26 -0
- package/conf/rule-type-list.json +91 -0
- package/lib/api.js +39 -0
- package/lib/cli-engine/formatters/formatters-meta.json +22 -0
- package/lib/cli-engine/formatters/gasoline.js +168 -0
- package/lib/cli-engine/formatters/html.js +359 -0
- package/lib/cli-engine/formatters/json-with-metadata.js +16 -0
- package/lib/cli-engine/formatters/json.js +13 -0
- package/lib/cli-engine/formatters/stylish.js +153 -0
- package/lib/cli-engine/hash.js +35 -0
- package/lib/cli-engine/lint-result-cache.js +220 -0
- package/lib/cli.js +607 -0
- package/lib/config/config-loader.js +683 -0
- package/lib/config/config.js +674 -0
- package/lib/config/default-config.js +78 -0
- package/lib/config/flat-config-array.js +217 -0
- package/lib/config/flat-config-schema.js +598 -0
- package/lib/config-api.js +12 -0
- package/lib/eslint/eslint-helpers.js +1462 -0
- package/lib/eslint/eslint.js +1364 -0
- package/lib/eslint/index.js +7 -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 +1178 -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/languages/js/source-code/token-store/cursor.js +76 -0
- package/lib/languages/js/source-code/token-store/cursors.js +120 -0
- package/lib/languages/js/source-code/token-store/decorative-cursor.js +38 -0
- package/lib/languages/js/source-code/token-store/filter-cursor.js +42 -0
- 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 +695 -0
- package/lib/languages/js/source-code/token-store/limit-cursor.js +39 -0
- package/lib/languages/js/source-code/token-store/padded-token-cursor.js +45 -0
- package/lib/languages/js/source-code/token-store/skip-cursor.js +41 -0
- package/lib/languages/js/source-code/token-store/utils.js +131 -0
- package/lib/languages/js/validate-language-options.js +196 -0
- package/lib/linter/apply-disable-directives.js +583 -0
- package/lib/linter/code-path-analysis/code-path-analyzer.js +828 -0
- package/lib/linter/code-path-analysis/code-path-segment.js +262 -0
- package/lib/linter/code-path-analysis/code-path-state.js +2370 -0
- package/lib/linter/code-path-analysis/code-path.js +332 -0
- package/lib/linter/code-path-analysis/debug-helpers.js +223 -0
- package/lib/linter/code-path-analysis/fork-context.js +374 -0
- package/lib/linter/code-path-analysis/id-generator.js +44 -0
- package/lib/linter/esquery.js +332 -0
- package/lib/linter/file-context.js +88 -0
- package/lib/linter/file-report.js +604 -0
- package/lib/linter/index.js +11 -0
- package/lib/linter/interpolate.js +50 -0
- package/lib/linter/linter.js +1614 -0
- package/lib/linter/rule-fixer.js +199 -0
- package/lib/linter/source-code-fixer.js +154 -0
- package/lib/linter/source-code-traverser.js +333 -0
- package/lib/linter/source-code-visitor.js +81 -0
- package/lib/linter/timing.js +209 -0
- package/lib/linter/vfile.js +115 -0
- package/lib/options.js +416 -0
- package/lib/rule-tester/index.js +7 -0
- package/lib/rule-tester/rule-tester.js +1817 -0
- package/lib/rules/accessor-pairs.js +420 -0
- package/lib/rules/array-bracket-newline.js +291 -0
- package/lib/rules/array-bracket-spacing.js +301 -0
- package/lib/rules/array-callback-return.js +493 -0
- package/lib/rules/array-element-newline.js +374 -0
- package/lib/rules/arrow-body-style.js +418 -0
- package/lib/rules/arrow-parens.js +237 -0
- package/lib/rules/arrow-spacing.js +188 -0
- package/lib/rules/block-scoped-var.js +137 -0
- package/lib/rules/block-spacing.js +202 -0
- package/lib/rules/brace-style.js +278 -0
- package/lib/rules/callback-return.js +216 -0
- package/lib/rules/camelcase.js +422 -0
- package/lib/rules/capitalized-comments.js +325 -0
- package/lib/rules/class-methods-use-this.js +250 -0
- package/lib/rules/comma-dangle.js +424 -0
- package/lib/rules/comma-spacing.js +205 -0
- package/lib/rules/comma-style.js +391 -0
- package/lib/rules/complexity.js +201 -0
- package/lib/rules/computed-property-spacing.js +251 -0
- package/lib/rules/consistent-return.js +221 -0
- package/lib/rules/consistent-this.js +179 -0
- package/lib/rules/constructor-super.js +453 -0
- package/lib/rules/curly.js +425 -0
- package/lib/rules/default-case-last.js +51 -0
- package/lib/rules/default-case.js +103 -0
- package/lib/rules/default-param-last.js +78 -0
- package/lib/rules/dot-location.js +138 -0
- package/lib/rules/dot-notation.js +216 -0
- package/lib/rules/eol-last.js +135 -0
- package/lib/rules/eqeqeq.js +210 -0
- package/lib/rules/for-direction.js +168 -0
- package/lib/rules/func-call-spacing.js +281 -0
- package/lib/rules/func-name-matching.js +338 -0
- package/lib/rules/func-names.js +194 -0
- package/lib/rules/func-style.js +221 -0
- package/lib/rules/function-call-argument-newline.js +166 -0
- package/lib/rules/function-paren-newline.js +368 -0
- package/lib/rules/generator-star-spacing.js +246 -0
- package/lib/rules/getter-return.js +242 -0
- package/lib/rules/global-require.js +117 -0
- package/lib/rules/grouped-accessor-pairs.js +268 -0
- package/lib/rules/guard-for-in.js +85 -0
- package/lib/rules/handle-callback-err.js +122 -0
- package/lib/rules/id-blacklist.js +241 -0
- package/lib/rules/id-denylist.js +223 -0
- package/lib/rules/id-length.js +217 -0
- package/lib/rules/id-match.js +363 -0
- package/lib/rules/implicit-arrow-linebreak.js +125 -0
- package/lib/rules/indent-legacy.js +1369 -0
- package/lib/rules/indent.js +2334 -0
- package/lib/rules/index.js +332 -0
- package/lib/rules/init-declarations.js +172 -0
- package/lib/rules/jsx-quotes.js +128 -0
- package/lib/rules/key-spacing.js +822 -0
- package/lib/rules/keyword-spacing.js +701 -0
- package/lib/rules/line-comment-position.js +157 -0
- package/lib/rules/linebreak-style.js +135 -0
- package/lib/rules/lines-around-comment.js +581 -0
- package/lib/rules/lines-around-directive.js +249 -0
- package/lib/rules/lines-between-class-members.js +358 -0
- package/lib/rules/logical-assignment-operators.js +688 -0
- package/lib/rules/max-classes-per-file.js +90 -0
- package/lib/rules/max-depth.js +159 -0
- package/lib/rules/max-len.js +497 -0
- package/lib/rules/max-lines-per-function.js +238 -0
- package/lib/rules/max-lines.js +189 -0
- package/lib/rules/max-nested-callbacks.js +115 -0
- package/lib/rules/max-params.js +148 -0
- package/lib/rules/max-statements-per-line.js +224 -0
- package/lib/rules/max-statements.js +188 -0
- package/lib/rules/multiline-comment-style.js +652 -0
- package/lib/rules/multiline-ternary.js +257 -0
- package/lib/rules/new-cap.js +277 -0
- package/lib/rules/new-parens.js +120 -0
- package/lib/rules/newline-after-var.js +307 -0
- package/lib/rules/newline-before-return.js +242 -0
- package/lib/rules/newline-per-chained-call.js +159 -0
- package/lib/rules/no-alert.js +149 -0
- package/lib/rules/no-array-constructor.js +195 -0
- package/lib/rules/no-async-promise-executor.js +45 -0
- package/lib/rules/no-await-in-loop.js +115 -0
- package/lib/rules/no-bitwise.js +145 -0
- package/lib/rules/no-buffer-constructor.js +74 -0
- package/lib/rules/no-caller.js +52 -0
- package/lib/rules/no-case-declarations.js +80 -0
- package/lib/rules/no-catch-shadow.js +96 -0
- package/lib/rules/no-class-assign.js +66 -0
- package/lib/rules/no-compare-neg-zero.js +74 -0
- package/lib/rules/no-cond-assign.js +175 -0
- package/lib/rules/no-confusing-arrow.js +127 -0
- package/lib/rules/no-console.js +221 -0
- package/lib/rules/no-const-assign.js +73 -0
- package/lib/rules/no-constant-binary-expression.js +603 -0
- package/lib/rules/no-constant-condition.js +177 -0
- package/lib/rules/no-constructor-return.js +62 -0
- package/lib/rules/no-continue.js +38 -0
- package/lib/rules/no-control-regex.js +142 -0
- package/lib/rules/no-debugger.js +41 -0
- package/lib/rules/no-delete-var.js +42 -0
- package/lib/rules/no-div-regex.js +60 -0
- package/lib/rules/no-dupe-args.js +92 -0
- package/lib/rules/no-dupe-class-members.js +117 -0
- package/lib/rules/no-dupe-else-if.js +145 -0
- package/lib/rules/no-dupe-keys.js +165 -0
- package/lib/rules/no-duplicate-case.js +78 -0
- package/lib/rules/no-duplicate-imports.js +368 -0
- package/lib/rules/no-else-return.js +450 -0
- package/lib/rules/no-empty-character-class.js +83 -0
- package/lib/rules/no-empty-function.js +236 -0
- package/lib/rules/no-empty-pattern.js +85 -0
- package/lib/rules/no-empty-static-block.js +73 -0
- package/lib/rules/no-empty.js +153 -0
- package/lib/rules/no-eq-null.js +51 -0
- package/lib/rules/no-eval.js +295 -0
- package/lib/rules/no-ex-assign.js +57 -0
- package/lib/rules/no-extend-native.js +180 -0
- package/lib/rules/no-extra-bind.js +224 -0
- package/lib/rules/no-extra-boolean-cast.js +420 -0
- package/lib/rules/no-extra-label.js +169 -0
- package/lib/rules/no-extra-parens.js +1669 -0
- package/lib/rules/no-extra-semi.js +167 -0
- package/lib/rules/no-fallthrough.js +260 -0
- package/lib/rules/no-floating-decimal.js +99 -0
- package/lib/rules/no-func-assign.js +77 -0
- package/lib/rules/no-global-assign.js +101 -0
- package/lib/rules/no-implicit-coercion.js +468 -0
- package/lib/rules/no-implicit-globals.js +187 -0
- package/lib/rules/no-implied-eval.js +170 -0
- package/lib/rules/no-import-assign.js +227 -0
- package/lib/rules/no-inline-comments.js +115 -0
- package/lib/rules/no-inner-declarations.js +147 -0
- package/lib/rules/no-invalid-regexp.js +244 -0
- package/lib/rules/no-invalid-this.js +178 -0
- package/lib/rules/no-irregular-whitespace.js +292 -0
- package/lib/rules/no-iterator.js +48 -0
- package/lib/rules/no-label-var.js +78 -0
- package/lib/rules/no-labels.js +156 -0
- package/lib/rules/no-lone-blocks.js +140 -0
- package/lib/rules/no-lonely-if.js +126 -0
- package/lib/rules/no-loop-func.js +267 -0
- package/lib/rules/no-loss-of-precision.js +249 -0
- package/lib/rules/no-magic-numbers.js +365 -0
- package/lib/rules/no-misleading-character-class.js +595 -0
- package/lib/rules/no-mixed-operators.js +253 -0
- package/lib/rules/no-mixed-requires.js +267 -0
- package/lib/rules/no-mixed-spaces-and-tabs.js +148 -0
- package/lib/rules/no-multi-assign.js +66 -0
- package/lib/rules/no-multi-spaces.js +179 -0
- package/lib/rules/no-multi-str.js +67 -0
- package/lib/rules/no-multiple-empty-lines.js +210 -0
- package/lib/rules/no-native-reassign.js +114 -0
- package/lib/rules/no-negated-condition.js +100 -0
- package/lib/rules/no-negated-in-lhs.js +59 -0
- package/lib/rules/no-nested-ternary.js +46 -0
- package/lib/rules/no-new-func.js +96 -0
- package/lib/rules/no-new-native-nonconstructor.js +70 -0
- package/lib/rules/no-new-object.js +76 -0
- package/lib/rules/no-new-require.js +67 -0
- package/lib/rules/no-new-symbol.js +74 -0
- package/lib/rules/no-new-wrappers.js +62 -0
- package/lib/rules/no-new.js +42 -0
- package/lib/rules/no-nonoctal-decimal-escape.js +176 -0
- package/lib/rules/no-obj-calls.js +99 -0
- package/lib/rules/no-object-constructor.js +124 -0
- package/lib/rules/no-octal-escape.js +53 -0
- package/lib/rules/no-octal.js +42 -0
- package/lib/rules/no-param-reassign.js +248 -0
- package/lib/rules/no-path-concat.js +79 -0
- package/lib/rules/no-plusplus.js +102 -0
- package/lib/rules/no-process-env.js +68 -0
- package/lib/rules/no-process-exit.js +67 -0
- package/lib/rules/no-promise-executor-return.js +264 -0
- package/lib/rules/no-proto.js +45 -0
- package/lib/rules/no-prototype-builtins.js +181 -0
- package/lib/rules/no-redeclare.js +173 -0
- package/lib/rules/no-regex-spaces.js +219 -0
- package/lib/rules/no-restricted-exports.js +227 -0
- package/lib/rules/no-restricted-globals.js +266 -0
- package/lib/rules/no-restricted-imports.js +892 -0
- package/lib/rules/no-restricted-modules.js +249 -0
- package/lib/rules/no-restricted-properties.js +233 -0
- package/lib/rules/no-restricted-syntax.js +74 -0
- package/lib/rules/no-return-assign.js +87 -0
- package/lib/rules/no-return-await.js +162 -0
- package/lib/rules/no-script-url.js +68 -0
- package/lib/rules/no-self-assign.js +186 -0
- package/lib/rules/no-self-compare.js +77 -0
- package/lib/rules/no-sequences.js +158 -0
- package/lib/rules/no-setter-return.js +224 -0
- package/lib/rules/no-shadow-restricted-names.js +113 -0
- package/lib/rules/no-shadow.js +624 -0
- package/lib/rules/no-spaced-func.js +105 -0
- package/lib/rules/no-sparse-arrays.js +68 -0
- package/lib/rules/no-sync.js +81 -0
- package/lib/rules/no-tabs.js +110 -0
- package/lib/rules/no-template-curly-in-string.js +45 -0
- package/lib/rules/no-ternary.js +38 -0
- package/lib/rules/no-this-before-super.js +365 -0
- package/lib/rules/no-throw-literal.js +46 -0
- package/lib/rules/no-trailing-spaces.js +227 -0
- package/lib/rules/no-unassigned-vars.js +80 -0
- package/lib/rules/no-undef-init.js +101 -0
- package/lib/rules/no-undef.js +84 -0
- package/lib/rules/no-undefined.js +85 -0
- package/lib/rules/no-underscore-dangle.js +383 -0
- package/lib/rules/no-unexpected-multiline.js +130 -0
- package/lib/rules/no-unmodified-loop-condition.js +360 -0
- package/lib/rules/no-unneeded-ternary.js +232 -0
- package/lib/rules/no-unreachable-loop.js +190 -0
- package/lib/rules/no-unreachable.js +300 -0
- package/lib/rules/no-unsafe-finally.js +119 -0
- package/lib/rules/no-unsafe-negation.js +152 -0
- package/lib/rules/no-unsafe-optional-chaining.js +221 -0
- package/lib/rules/no-unused-expressions.js +227 -0
- package/lib/rules/no-unused-labels.js +158 -0
- package/lib/rules/no-unused-private-class-members.js +219 -0
- package/lib/rules/no-unused-vars.js +1739 -0
- package/lib/rules/no-use-before-define.js +446 -0
- package/lib/rules/no-useless-assignment.js +657 -0
- package/lib/rules/no-useless-backreference.js +263 -0
- package/lib/rules/no-useless-call.js +95 -0
- package/lib/rules/no-useless-catch.js +57 -0
- package/lib/rules/no-useless-computed-key.js +204 -0
- package/lib/rules/no-useless-concat.js +121 -0
- package/lib/rules/no-useless-constructor.js +262 -0
- package/lib/rules/no-useless-escape.js +406 -0
- package/lib/rules/no-useless-rename.js +202 -0
- package/lib/rules/no-useless-return.js +401 -0
- package/lib/rules/no-var.js +367 -0
- package/lib/rules/no-void.js +69 -0
- package/lib/rules/no-warning-comments.js +209 -0
- package/lib/rules/no-whitespace-before-property.js +150 -0
- package/lib/rules/no-with.js +37 -0
- package/lib/rules/nonblock-statement-body-position.js +164 -0
- package/lib/rules/object-curly-newline.js +383 -0
- package/lib/rules/object-curly-spacing.js +369 -0
- package/lib/rules/object-property-newline.js +151 -0
- package/lib/rules/object-shorthand.js +652 -0
- package/lib/rules/one-var-declaration-per-line.js +117 -0
- package/lib/rules/one-var.js +717 -0
- package/lib/rules/operator-assignment.js +270 -0
- package/lib/rules/operator-linebreak.js +315 -0
- package/lib/rules/padded-blocks.js +366 -0
- package/lib/rules/padding-line-between-statements.js +612 -0
- package/lib/rules/prefer-arrow-callback.js +437 -0
- package/lib/rules/prefer-const.js +546 -0
- package/lib/rules/prefer-destructuring.js +332 -0
- package/lib/rules/prefer-exponentiation-operator.js +235 -0
- package/lib/rules/prefer-named-capture-group.js +197 -0
- package/lib/rules/prefer-numeric-literals.js +157 -0
- package/lib/rules/prefer-object-has-own.js +148 -0
- package/lib/rules/prefer-object-spread.js +319 -0
- package/lib/rules/prefer-promise-reject-errors.js +154 -0
- package/lib/rules/prefer-reflect.js +150 -0
- package/lib/rules/prefer-regex-literals.js +605 -0
- package/lib/rules/prefer-rest-params.js +117 -0
- package/lib/rules/prefer-spread.js +91 -0
- package/lib/rules/prefer-template.js +347 -0
- package/lib/rules/preserve-caught-error.js +535 -0
- package/lib/rules/quote-props.js +394 -0
- package/lib/rules/quotes.js +416 -0
- package/lib/rules/radix.js +193 -0
- package/lib/rules/require-atomic-updates.js +365 -0
- package/lib/rules/require-await.js +184 -0
- package/lib/rules/require-unicode-regexp.js +317 -0
- package/lib/rules/require-yield.js +86 -0
- package/lib/rules/rest-spread-spacing.js +150 -0
- package/lib/rules/semi-spacing.js +297 -0
- package/lib/rules/semi-style.js +218 -0
- package/lib/rules/semi.js +476 -0
- package/lib/rules/sort-imports.js +319 -0
- package/lib/rules/sort-keys.js +268 -0
- package/lib/rules/sort-vars.js +140 -0
- package/lib/rules/space-before-blocks.js +232 -0
- package/lib/rules/space-before-function-paren.js +202 -0
- package/lib/rules/space-in-parens.js +374 -0
- package/lib/rules/space-infix-ops.js +249 -0
- package/lib/rules/space-unary-ops.js +400 -0
- package/lib/rules/spaced-comment.js +447 -0
- package/lib/rules/strict.js +314 -0
- package/lib/rules/switch-colon-spacing.js +158 -0
- package/lib/rules/symbol-description.js +70 -0
- package/lib/rules/template-curly-spacing.js +168 -0
- package/lib/rules/template-tag-spacing.js +121 -0
- package/lib/rules/unicode-bom.js +73 -0
- package/lib/rules/use-isnan.js +268 -0
- package/lib/rules/utils/ast-utils.js +2828 -0
- package/lib/rules/utils/char-source.js +247 -0
- package/lib/rules/utils/fix-tracker.js +125 -0
- package/lib/rules/utils/keywords.js +67 -0
- package/lib/rules/utils/lazy-loading-rule-map.js +118 -0
- package/lib/rules/utils/regular-expressions.js +58 -0
- package/lib/rules/utils/unicode/index.js +16 -0
- package/lib/rules/utils/unicode/is-combining-character.js +13 -0
- package/lib/rules/utils/unicode/is-emoji-modifier.js +13 -0
- package/lib/rules/utils/unicode/is-regional-indicator-symbol.js +13 -0
- package/lib/rules/utils/unicode/is-surrogate-pair.js +14 -0
- package/lib/rules/valid-typeof.js +171 -0
- package/lib/rules/vars-on-top.js +165 -0
- package/lib/rules/wrap-iife.js +238 -0
- package/lib/rules/wrap-regex.js +91 -0
- package/lib/rules/yield-star-spacing.js +158 -0
- package/lib/rules/yoda.js +362 -0
- package/lib/services/parser-service.js +64 -0
- package/lib/services/processor-service.js +100 -0
- package/lib/services/suppressions-service.js +302 -0
- package/lib/services/warning-service.js +87 -0
- package/lib/shared/ajv.js +34 -0
- package/lib/shared/assert.js +21 -0
- package/lib/shared/ast-utils.js +30 -0
- package/lib/shared/deep-merge-arrays.js +62 -0
- package/lib/shared/directives.js +16 -0
- package/lib/shared/flags.js +89 -0
- package/lib/shared/logging.js +38 -0
- package/lib/shared/naming.js +109 -0
- package/lib/shared/option-utils.js +63 -0
- package/lib/shared/relative-module-resolver.js +28 -0
- package/lib/shared/runtime-info.js +177 -0
- package/lib/shared/serialization.js +78 -0
- package/lib/shared/severity.js +49 -0
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +58 -0
- package/lib/shared/text-table.js +68 -0
- package/lib/shared/translate-cli-options.js +223 -0
- package/lib/shared/traverser.js +202 -0
- package/lib/types/config-api.d.ts +12 -0
- package/lib/types/index.d.ts +1482 -0
- package/lib/types/rules.d.ts +5603 -0
- package/lib/types/universal.d.ts +6 -0
- package/lib/types/use-at-your-own-risk.d.ts +34 -0
- package/lib/universal.js +10 -0
- package/lib/unsupported-api.js +26 -0
- package/messages/all-files-ignored.js +16 -0
- 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 +117 -0
- package/messages/eslintrc-plugins.js +27 -0
- package/messages/extend-config-missing.js +13 -0
- package/messages/failed-to-read-json.js +11 -0
- package/messages/file-not-found.js +10 -0
- package/messages/invalid-rule-options.js +17 -0
- package/messages/invalid-rule-severity.js +13 -0
- package/messages/no-config-found.js +15 -0
- package/messages/plugin-conflict.js +22 -0
- package/messages/plugin-invalid.js +16 -0
- package/messages/plugin-missing.js +19 -0
- package/messages/print-config-with-directory-path.js +8 -0
- package/messages/shared.js +23 -0
- package/messages/whitespace-found.js +11 -0
- package/package.json +220 -0
|
@@ -0,0 +1,1462 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Helper functions for ESLint class
|
|
3
|
+
* @author Nicholas C. Zakas
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
//-----------------------------------------------------------------------------
|
|
9
|
+
// Requirements
|
|
10
|
+
//-----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
const path = require("node:path");
|
|
13
|
+
const fs = require("node:fs");
|
|
14
|
+
const { isMainThread, threadId } = require("node:worker_threads");
|
|
15
|
+
const fsp = fs.promises;
|
|
16
|
+
const isGlob = require("is-glob");
|
|
17
|
+
const hash = require("../cli-engine/hash");
|
|
18
|
+
const minimatch = require("minimatch");
|
|
19
|
+
const globParent = require("glob-parent");
|
|
20
|
+
const { Linter } = require("../linter");
|
|
21
|
+
const { getShorthandName } = require("../shared/naming");
|
|
22
|
+
const LintResultCache = require("../cli-engine/lint-result-cache");
|
|
23
|
+
const { ConfigLoader } = require("../config/config-loader");
|
|
24
|
+
const createDebug = require("debug");
|
|
25
|
+
|
|
26
|
+
//-----------------------------------------------------------------------------
|
|
27
|
+
// Fixup references
|
|
28
|
+
//-----------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
const Minimatch = minimatch.Minimatch;
|
|
31
|
+
const MINIMATCH_OPTIONS = { dot: true };
|
|
32
|
+
const hrtimeBigint = process.hrtime.bigint;
|
|
33
|
+
|
|
34
|
+
//-----------------------------------------------------------------------------
|
|
35
|
+
// Types
|
|
36
|
+
//-----------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @import { ESLintOptions } from "./eslint.js";
|
|
40
|
+
* @import { Config as CalculatedConfig } from "../config/config.js";
|
|
41
|
+
* @import { FlatConfigArray } from "../config/flat-config-array.js";
|
|
42
|
+
* @import { WarningService } from "../services/warning-service.js";
|
|
43
|
+
* @import { Retrier } from "@humanwhocodes/retry";
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/** @typedef {import("../types").Linter.Config} Config */
|
|
47
|
+
/** @typedef {import("../types").Linter.LintMessage} LintMessage */
|
|
48
|
+
/** @typedef {import("../types").ESLint.LintResult} LintResult */
|
|
49
|
+
/** @typedef {import("../types").ESLint.Plugin} Plugin */
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @typedef {Object} GlobSearch
|
|
53
|
+
* @property {Array<string>} patterns The normalized patterns to use for a search.
|
|
54
|
+
* @property {Array<string>} rawPatterns The patterns as entered by the user
|
|
55
|
+
* before doing any normalization.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
//------------------------------------------------------------------------------
|
|
59
|
+
// Debug Helpers
|
|
60
|
+
//------------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
// Add %t formatter to print bigint nanosecond times in milliseconds.
|
|
63
|
+
createDebug.formatters.t = timeDiff =>
|
|
64
|
+
`${(timeDiff + 500_000n) / 1_000_000n} ms`;
|
|
65
|
+
|
|
66
|
+
const debug = createDebug(
|
|
67
|
+
`eslint:eslint-helpers${isMainThread ? "" : `:thread-${threadId}`}`,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
//-----------------------------------------------------------------------------
|
|
71
|
+
// Errors
|
|
72
|
+
//-----------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The error type when no files match a glob.
|
|
76
|
+
*/
|
|
77
|
+
class NoFilesFoundError extends Error {
|
|
78
|
+
/**
|
|
79
|
+
* @param {string} pattern The glob pattern which was not found.
|
|
80
|
+
* @param {boolean} globEnabled If `false` then the pattern was a glob pattern, but glob was disabled.
|
|
81
|
+
*/
|
|
82
|
+
constructor(pattern, globEnabled) {
|
|
83
|
+
super(
|
|
84
|
+
`No files matching '${pattern}' were found${!globEnabled ? " (glob was disabled)" : ""}.`,
|
|
85
|
+
);
|
|
86
|
+
this.messageTemplate = "file-not-found";
|
|
87
|
+
this.messageData = { pattern, globDisabled: !globEnabled };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The error type when a search fails to match multiple patterns.
|
|
93
|
+
*/
|
|
94
|
+
class UnmatchedSearchPatternsError extends Error {
|
|
95
|
+
/**
|
|
96
|
+
* @param {Object} options The options for the error.
|
|
97
|
+
* @param {string} options.basePath The directory that was searched.
|
|
98
|
+
* @param {Array<string>} options.unmatchedPatterns The glob patterns
|
|
99
|
+
* which were not found.
|
|
100
|
+
* @param {Array<string>} options.patterns The glob patterns that were
|
|
101
|
+
* searched.
|
|
102
|
+
* @param {Array<string>} options.rawPatterns The raw glob patterns that
|
|
103
|
+
* were searched.
|
|
104
|
+
*/
|
|
105
|
+
constructor({ basePath, unmatchedPatterns, patterns, rawPatterns }) {
|
|
106
|
+
super(
|
|
107
|
+
`No files matching '${rawPatterns}' in '${basePath}' were found.`,
|
|
108
|
+
);
|
|
109
|
+
this.basePath = basePath;
|
|
110
|
+
this.unmatchedPatterns = unmatchedPatterns;
|
|
111
|
+
this.patterns = patterns;
|
|
112
|
+
this.rawPatterns = rawPatterns;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The error type when there are files matched by a glob, but all of them have been ignored.
|
|
118
|
+
*/
|
|
119
|
+
class AllFilesIgnoredError extends Error {
|
|
120
|
+
/**
|
|
121
|
+
* @param {string} pattern The glob pattern which was not found.
|
|
122
|
+
*/
|
|
123
|
+
constructor(pattern) {
|
|
124
|
+
super(`All files matched by '${pattern}' are ignored.`);
|
|
125
|
+
this.messageTemplate = "all-matched-files-ignored";
|
|
126
|
+
this.messageData = { pattern };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
//-----------------------------------------------------------------------------
|
|
131
|
+
// General Helpers
|
|
132
|
+
//-----------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if a given value is a non-empty string or not.
|
|
136
|
+
* @param {any} value The value to check.
|
|
137
|
+
* @returns {boolean} `true` if `value` is a non-empty string.
|
|
138
|
+
*/
|
|
139
|
+
function isNonEmptyString(value) {
|
|
140
|
+
return typeof value === "string" && value.trim() !== "";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if a given value is an array of non-empty strings or not.
|
|
145
|
+
* @param {any} value The value to check.
|
|
146
|
+
* @returns {boolean} `true` if `value` is an array of non-empty strings.
|
|
147
|
+
*/
|
|
148
|
+
function isArrayOfNonEmptyString(value) {
|
|
149
|
+
return (
|
|
150
|
+
Array.isArray(value) && !!value.length && value.every(isNonEmptyString)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if a given value is an empty array or an array of non-empty strings.
|
|
156
|
+
* @param {any} value The value to check.
|
|
157
|
+
* @returns {boolean} `true` if `value` is an empty array or an array of non-empty
|
|
158
|
+
* strings.
|
|
159
|
+
*/
|
|
160
|
+
function isEmptyArrayOrArrayOfNonEmptyString(value) {
|
|
161
|
+
return Array.isArray(value) && value.every(isNonEmptyString);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Check if a given value is a positive integer.
|
|
166
|
+
* @param {unknown} value The value to check.
|
|
167
|
+
* @returns {boolean} `true` if `value` is a positive integer.
|
|
168
|
+
*/
|
|
169
|
+
function isPositiveInteger(value) {
|
|
170
|
+
return Number.isInteger(value) && value > 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
//-----------------------------------------------------------------------------
|
|
174
|
+
// File-related Helpers
|
|
175
|
+
//-----------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Normalizes slashes in a file pattern to posix-style.
|
|
179
|
+
* @param {string} pattern The pattern to replace slashes in.
|
|
180
|
+
* @returns {string} The pattern with slashes normalized.
|
|
181
|
+
*/
|
|
182
|
+
function normalizeToPosix(pattern) {
|
|
183
|
+
return pattern.replace(/\\/gu, "/");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check if a string is a glob pattern or not.
|
|
188
|
+
* @param {string} pattern A glob pattern.
|
|
189
|
+
* @returns {boolean} `true` if the string is a glob pattern.
|
|
190
|
+
*/
|
|
191
|
+
function isGlobPattern(pattern) {
|
|
192
|
+
return isGlob(path.sep === "\\" ? normalizeToPosix(pattern) : pattern);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Determines if a given glob pattern will return any results.
|
|
197
|
+
* Used primarily to help with useful error messages.
|
|
198
|
+
* @param {Object} options The options for the function.
|
|
199
|
+
* @param {string} options.basePath The directory to search.
|
|
200
|
+
* @param {string} options.pattern An absolute path glob pattern to match.
|
|
201
|
+
* @returns {Promise<boolean>} True if there is a glob match, false if not.
|
|
202
|
+
*/
|
|
203
|
+
async function globMatch({ basePath, pattern }) {
|
|
204
|
+
let found = false;
|
|
205
|
+
const { hfs } = await import("@humanfs/node");
|
|
206
|
+
const patternToUse = normalizeToPosix(path.relative(basePath, pattern));
|
|
207
|
+
|
|
208
|
+
const matcher = new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
|
209
|
+
|
|
210
|
+
const walkSettings = {
|
|
211
|
+
directoryFilter(entry) {
|
|
212
|
+
return !found && matcher.match(entry.path, true);
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
entryFilter(entry) {
|
|
216
|
+
if (found || entry.isDirectory) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (matcher.match(entry.path)) {
|
|
221
|
+
found = true;
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return false;
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
if (await hfs.isDirectory(basePath)) {
|
|
230
|
+
return hfs
|
|
231
|
+
.walk(basePath, walkSettings)
|
|
232
|
+
.next()
|
|
233
|
+
.then(() => found);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return found;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Searches a directory looking for matching glob patterns. This uses
|
|
241
|
+
* the config array's logic to determine if a directory or file should
|
|
242
|
+
* be ignored, so it is consistent with how ignoring works throughout
|
|
243
|
+
* ESLint.
|
|
244
|
+
* @param {Object} options The options for this function.
|
|
245
|
+
* @param {string} options.basePath The directory to search.
|
|
246
|
+
* @param {Array<string>} options.patterns An array of absolute path glob patterns
|
|
247
|
+
* to match.
|
|
248
|
+
* @param {Array<string>} options.rawPatterns An array of glob patterns
|
|
249
|
+
* as the user inputted them. Used for errors.
|
|
250
|
+
* @param {ConfigLoader} options.configLoader The config array to use for
|
|
251
|
+
* determining what to ignore.
|
|
252
|
+
* @param {boolean} options.errorOnUnmatchedPattern Determines if an error
|
|
253
|
+
* should be thrown when a pattern is unmatched.
|
|
254
|
+
* @returns {Promise<Array<string>>} An array of matching file paths
|
|
255
|
+
* or an empty array if there are no matches.
|
|
256
|
+
* @throws {UnmatchedSearchPatternsError} If there is a pattern that doesn't
|
|
257
|
+
* match any files.
|
|
258
|
+
*/
|
|
259
|
+
async function globSearch({
|
|
260
|
+
basePath,
|
|
261
|
+
patterns,
|
|
262
|
+
rawPatterns,
|
|
263
|
+
configLoader,
|
|
264
|
+
errorOnUnmatchedPattern,
|
|
265
|
+
}) {
|
|
266
|
+
if (patterns.length === 0) {
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/*
|
|
271
|
+
* In this section we are converting the patterns into Minimatch
|
|
272
|
+
* instances for performance reasons. Because we are doing the same
|
|
273
|
+
* matches repeatedly, it's best to compile those patterns once and
|
|
274
|
+
* reuse them multiple times.
|
|
275
|
+
*
|
|
276
|
+
* To do that, we convert any patterns with an absolute path into a
|
|
277
|
+
* relative path and normalize it to Posix-style slashes. We also keep
|
|
278
|
+
* track of the relative patterns to map them back to the original
|
|
279
|
+
* patterns, which we need in order to throw an error if there are any
|
|
280
|
+
* unmatched patterns.
|
|
281
|
+
*/
|
|
282
|
+
const relativeToPatterns = new Map();
|
|
283
|
+
const matchers = patterns.map((pattern, i) => {
|
|
284
|
+
const patternToUse = normalizeToPosix(path.relative(basePath, pattern));
|
|
285
|
+
|
|
286
|
+
relativeToPatterns.set(patternToUse, patterns[i]);
|
|
287
|
+
|
|
288
|
+
return new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/*
|
|
292
|
+
* We track unmatched patterns because we may want to throw an error when
|
|
293
|
+
* they occur. To start, this set is initialized with all of the patterns.
|
|
294
|
+
* Every time a match occurs, the pattern is removed from the set, making
|
|
295
|
+
* it easy to tell if we have any unmatched patterns left at the end of
|
|
296
|
+
* search.
|
|
297
|
+
*/
|
|
298
|
+
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
|
|
299
|
+
const { hfs } = await import("@humanfs/node");
|
|
300
|
+
|
|
301
|
+
const walk = hfs.walk(basePath, {
|
|
302
|
+
async directoryFilter(entry) {
|
|
303
|
+
if (!matchers.some(matcher => matcher.match(entry.path, true))) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const absolutePath = path.resolve(basePath, entry.path);
|
|
308
|
+
const configs =
|
|
309
|
+
await configLoader.loadConfigArrayForDirectory(absolutePath);
|
|
310
|
+
|
|
311
|
+
return !configs.isDirectoryIgnored(absolutePath);
|
|
312
|
+
},
|
|
313
|
+
async entryFilter(entry) {
|
|
314
|
+
const absolutePath = path.resolve(basePath, entry.path);
|
|
315
|
+
|
|
316
|
+
// entries may be directories or files so filter out directories
|
|
317
|
+
if (entry.isDirectory) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const configs =
|
|
322
|
+
await configLoader.loadConfigArrayForFile(absolutePath);
|
|
323
|
+
const config = configs.getConfig(absolutePath);
|
|
324
|
+
|
|
325
|
+
/*
|
|
326
|
+
* Optimization: We need to track when patterns are left unmatched
|
|
327
|
+
* and so we use `unmatchedPatterns` to do that. There is a bit of
|
|
328
|
+
* complexity here because the same file can be matched by more than
|
|
329
|
+
* one pattern. So, when we start, we actually need to test every
|
|
330
|
+
* pattern against every file. Once we know there are no remaining
|
|
331
|
+
* unmatched patterns, then we can switch to just looking for the
|
|
332
|
+
* first matching pattern for improved speed.
|
|
333
|
+
*/
|
|
334
|
+
const matchesPattern =
|
|
335
|
+
unmatchedPatterns.size > 0
|
|
336
|
+
? matchers.reduce((previousValue, matcher) => {
|
|
337
|
+
const pathMatches = matcher.match(entry.path);
|
|
338
|
+
|
|
339
|
+
/*
|
|
340
|
+
* We updated the unmatched patterns set only if the path
|
|
341
|
+
* matches and the file has a config. If the file has no
|
|
342
|
+
* config, that means there wasn't a match for the
|
|
343
|
+
* pattern so it should not be removed.
|
|
344
|
+
*
|
|
345
|
+
* Performance note: `getConfig()` aggressively caches
|
|
346
|
+
* results so there is no performance penalty for calling
|
|
347
|
+
* it multiple times with the same argument.
|
|
348
|
+
*/
|
|
349
|
+
if (pathMatches && config) {
|
|
350
|
+
unmatchedPatterns.delete(matcher.pattern);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return pathMatches || previousValue;
|
|
354
|
+
}, false)
|
|
355
|
+
: matchers.some(matcher => matcher.match(entry.path));
|
|
356
|
+
|
|
357
|
+
return matchesPattern && config !== void 0;
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const filePaths = [];
|
|
362
|
+
|
|
363
|
+
if (await hfs.isDirectory(basePath)) {
|
|
364
|
+
for await (const entry of walk) {
|
|
365
|
+
filePaths.push(path.resolve(basePath, entry.path));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// now check to see if we have any unmatched patterns
|
|
370
|
+
if (errorOnUnmatchedPattern && unmatchedPatterns.size > 0) {
|
|
371
|
+
throw new UnmatchedSearchPatternsError({
|
|
372
|
+
basePath,
|
|
373
|
+
unmatchedPatterns: [...unmatchedPatterns].map(pattern =>
|
|
374
|
+
relativeToPatterns.get(pattern),
|
|
375
|
+
),
|
|
376
|
+
patterns,
|
|
377
|
+
rawPatterns,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return filePaths;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Throws an error for unmatched patterns. The error will only contain information about the first one.
|
|
386
|
+
* Checks to see if there are any ignored results for a given search.
|
|
387
|
+
* @param {Object} options The options for this function.
|
|
388
|
+
* @param {string} options.basePath The directory to search.
|
|
389
|
+
* @param {Array<string>} options.patterns An array of glob patterns
|
|
390
|
+
* that were used in the original search.
|
|
391
|
+
* @param {Array<string>} options.rawPatterns An array of glob patterns
|
|
392
|
+
* as the user inputted them. Used for errors.
|
|
393
|
+
* @param {Array<string>} options.unmatchedPatterns A non-empty array of absolute path glob patterns
|
|
394
|
+
* that were unmatched in the original search.
|
|
395
|
+
* @returns {Promise<never>} Always throws an error.
|
|
396
|
+
* @throws {NoFilesFoundError} If the first unmatched pattern
|
|
397
|
+
* doesn't match any files even when there are no ignores.
|
|
398
|
+
* @throws {AllFilesIgnoredError} If the first unmatched pattern
|
|
399
|
+
* matches some files when there are no ignores.
|
|
400
|
+
*/
|
|
401
|
+
async function throwErrorForUnmatchedPatterns({
|
|
402
|
+
basePath,
|
|
403
|
+
patterns,
|
|
404
|
+
rawPatterns,
|
|
405
|
+
unmatchedPatterns,
|
|
406
|
+
}) {
|
|
407
|
+
const pattern = unmatchedPatterns[0];
|
|
408
|
+
const rawPattern = rawPatterns[patterns.indexOf(pattern)];
|
|
409
|
+
|
|
410
|
+
const patternHasMatch = await globMatch({
|
|
411
|
+
basePath,
|
|
412
|
+
pattern,
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
if (patternHasMatch) {
|
|
416
|
+
throw new AllFilesIgnoredError(rawPattern);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// if we get here there are truly no matches
|
|
420
|
+
throw new NoFilesFoundError(rawPattern, true);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Performs multiple glob searches in parallel.
|
|
425
|
+
* @param {Object} options The options for this function.
|
|
426
|
+
* @param {Map<string,GlobSearch>} options.searches
|
|
427
|
+
* A map of absolute path glob patterns to match.
|
|
428
|
+
* @param {ConfigLoader} options.configLoader The config loader to use for
|
|
429
|
+
* determining what to ignore.
|
|
430
|
+
* @param {boolean} options.errorOnUnmatchedPattern Determines if an
|
|
431
|
+
* unmatched glob pattern should throw an error.
|
|
432
|
+
* @returns {Promise<Array<string>>} An array of matching file paths
|
|
433
|
+
* or an empty array if there are no matches.
|
|
434
|
+
*/
|
|
435
|
+
async function globMultiSearch({
|
|
436
|
+
searches,
|
|
437
|
+
configLoader,
|
|
438
|
+
errorOnUnmatchedPattern,
|
|
439
|
+
}) {
|
|
440
|
+
/*
|
|
441
|
+
* For convenience, we normalized the search map into an array of objects.
|
|
442
|
+
* Next, we filter out all searches that have no patterns. This happens
|
|
443
|
+
* primarily for the cwd, which is prepopulated in the searches map as an
|
|
444
|
+
* optimization. However, if it has no patterns, it means all patterns
|
|
445
|
+
* occur outside of the cwd and we can safely filter out that search.
|
|
446
|
+
*/
|
|
447
|
+
const normalizedSearches = [...searches]
|
|
448
|
+
.map(([basePath, { patterns, rawPatterns }]) => ({
|
|
449
|
+
basePath,
|
|
450
|
+
patterns,
|
|
451
|
+
rawPatterns,
|
|
452
|
+
}))
|
|
453
|
+
.filter(({ patterns }) => patterns.length > 0);
|
|
454
|
+
|
|
455
|
+
const results = await Promise.allSettled(
|
|
456
|
+
normalizedSearches.map(({ basePath, patterns, rawPatterns }) =>
|
|
457
|
+
globSearch({
|
|
458
|
+
basePath,
|
|
459
|
+
patterns,
|
|
460
|
+
rawPatterns,
|
|
461
|
+
configLoader,
|
|
462
|
+
errorOnUnmatchedPattern,
|
|
463
|
+
}),
|
|
464
|
+
),
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
/*
|
|
468
|
+
* The first loop handles errors from the glob searches. Since we can't
|
|
469
|
+
* use `await` inside `flatMap`, we process errors separately in this loop.
|
|
470
|
+
* This results in two iterations over `results`, but since the length is
|
|
471
|
+
* less than or equal to the number of globs and directories passed on the
|
|
472
|
+
* command line, the performance impact should be minimal.
|
|
473
|
+
*/
|
|
474
|
+
for (let i = 0; i < results.length; i++) {
|
|
475
|
+
const result = results[i];
|
|
476
|
+
const currentSearch = normalizedSearches[i];
|
|
477
|
+
|
|
478
|
+
if (result.status === "fulfilled") {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// if we make it here then there was an error
|
|
483
|
+
const error = result.reason;
|
|
484
|
+
|
|
485
|
+
// unexpected errors should be re-thrown
|
|
486
|
+
if (!error.basePath) {
|
|
487
|
+
throw error;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (errorOnUnmatchedPattern) {
|
|
491
|
+
await throwErrorForUnmatchedPatterns({
|
|
492
|
+
...currentSearch,
|
|
493
|
+
unmatchedPatterns: error.unmatchedPatterns,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// second loop for `fulfilled` results
|
|
499
|
+
return results.flatMap(result => result.value);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Finds all files matching the options specified.
|
|
504
|
+
* @param {Object} args The arguments objects.
|
|
505
|
+
* @param {Array<string>} args.patterns An array of glob patterns.
|
|
506
|
+
* @param {boolean} args.globInputPaths true to interpret glob patterns,
|
|
507
|
+
* false to not interpret glob patterns.
|
|
508
|
+
* @param {string} args.cwd The current working directory to find from.
|
|
509
|
+
* @param {ConfigLoader} args.configLoader The config loader for the current run.
|
|
510
|
+
* @param {boolean} args.errorOnUnmatchedPattern Determines if an unmatched pattern
|
|
511
|
+
* should throw an error.
|
|
512
|
+
* @returns {Promise<Array<string>>} The fully resolved file paths.
|
|
513
|
+
* @throws {AllFilesIgnoredError} If there are no results due to an ignore pattern.
|
|
514
|
+
* @throws {NoFilesFoundError} If no files matched the given patterns.
|
|
515
|
+
*/
|
|
516
|
+
async function findFiles({
|
|
517
|
+
patterns,
|
|
518
|
+
globInputPaths,
|
|
519
|
+
cwd,
|
|
520
|
+
configLoader,
|
|
521
|
+
errorOnUnmatchedPattern,
|
|
522
|
+
}) {
|
|
523
|
+
const results = [];
|
|
524
|
+
const missingPatterns = [];
|
|
525
|
+
let globbyPatterns = [];
|
|
526
|
+
let rawPatterns = [];
|
|
527
|
+
const searches = new Map([
|
|
528
|
+
[cwd, { patterns: globbyPatterns, rawPatterns: [] }],
|
|
529
|
+
]);
|
|
530
|
+
|
|
531
|
+
/*
|
|
532
|
+
* This part is a bit involved because we need to account for
|
|
533
|
+
* the different ways that the patterns can match directories.
|
|
534
|
+
* For each different way, we need to decide if we should look
|
|
535
|
+
* for a config file or just use the default config. (Directories
|
|
536
|
+
* without a config file always use the default config.)
|
|
537
|
+
*
|
|
538
|
+
* Here are the cases:
|
|
539
|
+
*
|
|
540
|
+
* 1. A directory is passed directly (e.g., "subdir"). In this case, we
|
|
541
|
+
* can assume that the user intends to lint this directory and we should
|
|
542
|
+
* not look for a config file in the parent directory, because the only
|
|
543
|
+
* reason to do that would be to ignore this directory (which we already
|
|
544
|
+
* know we don't want to do). Instead, we use the default config until we
|
|
545
|
+
* get to the directory that was passed, at which point we start looking
|
|
546
|
+
* for config files again.
|
|
547
|
+
*
|
|
548
|
+
* 2. A dot (".") or star ("*"). In this case, we want to read
|
|
549
|
+
* the config file in the current directory because the user is
|
|
550
|
+
* explicitly asking to lint the current directory. Note that "."
|
|
551
|
+
* will traverse into subdirectories while "*" will not.
|
|
552
|
+
*
|
|
553
|
+
* 3. A directory is passed in the form of "subdir/subsubdir".
|
|
554
|
+
* In this case, we don't want to look for a config file in the
|
|
555
|
+
* parent directory ("subdir"). We can skip looking for a config
|
|
556
|
+
* file until `entry.depth` is greater than 1 because there's no
|
|
557
|
+
* way that the pattern can match `entry.path` yet.
|
|
558
|
+
*
|
|
559
|
+
* 4. A directory glob pattern is passed (e.g., "subd*"). We want
|
|
560
|
+
* this case to act like case 2 because it's unclear whether or not
|
|
561
|
+
* any particular directory is meant to be traversed.
|
|
562
|
+
*
|
|
563
|
+
* 5. A recursive glob pattern is passed (e.g., "**"). We want this
|
|
564
|
+
* case to act like case 2.
|
|
565
|
+
*/
|
|
566
|
+
|
|
567
|
+
// check to see if we have explicit files and directories
|
|
568
|
+
const filePaths = patterns.map(filePath => path.resolve(cwd, filePath));
|
|
569
|
+
const stats = await Promise.all(
|
|
570
|
+
filePaths.map(filePath => fsp.stat(filePath).catch(() => {})),
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
const promises = [];
|
|
574
|
+
stats.forEach((stat, index) => {
|
|
575
|
+
const filePath = filePaths[index];
|
|
576
|
+
const pattern = normalizeToPosix(patterns[index]);
|
|
577
|
+
|
|
578
|
+
if (stat) {
|
|
579
|
+
// files are added directly to the list
|
|
580
|
+
if (stat.isFile()) {
|
|
581
|
+
results.push(filePath);
|
|
582
|
+
promises.push(configLoader.loadConfigArrayForFile(filePath));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// directories need extensions attached
|
|
586
|
+
if (stat.isDirectory()) {
|
|
587
|
+
if (!searches.has(filePath)) {
|
|
588
|
+
searches.set(filePath, { patterns: [], rawPatterns: [] });
|
|
589
|
+
}
|
|
590
|
+
({ patterns: globbyPatterns, rawPatterns } =
|
|
591
|
+
searches.get(filePath));
|
|
592
|
+
|
|
593
|
+
globbyPatterns.push(`${normalizeToPosix(filePath)}/**`);
|
|
594
|
+
rawPatterns.push(pattern);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// save patterns for later use based on whether globs are enabled
|
|
601
|
+
if (globInputPaths && isGlobPattern(pattern)) {
|
|
602
|
+
/*
|
|
603
|
+
* We are grouping patterns by their glob parent. This is done to
|
|
604
|
+
* make it easier to determine when a config file should be loaded.
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
const basePath = path.resolve(cwd, globParent(pattern));
|
|
608
|
+
|
|
609
|
+
if (!searches.has(basePath)) {
|
|
610
|
+
searches.set(basePath, { patterns: [], rawPatterns: [] });
|
|
611
|
+
}
|
|
612
|
+
({ patterns: globbyPatterns, rawPatterns } =
|
|
613
|
+
searches.get(basePath));
|
|
614
|
+
|
|
615
|
+
globbyPatterns.push(filePath);
|
|
616
|
+
rawPatterns.push(pattern);
|
|
617
|
+
} else {
|
|
618
|
+
missingPatterns.push(pattern);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
// there were patterns that didn't match anything, tell the user
|
|
623
|
+
if (errorOnUnmatchedPattern && missingPatterns.length) {
|
|
624
|
+
throw new NoFilesFoundError(missingPatterns[0], globInputPaths);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// now we are safe to do the search
|
|
628
|
+
promises.push(
|
|
629
|
+
globMultiSearch({
|
|
630
|
+
searches,
|
|
631
|
+
configLoader,
|
|
632
|
+
errorOnUnmatchedPattern,
|
|
633
|
+
}),
|
|
634
|
+
);
|
|
635
|
+
const globbyResults = (await Promise.all(promises)).at(-1);
|
|
636
|
+
|
|
637
|
+
return [...new Set([...results, ...globbyResults])];
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Return the absolute path of a file named `"__placeholder__.js"` in a given directory.
|
|
642
|
+
* This is used as a replacement for a missing file path.
|
|
643
|
+
* @param {string} cwd An absolute directory path.
|
|
644
|
+
* @returns {string} The absolute path of a file named `"__placeholder__.js"` in the given directory.
|
|
645
|
+
*/
|
|
646
|
+
function getPlaceholderPath(cwd) {
|
|
647
|
+
return path.join(cwd, "__placeholder__.js");
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
//-----------------------------------------------------------------------------
|
|
651
|
+
// Results-related Helpers
|
|
652
|
+
//-----------------------------------------------------------------------------
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Checks if the given message is an error message.
|
|
656
|
+
* @param {LintMessage} message The message to check.
|
|
657
|
+
* @returns {boolean} Whether or not the message is an error message.
|
|
658
|
+
* @private
|
|
659
|
+
*/
|
|
660
|
+
function isErrorMessage(message) {
|
|
661
|
+
return message.severity === 2;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Returns result with warning by ignore settings
|
|
666
|
+
* @param {string} filePath Absolute file path of checked code
|
|
667
|
+
* @param {string} baseDir Absolute path of base directory
|
|
668
|
+
* @param {"ignored"|"external"|"unconfigured"} configStatus A status that determines why the file is ignored
|
|
669
|
+
* @returns {LintResult} Result with single warning
|
|
670
|
+
* @private
|
|
671
|
+
*/
|
|
672
|
+
function createIgnoreResult(filePath, baseDir, configStatus) {
|
|
673
|
+
let message;
|
|
674
|
+
|
|
675
|
+
switch (configStatus) {
|
|
676
|
+
case "external":
|
|
677
|
+
message = "File ignored because outside of base path.";
|
|
678
|
+
break;
|
|
679
|
+
case "unconfigured":
|
|
680
|
+
message =
|
|
681
|
+
"File ignored because no matching configuration was supplied.";
|
|
682
|
+
break;
|
|
683
|
+
default:
|
|
684
|
+
{
|
|
685
|
+
const isInNodeModules =
|
|
686
|
+
baseDir &&
|
|
687
|
+
path
|
|
688
|
+
.dirname(path.relative(baseDir, filePath))
|
|
689
|
+
.split(path.sep)
|
|
690
|
+
.includes("node_modules");
|
|
691
|
+
|
|
692
|
+
if (isInNodeModules) {
|
|
693
|
+
message =
|
|
694
|
+
'File ignored by default because it is located under the node_modules directory. Use ignore pattern "!**/node_modules/" to disable file ignore settings or use "--no-warn-ignored" to suppress this warning.';
|
|
695
|
+
} else {
|
|
696
|
+
message =
|
|
697
|
+
'File ignored because of a matching ignore pattern. Use "--no-ignore" to disable file ignore settings or use "--no-warn-ignored" to suppress this warning.';
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return {
|
|
704
|
+
filePath,
|
|
705
|
+
messages: [
|
|
706
|
+
{
|
|
707
|
+
ruleId: null,
|
|
708
|
+
fatal: false,
|
|
709
|
+
severity: 1,
|
|
710
|
+
message,
|
|
711
|
+
},
|
|
712
|
+
],
|
|
713
|
+
suppressedMessages: [],
|
|
714
|
+
errorCount: 0,
|
|
715
|
+
warningCount: 1,
|
|
716
|
+
fatalErrorCount: 0,
|
|
717
|
+
fixableErrorCount: 0,
|
|
718
|
+
fixableWarningCount: 0,
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* It will calculate the error and warning count for collection of messages per file
|
|
724
|
+
* @param {LintMessage[]} messages Collection of messages
|
|
725
|
+
* @returns {Object} Contains the stats
|
|
726
|
+
* @private
|
|
727
|
+
*/
|
|
728
|
+
function calculateStatsPerFile(messages) {
|
|
729
|
+
const stat = {
|
|
730
|
+
errorCount: 0,
|
|
731
|
+
fatalErrorCount: 0,
|
|
732
|
+
warningCount: 0,
|
|
733
|
+
fixableErrorCount: 0,
|
|
734
|
+
fixableWarningCount: 0,
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
for (let i = 0; i < messages.length; i++) {
|
|
738
|
+
const message = messages[i];
|
|
739
|
+
|
|
740
|
+
if (message.fatal || message.severity === 2) {
|
|
741
|
+
stat.errorCount++;
|
|
742
|
+
if (message.fatal) {
|
|
743
|
+
stat.fatalErrorCount++;
|
|
744
|
+
}
|
|
745
|
+
if (message.fix) {
|
|
746
|
+
stat.fixableErrorCount++;
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
stat.warningCount++;
|
|
750
|
+
if (message.fix) {
|
|
751
|
+
stat.fixableWarningCount++;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return stat;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
//-----------------------------------------------------------------------------
|
|
759
|
+
// Options-related Helpers
|
|
760
|
+
//-----------------------------------------------------------------------------
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Check if a given value is a valid fix type or not.
|
|
764
|
+
* @param {any} x The value to check.
|
|
765
|
+
* @returns {boolean} `true` if `x` is valid fix type.
|
|
766
|
+
*/
|
|
767
|
+
function isFixType(x) {
|
|
768
|
+
return (
|
|
769
|
+
x === "directive" ||
|
|
770
|
+
x === "problem" ||
|
|
771
|
+
x === "suggestion" ||
|
|
772
|
+
x === "layout"
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Check if a given value is an array of fix types or not.
|
|
778
|
+
* @param {any} x The value to check.
|
|
779
|
+
* @returns {boolean} `true` if `x` is an array of fix types.
|
|
780
|
+
*/
|
|
781
|
+
function isFixTypeArray(x) {
|
|
782
|
+
return Array.isArray(x) && x.every(isFixType);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* The error for invalid options.
|
|
787
|
+
*/
|
|
788
|
+
class ESLintInvalidOptionsError extends Error {
|
|
789
|
+
constructor(messages) {
|
|
790
|
+
super(`Invalid Options:\n- ${messages.join("\n- ")}`);
|
|
791
|
+
this.code = "ESLINT_INVALID_OPTIONS";
|
|
792
|
+
Error.captureStackTrace(this, ESLintInvalidOptionsError);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Validates and normalizes options for the wrapped CLIEngine instance.
|
|
798
|
+
* @param {ESLintOptions} options The options to process.
|
|
799
|
+
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
|
800
|
+
* @returns {ESLintOptions} The normalized options.
|
|
801
|
+
*/
|
|
802
|
+
function processOptions({
|
|
803
|
+
allowInlineConfig = true, // ← we cannot use `overrideConfig.noInlineConfig` instead because `allowInlineConfig` has side-effect that suppress warnings that show inline configs are ignored.
|
|
804
|
+
baseConfig = null,
|
|
805
|
+
cache = false,
|
|
806
|
+
cacheLocation = ".eslintcache",
|
|
807
|
+
cacheStrategy = "metadata",
|
|
808
|
+
concurrency = "off",
|
|
809
|
+
cwd = process.cwd(),
|
|
810
|
+
errorOnUnmatchedPattern = true,
|
|
811
|
+
fix = false,
|
|
812
|
+
fixTypes = null, // ← should be null by default because if it's an array then it suppresses rules that don't have the `meta.type` property.
|
|
813
|
+
flags = [],
|
|
814
|
+
globInputPaths = true,
|
|
815
|
+
ignore = true,
|
|
816
|
+
ignorePatterns = null,
|
|
817
|
+
overrideConfig = null,
|
|
818
|
+
overrideConfigFile = null,
|
|
819
|
+
plugins = {},
|
|
820
|
+
stats = false,
|
|
821
|
+
warnIgnored = true,
|
|
822
|
+
passOnNoPatterns = false,
|
|
823
|
+
ruleFilter = () => true,
|
|
824
|
+
...unknownOptions
|
|
825
|
+
}) {
|
|
826
|
+
const errors = [];
|
|
827
|
+
const unknownOptionKeys = Object.keys(unknownOptions);
|
|
828
|
+
|
|
829
|
+
if (unknownOptionKeys.length >= 1) {
|
|
830
|
+
errors.push(`Unknown options: ${unknownOptionKeys.join(", ")}`);
|
|
831
|
+
if (unknownOptionKeys.includes("cacheFile")) {
|
|
832
|
+
errors.push(
|
|
833
|
+
"'cacheFile' has been removed. Please use the 'cacheLocation' option instead.",
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
if (unknownOptionKeys.includes("configFile")) {
|
|
837
|
+
errors.push(
|
|
838
|
+
"'configFile' has been removed. Please use the 'overrideConfigFile' option instead.",
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
if (unknownOptionKeys.includes("envs")) {
|
|
842
|
+
errors.push("'envs' has been removed.");
|
|
843
|
+
}
|
|
844
|
+
if (unknownOptionKeys.includes("extensions")) {
|
|
845
|
+
errors.push("'extensions' has been removed.");
|
|
846
|
+
}
|
|
847
|
+
if (unknownOptionKeys.includes("resolvePluginsRelativeTo")) {
|
|
848
|
+
errors.push("'resolvePluginsRelativeTo' has been removed.");
|
|
849
|
+
}
|
|
850
|
+
if (unknownOptionKeys.includes("globals")) {
|
|
851
|
+
errors.push(
|
|
852
|
+
"'globals' has been removed. Please use the 'overrideConfig.languageOptions.globals' option instead.",
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
if (unknownOptionKeys.includes("ignorePath")) {
|
|
856
|
+
errors.push("'ignorePath' has been removed.");
|
|
857
|
+
}
|
|
858
|
+
if (unknownOptionKeys.includes("ignorePattern")) {
|
|
859
|
+
errors.push(
|
|
860
|
+
"'ignorePattern' has been removed. Please use the 'overrideConfig.ignorePatterns' option instead.",
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
if (unknownOptionKeys.includes("parser")) {
|
|
864
|
+
errors.push(
|
|
865
|
+
"'parser' has been removed. Please use the 'overrideConfig.languageOptions.parser' option instead.",
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
if (unknownOptionKeys.includes("parserOptions")) {
|
|
869
|
+
errors.push(
|
|
870
|
+
"'parserOptions' has been removed. Please use the 'overrideConfig.languageOptions.parserOptions' option instead.",
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
if (unknownOptionKeys.includes("rules")) {
|
|
874
|
+
errors.push(
|
|
875
|
+
"'rules' has been removed. Please use the 'overrideConfig.rules' option instead.",
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
if (unknownOptionKeys.includes("rulePaths")) {
|
|
879
|
+
errors.push(
|
|
880
|
+
"'rulePaths' has been removed. Please define your rules using plugins.",
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
if (unknownOptionKeys.includes("reportUnusedDisableDirectives")) {
|
|
884
|
+
errors.push(
|
|
885
|
+
"'reportUnusedDisableDirectives' has been removed. Please use the 'overrideConfig.linterOptions.reportUnusedDisableDirectives' option instead.",
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
if (typeof allowInlineConfig !== "boolean") {
|
|
890
|
+
errors.push("'allowInlineConfig' must be a boolean.");
|
|
891
|
+
}
|
|
892
|
+
if (typeof baseConfig !== "object") {
|
|
893
|
+
errors.push("'baseConfig' must be an object or null.");
|
|
894
|
+
}
|
|
895
|
+
if (typeof cache !== "boolean") {
|
|
896
|
+
errors.push("'cache' must be a boolean.");
|
|
897
|
+
}
|
|
898
|
+
if (!isNonEmptyString(cacheLocation)) {
|
|
899
|
+
errors.push("'cacheLocation' must be a non-empty string.");
|
|
900
|
+
}
|
|
901
|
+
if (cacheStrategy !== "metadata" && cacheStrategy !== "content") {
|
|
902
|
+
errors.push('\'cacheStrategy\' must be any of "metadata", "content".');
|
|
903
|
+
}
|
|
904
|
+
if (
|
|
905
|
+
concurrency !== "off" &&
|
|
906
|
+
concurrency !== "auto" &&
|
|
907
|
+
!isPositiveInteger(concurrency)
|
|
908
|
+
) {
|
|
909
|
+
errors.push(
|
|
910
|
+
'\'concurrency\' must be a positive integer, "auto", or "off".',
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
if (!isNonEmptyString(cwd) || !path.isAbsolute(cwd)) {
|
|
914
|
+
errors.push("'cwd' must be an absolute path.");
|
|
915
|
+
}
|
|
916
|
+
if (typeof errorOnUnmatchedPattern !== "boolean") {
|
|
917
|
+
errors.push("'errorOnUnmatchedPattern' must be a boolean.");
|
|
918
|
+
}
|
|
919
|
+
if (typeof fix !== "boolean" && typeof fix !== "function") {
|
|
920
|
+
errors.push("'fix' must be a boolean or a function.");
|
|
921
|
+
}
|
|
922
|
+
if (fixTypes !== null && !isFixTypeArray(fixTypes)) {
|
|
923
|
+
errors.push(
|
|
924
|
+
'\'fixTypes\' must be an array of any of "directive", "problem", "suggestion", and "layout".',
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
if (!isEmptyArrayOrArrayOfNonEmptyString(flags)) {
|
|
928
|
+
errors.push("'flags' must be an array of non-empty strings.");
|
|
929
|
+
}
|
|
930
|
+
if (typeof globInputPaths !== "boolean") {
|
|
931
|
+
errors.push("'globInputPaths' must be a boolean.");
|
|
932
|
+
}
|
|
933
|
+
if (typeof ignore !== "boolean") {
|
|
934
|
+
errors.push("'ignore' must be a boolean.");
|
|
935
|
+
}
|
|
936
|
+
if (
|
|
937
|
+
!isEmptyArrayOrArrayOfNonEmptyString(ignorePatterns) &&
|
|
938
|
+
ignorePatterns !== null
|
|
939
|
+
) {
|
|
940
|
+
errors.push(
|
|
941
|
+
"'ignorePatterns' must be an array of non-empty strings or null.",
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
if (typeof overrideConfig !== "object") {
|
|
945
|
+
errors.push("'overrideConfig' must be an object or null.");
|
|
946
|
+
}
|
|
947
|
+
if (
|
|
948
|
+
!isNonEmptyString(overrideConfigFile) &&
|
|
949
|
+
overrideConfigFile !== null &&
|
|
950
|
+
overrideConfigFile !== true
|
|
951
|
+
) {
|
|
952
|
+
errors.push(
|
|
953
|
+
"'overrideConfigFile' must be a non-empty string, null, or true.",
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
if (typeof passOnNoPatterns !== "boolean") {
|
|
957
|
+
errors.push("'passOnNoPatterns' must be a boolean.");
|
|
958
|
+
}
|
|
959
|
+
if (typeof plugins !== "object") {
|
|
960
|
+
errors.push("'plugins' must be an object or null.");
|
|
961
|
+
} else if (plugins !== null && Object.keys(plugins).includes("")) {
|
|
962
|
+
errors.push("'plugins' must not include an empty string.");
|
|
963
|
+
}
|
|
964
|
+
if (Array.isArray(plugins)) {
|
|
965
|
+
errors.push(
|
|
966
|
+
"'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.",
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
if (typeof stats !== "boolean") {
|
|
970
|
+
errors.push("'stats' must be a boolean.");
|
|
971
|
+
}
|
|
972
|
+
if (typeof warnIgnored !== "boolean") {
|
|
973
|
+
errors.push("'warnIgnored' must be a boolean.");
|
|
974
|
+
}
|
|
975
|
+
if (typeof ruleFilter !== "function") {
|
|
976
|
+
errors.push("'ruleFilter' must be a function.");
|
|
977
|
+
}
|
|
978
|
+
if (errors.length > 0) {
|
|
979
|
+
throw new ESLintInvalidOptionsError(errors);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return {
|
|
983
|
+
allowInlineConfig,
|
|
984
|
+
baseConfig,
|
|
985
|
+
cache,
|
|
986
|
+
cacheLocation,
|
|
987
|
+
cacheStrategy,
|
|
988
|
+
concurrency,
|
|
989
|
+
|
|
990
|
+
// when overrideConfigFile is true that means don't do config file lookup
|
|
991
|
+
configFile: overrideConfigFile === true ? false : overrideConfigFile,
|
|
992
|
+
overrideConfig,
|
|
993
|
+
cwd: path.normalize(cwd),
|
|
994
|
+
errorOnUnmatchedPattern,
|
|
995
|
+
fix,
|
|
996
|
+
fixTypes,
|
|
997
|
+
flags: [...flags],
|
|
998
|
+
globInputPaths,
|
|
999
|
+
ignore,
|
|
1000
|
+
ignorePatterns,
|
|
1001
|
+
stats,
|
|
1002
|
+
passOnNoPatterns,
|
|
1003
|
+
warnIgnored,
|
|
1004
|
+
ruleFilter,
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Loads ESLint constructor options from an options module.
|
|
1010
|
+
* @param {string} optionsURL The URL string of the options module to load.
|
|
1011
|
+
* @returns {Promise<ESLintOptions>} ESLint constructor options.
|
|
1012
|
+
*/
|
|
1013
|
+
async function loadOptionsFromModule(optionsURL) {
|
|
1014
|
+
return (await import(optionsURL)).default;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
//-----------------------------------------------------------------------------
|
|
1018
|
+
// Cache-related helpers
|
|
1019
|
+
//-----------------------------------------------------------------------------
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* return the cacheFile to be used by eslint, based on whether the provided parameter is
|
|
1023
|
+
* a directory or looks like a directory (ends in `path.sep`), in which case the file
|
|
1024
|
+
* name will be the `cacheFile/.cache_hashOfCWD`
|
|
1025
|
+
*
|
|
1026
|
+
* if cacheFile points to a file or looks like a file then in will just use that file
|
|
1027
|
+
* @param {string} cacheFile The name of file to be used to store the cache
|
|
1028
|
+
* @param {string} cwd Current working directory
|
|
1029
|
+
* @param {Object} options The options
|
|
1030
|
+
* @param {string} [options.prefix] The prefix to use for the cache file
|
|
1031
|
+
* @returns {string} the resolved path to the cache file
|
|
1032
|
+
*/
|
|
1033
|
+
function getCacheFile(cacheFile, cwd, { prefix = ".cache_" } = {}) {
|
|
1034
|
+
/*
|
|
1035
|
+
* make sure the path separators are normalized for the environment/os
|
|
1036
|
+
* keeping the trailing path separator if present
|
|
1037
|
+
*/
|
|
1038
|
+
const normalizedCacheFile = path.normalize(cacheFile);
|
|
1039
|
+
|
|
1040
|
+
const resolvedCacheFile = path.resolve(cwd, normalizedCacheFile);
|
|
1041
|
+
const looksLikeADirectory = normalizedCacheFile.slice(-1) === path.sep;
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* return the name for the cache file in case the provided parameter is a directory
|
|
1045
|
+
* @returns {string} the resolved path to the cacheFile
|
|
1046
|
+
*/
|
|
1047
|
+
function getCacheFileForDirectory() {
|
|
1048
|
+
return path.join(resolvedCacheFile, `${prefix}${hash(cwd)}`);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
let fileStats;
|
|
1052
|
+
|
|
1053
|
+
try {
|
|
1054
|
+
fileStats = fs.lstatSync(resolvedCacheFile);
|
|
1055
|
+
} catch {
|
|
1056
|
+
fileStats = null;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/*
|
|
1060
|
+
* in case the file exists we need to verify if the provided path
|
|
1061
|
+
* is a directory or a file. If it is a directory we want to create a file
|
|
1062
|
+
* inside that directory
|
|
1063
|
+
*/
|
|
1064
|
+
if (fileStats) {
|
|
1065
|
+
/*
|
|
1066
|
+
* is a directory or is a file, but the original file the user provided
|
|
1067
|
+
* looks like a directory but `path.resolve` removed the `last path.sep`
|
|
1068
|
+
* so we need to still treat this like a directory
|
|
1069
|
+
*/
|
|
1070
|
+
if (fileStats.isDirectory() || looksLikeADirectory) {
|
|
1071
|
+
return getCacheFileForDirectory();
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// is file so just use that file
|
|
1075
|
+
return resolvedCacheFile;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/*
|
|
1079
|
+
* here we known the file or directory doesn't exist,
|
|
1080
|
+
* so we will try to infer if its a directory if it looks like a directory
|
|
1081
|
+
* for the current operating system.
|
|
1082
|
+
*/
|
|
1083
|
+
|
|
1084
|
+
// if the last character passed is a path separator we assume is a directory
|
|
1085
|
+
if (looksLikeADirectory) {
|
|
1086
|
+
return getCacheFileForDirectory();
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
return resolvedCacheFile;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Creates a new lint result cache.
|
|
1094
|
+
* @param {ESLintOptions} eslintOptions The processed ESLint options.
|
|
1095
|
+
* @param {string} cacheFilePath The path to the cache file.
|
|
1096
|
+
* @returns {?LintResultCache} A new lint result cache or `null`.
|
|
1097
|
+
*/
|
|
1098
|
+
function createLintResultCache({ cache, cacheStrategy }, cacheFilePath) {
|
|
1099
|
+
return cache ? new LintResultCache(cacheFilePath, cacheStrategy) : null;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
//-----------------------------------------------------------------------------
|
|
1103
|
+
// Lint helpers
|
|
1104
|
+
//-----------------------------------------------------------------------------
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* Checks whether a message's rule type should be fixed.
|
|
1108
|
+
* @param {LintMessage} message The message to check.
|
|
1109
|
+
* @param {CalculatedConfig} config The config for the file that generated the message.
|
|
1110
|
+
* @param {string[]} fixTypes An array of fix types to check.
|
|
1111
|
+
* @returns {boolean} Whether the message should be fixed.
|
|
1112
|
+
*/
|
|
1113
|
+
function shouldMessageBeFixed(message, config, fixTypes) {
|
|
1114
|
+
if (!message.ruleId) {
|
|
1115
|
+
return fixTypes.has("directive");
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
const rule = message.ruleId && config.getRuleDefinition(message.ruleId);
|
|
1119
|
+
|
|
1120
|
+
return Boolean(rule && rule.meta && fixTypes.has(rule.meta.type));
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Creates a fixer function based on the provided fix, fixTypesSet, and config.
|
|
1125
|
+
* @param {Function|boolean} fix The original fix option.
|
|
1126
|
+
* @param {Set<string>} fixTypesSet A set of fix types to filter messages for fixing.
|
|
1127
|
+
* @param {CalculatedConfig} config The config for the file that generated the message.
|
|
1128
|
+
* @returns {Function|boolean} The fixer function or the original fix value.
|
|
1129
|
+
*/
|
|
1130
|
+
function getFixerForFixTypes(fix, fixTypesSet, config) {
|
|
1131
|
+
if (!fix || !fixTypesSet) {
|
|
1132
|
+
return fix;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const originalFix = typeof fix === "function" ? fix : () => true;
|
|
1136
|
+
|
|
1137
|
+
return message =>
|
|
1138
|
+
shouldMessageBeFixed(message, config, fixTypesSet) &&
|
|
1139
|
+
originalFix(message);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* Processes a source code using ESLint.
|
|
1144
|
+
* @param {Object} config The config object.
|
|
1145
|
+
* @param {string} config.text The source code to verify.
|
|
1146
|
+
* @param {string} config.cwd The path to the current working directory.
|
|
1147
|
+
* @param {string|undefined} config.filePath The path to the file of `text`. If this is undefined, it uses `<text>`.
|
|
1148
|
+
* @param {FlatConfigArray} config.configs The config.
|
|
1149
|
+
* @param {boolean} config.fix If `true` then it does fix.
|
|
1150
|
+
* @param {boolean} config.allowInlineConfig If `true` then it uses directive comments.
|
|
1151
|
+
* @param {Function} config.ruleFilter A predicate function to filter which rules should be run.
|
|
1152
|
+
* @param {boolean} config.stats If `true`, then if reports extra statistics with the lint results.
|
|
1153
|
+
* @param {Linter} config.linter The linter instance to verify.
|
|
1154
|
+
* @returns {LintResult} The result of linting.
|
|
1155
|
+
* @private
|
|
1156
|
+
*/
|
|
1157
|
+
function verifyText({
|
|
1158
|
+
text,
|
|
1159
|
+
cwd,
|
|
1160
|
+
filePath: providedFilePath,
|
|
1161
|
+
configs,
|
|
1162
|
+
fix,
|
|
1163
|
+
allowInlineConfig,
|
|
1164
|
+
ruleFilter,
|
|
1165
|
+
stats,
|
|
1166
|
+
linter,
|
|
1167
|
+
}) {
|
|
1168
|
+
const startTime = hrtimeBigint();
|
|
1169
|
+
|
|
1170
|
+
const filePath = providedFilePath || "<text>";
|
|
1171
|
+
|
|
1172
|
+
/*
|
|
1173
|
+
* Verify.
|
|
1174
|
+
* `config.extractConfig(filePath)` requires an absolute path, but `linter`
|
|
1175
|
+
* doesn't know CWD, so it gives `linter` an absolute path always.
|
|
1176
|
+
*/
|
|
1177
|
+
const filePathToVerify =
|
|
1178
|
+
filePath === "<text>" ? getPlaceholderPath(cwd) : filePath;
|
|
1179
|
+
const { fixed, messages, output } = linter.verifyAndFix(text, configs, {
|
|
1180
|
+
allowInlineConfig,
|
|
1181
|
+
filename: filePathToVerify,
|
|
1182
|
+
fix,
|
|
1183
|
+
ruleFilter,
|
|
1184
|
+
stats,
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* Check if the linter should adopt a given code block or not.
|
|
1188
|
+
* @param {string} blockFilename The virtual filename of a code block.
|
|
1189
|
+
* @returns {boolean} `true` if the linter should adopt the code block.
|
|
1190
|
+
*/
|
|
1191
|
+
filterCodeBlock(blockFilename) {
|
|
1192
|
+
return configs.getConfig(blockFilename) !== void 0;
|
|
1193
|
+
},
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
// Tweak and return.
|
|
1197
|
+
const result = {
|
|
1198
|
+
filePath: filePath === "<text>" ? filePath : path.resolve(filePath),
|
|
1199
|
+
messages,
|
|
1200
|
+
suppressedMessages: linter.getSuppressedMessages(),
|
|
1201
|
+
...calculateStatsPerFile(messages),
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
if (fixed) {
|
|
1205
|
+
result.output = output;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if (
|
|
1209
|
+
result.errorCount + result.warningCount > 0 &&
|
|
1210
|
+
typeof result.output === "undefined"
|
|
1211
|
+
) {
|
|
1212
|
+
result.source = text;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
if (stats) {
|
|
1216
|
+
result.stats = {
|
|
1217
|
+
times: linter.getTimes(),
|
|
1218
|
+
fixPasses: linter.getFixPassCount(),
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
const endTime = hrtimeBigint();
|
|
1223
|
+
debug('File "%s" linted in %t', filePath, endTime - startTime);
|
|
1224
|
+
|
|
1225
|
+
return result;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* Lints a single file.
|
|
1230
|
+
* @param {string} filePath File path to lint.
|
|
1231
|
+
* @param {FlatConfigArray} configs The config array for the file.
|
|
1232
|
+
* @param {ESLintOptions} eslintOptions The processed ESLint options.
|
|
1233
|
+
* @param {Linter} linter The linter instance to use.
|
|
1234
|
+
* @param {?LintResultCache} lintResultCache The result cache or `null`.
|
|
1235
|
+
* @param {?{ duration: bigint; }} readFileCounter Used to keep track of the time spent reading files.
|
|
1236
|
+
* @param {Retrier} [retrier] Used to retry linting on certain errors.
|
|
1237
|
+
* @param {AbortController} [controller] Used to stop linting when an error occurs.
|
|
1238
|
+
* @returns {Promise<LintResult>} The lint result.
|
|
1239
|
+
*/
|
|
1240
|
+
async function lintFile(
|
|
1241
|
+
filePath,
|
|
1242
|
+
configs,
|
|
1243
|
+
eslintOptions,
|
|
1244
|
+
linter,
|
|
1245
|
+
lintResultCache,
|
|
1246
|
+
readFileCounter,
|
|
1247
|
+
retrier,
|
|
1248
|
+
controller,
|
|
1249
|
+
) {
|
|
1250
|
+
const config = configs.getConfig(filePath);
|
|
1251
|
+
const {
|
|
1252
|
+
allowInlineConfig,
|
|
1253
|
+
cwd,
|
|
1254
|
+
fix,
|
|
1255
|
+
fixTypes,
|
|
1256
|
+
ruleFilter,
|
|
1257
|
+
stats,
|
|
1258
|
+
warnIgnored,
|
|
1259
|
+
} = eslintOptions;
|
|
1260
|
+
const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
|
|
1261
|
+
|
|
1262
|
+
/*
|
|
1263
|
+
* If a filename was entered that cannot be matched
|
|
1264
|
+
* to a config, then notify the user.
|
|
1265
|
+
*/
|
|
1266
|
+
if (!config) {
|
|
1267
|
+
if (warnIgnored) {
|
|
1268
|
+
const configStatus = configs.getConfigStatus(filePath);
|
|
1269
|
+
|
|
1270
|
+
return createIgnoreResult(filePath, cwd, configStatus);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
return void 0;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// Skip if there is cached result.
|
|
1277
|
+
if (lintResultCache) {
|
|
1278
|
+
const cachedResult = lintResultCache.getCachedLintResults(
|
|
1279
|
+
filePath,
|
|
1280
|
+
config,
|
|
1281
|
+
);
|
|
1282
|
+
|
|
1283
|
+
if (cachedResult) {
|
|
1284
|
+
const hadMessages =
|
|
1285
|
+
cachedResult.messages && cachedResult.messages.length > 0;
|
|
1286
|
+
|
|
1287
|
+
if (hadMessages && fix) {
|
|
1288
|
+
debug(`Reprocessing cached file to allow autofix: ${filePath}`);
|
|
1289
|
+
} else {
|
|
1290
|
+
debug(`Skipping file since it hasn't changed: ${filePath}`);
|
|
1291
|
+
return cachedResult;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// set up fixer for fixTypes if necessary
|
|
1297
|
+
const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Reads the file and lints its content.
|
|
1301
|
+
* @returns {Promise<LintResult>} A lint result.
|
|
1302
|
+
*/
|
|
1303
|
+
async function readAndVerifyFile() {
|
|
1304
|
+
const readFileEnterTime = hrtimeBigint();
|
|
1305
|
+
const text = await fsp.readFile(filePath, {
|
|
1306
|
+
encoding: "utf8",
|
|
1307
|
+
signal: controller?.signal,
|
|
1308
|
+
});
|
|
1309
|
+
const readFileExitTime = hrtimeBigint();
|
|
1310
|
+
const readFileDuration = readFileExitTime - readFileEnterTime;
|
|
1311
|
+
debug('File "%s" read in %t', filePath, readFileDuration);
|
|
1312
|
+
if (readFileCounter) {
|
|
1313
|
+
readFileCounter.duration += readFileDuration;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// fail immediately if an error occurred in another file
|
|
1317
|
+
controller?.signal.throwIfAborted();
|
|
1318
|
+
|
|
1319
|
+
// do the linting
|
|
1320
|
+
return verifyText({
|
|
1321
|
+
text,
|
|
1322
|
+
filePath,
|
|
1323
|
+
configs,
|
|
1324
|
+
cwd,
|
|
1325
|
+
fix: fixer,
|
|
1326
|
+
allowInlineConfig,
|
|
1327
|
+
ruleFilter,
|
|
1328
|
+
stats,
|
|
1329
|
+
linter,
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// Use the retrier if provided, otherwise just call the function.
|
|
1334
|
+
const readAndVerifyFilePromise = retrier
|
|
1335
|
+
? retrier.retry(readAndVerifyFile, { signal: controller?.signal })
|
|
1336
|
+
: readAndVerifyFile();
|
|
1337
|
+
|
|
1338
|
+
return readAndVerifyFilePromise.catch(error => {
|
|
1339
|
+
controller?.abort(error);
|
|
1340
|
+
throw error;
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* Retrieves flags from the environment variable ESLINT_FLAGS.
|
|
1346
|
+
* @param {string[]} flags The flags defined via the API.
|
|
1347
|
+
* @returns {string[]} The merged flags to use.
|
|
1348
|
+
*/
|
|
1349
|
+
function mergeEnvironmentFlags(flags) {
|
|
1350
|
+
if (!process.env.ESLINT_FLAGS) {
|
|
1351
|
+
return flags;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
const envFlags = process.env.ESLINT_FLAGS.trim().split(/\s*,\s*/gu);
|
|
1355
|
+
return Array.from(new Set([...envFlags, ...flags]));
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
/**
|
|
1359
|
+
* Creates a new linter instance.
|
|
1360
|
+
* @param {ESLintOptions} eslintOptions The processed ESLint options.
|
|
1361
|
+
* @param {WarningService} warningService The warning service to use.
|
|
1362
|
+
* @returns {Linter} The linter instance.
|
|
1363
|
+
*/
|
|
1364
|
+
function createLinter({ cwd, flags }, warningService) {
|
|
1365
|
+
return new Linter({
|
|
1366
|
+
configType: "flat",
|
|
1367
|
+
cwd,
|
|
1368
|
+
flags: mergeEnvironmentFlags(flags),
|
|
1369
|
+
warningService,
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
/**
|
|
1374
|
+
* Creates default configs with the specified plugins.
|
|
1375
|
+
* @param {Record<string, Plugin> | undefined} optionPlugins The plugins specified in the ESLint options.
|
|
1376
|
+
* @returns {Config[]} The default configs.
|
|
1377
|
+
*/
|
|
1378
|
+
function createDefaultConfigs(optionPlugins) {
|
|
1379
|
+
const defaultConfigs = [];
|
|
1380
|
+
|
|
1381
|
+
// Add plugins
|
|
1382
|
+
if (optionPlugins) {
|
|
1383
|
+
const plugins = {};
|
|
1384
|
+
|
|
1385
|
+
for (const [pluginName, plugin] of Object.entries(optionPlugins)) {
|
|
1386
|
+
plugins[getShorthandName(pluginName, "eslint-plugin")] = plugin;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
defaultConfigs.push({ plugins });
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
return defaultConfigs;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Creates a config loader.
|
|
1397
|
+
* @param {ESLintOptions} eslintOptions The processed ESLint options.
|
|
1398
|
+
* @param {Config[]} defaultConfigs The default configs.
|
|
1399
|
+
* @param {Linter} linter The linter instance.
|
|
1400
|
+
* @param {WarningService} warningService The warning service to use.
|
|
1401
|
+
* @returns {ConfigLoader} The config loader.
|
|
1402
|
+
*/
|
|
1403
|
+
function createConfigLoader(
|
|
1404
|
+
{
|
|
1405
|
+
cwd,
|
|
1406
|
+
baseConfig,
|
|
1407
|
+
overrideConfig,
|
|
1408
|
+
configFile,
|
|
1409
|
+
ignore: ignoreEnabled,
|
|
1410
|
+
ignorePatterns,
|
|
1411
|
+
},
|
|
1412
|
+
defaultConfigs,
|
|
1413
|
+
linter,
|
|
1414
|
+
warningService,
|
|
1415
|
+
) {
|
|
1416
|
+
const configLoaderOptions = {
|
|
1417
|
+
cwd,
|
|
1418
|
+
baseConfig,
|
|
1419
|
+
overrideConfig,
|
|
1420
|
+
configFile,
|
|
1421
|
+
ignoreEnabled,
|
|
1422
|
+
ignorePatterns,
|
|
1423
|
+
defaultConfigs,
|
|
1424
|
+
hasUnstableNativeNodeJsTSConfigFlag: linter.hasFlag(
|
|
1425
|
+
"unstable_native_nodejs_ts_config",
|
|
1426
|
+
),
|
|
1427
|
+
warningService,
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
return new ConfigLoader(configLoaderOptions);
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
//-----------------------------------------------------------------------------
|
|
1434
|
+
// Exports
|
|
1435
|
+
//-----------------------------------------------------------------------------
|
|
1436
|
+
|
|
1437
|
+
module.exports = {
|
|
1438
|
+
createDebug,
|
|
1439
|
+
|
|
1440
|
+
findFiles,
|
|
1441
|
+
|
|
1442
|
+
isNonEmptyString,
|
|
1443
|
+
isArrayOfNonEmptyString,
|
|
1444
|
+
|
|
1445
|
+
createIgnoreResult,
|
|
1446
|
+
isErrorMessage,
|
|
1447
|
+
calculateStatsPerFile,
|
|
1448
|
+
getPlaceholderPath,
|
|
1449
|
+
|
|
1450
|
+
processOptions,
|
|
1451
|
+
loadOptionsFromModule,
|
|
1452
|
+
|
|
1453
|
+
getCacheFile,
|
|
1454
|
+
createLintResultCache,
|
|
1455
|
+
|
|
1456
|
+
getFixerForFixTypes,
|
|
1457
|
+
verifyText,
|
|
1458
|
+
lintFile,
|
|
1459
|
+
createLinter,
|
|
1460
|
+
createDefaultConfigs,
|
|
1461
|
+
createConfigLoader,
|
|
1462
|
+
};
|