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,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview A rule to disallow the type conversions with shorter notations.
|
|
3
|
+
* @author Toru Nagashima
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const astUtils = require("./utils/ast-utils");
|
|
9
|
+
|
|
10
|
+
//------------------------------------------------------------------------------
|
|
11
|
+
// Helpers
|
|
12
|
+
//------------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/u;
|
|
15
|
+
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "- -", "-", "*"];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks whether or not a node is a double logical negating.
|
|
19
|
+
* @param {ASTNode} node An UnaryExpression node to check.
|
|
20
|
+
* @returns {boolean} Whether or not the node is a double logical negating.
|
|
21
|
+
*/
|
|
22
|
+
function isDoubleLogicalNegating(node) {
|
|
23
|
+
return (
|
|
24
|
+
node.operator === "!" &&
|
|
25
|
+
node.argument.type === "UnaryExpression" &&
|
|
26
|
+
node.argument.operator === "!"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checks whether or not a node is a binary negating of `.indexOf()` method calling.
|
|
32
|
+
* @param {ASTNode} node An UnaryExpression node to check.
|
|
33
|
+
* @returns {boolean} Whether or not the node is a binary negating of `.indexOf()` method calling.
|
|
34
|
+
*/
|
|
35
|
+
function isBinaryNegatingOfIndexOf(node) {
|
|
36
|
+
if (node.operator !== "~") {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const callNode = astUtils.skipChainExpression(node.argument);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
callNode.type === "CallExpression" &&
|
|
43
|
+
astUtils.isSpecificMemberAccess(callNode.callee, null, INDEX_OF_PATTERN)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Checks whether or not a node is a multiplying by one.
|
|
49
|
+
* @param {BinaryExpression} node A BinaryExpression node to check.
|
|
50
|
+
* @returns {boolean} Whether or not the node is a multiplying by one.
|
|
51
|
+
*/
|
|
52
|
+
function isMultiplyByOne(node) {
|
|
53
|
+
return (
|
|
54
|
+
node.operator === "*" &&
|
|
55
|
+
((node.left.type === "Literal" && node.left.value === 1) ||
|
|
56
|
+
(node.right.type === "Literal" && node.right.value === 1))
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Checks whether the given node logically represents multiplication by a fraction of `1`.
|
|
62
|
+
* For example, `a * 1` in `a * 1 / b` is technically multiplication by `1`, but the
|
|
63
|
+
* whole expression can be logically interpreted as `a * (1 / b)` rather than `(a * 1) / b`.
|
|
64
|
+
* @param {BinaryExpression} node A BinaryExpression node to check.
|
|
65
|
+
* @param {SourceCode} sourceCode The source code object.
|
|
66
|
+
* @returns {boolean} Whether or not the node is a multiplying by a fraction of `1`.
|
|
67
|
+
*/
|
|
68
|
+
function isMultiplyByFractionOfOne(node, sourceCode) {
|
|
69
|
+
return (
|
|
70
|
+
node.type === "BinaryExpression" &&
|
|
71
|
+
node.operator === "*" &&
|
|
72
|
+
node.right.type === "Literal" &&
|
|
73
|
+
node.right.value === 1 &&
|
|
74
|
+
node.parent.type === "BinaryExpression" &&
|
|
75
|
+
node.parent.operator === "/" &&
|
|
76
|
+
node.parent.left === node &&
|
|
77
|
+
!astUtils.isParenthesised(sourceCode, node)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Checks whether the result of a node is numeric or not
|
|
83
|
+
* @param {ASTNode} node The node to test
|
|
84
|
+
* @returns {boolean} true if the node is a number literal or a `Number()`, `parseInt` or `parseFloat` call
|
|
85
|
+
*/
|
|
86
|
+
function isNumeric(node) {
|
|
87
|
+
return (
|
|
88
|
+
(node.type === "Literal" && typeof node.value === "number") ||
|
|
89
|
+
(node.type === "CallExpression" &&
|
|
90
|
+
(node.callee.name === "Number" ||
|
|
91
|
+
node.callee.name === "parseInt" ||
|
|
92
|
+
node.callee.name === "parseFloat"))
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns the first non-numeric operand in a BinaryExpression. Designed to be
|
|
98
|
+
* used from bottom to up since it walks up the BinaryExpression trees using
|
|
99
|
+
* node.parent to find the result.
|
|
100
|
+
* @param {BinaryExpression} node The BinaryExpression node to be walked up on
|
|
101
|
+
* @returns {ASTNode|null} The first non-numeric item in the BinaryExpression tree or null
|
|
102
|
+
*/
|
|
103
|
+
function getNonNumericOperand(node) {
|
|
104
|
+
const left = node.left,
|
|
105
|
+
right = node.right;
|
|
106
|
+
|
|
107
|
+
if (right.type !== "BinaryExpression" && !isNumeric(right)) {
|
|
108
|
+
return right;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (left.type !== "BinaryExpression" && !isNumeric(left)) {
|
|
112
|
+
return left;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Checks whether an expression evaluates to a string.
|
|
120
|
+
* @param {ASTNode} node node that represents the expression to check.
|
|
121
|
+
* @returns {boolean} Whether or not the expression evaluates to a string.
|
|
122
|
+
*/
|
|
123
|
+
function isStringType(node) {
|
|
124
|
+
return (
|
|
125
|
+
astUtils.isStringLiteral(node) ||
|
|
126
|
+
(node.type === "CallExpression" &&
|
|
127
|
+
node.callee.type === "Identifier" &&
|
|
128
|
+
node.callee.name === "String")
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Checks whether a node is an empty string literal or not.
|
|
134
|
+
* @param {ASTNode} node The node to check.
|
|
135
|
+
* @returns {boolean} Whether or not the passed in node is an
|
|
136
|
+
* empty string literal or not.
|
|
137
|
+
*/
|
|
138
|
+
function isEmptyString(node) {
|
|
139
|
+
return (
|
|
140
|
+
astUtils.isStringLiteral(node) &&
|
|
141
|
+
(node.value === "" ||
|
|
142
|
+
(node.type === "TemplateLiteral" &&
|
|
143
|
+
node.quasis.length === 1 &&
|
|
144
|
+
node.quasis[0].value.cooked === ""))
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Checks whether or not a node is a concatenating with an empty string.
|
|
150
|
+
* @param {ASTNode} node A BinaryExpression node to check.
|
|
151
|
+
* @returns {boolean} Whether or not the node is a concatenating with an empty string.
|
|
152
|
+
*/
|
|
153
|
+
function isConcatWithEmptyString(node) {
|
|
154
|
+
return (
|
|
155
|
+
node.operator === "+" &&
|
|
156
|
+
((isEmptyString(node.left) && !isStringType(node.right)) ||
|
|
157
|
+
(isEmptyString(node.right) && !isStringType(node.left)))
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Checks whether or not a node is appended with an empty string.
|
|
163
|
+
* @param {ASTNode} node An AssignmentExpression node to check.
|
|
164
|
+
* @returns {boolean} Whether or not the node is appended with an empty string.
|
|
165
|
+
*/
|
|
166
|
+
function isAppendEmptyString(node) {
|
|
167
|
+
return node.operator === "+=" && isEmptyString(node.right);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Returns the operand that is not an empty string from a flagged BinaryExpression.
|
|
172
|
+
* @param {ASTNode} node The flagged BinaryExpression node to check.
|
|
173
|
+
* @returns {ASTNode} The operand that is not an empty string from a flagged BinaryExpression.
|
|
174
|
+
*/
|
|
175
|
+
function getNonEmptyOperand(node) {
|
|
176
|
+
return isEmptyString(node.left) ? node.right : node.left;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
//------------------------------------------------------------------------------
|
|
180
|
+
// Rule Definition
|
|
181
|
+
//------------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
184
|
+
module.exports = {
|
|
185
|
+
meta: {
|
|
186
|
+
hasSuggestions: true,
|
|
187
|
+
type: "suggestion",
|
|
188
|
+
|
|
189
|
+
docs: {
|
|
190
|
+
description: "Disallow shorthand type conversions",
|
|
191
|
+
recommended: false,
|
|
192
|
+
frozen: true,
|
|
193
|
+
url: "https://eslint.org/docs/latest/rules/no-implicit-coercion",
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
fixable: "code",
|
|
197
|
+
|
|
198
|
+
schema: [
|
|
199
|
+
{
|
|
200
|
+
type: "object",
|
|
201
|
+
properties: {
|
|
202
|
+
boolean: {
|
|
203
|
+
type: "boolean",
|
|
204
|
+
},
|
|
205
|
+
number: {
|
|
206
|
+
type: "boolean",
|
|
207
|
+
},
|
|
208
|
+
string: {
|
|
209
|
+
type: "boolean",
|
|
210
|
+
},
|
|
211
|
+
disallowTemplateShorthand: {
|
|
212
|
+
type: "boolean",
|
|
213
|
+
},
|
|
214
|
+
allow: {
|
|
215
|
+
type: "array",
|
|
216
|
+
items: {
|
|
217
|
+
enum: ALLOWABLE_OPERATORS,
|
|
218
|
+
},
|
|
219
|
+
uniqueItems: true,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
additionalProperties: false,
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
|
|
226
|
+
defaultOptions: [
|
|
227
|
+
{
|
|
228
|
+
allow: [],
|
|
229
|
+
boolean: true,
|
|
230
|
+
disallowTemplateShorthand: false,
|
|
231
|
+
number: true,
|
|
232
|
+
string: true,
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
|
|
236
|
+
messages: {
|
|
237
|
+
implicitCoercion:
|
|
238
|
+
"Unexpected implicit coercion encountered. Use `{{recommendation}}` instead.",
|
|
239
|
+
useRecommendation: "Use `{{recommendation}}` instead.",
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
create(context) {
|
|
244
|
+
const [options] = context.options;
|
|
245
|
+
const sourceCode = context.sourceCode;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Reports an error and autofixes the node
|
|
249
|
+
* @param {ASTNode} node An ast node to report the error on.
|
|
250
|
+
* @param {string} recommendation The recommended code for the issue
|
|
251
|
+
* @param {bool} shouldSuggest Whether this report should offer a suggestion
|
|
252
|
+
* @param {bool} shouldFix Whether this report should fix the node
|
|
253
|
+
* @returns {void}
|
|
254
|
+
*/
|
|
255
|
+
function report(node, recommendation, shouldSuggest, shouldFix) {
|
|
256
|
+
/**
|
|
257
|
+
* Fix function
|
|
258
|
+
* @param {RuleFixer} fixer The fixer to fix.
|
|
259
|
+
* @returns {Fix} The fix object.
|
|
260
|
+
*/
|
|
261
|
+
function fix(fixer) {
|
|
262
|
+
const tokenBefore = sourceCode.getTokenBefore(node);
|
|
263
|
+
|
|
264
|
+
if (
|
|
265
|
+
tokenBefore?.range[1] === node.range[0] &&
|
|
266
|
+
!astUtils.canTokensBeAdjacent(tokenBefore, recommendation)
|
|
267
|
+
) {
|
|
268
|
+
return fixer.replaceText(node, ` ${recommendation}`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return fixer.replaceText(node, recommendation);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
context.report({
|
|
275
|
+
node,
|
|
276
|
+
messageId: "implicitCoercion",
|
|
277
|
+
data: { recommendation },
|
|
278
|
+
fix(fixer) {
|
|
279
|
+
if (!shouldFix) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return fix(fixer);
|
|
284
|
+
},
|
|
285
|
+
suggest: [
|
|
286
|
+
{
|
|
287
|
+
messageId: "useRecommendation",
|
|
288
|
+
data: { recommendation },
|
|
289
|
+
fix(fixer) {
|
|
290
|
+
if (shouldFix || !shouldSuggest) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return fix(fixer);
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
UnaryExpression(node) {
|
|
303
|
+
let operatorAllowed;
|
|
304
|
+
|
|
305
|
+
// !!foo
|
|
306
|
+
operatorAllowed = options.allow.includes("!!");
|
|
307
|
+
if (
|
|
308
|
+
!operatorAllowed &&
|
|
309
|
+
options.boolean &&
|
|
310
|
+
isDoubleLogicalNegating(node)
|
|
311
|
+
) {
|
|
312
|
+
const recommendation = `Boolean(${sourceCode.getText(node.argument.argument)})`;
|
|
313
|
+
const variable = astUtils.getVariableByName(
|
|
314
|
+
sourceCode.getScope(node),
|
|
315
|
+
"Boolean",
|
|
316
|
+
);
|
|
317
|
+
const booleanExists = variable?.identifiers.length === 0;
|
|
318
|
+
|
|
319
|
+
report(node, recommendation, true, booleanExists);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ~foo.indexOf(bar)
|
|
323
|
+
operatorAllowed = options.allow.includes("~");
|
|
324
|
+
if (
|
|
325
|
+
!operatorAllowed &&
|
|
326
|
+
options.boolean &&
|
|
327
|
+
isBinaryNegatingOfIndexOf(node)
|
|
328
|
+
) {
|
|
329
|
+
// `foo?.indexOf(bar) !== -1` will be true (== found) if the `foo` is nullish. So use `>= 0` in that case.
|
|
330
|
+
const comparison =
|
|
331
|
+
node.argument.type === "ChainExpression"
|
|
332
|
+
? ">= 0"
|
|
333
|
+
: "!== -1";
|
|
334
|
+
const recommendation = `${sourceCode.getText(node.argument)} ${comparison}`;
|
|
335
|
+
|
|
336
|
+
report(node, recommendation, false, false);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// +foo
|
|
340
|
+
operatorAllowed = options.allow.includes("+");
|
|
341
|
+
if (
|
|
342
|
+
!operatorAllowed &&
|
|
343
|
+
options.number &&
|
|
344
|
+
node.operator === "+" &&
|
|
345
|
+
!isNumeric(node.argument)
|
|
346
|
+
) {
|
|
347
|
+
const recommendation = `Number(${sourceCode.getText(node.argument)})`;
|
|
348
|
+
|
|
349
|
+
report(node, recommendation, true, false);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// -(-foo)
|
|
353
|
+
operatorAllowed = options.allow.includes("- -");
|
|
354
|
+
if (
|
|
355
|
+
!operatorAllowed &&
|
|
356
|
+
options.number &&
|
|
357
|
+
node.operator === "-" &&
|
|
358
|
+
node.argument.type === "UnaryExpression" &&
|
|
359
|
+
node.argument.operator === "-" &&
|
|
360
|
+
!isNumeric(node.argument.argument)
|
|
361
|
+
) {
|
|
362
|
+
const recommendation = `Number(${sourceCode.getText(node.argument.argument)})`;
|
|
363
|
+
|
|
364
|
+
report(node, recommendation, true, false);
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
// Use `:exit` to prevent double reporting
|
|
369
|
+
"BinaryExpression:exit"(node) {
|
|
370
|
+
let operatorAllowed;
|
|
371
|
+
|
|
372
|
+
// 1 * foo
|
|
373
|
+
operatorAllowed = options.allow.includes("*");
|
|
374
|
+
const nonNumericOperand =
|
|
375
|
+
!operatorAllowed &&
|
|
376
|
+
options.number &&
|
|
377
|
+
isMultiplyByOne(node) &&
|
|
378
|
+
!isMultiplyByFractionOfOne(node, sourceCode) &&
|
|
379
|
+
getNonNumericOperand(node);
|
|
380
|
+
|
|
381
|
+
if (nonNumericOperand) {
|
|
382
|
+
const recommendation = `Number(${sourceCode.getText(nonNumericOperand)})`;
|
|
383
|
+
|
|
384
|
+
report(node, recommendation, true, false);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// foo - 0
|
|
388
|
+
operatorAllowed = options.allow.includes("-");
|
|
389
|
+
if (
|
|
390
|
+
!operatorAllowed &&
|
|
391
|
+
options.number &&
|
|
392
|
+
node.operator === "-" &&
|
|
393
|
+
node.right.type === "Literal" &&
|
|
394
|
+
node.right.value === 0 &&
|
|
395
|
+
!isNumeric(node.left)
|
|
396
|
+
) {
|
|
397
|
+
const recommendation = `Number(${sourceCode.getText(node.left)})`;
|
|
398
|
+
|
|
399
|
+
report(node, recommendation, true, false);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// "" + foo
|
|
403
|
+
operatorAllowed = options.allow.includes("+");
|
|
404
|
+
if (
|
|
405
|
+
!operatorAllowed &&
|
|
406
|
+
options.string &&
|
|
407
|
+
isConcatWithEmptyString(node)
|
|
408
|
+
) {
|
|
409
|
+
const recommendation = `String(${sourceCode.getText(getNonEmptyOperand(node))})`;
|
|
410
|
+
|
|
411
|
+
report(node, recommendation, true, false);
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
|
|
415
|
+
AssignmentExpression(node) {
|
|
416
|
+
// foo += ""
|
|
417
|
+
const operatorAllowed = options.allow.includes("+");
|
|
418
|
+
|
|
419
|
+
if (
|
|
420
|
+
!operatorAllowed &&
|
|
421
|
+
options.string &&
|
|
422
|
+
isAppendEmptyString(node)
|
|
423
|
+
) {
|
|
424
|
+
const code = sourceCode.getText(getNonEmptyOperand(node));
|
|
425
|
+
const recommendation = `${code} = String(${code})`;
|
|
426
|
+
|
|
427
|
+
report(node, recommendation, true, false);
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
|
|
431
|
+
TemplateLiteral(node) {
|
|
432
|
+
if (!options.disallowTemplateShorthand) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// tag`${foo}`
|
|
437
|
+
if (node.parent.type === "TaggedTemplateExpression") {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// `` or `${foo}${bar}`
|
|
442
|
+
if (node.expressions.length !== 1) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// `prefix${foo}`
|
|
447
|
+
if (node.quasis[0].value.cooked !== "") {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// `${foo}postfix`
|
|
452
|
+
if (node.quasis[1].value.cooked !== "") {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// if the expression is already a string, then this isn't a coercion
|
|
457
|
+
if (isStringType(node.expressions[0])) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const code = sourceCode.getText(node.expressions[0]);
|
|
462
|
+
const recommendation = `String(${code})`;
|
|
463
|
+
|
|
464
|
+
report(node, recommendation, true, false);
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
},
|
|
468
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule to check for implicit global variables, functions and classes.
|
|
3
|
+
* @author Joshua Peek
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const ASSIGNMENT_NODES = new Set([
|
|
9
|
+
"AssignmentExpression",
|
|
10
|
+
"ForInStatement",
|
|
11
|
+
"ForOfStatement",
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
//------------------------------------------------------------------------------
|
|
15
|
+
// Rule Definition
|
|
16
|
+
//------------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
19
|
+
module.exports = {
|
|
20
|
+
meta: {
|
|
21
|
+
type: "suggestion",
|
|
22
|
+
|
|
23
|
+
defaultOptions: [
|
|
24
|
+
{
|
|
25
|
+
lexicalBindings: false,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
|
|
29
|
+
docs: {
|
|
30
|
+
description: "Disallow declarations in the global scope",
|
|
31
|
+
recommended: false,
|
|
32
|
+
url: "https://eslint.org/docs/latest/rules/no-implicit-globals",
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
schema: [
|
|
36
|
+
{
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
lexicalBindings: {
|
|
40
|
+
type: "boolean",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
additionalProperties: false,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
|
|
47
|
+
messages: {
|
|
48
|
+
globalNonLexicalBinding:
|
|
49
|
+
"Unexpected {{kind}} declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable.",
|
|
50
|
+
globalLexicalBinding:
|
|
51
|
+
"Unexpected {{kind}} declaration in the global scope, wrap in a block or in an IIFE.",
|
|
52
|
+
globalVariableLeak:
|
|
53
|
+
"Global variable leak, declare the variable if it is intended to be local.",
|
|
54
|
+
assignmentToReadonlyGlobal:
|
|
55
|
+
"Unexpected assignment to read-only global variable.",
|
|
56
|
+
redeclarationOfReadonlyGlobal:
|
|
57
|
+
"Unexpected redeclaration of read-only global variable.",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
create(context) {
|
|
62
|
+
const [{ lexicalBindings: checkLexicalBindings }] = context.options;
|
|
63
|
+
const sourceCode = context.sourceCode;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Reports the node.
|
|
67
|
+
* @param {ASTNode} node Node to report.
|
|
68
|
+
* @param {string} messageId Id of the message to report.
|
|
69
|
+
* @param {string|undefined} kind Declaration kind, can be 'var', 'const', 'let', function or class.
|
|
70
|
+
* @returns {void}
|
|
71
|
+
*/
|
|
72
|
+
function report(node, messageId, kind) {
|
|
73
|
+
context.report({
|
|
74
|
+
node,
|
|
75
|
+
messageId,
|
|
76
|
+
data: {
|
|
77
|
+
kind,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
Program(node) {
|
|
84
|
+
const scope = sourceCode.getScope(node);
|
|
85
|
+
|
|
86
|
+
scope.variables.forEach(variable => {
|
|
87
|
+
// Only ESLint global variables have the `writable` key.
|
|
88
|
+
const isReadonlyEslintGlobalVariable =
|
|
89
|
+
variable.writeable === false;
|
|
90
|
+
const isWritableEslintGlobalVariable =
|
|
91
|
+
variable.writeable === true;
|
|
92
|
+
|
|
93
|
+
if (isWritableEslintGlobalVariable) {
|
|
94
|
+
// Everything is allowed with writable ESLint global variables.
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Variables exported by "exported" block comments
|
|
99
|
+
if (variable.eslintExported) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
variable.defs.forEach(def => {
|
|
104
|
+
const defNode = def.node;
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
def.type === "FunctionName" ||
|
|
108
|
+
(def.type === "Variable" &&
|
|
109
|
+
def.parent.kind === "var")
|
|
110
|
+
) {
|
|
111
|
+
if (isReadonlyEslintGlobalVariable) {
|
|
112
|
+
report(
|
|
113
|
+
defNode,
|
|
114
|
+
"redeclarationOfReadonlyGlobal",
|
|
115
|
+
);
|
|
116
|
+
} else {
|
|
117
|
+
report(
|
|
118
|
+
defNode,
|
|
119
|
+
"globalNonLexicalBinding",
|
|
120
|
+
def.type === "FunctionName"
|
|
121
|
+
? "function"
|
|
122
|
+
: `'${def.parent.kind}'`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (checkLexicalBindings) {
|
|
128
|
+
if (
|
|
129
|
+
def.type === "ClassName" ||
|
|
130
|
+
(def.type === "Variable" &&
|
|
131
|
+
(def.parent.kind === "let" ||
|
|
132
|
+
def.parent.kind === "const"))
|
|
133
|
+
) {
|
|
134
|
+
if (isReadonlyEslintGlobalVariable) {
|
|
135
|
+
report(
|
|
136
|
+
defNode,
|
|
137
|
+
"redeclarationOfReadonlyGlobal",
|
|
138
|
+
);
|
|
139
|
+
} else {
|
|
140
|
+
report(
|
|
141
|
+
defNode,
|
|
142
|
+
"globalLexicalBinding",
|
|
143
|
+
def.type === "ClassName"
|
|
144
|
+
? "class"
|
|
145
|
+
: `'${def.parent.kind}'`,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (
|
|
153
|
+
isReadonlyEslintGlobalVariable &&
|
|
154
|
+
variable.defs.length === 0
|
|
155
|
+
) {
|
|
156
|
+
variable.references.forEach(reference => {
|
|
157
|
+
if (reference.isWrite() && !reference.isRead()) {
|
|
158
|
+
let assignmentParent =
|
|
159
|
+
reference.identifier.parent;
|
|
160
|
+
|
|
161
|
+
while (
|
|
162
|
+
assignmentParent &&
|
|
163
|
+
!ASSIGNMENT_NODES.has(assignmentParent.type)
|
|
164
|
+
) {
|
|
165
|
+
assignmentParent = assignmentParent.parent;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
report(
|
|
169
|
+
assignmentParent ?? reference.identifier,
|
|
170
|
+
"assignmentToReadonlyGlobal",
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Undeclared assigned variables.
|
|
178
|
+
scope.implicit.variables.forEach(variable => {
|
|
179
|
+
// def.node is an AssignmentExpression, ForInStatement or ForOfStatement.
|
|
180
|
+
variable.defs.forEach(def => {
|
|
181
|
+
report(def.node, "globalVariableLeak");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
};
|