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,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule to disallow loops with a body that allows only one iteration
|
|
3
|
+
* @author Milos Djermanovic
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
//------------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
//------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
const allLoopTypes = [
|
|
13
|
+
"WhileStatement",
|
|
14
|
+
"DoWhileStatement",
|
|
15
|
+
"ForStatement",
|
|
16
|
+
"ForInStatement",
|
|
17
|
+
"ForOfStatement",
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Checks all segments in a set and returns true if any are reachable.
|
|
22
|
+
* @param {Set<CodePathSegment>} segments The segments to check.
|
|
23
|
+
* @returns {boolean} True if any segment is reachable; false otherwise.
|
|
24
|
+
*/
|
|
25
|
+
function isAnySegmentReachable(segments) {
|
|
26
|
+
for (const segment of segments) {
|
|
27
|
+
if (segment.reachable) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Determines whether the given node is the first node in the code path to which a loop statement
|
|
37
|
+
* 'loops' for the next iteration.
|
|
38
|
+
* @param {ASTNode} node The node to check.
|
|
39
|
+
* @returns {boolean} `true` if the node is a looping target.
|
|
40
|
+
*/
|
|
41
|
+
function isLoopingTarget(node) {
|
|
42
|
+
const parent = node.parent;
|
|
43
|
+
|
|
44
|
+
if (parent) {
|
|
45
|
+
switch (parent.type) {
|
|
46
|
+
case "WhileStatement":
|
|
47
|
+
return node === parent.test;
|
|
48
|
+
case "DoWhileStatement":
|
|
49
|
+
return node === parent.body;
|
|
50
|
+
case "ForStatement":
|
|
51
|
+
return node === (parent.update || parent.test || parent.body);
|
|
52
|
+
case "ForInStatement":
|
|
53
|
+
case "ForOfStatement":
|
|
54
|
+
return node === parent.left;
|
|
55
|
+
|
|
56
|
+
// no default
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates an array with elements from the first given array that are not included in the second given array.
|
|
65
|
+
* @param {Array} arrA The array to compare from.
|
|
66
|
+
* @param {Array} arrB The array to compare against.
|
|
67
|
+
* @returns {Array} a new array that represents `arrA \ arrB`.
|
|
68
|
+
*/
|
|
69
|
+
function getDifference(arrA, arrB) {
|
|
70
|
+
return arrA.filter(a => !arrB.includes(a));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//------------------------------------------------------------------------------
|
|
74
|
+
// Rule Definition
|
|
75
|
+
//------------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
78
|
+
module.exports = {
|
|
79
|
+
meta: {
|
|
80
|
+
type: "problem",
|
|
81
|
+
|
|
82
|
+
defaultOptions: [{ ignore: [] }],
|
|
83
|
+
|
|
84
|
+
docs: {
|
|
85
|
+
description:
|
|
86
|
+
"Disallow loops with a body that allows only one iteration",
|
|
87
|
+
recommended: false,
|
|
88
|
+
url: "https://eslint.org/docs/latest/rules/no-unreachable-loop",
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
schema: [
|
|
92
|
+
{
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
ignore: {
|
|
96
|
+
type: "array",
|
|
97
|
+
items: {
|
|
98
|
+
enum: allLoopTypes,
|
|
99
|
+
},
|
|
100
|
+
uniqueItems: true,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
additionalProperties: false,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
|
|
107
|
+
messages: {
|
|
108
|
+
invalid: "Invalid loop. Its body allows only one iteration.",
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
create(context) {
|
|
113
|
+
const [{ ignore: ignoredLoopTypes }] = context.options;
|
|
114
|
+
const loopTypesToCheck = getDifference(allLoopTypes, ignoredLoopTypes),
|
|
115
|
+
loopSelector = loopTypesToCheck.join(","),
|
|
116
|
+
loopsByTargetSegments = new Map(),
|
|
117
|
+
loopsToReport = new Set();
|
|
118
|
+
|
|
119
|
+
const codePathSegments = [];
|
|
120
|
+
let currentCodePathSegments = new Set();
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
onCodePathStart() {
|
|
124
|
+
codePathSegments.push(currentCodePathSegments);
|
|
125
|
+
currentCodePathSegments = new Set();
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
onCodePathEnd() {
|
|
129
|
+
currentCodePathSegments = codePathSegments.pop();
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
onUnreachableCodePathSegmentStart(segment) {
|
|
133
|
+
currentCodePathSegments.add(segment);
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
onUnreachableCodePathSegmentEnd(segment) {
|
|
137
|
+
currentCodePathSegments.delete(segment);
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
onCodePathSegmentEnd(segment) {
|
|
141
|
+
currentCodePathSegments.delete(segment);
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
onCodePathSegmentStart(segment, node) {
|
|
145
|
+
currentCodePathSegments.add(segment);
|
|
146
|
+
|
|
147
|
+
if (isLoopingTarget(node)) {
|
|
148
|
+
const loop = node.parent;
|
|
149
|
+
|
|
150
|
+
loopsByTargetSegments.set(segment, loop);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
onCodePathSegmentLoop(_, toSegment, node) {
|
|
155
|
+
const loop = loopsByTargetSegments.get(toSegment);
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The second iteration is reachable, meaning that the loop is valid by the logic of this rule,
|
|
159
|
+
* only if there is at least one loop event with the appropriate target (which has been already
|
|
160
|
+
* determined in the `loopsByTargetSegments` map), raised from either:
|
|
161
|
+
*
|
|
162
|
+
* - the end of the loop's body (in which case `node === loop`)
|
|
163
|
+
* - a `continue` statement
|
|
164
|
+
*
|
|
165
|
+
* This condition skips loop events raised from `ForInStatement > .right` and `ForOfStatement > .right` nodes.
|
|
166
|
+
*/
|
|
167
|
+
if (node === loop || node.type === "ContinueStatement") {
|
|
168
|
+
// Removes loop if it exists in the set. Otherwise, `Set#delete` has no effect and doesn't throw.
|
|
169
|
+
loopsToReport.delete(loop);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
[loopSelector](node) {
|
|
174
|
+
/**
|
|
175
|
+
* Ignore unreachable loop statements to avoid unnecessary complexity in the implementation, or false positives otherwise.
|
|
176
|
+
* For unreachable segments, the code path analysis does not raise events required for this implementation.
|
|
177
|
+
*/
|
|
178
|
+
if (isAnySegmentReachable(currentCodePathSegments)) {
|
|
179
|
+
loopsToReport.add(node);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
"Program:exit"() {
|
|
184
|
+
loopsToReport.forEach(node =>
|
|
185
|
+
context.report({ node, messageId: "invalid" }),
|
|
186
|
+
);
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
};
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Checks for unreachable code due to return, throws, break, and continue.
|
|
3
|
+
* @author Joel Feenstra
|
|
4
|
+
*/
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
//------------------------------------------------------------------------------
|
|
8
|
+
// Helpers
|
|
9
|
+
//------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} ConstructorInfo
|
|
13
|
+
* @property {ConstructorInfo | null} upper Info about the constructor that encloses this constructor.
|
|
14
|
+
* @property {boolean} hasSuperCall The flag about having `super()` expressions.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks whether or not a given variable declarator has the initializer.
|
|
19
|
+
* @param {ASTNode} node A VariableDeclarator node to check.
|
|
20
|
+
* @returns {boolean} `true` if the node has the initializer.
|
|
21
|
+
*/
|
|
22
|
+
function isInitialized(node) {
|
|
23
|
+
return Boolean(node.init);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Checks all segments in a set and returns true if all are unreachable.
|
|
28
|
+
* @param {Set<CodePathSegment>} segments The segments to check.
|
|
29
|
+
* @returns {boolean} True if all segments are unreachable; false otherwise.
|
|
30
|
+
*/
|
|
31
|
+
function areAllSegmentsUnreachable(segments) {
|
|
32
|
+
for (const segment of segments) {
|
|
33
|
+
if (segment.reachable) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The class to distinguish consecutive unreachable statements.
|
|
43
|
+
*/
|
|
44
|
+
class ConsecutiveRange {
|
|
45
|
+
constructor(sourceCode) {
|
|
46
|
+
this.sourceCode = sourceCode;
|
|
47
|
+
this.startNode = null;
|
|
48
|
+
this.endNode = null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The location object of this range.
|
|
53
|
+
* @type {Object}
|
|
54
|
+
*/
|
|
55
|
+
get location() {
|
|
56
|
+
return {
|
|
57
|
+
start: this.startNode.loc.start,
|
|
58
|
+
end: this.endNode.loc.end,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* `true` if this range is empty.
|
|
64
|
+
* @type {boolean}
|
|
65
|
+
*/
|
|
66
|
+
get isEmpty() {
|
|
67
|
+
return !(this.startNode && this.endNode);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Checks whether the given node is inside of this range.
|
|
72
|
+
* @param {ASTNode|Token} node The node to check.
|
|
73
|
+
* @returns {boolean} `true` if the node is inside of this range.
|
|
74
|
+
*/
|
|
75
|
+
contains(node) {
|
|
76
|
+
return (
|
|
77
|
+
node.range[0] >= this.startNode.range[0] &&
|
|
78
|
+
node.range[1] <= this.endNode.range[1]
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Checks whether the given node is consecutive to this range.
|
|
84
|
+
* @param {ASTNode} node The node to check.
|
|
85
|
+
* @returns {boolean} `true` if the node is consecutive to this range.
|
|
86
|
+
*/
|
|
87
|
+
isConsecutive(node) {
|
|
88
|
+
return this.contains(this.sourceCode.getTokenBefore(node));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Merges the given node to this range.
|
|
93
|
+
* @param {ASTNode} node The node to merge.
|
|
94
|
+
* @returns {void}
|
|
95
|
+
*/
|
|
96
|
+
merge(node) {
|
|
97
|
+
this.endNode = node;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Resets this range by the given node or null.
|
|
102
|
+
* @param {ASTNode|null} node The node to reset, or null.
|
|
103
|
+
* @returns {void}
|
|
104
|
+
*/
|
|
105
|
+
reset(node) {
|
|
106
|
+
this.startNode = this.endNode = node;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//------------------------------------------------------------------------------
|
|
111
|
+
// Rule Definition
|
|
112
|
+
//------------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
115
|
+
module.exports = {
|
|
116
|
+
meta: {
|
|
117
|
+
type: "problem",
|
|
118
|
+
|
|
119
|
+
docs: {
|
|
120
|
+
description:
|
|
121
|
+
"Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
|
|
122
|
+
recommended: true,
|
|
123
|
+
url: "https://eslint.org/docs/latest/rules/no-unreachable",
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
schema: [],
|
|
127
|
+
|
|
128
|
+
messages: {
|
|
129
|
+
unreachableCode: "Unreachable code.",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
create(context) {
|
|
134
|
+
/** @type {ConstructorInfo | null} */
|
|
135
|
+
let constructorInfo = null;
|
|
136
|
+
|
|
137
|
+
/** @type {ConsecutiveRange} */
|
|
138
|
+
const range = new ConsecutiveRange(context.sourceCode);
|
|
139
|
+
|
|
140
|
+
/** @type {Array<Set<CodePathSegment>>} */
|
|
141
|
+
const codePathSegments = [];
|
|
142
|
+
|
|
143
|
+
/** @type {Set<CodePathSegment>} */
|
|
144
|
+
let currentCodePathSegments = new Set();
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Reports a given node if it's unreachable.
|
|
148
|
+
* @param {ASTNode} node A statement node to report.
|
|
149
|
+
* @returns {void}
|
|
150
|
+
*/
|
|
151
|
+
function reportIfUnreachable(node) {
|
|
152
|
+
let nextNode = null;
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
node &&
|
|
156
|
+
(node.type === "PropertyDefinition" ||
|
|
157
|
+
areAllSegmentsUnreachable(currentCodePathSegments))
|
|
158
|
+
) {
|
|
159
|
+
// Store this statement to distinguish consecutive statements.
|
|
160
|
+
if (range.isEmpty) {
|
|
161
|
+
range.reset(node);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Skip if this statement is inside of the current range.
|
|
166
|
+
if (range.contains(node)) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Merge if this statement is consecutive to the current range.
|
|
171
|
+
if (range.isConsecutive(node)) {
|
|
172
|
+
range.merge(node);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
nextNode = node;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Report the current range since this statement is reachable or is
|
|
181
|
+
* not consecutive to the current range.
|
|
182
|
+
*/
|
|
183
|
+
if (!range.isEmpty) {
|
|
184
|
+
context.report({
|
|
185
|
+
messageId: "unreachableCode",
|
|
186
|
+
loc: range.location,
|
|
187
|
+
node: range.startNode,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Update the current range.
|
|
192
|
+
range.reset(nextNode);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
// Manages the current code path.
|
|
197
|
+
onCodePathStart() {
|
|
198
|
+
codePathSegments.push(currentCodePathSegments);
|
|
199
|
+
currentCodePathSegments = new Set();
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
onCodePathEnd() {
|
|
203
|
+
currentCodePathSegments = codePathSegments.pop();
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
onUnreachableCodePathSegmentStart(segment) {
|
|
207
|
+
currentCodePathSegments.add(segment);
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
onUnreachableCodePathSegmentEnd(segment) {
|
|
211
|
+
currentCodePathSegments.delete(segment);
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
onCodePathSegmentEnd(segment) {
|
|
215
|
+
currentCodePathSegments.delete(segment);
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
onCodePathSegmentStart(segment) {
|
|
219
|
+
currentCodePathSegments.add(segment);
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
// Registers for all statement nodes (excludes FunctionDeclaration).
|
|
223
|
+
BlockStatement: reportIfUnreachable,
|
|
224
|
+
BreakStatement: reportIfUnreachable,
|
|
225
|
+
ClassDeclaration: reportIfUnreachable,
|
|
226
|
+
ContinueStatement: reportIfUnreachable,
|
|
227
|
+
DebuggerStatement: reportIfUnreachable,
|
|
228
|
+
DoWhileStatement: reportIfUnreachable,
|
|
229
|
+
ExpressionStatement: reportIfUnreachable,
|
|
230
|
+
ForInStatement: reportIfUnreachable,
|
|
231
|
+
ForOfStatement: reportIfUnreachable,
|
|
232
|
+
ForStatement: reportIfUnreachable,
|
|
233
|
+
IfStatement: reportIfUnreachable,
|
|
234
|
+
ImportDeclaration: reportIfUnreachable,
|
|
235
|
+
LabeledStatement: reportIfUnreachable,
|
|
236
|
+
ReturnStatement: reportIfUnreachable,
|
|
237
|
+
SwitchStatement: reportIfUnreachable,
|
|
238
|
+
ThrowStatement: reportIfUnreachable,
|
|
239
|
+
TryStatement: reportIfUnreachable,
|
|
240
|
+
|
|
241
|
+
VariableDeclaration(node) {
|
|
242
|
+
if (
|
|
243
|
+
node.kind !== "var" ||
|
|
244
|
+
node.declarations.some(isInitialized)
|
|
245
|
+
) {
|
|
246
|
+
reportIfUnreachable(node);
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
WhileStatement: reportIfUnreachable,
|
|
251
|
+
WithStatement: reportIfUnreachable,
|
|
252
|
+
ExportNamedDeclaration: reportIfUnreachable,
|
|
253
|
+
ExportDefaultDeclaration: reportIfUnreachable,
|
|
254
|
+
ExportAllDeclaration: reportIfUnreachable,
|
|
255
|
+
|
|
256
|
+
"Program:exit"() {
|
|
257
|
+
reportIfUnreachable();
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
* Instance fields defined in a subclass are never created if the constructor of the subclass
|
|
262
|
+
* doesn't call `super()`, so their definitions are unreachable code.
|
|
263
|
+
*/
|
|
264
|
+
"MethodDefinition[kind='constructor']"() {
|
|
265
|
+
constructorInfo = {
|
|
266
|
+
upper: constructorInfo,
|
|
267
|
+
hasSuperCall: false,
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
"MethodDefinition[kind='constructor']:exit"(node) {
|
|
271
|
+
const { hasSuperCall } = constructorInfo;
|
|
272
|
+
|
|
273
|
+
constructorInfo = constructorInfo.upper;
|
|
274
|
+
|
|
275
|
+
// skip typescript constructors without the body
|
|
276
|
+
if (!node.value.body) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const classDefinition = node.parent.parent;
|
|
281
|
+
|
|
282
|
+
if (classDefinition.superClass && !hasSuperCall) {
|
|
283
|
+
for (const element of classDefinition.body.body) {
|
|
284
|
+
if (
|
|
285
|
+
element.type === "PropertyDefinition" &&
|
|
286
|
+
!element.static
|
|
287
|
+
) {
|
|
288
|
+
reportIfUnreachable(element);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
"CallExpression > Super.callee"() {
|
|
294
|
+
if (constructorInfo) {
|
|
295
|
+
constructorInfo.hasSuperCall = true;
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rule to flag unsafe statements in finally block
|
|
3
|
+
* @author Onur Temizkan
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
//------------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
//------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
const SENTINEL_NODE_TYPE_RETURN_THROW =
|
|
13
|
+
/^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/u;
|
|
14
|
+
const SENTINEL_NODE_TYPE_BREAK =
|
|
15
|
+
/^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/u;
|
|
16
|
+
const SENTINEL_NODE_TYPE_CONTINUE =
|
|
17
|
+
/^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/u;
|
|
18
|
+
|
|
19
|
+
//------------------------------------------------------------------------------
|
|
20
|
+
// Rule Definition
|
|
21
|
+
//------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
24
|
+
module.exports = {
|
|
25
|
+
meta: {
|
|
26
|
+
type: "problem",
|
|
27
|
+
|
|
28
|
+
docs: {
|
|
29
|
+
description: "Disallow control flow statements in `finally` blocks",
|
|
30
|
+
recommended: true,
|
|
31
|
+
url: "https://eslint.org/docs/latest/rules/no-unsafe-finally",
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
schema: [],
|
|
35
|
+
|
|
36
|
+
messages: {
|
|
37
|
+
unsafeUsage: "Unsafe usage of {{nodeType}}.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
create(context) {
|
|
41
|
+
/**
|
|
42
|
+
* Checks if the node is the finalizer of a TryStatement
|
|
43
|
+
* @param {ASTNode} node node to check.
|
|
44
|
+
* @returns {boolean} - true if the node is the finalizer of a TryStatement
|
|
45
|
+
*/
|
|
46
|
+
function isFinallyBlock(node) {
|
|
47
|
+
return (
|
|
48
|
+
node.parent.type === "TryStatement" &&
|
|
49
|
+
node.parent.finalizer === node
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Climbs up the tree if the node is not a sentinel node
|
|
55
|
+
* @param {ASTNode} node node to check.
|
|
56
|
+
* @param {string} label label of the break or continue statement
|
|
57
|
+
* @returns {boolean} - return whether the node is a finally block or a sentinel node
|
|
58
|
+
*/
|
|
59
|
+
function isInFinallyBlock(node, label) {
|
|
60
|
+
let labelInside = false;
|
|
61
|
+
let sentinelNodeType;
|
|
62
|
+
|
|
63
|
+
if (node.type === "BreakStatement" && !node.label) {
|
|
64
|
+
sentinelNodeType = SENTINEL_NODE_TYPE_BREAK;
|
|
65
|
+
} else if (node.type === "ContinueStatement") {
|
|
66
|
+
sentinelNodeType = SENTINEL_NODE_TYPE_CONTINUE;
|
|
67
|
+
} else {
|
|
68
|
+
sentinelNodeType = SENTINEL_NODE_TYPE_RETURN_THROW;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (
|
|
72
|
+
let currentNode = node;
|
|
73
|
+
currentNode && !sentinelNodeType.test(currentNode.type);
|
|
74
|
+
currentNode = currentNode.parent
|
|
75
|
+
) {
|
|
76
|
+
if (
|
|
77
|
+
currentNode.parent.label &&
|
|
78
|
+
label &&
|
|
79
|
+
currentNode.parent.label.name === label.name
|
|
80
|
+
) {
|
|
81
|
+
labelInside = true;
|
|
82
|
+
}
|
|
83
|
+
if (isFinallyBlock(currentNode)) {
|
|
84
|
+
if (label && labelInside) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Checks whether the possibly-unsafe statement is inside a finally block.
|
|
95
|
+
* @param {ASTNode} node node to check.
|
|
96
|
+
* @returns {void}
|
|
97
|
+
*/
|
|
98
|
+
function check(node) {
|
|
99
|
+
if (isInFinallyBlock(node, node.label)) {
|
|
100
|
+
context.report({
|
|
101
|
+
messageId: "unsafeUsage",
|
|
102
|
+
data: {
|
|
103
|
+
nodeType: node.type,
|
|
104
|
+
},
|
|
105
|
+
node,
|
|
106
|
+
line: node.loc.line,
|
|
107
|
+
column: node.loc.column,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
ReturnStatement: check,
|
|
114
|
+
ThrowStatement: check,
|
|
115
|
+
BreakStatement: check,
|
|
116
|
+
ContinueStatement: check,
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
};
|