eslint 8.57.1 → 9.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -115
- package/bin/eslint.js +112 -89
- package/conf/default-cli-options.js +22 -22
- package/conf/ecma-version.js +16 -0
- package/conf/globals.js +109 -94
- package/conf/replacements.json +24 -20
- package/conf/rule-type-list.json +89 -26
- package/lib/api.js +16 -20
- package/lib/cli-engine/cli-engine.js +841 -810
- package/lib/cli-engine/file-enumerator.js +384 -390
- package/lib/cli-engine/formatters/formatters-meta.json +17 -45
- package/lib/cli-engine/formatters/html.js +110 -102
- package/lib/cli-engine/formatters/json-with-metadata.js +5 -5
- package/lib/cli-engine/formatters/json.js +2 -2
- package/lib/cli-engine/formatters/stylish.js +97 -76
- package/lib/cli-engine/hash.js +1 -1
- package/lib/cli-engine/index.js +1 -1
- package/lib/cli-engine/lint-result-cache.js +165 -148
- package/lib/cli-engine/load-rules.js +17 -17
- package/lib/cli.js +481 -399
- package/lib/config/config-loader.js +816 -0
- package/lib/config/config.js +674 -0
- package/lib/config/default-config.js +57 -46
- package/lib/config/flat-config-array.js +170 -333
- package/lib/config/flat-config-schema.js +389 -389
- package/lib/config-api.js +12 -0
- package/lib/eslint/eslint-helpers.js +1196 -663
- package/lib/eslint/eslint.js +1262 -607
- package/lib/eslint/index.js +3 -3
- package/lib/eslint/legacy-eslint.js +786 -0
- package/lib/eslint/worker.js +173 -0
- package/lib/languages/js/index.js +336 -0
- package/lib/languages/js/source-code/index.js +7 -0
- package/lib/languages/js/source-code/source-code.js +1364 -0
- package/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js +61 -0
- package/lib/languages/js/source-code/token-store/backward-token-cursor.js +57 -0
- package/lib/{source-code → languages/js/source-code}/token-store/cursor.js +36 -36
- package/lib/languages/js/source-code/token-store/cursors.js +120 -0
- package/lib/{source-code → languages/js/source-code}/token-store/decorative-cursor.js +17 -18
- package/lib/{source-code → languages/js/source-code}/token-store/filter-cursor.js +19 -20
- package/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js +65 -0
- package/lib/languages/js/source-code/token-store/forward-token-cursor.js +62 -0
- package/lib/languages/js/source-code/token-store/index.js +721 -0
- package/lib/{source-code → languages/js/source-code}/token-store/limit-cursor.js +17 -18
- package/lib/languages/js/source-code/token-store/padded-token-cursor.js +45 -0
- package/lib/{source-code → languages/js/source-code}/token-store/skip-cursor.js +19 -20
- package/lib/languages/js/source-code/token-store/utils.js +110 -0
- package/lib/languages/js/validate-language-options.js +196 -0
- package/lib/linter/apply-disable-directives.js +490 -371
- package/lib/linter/code-path-analysis/code-path-analyzer.js +650 -674
- package/lib/linter/code-path-analysis/code-path-segment.js +215 -216
- package/lib/linter/code-path-analysis/code-path-state.js +2118 -2096
- package/lib/linter/code-path-analysis/code-path.js +307 -317
- package/lib/linter/code-path-analysis/debug-helpers.js +183 -163
- package/lib/linter/code-path-analysis/fork-context.js +297 -272
- package/lib/linter/code-path-analysis/id-generator.js +22 -23
- package/lib/linter/esquery.js +332 -0
- package/lib/linter/file-context.js +144 -0
- package/lib/linter/file-report.js +608 -0
- package/lib/linter/index.js +3 -5
- package/lib/linter/interpolate.js +38 -16
- package/lib/linter/linter.js +2328 -1785
- package/lib/linter/rule-fixer.js +136 -107
- package/lib/linter/rules.js +37 -46
- package/lib/linter/source-code-fixer.js +96 -94
- package/lib/linter/source-code-traverser.js +333 -0
- package/lib/linter/source-code-visitor.js +81 -0
- package/lib/linter/timing.js +145 -97
- package/lib/linter/vfile.js +115 -0
- package/lib/options.js +464 -326
- package/lib/rule-tester/index.js +3 -1
- package/lib/rule-tester/rule-tester.js +1371 -998
- package/lib/rules/accessor-pairs.js +333 -259
- package/lib/rules/array-bracket-newline.js +250 -220
- package/lib/rules/array-bracket-spacing.js +286 -229
- package/lib/rules/array-callback-return.js +401 -354
- package/lib/rules/array-element-newline.js +358 -295
- package/lib/rules/arrow-body-style.js +400 -278
- package/lib/rules/arrow-parens.js +206 -155
- package/lib/rules/arrow-spacing.js +169 -145
- package/lib/rules/block-scoped-var.js +125 -123
- package/lib/rules/block-spacing.js +186 -158
- package/lib/rules/brace-style.js +262 -181
- package/lib/rules/callback-return.js +203 -174
- package/lib/rules/camelcase.js +403 -380
- package/lib/rules/capitalized-comments.js +253 -228
- package/lib/rules/class-methods-use-this.js +231 -168
- package/lib/rules/comma-dangle.js +379 -328
- package/lib/rules/comma-spacing.js +193 -177
- package/lib/rules/comma-style.js +375 -298
- package/lib/rules/complexity.js +180 -144
- package/lib/rules/computed-property-spacing.js +236 -193
- package/lib/rules/consistent-return.js +181 -170
- package/lib/rules/consistent-this.js +167 -141
- package/lib/rules/constructor-super.js +418 -411
- package/lib/rules/curly.js +407 -468
- package/lib/rules/default-case-last.js +39 -32
- package/lib/rules/default-case.js +89 -83
- package/lib/rules/default-param-last.js +69 -53
- package/lib/rules/dot-location.js +122 -92
- package/lib/rules/dot-notation.js +193 -153
- package/lib/rules/eol-last.js +122 -102
- package/lib/rules/eqeqeq.js +191 -155
- package/lib/rules/for-direction.js +150 -122
- package/lib/rules/func-call-spacing.js +261 -213
- package/lib/rules/func-name-matching.js +294 -209
- package/lib/rules/func-names.js +165 -164
- package/lib/rules/func-style.js +209 -86
- package/lib/rules/function-call-argument-newline.js +152 -111
- package/lib/rules/function-paren-newline.js +349 -273
- package/lib/rules/generator-star-spacing.js +229 -192
- package/lib/rules/getter-return.js +208 -170
- package/lib/rules/global-require.js +85 -58
- package/lib/rules/grouped-accessor-pairs.js +201 -148
- package/lib/rules/guard-for-in.js +72 -63
- package/lib/rules/handle-callback-err.js +108 -87
- package/lib/rules/id-blacklist.js +182 -187
- package/lib/rules/id-denylist.js +174 -179
- package/lib/rules/id-length.js +197 -157
- package/lib/rules/id-match.js +350 -286
- package/lib/rules/implicit-arrow-linebreak.js +102 -61
- package/lib/rules/indent-legacy.js +1345 -1102
- package/lib/rules/indent.js +2272 -1741
- package/lib/rules/index.js +320 -294
- package/lib/rules/init-declarations.js +139 -106
- package/lib/rules/jsx-quotes.js +94 -64
- package/lib/rules/key-spacing.js +750 -615
- package/lib/rules/keyword-spacing.js +648 -587
- package/lib/rules/line-comment-position.js +143 -108
- package/lib/rules/linebreak-style.js +115 -88
- package/lib/rules/lines-around-comment.js +540 -430
- package/lib/rules/lines-around-directive.js +233 -185
- package/lib/rules/lines-between-class-members.js +305 -216
- package/lib/rules/logical-assignment-operators.js +582 -398
- package/lib/rules/max-classes-per-file.js +69 -68
- package/lib/rules/max-depth.js +146 -143
- package/lib/rules/max-len.js +473 -416
- package/lib/rules/max-lines-per-function.js +201 -176
- package/lib/rules/max-lines.js +158 -162
- package/lib/rules/max-nested-callbacks.js +102 -104
- package/lib/rules/max-params.js +102 -75
- package/lib/rules/max-statements-per-line.js +205 -180
- package/lib/rules/max-statements.js +168 -164
- package/lib/rules/multiline-comment-style.js +638 -460
- package/lib/rules/multiline-ternary.js +241 -158
- package/lib/rules/new-cap.js +233 -232
- package/lib/rules/new-parens.js +88 -61
- package/lib/rules/newline-after-var.js +287 -233
- package/lib/rules/newline-before-return.js +229 -204
- package/lib/rules/newline-per-chained-call.js +142 -109
- package/lib/rules/no-alert.js +90 -79
- package/lib/rules/no-array-constructor.js +175 -113
- package/lib/rules/no-async-promise-executor.js +30 -24
- package/lib/rules/no-await-in-loop.js +79 -70
- package/lib/rules/no-bitwise.js +113 -87
- package/lib/rules/no-buffer-constructor.js +61 -37
- package/lib/rules/no-caller.js +39 -33
- package/lib/rules/no-case-declarations.js +61 -45
- package/lib/rules/no-catch-shadow.js +76 -62
- package/lib/rules/no-class-assign.js +51 -48
- package/lib/rules/no-compare-neg-zero.js +62 -48
- package/lib/rules/no-cond-assign.js +148 -132
- package/lib/rules/no-confusing-arrow.js +98 -63
- package/lib/rules/no-console.js +202 -188
- package/lib/rules/no-const-assign.js +58 -41
- package/lib/rules/no-constant-binary-expression.js +501 -407
- package/lib/rules/no-constant-condition.js +158 -131
- package/lib/rules/no-constructor-return.js +49 -49
- package/lib/rules/no-continue.js +25 -26
- package/lib/rules/no-control-regex.js +125 -121
- package/lib/rules/no-debugger.js +28 -30
- package/lib/rules/no-delete-var.js +29 -29
- package/lib/rules/no-div-regex.js +47 -40
- package/lib/rules/no-dupe-args.js +79 -69
- package/lib/rules/no-dupe-class-members.js +102 -89
- package/lib/rules/no-dupe-else-if.js +100 -77
- package/lib/rules/no-dupe-keys.js +133 -110
- package/lib/rules/no-duplicate-case.js +50 -43
- package/lib/rules/no-duplicate-imports.js +266 -188
- package/lib/rules/no-else-return.js +430 -385
- package/lib/rules/no-empty-character-class.js +57 -50
- package/lib/rules/no-empty-function.js +197 -128
- package/lib/rules/no-empty-pattern.js +63 -56
- package/lib/rules/no-empty-static-block.js +61 -35
- package/lib/rules/no-empty.js +135 -85
- package/lib/rules/no-eq-null.js +37 -32
- package/lib/rules/no-eval.js +258 -249
- package/lib/rules/no-ex-assign.js +42 -39
- package/lib/rules/no-extend-native.js +161 -160
- package/lib/rules/no-extra-bind.js +201 -190
- package/lib/rules/no-extra-boolean-cast.js +398 -295
- package/lib/rules/no-extra-label.js +150 -130
- package/lib/rules/no-extra-parens.js +1654 -1307
- package/lib/rules/no-extra-semi.js +146 -126
- package/lib/rules/no-fallthrough.js +200 -136
- package/lib/rules/no-floating-decimal.js +74 -48
- package/lib/rules/no-func-assign.js +54 -55
- package/lib/rules/no-global-assign.js +78 -72
- package/lib/rules/no-implicit-coercion.js +350 -262
- package/lib/rules/no-implicit-globals.js +174 -133
- package/lib/rules/no-implied-eval.js +150 -112
- package/lib/rules/no-import-assign.js +145 -159
- package/lib/rules/no-inline-comments.js +101 -96
- package/lib/rules/no-inner-declarations.js +115 -78
- package/lib/rules/no-invalid-regexp.js +223 -174
- package/lib/rules/no-invalid-this.js +145 -117
- package/lib/rules/no-irregular-whitespace.js +266 -250
- package/lib/rules/no-iterator.js +29 -33
- package/lib/rules/no-label-var.js +59 -61
- package/lib/rules/no-labels.js +138 -131
- package/lib/rules/no-lone-blocks.js +127 -123
- package/lib/rules/no-lonely-if.js +105 -67
- package/lib/rules/no-loop-func.js +245 -184
- package/lib/rules/no-loss-of-precision.js +236 -201
- package/lib/rules/no-magic-numbers.js +339 -217
- package/lib/rules/no-misleading-character-class.js +548 -253
- package/lib/rules/no-mixed-operators.js +188 -164
- package/lib/rules/no-mixed-requires.js +253 -224
- package/lib/rules/no-mixed-spaces-and-tabs.js +135 -103
- package/lib/rules/no-multi-assign.js +46 -47
- package/lib/rules/no-multi-spaces.js +163 -125
- package/lib/rules/no-multi-str.js +42 -40
- package/lib/rules/no-multiple-empty-lines.js +196 -140
- package/lib/rules/no-native-reassign.js +90 -74
- package/lib/rules/no-negated-condition.js +79 -74
- package/lib/rules/no-negated-in-lhs.js +45 -32
- package/lib/rules/no-nested-ternary.js +33 -31
- package/lib/rules/no-new-func.js +71 -62
- package/lib/rules/no-new-native-nonconstructor.js +43 -39
- package/lib/rules/no-new-object.js +48 -39
- package/lib/rules/no-new-require.js +48 -31
- package/lib/rules/no-new-symbol.js +61 -43
- package/lib/rules/no-new-wrappers.js +43 -41
- package/lib/rules/no-new.js +28 -29
- package/lib/rules/no-nonoctal-decimal-escape.js +149 -121
- package/lib/rules/no-obj-calls.js +66 -53
- package/lib/rules/no-object-constructor.js +104 -97
- package/lib/rules/no-octal-escape.js +40 -43
- package/lib/rules/no-octal.js +29 -32
- package/lib/rules/no-param-reassign.js +236 -218
- package/lib/rules/no-path-concat.js +66 -51
- package/lib/rules/no-plusplus.js +60 -63
- package/lib/rules/no-process-env.js +49 -32
- package/lib/rules/no-process-exit.js +48 -28
- package/lib/rules/no-promise-executor-return.js +205 -204
- package/lib/rules/no-proto.js +26 -29
- package/lib/rules/no-prototype-builtins.js +146 -124
- package/lib/rules/no-redeclare.js +154 -155
- package/lib/rules/no-regex-spaces.js +183 -161
- package/lib/rules/no-restricted-exports.js +208 -174
- package/lib/rules/no-restricted-globals.js +254 -112
- package/lib/rules/no-restricted-imports.js +824 -384
- package/lib/rules/no-restricted-modules.js +222 -186
- package/lib/rules/no-restricted-properties.js +218 -153
- package/lib/rules/no-restricted-syntax.js +56 -52
- package/lib/rules/no-return-assign.js +56 -49
- package/lib/rules/no-return-await.js +147 -120
- package/lib/rules/no-script-url.js +53 -46
- package/lib/rules/no-self-assign.js +148 -145
- package/lib/rules/no-self-compare.js +63 -46
- package/lib/rules/no-sequences.js +135 -115
- package/lib/rules/no-setter-return.js +176 -178
- package/lib/rules/no-shadow-restricted-names.js +84 -36
- package/lib/rules/no-shadow.js +598 -310
- package/lib/rules/no-spaced-func.js +82 -60
- package/lib/rules/no-sparse-arrays.js +46 -28
- package/lib/rules/no-sync.js +61 -44
- package/lib/rules/no-tabs.js +83 -54
- package/lib/rules/no-template-curly-in-string.js +33 -32
- package/lib/rules/no-ternary.js +25 -28
- package/lib/rules/no-this-before-super.js +332 -298
- package/lib/rules/no-throw-literal.js +31 -36
- package/lib/rules/no-trailing-spaces.js +208 -174
- package/lib/rules/no-unassigned-vars.js +80 -0
- package/lib/rules/no-undef-init.js +86 -60
- package/lib/rules/no-undef.js +52 -47
- package/lib/rules/no-undefined.js +73 -74
- package/lib/rules/no-underscore-dangle.js +370 -322
- package/lib/rules/no-unexpected-multiline.js +112 -102
- package/lib/rules/no-unmodified-loop-condition.js +254 -254
- package/lib/rules/no-unneeded-ternary.js +212 -146
- package/lib/rules/no-unreachable-loop.js +145 -140
- package/lib/rules/no-unreachable.js +255 -248
- package/lib/rules/no-unsafe-finally.js +93 -85
- package/lib/rules/no-unsafe-negation.js +105 -81
- package/lib/rules/no-unsafe-optional-chaining.js +193 -177
- package/lib/rules/no-unused-expressions.js +199 -158
- package/lib/rules/no-unused-labels.js +139 -124
- package/lib/rules/no-unused-private-class-members.js +206 -182
- package/lib/rules/no-unused-vars.js +1708 -687
- package/lib/rules/no-use-before-define.js +327 -229
- package/lib/rules/no-useless-assignment.js +654 -0
- package/lib/rules/no-useless-backreference.js +212 -143
- package/lib/rules/no-useless-call.js +58 -53
- package/lib/rules/no-useless-catch.js +40 -40
- package/lib/rules/no-useless-computed-key.js +144 -108
- package/lib/rules/no-useless-concat.js +65 -59
- package/lib/rules/no-useless-constructor.js +160 -97
- package/lib/rules/no-useless-escape.js +364 -291
- package/lib/rules/no-useless-rename.js +183 -153
- package/lib/rules/no-useless-return.js +344 -307
- package/lib/rules/no-var.js +245 -212
- package/lib/rules/no-void.js +51 -46
- package/lib/rules/no-warning-comments.js +191 -183
- package/lib/rules/no-whitespace-before-property.js +131 -97
- package/lib/rules/no-with.js +24 -26
- package/lib/rules/nonblock-statement-body-position.js +149 -112
- package/lib/rules/object-curly-newline.js +306 -247
- package/lib/rules/object-curly-spacing.js +360 -296
- package/lib/rules/object-property-newline.js +137 -88
- package/lib/rules/object-shorthand.js +632 -500
- package/lib/rules/one-var-declaration-per-line.js +104 -82
- package/lib/rules/one-var.js +686 -536
- package/lib/rules/operator-assignment.js +219 -158
- package/lib/rules/operator-linebreak.js +295 -233
- package/lib/rules/padded-blocks.js +346 -290
- package/lib/rules/padding-line-between-statements.js +443 -421
- package/lib/rules/prefer-arrow-callback.js +371 -315
- package/lib/rules/prefer-const.js +418 -373
- package/lib/rules/prefer-destructuring.js +309 -278
- package/lib/rules/prefer-exponentiation-operator.js +176 -132
- package/lib/rules/prefer-named-capture-group.js +160 -141
- package/lib/rules/prefer-numeric-literals.js +121 -112
- package/lib/rules/prefer-object-has-own.js +116 -82
- package/lib/rules/prefer-object-spread.js +214 -193
- package/lib/rules/prefer-promise-reject-errors.js +140 -118
- package/lib/rules/prefer-reflect.js +126 -103
- package/lib/rules/prefer-regex-literals.js +561 -463
- package/lib/rules/prefer-rest-params.js +79 -80
- package/lib/rules/prefer-spread.js +47 -43
- package/lib/rules/prefer-template.js +266 -194
- package/lib/rules/preserve-caught-error.js +535 -0
- package/lib/rules/quote-props.js +373 -289
- package/lib/rules/quotes.js +374 -308
- package/lib/rules/radix.js +152 -134
- package/lib/rules/require-atomic-updates.js +316 -282
- package/lib/rules/require-await.js +153 -82
- package/lib/rules/require-unicode-regexp.js +296 -108
- package/lib/rules/require-yield.js +53 -54
- package/lib/rules/rest-spread-spacing.js +128 -98
- package/lib/rules/semi-spacing.js +281 -232
- package/lib/rules/semi-style.js +176 -116
- package/lib/rules/semi.js +456 -418
- package/lib/rules/sort-imports.js +307 -229
- package/lib/rules/sort-keys.js +219 -181
- package/lib/rules/sort-vars.js +127 -91
- package/lib/rules/space-before-blocks.js +199 -171
- package/lib/rules/space-before-function-paren.js +186 -148
- package/lib/rules/space-in-parens.js +359 -270
- package/lib/rules/space-infix-ops.js +237 -183
- package/lib/rules/space-unary-ops.js +356 -280
- package/lib/rules/spaced-comment.js +363 -301
- package/lib/rules/strict.js +266 -229
- package/lib/rules/switch-colon-spacing.js +130 -104
- package/lib/rules/symbol-description.js +45 -48
- package/lib/rules/template-curly-spacing.js +148 -124
- package/lib/rules/template-tag-spacing.js +98 -70
- package/lib/rules/unicode-bom.js +54 -54
- package/lib/rules/use-isnan.js +237 -110
- package/lib/rules/utils/ast-utils.js +2139 -1688
- package/lib/rules/utils/char-source.js +247 -0
- package/lib/rules/utils/fix-tracker.js +99 -88
- package/lib/rules/utils/keywords.js +59 -59
- package/lib/rules/utils/lazy-loading-rule-map.js +81 -78
- package/lib/rules/utils/regular-expressions.js +35 -19
- package/lib/rules/utils/unicode/index.js +9 -4
- package/lib/rules/utils/unicode/is-combining-character.js +1 -1
- package/lib/rules/utils/unicode/is-emoji-modifier.js +1 -1
- package/lib/rules/utils/unicode/is-regional-indicator-symbol.js +1 -1
- package/lib/rules/utils/unicode/is-surrogate-pair.js +1 -1
- package/lib/rules/valid-typeof.js +153 -109
- package/lib/rules/vars-on-top.js +152 -144
- package/lib/rules/wrap-iife.js +204 -173
- package/lib/rules/wrap-regex.js +77 -47
- package/lib/rules/yield-star-spacing.js +145 -116
- package/lib/rules/yoda.js +283 -274
- package/lib/services/parser-service.js +65 -0
- package/lib/services/processor-service.js +101 -0
- package/lib/services/suppressions-service.js +302 -0
- package/lib/services/warning-service.js +98 -0
- package/lib/shared/ajv.js +14 -14
- package/lib/shared/assert.js +21 -0
- package/lib/shared/ast-utils.js +7 -6
- package/lib/shared/deep-merge-arrays.js +62 -0
- package/lib/shared/directives.js +3 -2
- package/lib/shared/flags.js +108 -0
- package/lib/shared/logging.js +24 -16
- package/lib/shared/naming.js +109 -0
- package/lib/shared/option-utils.js +63 -0
- package/lib/shared/relative-module-resolver.js +18 -40
- package/lib/shared/runtime-info.js +138 -128
- package/lib/shared/serialization.js +78 -0
- package/lib/shared/severity.js +22 -22
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +19 -21
- package/lib/shared/text-table.js +68 -0
- package/lib/shared/translate-cli-options.js +281 -0
- package/lib/shared/traverser.js +153 -146
- package/lib/types/config-api.d.ts +12 -0
- package/lib/types/index.d.ts +1473 -0
- package/lib/types/rules.d.ts +5589 -0
- package/lib/types/universal.d.ts +6 -0
- package/lib/types/use-at-your-own-risk.d.ts +87 -0
- package/lib/universal.js +10 -0
- package/lib/unsupported-api.js +8 -9
- package/messages/all-files-ignored.js +3 -3
- package/messages/all-matched-files-ignored.js +21 -0
- package/messages/config-file-missing.js +16 -0
- package/messages/config-plugin-missing.js +14 -0
- package/messages/config-serialize-function.js +30 -0
- package/messages/eslintrc-incompat.js +35 -16
- package/messages/eslintrc-plugins.js +8 -5
- package/messages/extend-config-missing.js +3 -3
- package/messages/failed-to-read-json.js +3 -3
- package/messages/file-not-found.js +3 -3
- package/messages/invalid-rule-options.js +2 -2
- package/messages/invalid-rule-severity.js +2 -2
- package/messages/no-config-found.js +4 -4
- package/messages/plugin-conflict.js +9 -9
- package/messages/plugin-invalid.js +4 -4
- package/messages/plugin-missing.js +4 -4
- package/messages/print-config-with-directory-path.js +2 -2
- package/messages/shared.js +6 -1
- package/messages/whitespace-found.js +3 -3
- package/package.json +105 -60
- package/conf/config-schema.js +0 -93
- package/lib/cli-engine/formatters/checkstyle.js +0 -60
- package/lib/cli-engine/formatters/compact.js +0 -60
- package/lib/cli-engine/formatters/jslint-xml.js +0 -41
- package/lib/cli-engine/formatters/junit.js +0 -82
- package/lib/cli-engine/formatters/tap.js +0 -95
- package/lib/cli-engine/formatters/unix.js +0 -58
- package/lib/cli-engine/formatters/visualstudio.js +0 -63
- package/lib/cli-engine/xml-escape.js +0 -34
- package/lib/config/flat-config-helpers.js +0 -111
- package/lib/config/rule-validator.js +0 -158
- package/lib/eslint/flat-eslint.js +0 -1159
- package/lib/linter/config-comment-parser.js +0 -185
- package/lib/linter/node-event-generator.js +0 -354
- package/lib/linter/report-translator.js +0 -369
- package/lib/linter/safe-emitter.js +0 -52
- package/lib/rule-tester/flat-rule-tester.js +0 -1131
- package/lib/rules/require-jsdoc.js +0 -122
- package/lib/rules/utils/patterns/letters.js +0 -36
- package/lib/rules/valid-jsdoc.js +0 -516
- package/lib/shared/config-validator.js +0 -347
- package/lib/shared/deprecation-warnings.js +0 -58
- package/lib/shared/types.js +0 -216
- package/lib/source-code/index.js +0 -5
- package/lib/source-code/source-code.js +0 -1055
- package/lib/source-code/token-store/backward-token-comment-cursor.js +0 -57
- package/lib/source-code/token-store/backward-token-cursor.js +0 -58
- package/lib/source-code/token-store/cursors.js +0 -90
- package/lib/source-code/token-store/forward-token-comment-cursor.js +0 -57
- package/lib/source-code/token-store/forward-token-cursor.js +0 -63
- package/lib/source-code/token-store/index.js +0 -627
- package/lib/source-code/token-store/padded-token-cursor.js +0 -38
- package/lib/source-code/token-store/utils.js +0 -107
|
@@ -14,62 +14,85 @@ const esutils = require("esutils");
|
|
|
14
14
|
const espree = require("espree");
|
|
15
15
|
const escapeRegExp = require("escape-string-regexp");
|
|
16
16
|
const {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
breakableTypePattern,
|
|
18
|
+
createGlobalLinebreakMatcher,
|
|
19
|
+
lineBreakPattern,
|
|
20
|
+
shebangPattern,
|
|
21
21
|
} = require("../../shared/ast-utils");
|
|
22
|
+
const globals = require("../../../conf/globals");
|
|
23
|
+
const { LATEST_ECMA_VERSION } = require("../../../conf/ecma-version");
|
|
22
24
|
|
|
23
25
|
//------------------------------------------------------------------------------
|
|
24
26
|
// Helpers
|
|
25
27
|
//------------------------------------------------------------------------------
|
|
26
28
|
|
|
27
|
-
const anyFunctionPattern =
|
|
29
|
+
const anyFunctionPattern =
|
|
30
|
+
/^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/u;
|
|
28
31
|
const anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/u;
|
|
29
|
-
const arrayMethodWithThisArgPattern =
|
|
32
|
+
const arrayMethodWithThisArgPattern =
|
|
33
|
+
/^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|some)$/u;
|
|
30
34
|
const arrayOrTypedArrayPattern = /Array$/u;
|
|
31
35
|
const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/u;
|
|
32
36
|
const thisTagPattern = /^[\s*]*@this/mu;
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
const COMMENTS_IGNORE_PATTERN =
|
|
39
|
+
/^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u;
|
|
36
40
|
const ESLINT_DIRECTIVE_PATTERN = /^(?:eslint[- ]|(?:globals?|exported) )/u;
|
|
37
41
|
const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
|
|
38
42
|
|
|
39
43
|
// A set of node types that can contain a list of statements
|
|
40
|
-
const STATEMENT_LIST_PARENTS = new Set([
|
|
44
|
+
const STATEMENT_LIST_PARENTS = new Set([
|
|
45
|
+
"Program",
|
|
46
|
+
"BlockStatement",
|
|
47
|
+
"StaticBlock",
|
|
48
|
+
"SwitchCase",
|
|
49
|
+
]);
|
|
50
|
+
const LEXICAL_DECLARATION_KINDS = new Set([
|
|
51
|
+
"let",
|
|
52
|
+
"const",
|
|
53
|
+
"using",
|
|
54
|
+
"await using",
|
|
55
|
+
]);
|
|
41
56
|
|
|
42
57
|
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
|
|
43
58
|
|
|
44
59
|
// Tests the presence of at least one LegacyOctalEscapeSequence or NonOctalDecimalEscapeSequence in a raw string
|
|
45
|
-
const OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN =
|
|
60
|
+
const OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN =
|
|
61
|
+
/^(?:[^\\]|\\.)*\\(?:[1-9]|0\d)/su;
|
|
46
62
|
|
|
47
63
|
const LOGICAL_ASSIGNMENT_OPERATORS = new Set(["&&=", "||=", "??="]);
|
|
48
64
|
|
|
65
|
+
/**
|
|
66
|
+
* All builtin global variables defined in the latest ECMAScript specification.
|
|
67
|
+
* @type {Record<string,boolean>} Key is the name of the variable. Value is `true` if the variable is considered writable, `false` otherwise.
|
|
68
|
+
*/
|
|
69
|
+
const ECMASCRIPT_GLOBALS = globals[`es${LATEST_ECMA_VERSION}`];
|
|
70
|
+
|
|
49
71
|
/**
|
|
50
72
|
* Checks reference if is non initializer and writable.
|
|
51
73
|
* @param {Reference} reference A reference to check.
|
|
52
|
-
* @param {
|
|
74
|
+
* @param {number} index The index of the reference in the references.
|
|
53
75
|
* @param {Reference[]} references The array that the reference belongs to.
|
|
54
76
|
* @returns {boolean} Success/Failure
|
|
55
77
|
* @private
|
|
56
78
|
*/
|
|
57
79
|
function isModifyingReference(reference, index, references) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
const identifier = reference.identifier;
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Destructuring assignments can have multiple default value, so
|
|
84
|
+
* possibly there are multiple writeable references for the same
|
|
85
|
+
* identifier.
|
|
86
|
+
*/
|
|
87
|
+
const modifyingDifferentIdentifier =
|
|
88
|
+
index === 0 || references[index - 1].identifier !== identifier;
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
identifier &&
|
|
92
|
+
reference.init === false &&
|
|
93
|
+
reference.isWrite() &&
|
|
94
|
+
modifyingDifferentIdentifier
|
|
95
|
+
);
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
/**
|
|
@@ -78,7 +101,7 @@ function isModifyingReference(reference, index, references) {
|
|
|
78
101
|
* @returns {boolean} `true` if the string starts with uppercase.
|
|
79
102
|
*/
|
|
80
103
|
function startsWithUpperCase(s) {
|
|
81
|
-
|
|
104
|
+
return s[0] !== s[0].toLocaleLowerCase();
|
|
82
105
|
}
|
|
83
106
|
|
|
84
107
|
/**
|
|
@@ -87,7 +110,7 @@ function startsWithUpperCase(s) {
|
|
|
87
110
|
* @returns {boolean} Whether or not a node is a constructor.
|
|
88
111
|
*/
|
|
89
112
|
function isES5Constructor(node) {
|
|
90
|
-
|
|
113
|
+
return node.id && startsWithUpperCase(node.id.name);
|
|
91
114
|
}
|
|
92
115
|
|
|
93
116
|
/**
|
|
@@ -96,12 +119,16 @@ function isES5Constructor(node) {
|
|
|
96
119
|
* @returns {Node|null} A found function node.
|
|
97
120
|
*/
|
|
98
121
|
function getUpperFunction(node) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
122
|
+
for (
|
|
123
|
+
let currentNode = node;
|
|
124
|
+
currentNode;
|
|
125
|
+
currentNode = currentNode.parent
|
|
126
|
+
) {
|
|
127
|
+
if (anyFunctionPattern.test(currentNode.type)) {
|
|
128
|
+
return currentNode;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
105
132
|
}
|
|
106
133
|
|
|
107
134
|
/**
|
|
@@ -115,7 +142,7 @@ function getUpperFunction(node) {
|
|
|
115
142
|
* @returns {boolean} `true` if the node is a function node.
|
|
116
143
|
*/
|
|
117
144
|
function isFunction(node) {
|
|
118
|
-
|
|
145
|
+
return Boolean(node && anyFunctionPattern.test(node.type));
|
|
119
146
|
}
|
|
120
147
|
|
|
121
148
|
/**
|
|
@@ -131,7 +158,7 @@ function isFunction(node) {
|
|
|
131
158
|
* @returns {boolean} `true` if the node is a loop node.
|
|
132
159
|
*/
|
|
133
160
|
function isLoop(node) {
|
|
134
|
-
|
|
161
|
+
return Boolean(node && anyLoopPattern.test(node.type));
|
|
135
162
|
}
|
|
136
163
|
|
|
137
164
|
/**
|
|
@@ -140,13 +167,17 @@ function isLoop(node) {
|
|
|
140
167
|
* @returns {boolean} `true` if the node is in a loop.
|
|
141
168
|
*/
|
|
142
169
|
function isInLoop(node) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
170
|
+
for (
|
|
171
|
+
let currentNode = node;
|
|
172
|
+
currentNode && !isFunction(currentNode);
|
|
173
|
+
currentNode = currentNode.parent
|
|
174
|
+
) {
|
|
175
|
+
if (isLoop(currentNode)) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return false;
|
|
150
181
|
}
|
|
151
182
|
|
|
152
183
|
/**
|
|
@@ -155,15 +186,19 @@ function isInLoop(node) {
|
|
|
155
186
|
* @returns {boolean} `true` if the node is a `null` literal
|
|
156
187
|
*/
|
|
157
188
|
function isNullLiteral(node) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
189
|
+
/*
|
|
190
|
+
* Checking `node.value === null` does not guarantee that a literal is a null literal.
|
|
191
|
+
* When parsing values that cannot be represented in the current environment (e.g. unicode
|
|
192
|
+
* regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
|
|
193
|
+
* set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
|
|
194
|
+
* `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
|
|
195
|
+
*/
|
|
196
|
+
return (
|
|
197
|
+
node.type === "Literal" &&
|
|
198
|
+
node.value === null &&
|
|
199
|
+
!node.regex &&
|
|
200
|
+
!node.bigint
|
|
201
|
+
);
|
|
167
202
|
}
|
|
168
203
|
|
|
169
204
|
/**
|
|
@@ -173,11 +208,11 @@ function isNullLiteral(node) {
|
|
|
173
208
|
* @public
|
|
174
209
|
*/
|
|
175
210
|
function isNullOrUndefined(node) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
211
|
+
return (
|
|
212
|
+
isNullLiteral(node) ||
|
|
213
|
+
(node.type === "Identifier" && node.name === "undefined") ||
|
|
214
|
+
(node.type === "UnaryExpression" && node.operator === "void")
|
|
215
|
+
);
|
|
181
216
|
}
|
|
182
217
|
|
|
183
218
|
/**
|
|
@@ -186,7 +221,7 @@ function isNullOrUndefined(node) {
|
|
|
186
221
|
* @returns {boolean} Whether or not the node is callee.
|
|
187
222
|
*/
|
|
188
223
|
function isCallee(node) {
|
|
189
|
-
|
|
224
|
+
return node.parent.type === "CallExpression" && node.parent.callee === node;
|
|
190
225
|
}
|
|
191
226
|
|
|
192
227
|
/**
|
|
@@ -199,35 +234,34 @@ function isCallee(node) {
|
|
|
199
234
|
* @returns {string|null} String value if it can be determined. Otherwise, `null`.
|
|
200
235
|
*/
|
|
201
236
|
function getStaticStringValue(node) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return null;
|
|
237
|
+
switch (node.type) {
|
|
238
|
+
case "Literal":
|
|
239
|
+
if (node.value === null) {
|
|
240
|
+
if (isNullLiteral(node)) {
|
|
241
|
+
return String(node.value); // "null"
|
|
242
|
+
}
|
|
243
|
+
if (node.regex) {
|
|
244
|
+
return `/${node.regex.pattern}/${node.regex.flags}`;
|
|
245
|
+
}
|
|
246
|
+
if (node.bigint) {
|
|
247
|
+
return node.bigint;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Otherwise, this is an unknown literal. The function will return null.
|
|
251
|
+
} else {
|
|
252
|
+
return String(node.value);
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
case "TemplateLiteral":
|
|
256
|
+
if (node.expressions.length === 0 && node.quasis.length === 1) {
|
|
257
|
+
return node.quasis[0].value.cooked;
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
|
|
261
|
+
// no default
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return null;
|
|
231
265
|
}
|
|
232
266
|
|
|
233
267
|
/**
|
|
@@ -261,34 +295,36 @@ function getStaticStringValue(node) {
|
|
|
261
295
|
* @returns {string|null} The property name if static. Otherwise, null.
|
|
262
296
|
*/
|
|
263
297
|
function getStaticPropertyName(node) {
|
|
264
|
-
|
|
298
|
+
let prop;
|
|
265
299
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
300
|
+
switch (node && node.type) {
|
|
301
|
+
case "ChainExpression":
|
|
302
|
+
return getStaticPropertyName(node.expression);
|
|
269
303
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
304
|
+
case "Property":
|
|
305
|
+
case "PropertyDefinition":
|
|
306
|
+
case "MethodDefinition":
|
|
307
|
+
case "TSPropertySignature":
|
|
308
|
+
case "TSMethodSignature":
|
|
309
|
+
prop = node.key;
|
|
310
|
+
break;
|
|
275
311
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
312
|
+
case "MemberExpression":
|
|
313
|
+
prop = node.property;
|
|
314
|
+
break;
|
|
279
315
|
|
|
280
|
-
|
|
281
|
-
|
|
316
|
+
// no default
|
|
317
|
+
}
|
|
282
318
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
319
|
+
if (prop) {
|
|
320
|
+
if (prop.type === "Identifier" && !node.computed) {
|
|
321
|
+
return prop.name;
|
|
322
|
+
}
|
|
287
323
|
|
|
288
|
-
|
|
289
|
-
|
|
324
|
+
return getStaticStringValue(prop);
|
|
325
|
+
}
|
|
290
326
|
|
|
291
|
-
|
|
327
|
+
return null;
|
|
292
328
|
}
|
|
293
329
|
|
|
294
330
|
/**
|
|
@@ -297,7 +333,7 @@ function getStaticPropertyName(node) {
|
|
|
297
333
|
* @returns {ASTNode} The `ChainExpression#expression` value if the node is a `ChainExpression` node. Otherwise, the node.
|
|
298
334
|
*/
|
|
299
335
|
function skipChainExpression(node) {
|
|
300
|
-
|
|
336
|
+
return node && node.type === "ChainExpression" ? node.expression : node;
|
|
301
337
|
}
|
|
302
338
|
|
|
303
339
|
/**
|
|
@@ -307,9 +343,9 @@ function skipChainExpression(node) {
|
|
|
307
343
|
* @returns {boolean} `true` if the `actual` is an expected value.
|
|
308
344
|
*/
|
|
309
345
|
function checkText(actual, expected) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
346
|
+
return typeof expected === "string"
|
|
347
|
+
? actual === expected
|
|
348
|
+
: expected.test(actual);
|
|
313
349
|
}
|
|
314
350
|
|
|
315
351
|
/**
|
|
@@ -319,7 +355,7 @@ function checkText(actual, expected) {
|
|
|
319
355
|
* @returns {boolean} `true` if the node is an Identifier node with the name.
|
|
320
356
|
*/
|
|
321
357
|
function isSpecificId(node, name) {
|
|
322
|
-
|
|
358
|
+
return node.type === "Identifier" && checkText(node.name, name);
|
|
323
359
|
}
|
|
324
360
|
|
|
325
361
|
/**
|
|
@@ -332,25 +368,28 @@ function isSpecificId(node, name) {
|
|
|
332
368
|
* The node is a `MemberExpression` or `ChainExpression`.
|
|
333
369
|
*/
|
|
334
370
|
function isSpecificMemberAccess(node, objectName, propertyName) {
|
|
335
|
-
|
|
371
|
+
const checkNode = skipChainExpression(node);
|
|
336
372
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
373
|
+
if (checkNode.type !== "MemberExpression") {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
340
376
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
377
|
+
if (objectName && !isSpecificId(checkNode.object, objectName)) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
344
380
|
|
|
345
|
-
|
|
346
|
-
|
|
381
|
+
if (propertyName) {
|
|
382
|
+
const actualPropertyName = getStaticPropertyName(checkNode);
|
|
347
383
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
384
|
+
if (
|
|
385
|
+
typeof actualPropertyName !== "string" ||
|
|
386
|
+
!checkText(actualPropertyName, propertyName)
|
|
387
|
+
) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
352
391
|
|
|
353
|
-
|
|
392
|
+
return true;
|
|
354
393
|
}
|
|
355
394
|
|
|
356
395
|
/**
|
|
@@ -360,23 +399,22 @@ function isSpecificMemberAccess(node, objectName, propertyName) {
|
|
|
360
399
|
* @returns {boolean} `true` if the two literal nodes are the same value.
|
|
361
400
|
*/
|
|
362
401
|
function equalLiteralValue(left, right) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
return left.value === right.value;
|
|
402
|
+
// RegExp literal.
|
|
403
|
+
if (left.regex || right.regex) {
|
|
404
|
+
return Boolean(
|
|
405
|
+
left.regex &&
|
|
406
|
+
right.regex &&
|
|
407
|
+
left.regex.pattern === right.regex.pattern &&
|
|
408
|
+
left.regex.flags === right.regex.flags,
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// BigInt literal.
|
|
413
|
+
if (left.bigint || right.bigint) {
|
|
414
|
+
return left.bigint === right.bigint;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return left.value === right.value;
|
|
380
418
|
}
|
|
381
419
|
|
|
382
420
|
/**
|
|
@@ -391,61 +429,83 @@ function equalLiteralValue(left, right) {
|
|
|
391
429
|
* @returns {boolean} `true` if both sides match and reference the same value.
|
|
392
430
|
*/
|
|
393
431
|
function isSameReference(left, right, disableStaticComputedKey = false) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
432
|
+
if (left.type !== right.type) {
|
|
433
|
+
// Handle `a.b` and `a?.b` are samely.
|
|
434
|
+
if (left.type === "ChainExpression") {
|
|
435
|
+
return isSameReference(
|
|
436
|
+
left.expression,
|
|
437
|
+
right,
|
|
438
|
+
disableStaticComputedKey,
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
if (right.type === "ChainExpression") {
|
|
442
|
+
return isSameReference(
|
|
443
|
+
left,
|
|
444
|
+
right.expression,
|
|
445
|
+
disableStaticComputedKey,
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
switch (left.type) {
|
|
453
|
+
case "Super":
|
|
454
|
+
case "ThisExpression":
|
|
455
|
+
return true;
|
|
456
|
+
|
|
457
|
+
case "Identifier":
|
|
458
|
+
case "PrivateIdentifier":
|
|
459
|
+
return left.name === right.name;
|
|
460
|
+
case "Literal":
|
|
461
|
+
return equalLiteralValue(left, right);
|
|
462
|
+
|
|
463
|
+
case "ChainExpression":
|
|
464
|
+
return isSameReference(
|
|
465
|
+
left.expression,
|
|
466
|
+
right.expression,
|
|
467
|
+
disableStaticComputedKey,
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
case "MemberExpression": {
|
|
471
|
+
if (!disableStaticComputedKey) {
|
|
472
|
+
const nameA = getStaticPropertyName(left);
|
|
473
|
+
|
|
474
|
+
// x.y = x["y"]
|
|
475
|
+
if (nameA !== null) {
|
|
476
|
+
return (
|
|
477
|
+
isSameReference(
|
|
478
|
+
left.object,
|
|
479
|
+
right.object,
|
|
480
|
+
disableStaticComputedKey,
|
|
481
|
+
) && nameA === getStaticPropertyName(right)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/*
|
|
487
|
+
* x[0] = x[0]
|
|
488
|
+
* x[y] = x[y]
|
|
489
|
+
* x.y = x.y
|
|
490
|
+
*/
|
|
491
|
+
return (
|
|
492
|
+
left.computed === right.computed &&
|
|
493
|
+
isSameReference(
|
|
494
|
+
left.object,
|
|
495
|
+
right.object,
|
|
496
|
+
disableStaticComputedKey,
|
|
497
|
+
) &&
|
|
498
|
+
isSameReference(
|
|
499
|
+
left.property,
|
|
500
|
+
right.property,
|
|
501
|
+
disableStaticComputedKey,
|
|
502
|
+
)
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
default:
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
449
509
|
}
|
|
450
510
|
|
|
451
511
|
/**
|
|
@@ -454,7 +514,7 @@ function isSameReference(left, right, disableStaticComputedKey = false) {
|
|
|
454
514
|
* @returns {boolean} Whether or not the node is a `Reflect.apply`.
|
|
455
515
|
*/
|
|
456
516
|
function isReflectApply(node) {
|
|
457
|
-
|
|
517
|
+
return isSpecificMemberAccess(node, "Reflect", "apply");
|
|
458
518
|
}
|
|
459
519
|
|
|
460
520
|
/**
|
|
@@ -463,7 +523,7 @@ function isReflectApply(node) {
|
|
|
463
523
|
* @returns {boolean} Whether or not the node is a `Array.from`.
|
|
464
524
|
*/
|
|
465
525
|
function isArrayFromMethod(node) {
|
|
466
|
-
|
|
526
|
+
return isSpecificMemberAccess(node, arrayOrTypedArrayPattern, "from");
|
|
467
527
|
}
|
|
468
528
|
|
|
469
529
|
/**
|
|
@@ -472,7 +532,7 @@ function isArrayFromMethod(node) {
|
|
|
472
532
|
* @returns {boolean} Whether or not the node is a method which expects a function as a first argument, and `thisArg` as a second argument.
|
|
473
533
|
*/
|
|
474
534
|
function isMethodWhichHasThisArg(node) {
|
|
475
|
-
|
|
535
|
+
return isSpecificMemberAccess(node, null, arrayMethodWithThisArgPattern);
|
|
476
536
|
}
|
|
477
537
|
|
|
478
538
|
/**
|
|
@@ -481,7 +541,7 @@ function isMethodWhichHasThisArg(node) {
|
|
|
481
541
|
* @returns {Function} Negated function.
|
|
482
542
|
*/
|
|
483
543
|
function negate(f) {
|
|
484
|
-
|
|
544
|
+
return token => !f(token);
|
|
485
545
|
}
|
|
486
546
|
|
|
487
547
|
/**
|
|
@@ -491,17 +551,19 @@ function negate(f) {
|
|
|
491
551
|
* @returns {boolean} Whether or not the node has a `@this` tag in its comments.
|
|
492
552
|
*/
|
|
493
553
|
function hasJSDocThisTag(node, sourceCode) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
554
|
+
const jsdocComment = sourceCode.getJSDocComment(node);
|
|
555
|
+
|
|
556
|
+
if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Checks `@this` in its leading comments for callbacks,
|
|
561
|
+
// because callbacks don't have its JSDoc comment.
|
|
562
|
+
// e.g.
|
|
563
|
+
// sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
|
|
564
|
+
return sourceCode
|
|
565
|
+
.getCommentsBefore(node)
|
|
566
|
+
.some(comment => thisTagPattern.test(comment.value));
|
|
505
567
|
}
|
|
506
568
|
|
|
507
569
|
/**
|
|
@@ -512,12 +574,16 @@ function hasJSDocThisTag(node, sourceCode) {
|
|
|
512
574
|
* @private
|
|
513
575
|
*/
|
|
514
576
|
function isParenthesised(sourceCode, node) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
577
|
+
const previousToken = sourceCode.getTokenBefore(node),
|
|
578
|
+
nextToken = sourceCode.getTokenAfter(node);
|
|
579
|
+
|
|
580
|
+
return (
|
|
581
|
+
Boolean(previousToken && nextToken) &&
|
|
582
|
+
previousToken.value === "(" &&
|
|
583
|
+
previousToken.range[1] <= node.range[0] &&
|
|
584
|
+
nextToken.value === ")" &&
|
|
585
|
+
nextToken.range[0] >= node.range[1]
|
|
586
|
+
);
|
|
521
587
|
}
|
|
522
588
|
|
|
523
589
|
/**
|
|
@@ -526,7 +592,7 @@ function isParenthesised(sourceCode, node) {
|
|
|
526
592
|
* @returns {boolean} `true` if the token is a `=` token.
|
|
527
593
|
*/
|
|
528
594
|
function isEqToken(token) {
|
|
529
|
-
|
|
595
|
+
return token.value === "=" && token.type === "Punctuator";
|
|
530
596
|
}
|
|
531
597
|
|
|
532
598
|
/**
|
|
@@ -535,7 +601,7 @@ function isEqToken(token) {
|
|
|
535
601
|
* @returns {boolean} `true` if the token is an arrow token.
|
|
536
602
|
*/
|
|
537
603
|
function isArrowToken(token) {
|
|
538
|
-
|
|
604
|
+
return token.value === "=>" && token.type === "Punctuator";
|
|
539
605
|
}
|
|
540
606
|
|
|
541
607
|
/**
|
|
@@ -544,7 +610,7 @@ function isArrowToken(token) {
|
|
|
544
610
|
* @returns {boolean} `true` if the token is a comma token.
|
|
545
611
|
*/
|
|
546
612
|
function isCommaToken(token) {
|
|
547
|
-
|
|
613
|
+
return token.value === "," && token.type === "Punctuator";
|
|
548
614
|
}
|
|
549
615
|
|
|
550
616
|
/**
|
|
@@ -553,7 +619,7 @@ function isCommaToken(token) {
|
|
|
553
619
|
* @returns {boolean} `true` if the token is a dot token.
|
|
554
620
|
*/
|
|
555
621
|
function isDotToken(token) {
|
|
556
|
-
|
|
622
|
+
return token.value === "." && token.type === "Punctuator";
|
|
557
623
|
}
|
|
558
624
|
|
|
559
625
|
/**
|
|
@@ -562,7 +628,7 @@ function isDotToken(token) {
|
|
|
562
628
|
* @returns {boolean} `true` if the token is a `?.` token.
|
|
563
629
|
*/
|
|
564
630
|
function isQuestionDotToken(token) {
|
|
565
|
-
|
|
631
|
+
return token.value === "?." && token.type === "Punctuator";
|
|
566
632
|
}
|
|
567
633
|
|
|
568
634
|
/**
|
|
@@ -571,7 +637,7 @@ function isQuestionDotToken(token) {
|
|
|
571
637
|
* @returns {boolean} `true` if the token is a semicolon token.
|
|
572
638
|
*/
|
|
573
639
|
function isSemicolonToken(token) {
|
|
574
|
-
|
|
640
|
+
return token.value === ";" && token.type === "Punctuator";
|
|
575
641
|
}
|
|
576
642
|
|
|
577
643
|
/**
|
|
@@ -580,7 +646,7 @@ function isSemicolonToken(token) {
|
|
|
580
646
|
* @returns {boolean} `true` if the token is a colon token.
|
|
581
647
|
*/
|
|
582
648
|
function isColonToken(token) {
|
|
583
|
-
|
|
649
|
+
return token.value === ":" && token.type === "Punctuator";
|
|
584
650
|
}
|
|
585
651
|
|
|
586
652
|
/**
|
|
@@ -589,7 +655,7 @@ function isColonToken(token) {
|
|
|
589
655
|
* @returns {boolean} `true` if the token is an opening parenthesis token.
|
|
590
656
|
*/
|
|
591
657
|
function isOpeningParenToken(token) {
|
|
592
|
-
|
|
658
|
+
return token.value === "(" && token.type === "Punctuator";
|
|
593
659
|
}
|
|
594
660
|
|
|
595
661
|
/**
|
|
@@ -598,7 +664,7 @@ function isOpeningParenToken(token) {
|
|
|
598
664
|
* @returns {boolean} `true` if the token is a closing parenthesis token.
|
|
599
665
|
*/
|
|
600
666
|
function isClosingParenToken(token) {
|
|
601
|
-
|
|
667
|
+
return token.value === ")" && token.type === "Punctuator";
|
|
602
668
|
}
|
|
603
669
|
|
|
604
670
|
/**
|
|
@@ -607,7 +673,7 @@ function isClosingParenToken(token) {
|
|
|
607
673
|
* @returns {boolean} `true` if the token is an opening square bracket token.
|
|
608
674
|
*/
|
|
609
675
|
function isOpeningBracketToken(token) {
|
|
610
|
-
|
|
676
|
+
return token.value === "[" && token.type === "Punctuator";
|
|
611
677
|
}
|
|
612
678
|
|
|
613
679
|
/**
|
|
@@ -616,7 +682,7 @@ function isOpeningBracketToken(token) {
|
|
|
616
682
|
* @returns {boolean} `true` if the token is a closing square bracket token.
|
|
617
683
|
*/
|
|
618
684
|
function isClosingBracketToken(token) {
|
|
619
|
-
|
|
685
|
+
return token.value === "]" && token.type === "Punctuator";
|
|
620
686
|
}
|
|
621
687
|
|
|
622
688
|
/**
|
|
@@ -625,7 +691,7 @@ function isClosingBracketToken(token) {
|
|
|
625
691
|
* @returns {boolean} `true` if the token is an opening brace token.
|
|
626
692
|
*/
|
|
627
693
|
function isOpeningBraceToken(token) {
|
|
628
|
-
|
|
694
|
+
return token.value === "{" && token.type === "Punctuator";
|
|
629
695
|
}
|
|
630
696
|
|
|
631
697
|
/**
|
|
@@ -634,7 +700,7 @@ function isOpeningBraceToken(token) {
|
|
|
634
700
|
* @returns {boolean} `true` if the token is a closing brace token.
|
|
635
701
|
*/
|
|
636
702
|
function isClosingBraceToken(token) {
|
|
637
|
-
|
|
703
|
+
return token.value === "}" && token.type === "Punctuator";
|
|
638
704
|
}
|
|
639
705
|
|
|
640
706
|
/**
|
|
@@ -643,7 +709,11 @@ function isClosingBraceToken(token) {
|
|
|
643
709
|
* @returns {boolean} `true` if the token is a comment token.
|
|
644
710
|
*/
|
|
645
711
|
function isCommentToken(token) {
|
|
646
|
-
|
|
712
|
+
return (
|
|
713
|
+
token.type === "Line" ||
|
|
714
|
+
token.type === "Block" ||
|
|
715
|
+
token.type === "Shebang"
|
|
716
|
+
);
|
|
647
717
|
}
|
|
648
718
|
|
|
649
719
|
/**
|
|
@@ -652,7 +722,7 @@ function isCommentToken(token) {
|
|
|
652
722
|
* @returns {boolean} `true` if the token is a keyword token.
|
|
653
723
|
*/
|
|
654
724
|
function isKeywordToken(token) {
|
|
655
|
-
|
|
725
|
+
return token.type === "Keyword";
|
|
656
726
|
}
|
|
657
727
|
|
|
658
728
|
/**
|
|
@@ -662,19 +732,20 @@ function isKeywordToken(token) {
|
|
|
662
732
|
* @returns {Token} `(` token.
|
|
663
733
|
*/
|
|
664
734
|
function getOpeningParenOfParams(node, sourceCode) {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
735
|
+
// If the node is an arrow function and doesn't have parens, this returns the identifier of the first param.
|
|
736
|
+
if (node.type === "ArrowFunctionExpression" && node.params.length === 1) {
|
|
737
|
+
const argToken = sourceCode.getFirstToken(node.params[0]);
|
|
738
|
+
const maybeParenToken = sourceCode.getTokenBefore(argToken);
|
|
739
|
+
|
|
740
|
+
return isOpeningParenToken(maybeParenToken)
|
|
741
|
+
? maybeParenToken
|
|
742
|
+
: argToken;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Otherwise, returns paren.
|
|
746
|
+
return node.id
|
|
747
|
+
? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
|
|
748
|
+
: sourceCode.getFirstToken(node, isOpeningParenToken);
|
|
678
749
|
}
|
|
679
750
|
|
|
680
751
|
/**
|
|
@@ -685,21 +756,22 @@ function getOpeningParenOfParams(node, sourceCode) {
|
|
|
685
756
|
* @returns {boolean} the source code for the given node.
|
|
686
757
|
*/
|
|
687
758
|
function equalTokens(left, right, sourceCode) {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
759
|
+
const tokensL = sourceCode.getTokens(left);
|
|
760
|
+
const tokensR = sourceCode.getTokens(right);
|
|
761
|
+
|
|
762
|
+
if (tokensL.length !== tokensR.length) {
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
for (let i = 0; i < tokensL.length; ++i) {
|
|
766
|
+
if (
|
|
767
|
+
tokensL[i].type !== tokensR[i].type ||
|
|
768
|
+
tokensL[i].value !== tokensR[i].value
|
|
769
|
+
) {
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return true;
|
|
703
775
|
}
|
|
704
776
|
|
|
705
777
|
/**
|
|
@@ -715,10 +787,10 @@ function equalTokens(left, right, sourceCode) {
|
|
|
715
787
|
* @see https://tc39.es/ecma262/#prod-ShortCircuitExpression
|
|
716
788
|
*/
|
|
717
789
|
function isLogicalExpression(node) {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
790
|
+
return (
|
|
791
|
+
node.type === "LogicalExpression" &&
|
|
792
|
+
(node.operator === "&&" || node.operator === "||")
|
|
793
|
+
);
|
|
722
794
|
}
|
|
723
795
|
|
|
724
796
|
/**
|
|
@@ -733,7 +805,7 @@ function isLogicalExpression(node) {
|
|
|
733
805
|
* @returns {boolean} `true` if the node is `??`.
|
|
734
806
|
*/
|
|
735
807
|
function isCoalesceExpression(node) {
|
|
736
|
-
|
|
808
|
+
return node.type === "LogicalExpression" && node.operator === "??";
|
|
737
809
|
}
|
|
738
810
|
|
|
739
811
|
/**
|
|
@@ -743,10 +815,10 @@ function isCoalesceExpression(node) {
|
|
|
743
815
|
* @returns {boolean} `true` if the two nodes are the pair of a logical expression and a coalesce expression.
|
|
744
816
|
*/
|
|
745
817
|
function isMixedLogicalAndCoalesceExpressions(left, right) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
818
|
+
return (
|
|
819
|
+
(isLogicalExpression(left) && isCoalesceExpression(right)) ||
|
|
820
|
+
(isCoalesceExpression(left) && isLogicalExpression(right))
|
|
821
|
+
);
|
|
750
822
|
}
|
|
751
823
|
|
|
752
824
|
/**
|
|
@@ -755,7 +827,7 @@ function isMixedLogicalAndCoalesceExpressions(left, right) {
|
|
|
755
827
|
* @returns {boolean} `true` if the operator is a logical assignment operator.
|
|
756
828
|
*/
|
|
757
829
|
function isLogicalAssignmentOperator(operator) {
|
|
758
|
-
|
|
830
|
+
return LOGICAL_ASSIGNMENT_OPERATORS.has(operator);
|
|
759
831
|
}
|
|
760
832
|
|
|
761
833
|
/**
|
|
@@ -765,10 +837,10 @@ function isLogicalAssignmentOperator(operator) {
|
|
|
765
837
|
* @returns {Token} The colon token of the node.
|
|
766
838
|
*/
|
|
767
839
|
function getSwitchCaseColonToken(node, sourceCode) {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
840
|
+
if (node.test) {
|
|
841
|
+
return sourceCode.getTokenAfter(node.test, isColonToken);
|
|
842
|
+
}
|
|
843
|
+
return sourceCode.getFirstToken(node, 1);
|
|
772
844
|
}
|
|
773
845
|
|
|
774
846
|
/**
|
|
@@ -782,12 +854,12 @@ function getSwitchCaseColonToken(node, sourceCode) {
|
|
|
782
854
|
* @returns {string} The module export name.
|
|
783
855
|
*/
|
|
784
856
|
function getModuleExportName(node) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
857
|
+
if (node.type === "Identifier") {
|
|
858
|
+
return node.name;
|
|
859
|
+
}
|
|
788
860
|
|
|
789
|
-
|
|
790
|
-
|
|
861
|
+
// string literal
|
|
862
|
+
return node.value;
|
|
791
863
|
}
|
|
792
864
|
|
|
793
865
|
/**
|
|
@@ -797,27 +869,26 @@ function getModuleExportName(node) {
|
|
|
797
869
|
* `null` when it cannot be determined.
|
|
798
870
|
*/
|
|
799
871
|
function getBooleanValue(node) {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
return !!node.value;
|
|
872
|
+
if (node.value === null) {
|
|
873
|
+
/*
|
|
874
|
+
* it might be a null literal or bigint/regex literal in unsupported environments .
|
|
875
|
+
* https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es5.md#regexpliteral
|
|
876
|
+
* https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es2020.md#bigintliteral
|
|
877
|
+
*/
|
|
878
|
+
|
|
879
|
+
if (node.raw === "null") {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// regex is always truthy
|
|
884
|
+
if (typeof node.regex === "object") {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
return !!node.value;
|
|
821
892
|
}
|
|
822
893
|
|
|
823
894
|
/**
|
|
@@ -827,34 +898,37 @@ function getBooleanValue(node) {
|
|
|
827
898
|
* @returns {boolean} true when condition short circuits whole condition
|
|
828
899
|
*/
|
|
829
900
|
function isLogicalIdentity(node, operator) {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
901
|
+
switch (node.type) {
|
|
902
|
+
case "Literal":
|
|
903
|
+
return (
|
|
904
|
+
(operator === "||" && getBooleanValue(node) === true) ||
|
|
905
|
+
(operator === "&&" && getBooleanValue(node) === false)
|
|
906
|
+
);
|
|
907
|
+
|
|
908
|
+
case "UnaryExpression":
|
|
909
|
+
return operator === "&&" && node.operator === "void";
|
|
910
|
+
|
|
911
|
+
case "LogicalExpression":
|
|
912
|
+
/*
|
|
913
|
+
* handles `a && false || b`
|
|
914
|
+
* `false` is an identity element of `&&` but not `||`
|
|
915
|
+
*/
|
|
916
|
+
return (
|
|
917
|
+
operator === node.operator &&
|
|
918
|
+
(isLogicalIdentity(node.left, operator) ||
|
|
919
|
+
isLogicalIdentity(node.right, operator))
|
|
920
|
+
);
|
|
921
|
+
|
|
922
|
+
case "AssignmentExpression":
|
|
923
|
+
return (
|
|
924
|
+
["||=", "&&="].includes(node.operator) &&
|
|
925
|
+
operator === node.operator.slice(0, -1) &&
|
|
926
|
+
isLogicalIdentity(node.right, operator)
|
|
927
|
+
);
|
|
928
|
+
|
|
929
|
+
// no default
|
|
930
|
+
}
|
|
931
|
+
return false;
|
|
858
932
|
}
|
|
859
933
|
|
|
860
934
|
/**
|
|
@@ -864,17 +938,16 @@ function isLogicalIdentity(node, operator) {
|
|
|
864
938
|
* @returns {boolean} `true` if the identifier is a reference to a global variable.
|
|
865
939
|
*/
|
|
866
940
|
function isReferenceToGlobalVariable(scope, node) {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
941
|
+
const reference = scope.references.find(ref => ref.identifier === node);
|
|
942
|
+
|
|
943
|
+
return Boolean(
|
|
944
|
+
reference &&
|
|
945
|
+
reference.resolved &&
|
|
946
|
+
reference.resolved.scope.type === "global" &&
|
|
947
|
+
reference.resolved.defs.length === 0,
|
|
948
|
+
);
|
|
875
949
|
}
|
|
876
950
|
|
|
877
|
-
|
|
878
951
|
/**
|
|
879
952
|
* Checks if a node has a constant truthiness value.
|
|
880
953
|
* @param {Scope} scope Scope in which the node appears.
|
|
@@ -887,123 +960,161 @@ function isReferenceToGlobalVariable(scope, node) {
|
|
|
887
960
|
* @private
|
|
888
961
|
*/
|
|
889
962
|
function isConstant(scope, node, inBooleanPosition) {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
963
|
+
// node.elements can return null values in the case of sparse arrays ex. [,]
|
|
964
|
+
if (!node) {
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
switch (node.type) {
|
|
968
|
+
case "Literal":
|
|
969
|
+
case "ArrowFunctionExpression":
|
|
970
|
+
case "FunctionExpression":
|
|
971
|
+
return true;
|
|
972
|
+
case "ClassExpression":
|
|
973
|
+
case "ObjectExpression":
|
|
974
|
+
/**
|
|
975
|
+
* In theory objects like:
|
|
976
|
+
*
|
|
977
|
+
* `{toString: () => a}`
|
|
978
|
+
* `{valueOf: () => a}`
|
|
979
|
+
*
|
|
980
|
+
* Or a classes like:
|
|
981
|
+
*
|
|
982
|
+
* `class { static toString() { return a } }`
|
|
983
|
+
* `class { static valueOf() { return a } }`
|
|
984
|
+
*
|
|
985
|
+
* Are not constant verifiably when `inBooleanPosition` is
|
|
986
|
+
* false, but it's an edge case we've opted not to handle.
|
|
987
|
+
*/
|
|
988
|
+
return true;
|
|
989
|
+
case "TemplateLiteral":
|
|
990
|
+
return (
|
|
991
|
+
(inBooleanPosition &&
|
|
992
|
+
node.quasis.some(quasi => quasi.value.cooked.length)) ||
|
|
993
|
+
node.expressions.every(exp => isConstant(scope, exp, false))
|
|
994
|
+
);
|
|
995
|
+
|
|
996
|
+
case "ArrayExpression": {
|
|
997
|
+
if (!inBooleanPosition) {
|
|
998
|
+
return node.elements.every(element =>
|
|
999
|
+
isConstant(scope, element, false),
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
return true;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
case "UnaryExpression":
|
|
1006
|
+
if (
|
|
1007
|
+
node.operator === "void" ||
|
|
1008
|
+
(node.operator === "typeof" && inBooleanPosition)
|
|
1009
|
+
) {
|
|
1010
|
+
return true;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (node.operator === "!") {
|
|
1014
|
+
return isConstant(scope, node.argument, true);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
return isConstant(scope, node.argument, false);
|
|
1018
|
+
|
|
1019
|
+
case "BinaryExpression":
|
|
1020
|
+
return (
|
|
1021
|
+
isConstant(scope, node.left, false) &&
|
|
1022
|
+
isConstant(scope, node.right, false) &&
|
|
1023
|
+
node.operator !== "in"
|
|
1024
|
+
);
|
|
1025
|
+
|
|
1026
|
+
case "LogicalExpression": {
|
|
1027
|
+
const isLeftConstant = isConstant(
|
|
1028
|
+
scope,
|
|
1029
|
+
node.left,
|
|
1030
|
+
inBooleanPosition,
|
|
1031
|
+
);
|
|
1032
|
+
const isRightConstant = isConstant(
|
|
1033
|
+
scope,
|
|
1034
|
+
node.right,
|
|
1035
|
+
inBooleanPosition,
|
|
1036
|
+
);
|
|
1037
|
+
const isLeftShortCircuit =
|
|
1038
|
+
isLeftConstant && isLogicalIdentity(node.left, node.operator);
|
|
1039
|
+
const isRightShortCircuit =
|
|
1040
|
+
inBooleanPosition &&
|
|
1041
|
+
isRightConstant &&
|
|
1042
|
+
isLogicalIdentity(node.right, node.operator);
|
|
1043
|
+
|
|
1044
|
+
return (
|
|
1045
|
+
(isLeftConstant && isRightConstant) ||
|
|
1046
|
+
isLeftShortCircuit ||
|
|
1047
|
+
isRightShortCircuit
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
case "NewExpression":
|
|
1051
|
+
return inBooleanPosition;
|
|
1052
|
+
case "AssignmentExpression":
|
|
1053
|
+
if (node.operator === "=") {
|
|
1054
|
+
return isConstant(scope, node.right, inBooleanPosition);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
if (["||=", "&&="].includes(node.operator) && inBooleanPosition) {
|
|
1058
|
+
return isLogicalIdentity(
|
|
1059
|
+
node.right,
|
|
1060
|
+
node.operator.slice(0, -1),
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
return false;
|
|
1065
|
+
|
|
1066
|
+
case "SequenceExpression":
|
|
1067
|
+
return isConstant(
|
|
1068
|
+
scope,
|
|
1069
|
+
node.expressions.at(-1),
|
|
1070
|
+
inBooleanPosition,
|
|
1071
|
+
);
|
|
1072
|
+
case "SpreadElement":
|
|
1073
|
+
return isConstant(scope, node.argument, inBooleanPosition);
|
|
1074
|
+
case "CallExpression":
|
|
1075
|
+
if (
|
|
1076
|
+
node.callee.type === "Identifier" &&
|
|
1077
|
+
node.callee.name === "Boolean"
|
|
1078
|
+
) {
|
|
1079
|
+
if (
|
|
1080
|
+
node.arguments.length === 0 ||
|
|
1081
|
+
isConstant(scope, node.arguments[0], true)
|
|
1082
|
+
) {
|
|
1083
|
+
return isReferenceToGlobalVariable(scope, node.callee);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return false;
|
|
1087
|
+
case "Identifier":
|
|
1088
|
+
return (
|
|
1089
|
+
node.name === "undefined" &&
|
|
1090
|
+
isReferenceToGlobalVariable(scope, node)
|
|
1091
|
+
);
|
|
1092
|
+
|
|
1093
|
+
// no default
|
|
1094
|
+
}
|
|
1095
|
+
return false;
|
|
988
1096
|
}
|
|
989
1097
|
|
|
990
1098
|
/**
|
|
991
|
-
* Checks whether a node is an ExpressionStatement at the top level of a file or
|
|
1099
|
+
* Checks whether a node is an ExpressionStatement at the top level of a file, function body, or TypeScript module block.
|
|
992
1100
|
* A top-level ExpressionStatement node is a directive if it contains a single unparenthesized
|
|
993
1101
|
* string literal and if it occurs either as the first sibling or immediately after another
|
|
994
1102
|
* directive.
|
|
995
1103
|
* @param {ASTNode} node The node to check.
|
|
996
1104
|
* @returns {boolean} Whether or not the node is an ExpressionStatement at the top level of a
|
|
997
|
-
* file or
|
|
1105
|
+
* file, function body, or TypeScript module block.
|
|
998
1106
|
*/
|
|
999
1107
|
function isTopLevelExpressionStatement(node) {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1108
|
+
if (node.type !== "ExpressionStatement") {
|
|
1109
|
+
return false;
|
|
1110
|
+
}
|
|
1111
|
+
const parent = node.parent;
|
|
1112
|
+
|
|
1113
|
+
return (
|
|
1114
|
+
parent.type === "Program" ||
|
|
1115
|
+
parent.type === "TSModuleBlock" ||
|
|
1116
|
+
(parent.type === "BlockStatement" && isFunction(parent.parent))
|
|
1117
|
+
);
|
|
1007
1118
|
}
|
|
1008
1119
|
|
|
1009
1120
|
/**
|
|
@@ -1012,7 +1123,10 @@ function isTopLevelExpressionStatement(node) {
|
|
|
1012
1123
|
* @returns {boolean} `true` if the node is a part of directive prologue.
|
|
1013
1124
|
*/
|
|
1014
1125
|
function isDirective(node) {
|
|
1015
|
-
|
|
1126
|
+
return (
|
|
1127
|
+
node.type === "ExpressionStatement" &&
|
|
1128
|
+
typeof node.directive === "string"
|
|
1129
|
+
);
|
|
1016
1130
|
}
|
|
1017
1131
|
|
|
1018
1132
|
/**
|
|
@@ -1021,106 +1135,205 @@ function isDirective(node) {
|
|
|
1021
1135
|
* @returns {boolean} Whether the node appears at the beginning of an ancestor ExpressionStatement node.
|
|
1022
1136
|
*/
|
|
1023
1137
|
function isStartOfExpressionStatement(node) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1138
|
+
const start = node.range[0];
|
|
1139
|
+
let ancestor = node;
|
|
1140
|
+
|
|
1141
|
+
while ((ancestor = ancestor.parent) && ancestor.range[0] === start) {
|
|
1142
|
+
if (ancestor.type === "ExpressionStatement") {
|
|
1143
|
+
return true;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return false;
|
|
1033
1147
|
}
|
|
1034
1148
|
|
|
1035
1149
|
/**
|
|
1036
1150
|
* Determines whether an opening parenthesis `(`, bracket `[` or backtick ``` ` ``` needs to be preceded by a semicolon.
|
|
1037
|
-
* This opening parenthesis or bracket should be at the start of an `ExpressionStatement` or at
|
|
1151
|
+
* This opening parenthesis or bracket should be at the start of an `ExpressionStatement`, a `MethodDefinition` or at
|
|
1152
|
+
* the start of the body of an `ArrowFunctionExpression`.
|
|
1038
1153
|
* @type {(sourceCode: SourceCode, node: ASTNode) => boolean}
|
|
1039
1154
|
* @param {SourceCode} sourceCode The source code object.
|
|
1040
1155
|
* @param {ASTNode} node A node at the position where an opening parenthesis or bracket will be inserted.
|
|
1041
|
-
* @returns {boolean} Whether a semicolon is required before the opening parenthesis or
|
|
1156
|
+
* @returns {boolean} Whether a semicolon is required before the opening parenthesis or bracket.
|
|
1042
1157
|
*/
|
|
1043
1158
|
let needsPrecedingSemicolon;
|
|
1044
1159
|
|
|
1045
1160
|
{
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1161
|
+
const BREAK_OR_CONTINUE = new Set(["BreakStatement", "ContinueStatement"]);
|
|
1162
|
+
|
|
1163
|
+
// Declaration types that cannot be continued by a punctuator when ending with a string Literal that is a direct child.
|
|
1164
|
+
const DECLARATIONS = new Set([
|
|
1165
|
+
"ExportAllDeclaration",
|
|
1166
|
+
"ExportNamedDeclaration",
|
|
1167
|
+
"ImportDeclaration",
|
|
1168
|
+
]);
|
|
1169
|
+
|
|
1170
|
+
const IDENTIFIER_OR_KEYWORD = new Set(["Identifier", "Keyword"]);
|
|
1171
|
+
|
|
1172
|
+
// Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types.
|
|
1173
|
+
const NODE_TYPES_BY_KEYWORD = {
|
|
1174
|
+
__proto__: null,
|
|
1175
|
+
break: "BreakStatement",
|
|
1176
|
+
continue: "ContinueStatement",
|
|
1177
|
+
debugger: "DebuggerStatement",
|
|
1178
|
+
do: "DoWhileStatement",
|
|
1179
|
+
else: "IfStatement",
|
|
1180
|
+
return: "ReturnStatement",
|
|
1181
|
+
yield: "YieldExpression",
|
|
1182
|
+
};
|
|
1183
|
+
|
|
1184
|
+
/*
|
|
1185
|
+
* Before an opening parenthesis, postfix `++` and `--` always trigger ASI;
|
|
1186
|
+
* the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement.
|
|
1187
|
+
*/
|
|
1188
|
+
const PUNCTUATORS = new Set([":", ";", "{", "=>", "++", "--"]);
|
|
1189
|
+
|
|
1190
|
+
/*
|
|
1191
|
+
* Statements that can contain an `ExpressionStatement` after a closing parenthesis.
|
|
1192
|
+
* DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis.
|
|
1193
|
+
*/
|
|
1194
|
+
const STATEMENTS = new Set([
|
|
1195
|
+
"DoWhileStatement",
|
|
1196
|
+
"ForInStatement",
|
|
1197
|
+
"ForOfStatement",
|
|
1198
|
+
"ForStatement",
|
|
1199
|
+
"IfStatement",
|
|
1200
|
+
"WhileStatement",
|
|
1201
|
+
"WithStatement",
|
|
1202
|
+
]);
|
|
1203
|
+
|
|
1204
|
+
const TS_TYPE_NODE_TYPES = new Set([
|
|
1205
|
+
"TSAsExpression",
|
|
1206
|
+
"TSSatisfiesExpression",
|
|
1207
|
+
"TSTypeAliasDeclaration",
|
|
1208
|
+
"TSTypeAnnotation",
|
|
1209
|
+
]);
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* Determines whether a specified node is inside a TypeScript type context.
|
|
1213
|
+
* @param {ASTNode} node The node to check.
|
|
1214
|
+
* @returns {boolean} Whether the node is inside a TypeScript type context.
|
|
1215
|
+
*/
|
|
1216
|
+
function isInType(node) {
|
|
1217
|
+
for (let currNode = node; ; ) {
|
|
1218
|
+
const { parent } = currNode;
|
|
1219
|
+
if (!parent) {
|
|
1220
|
+
break;
|
|
1221
|
+
}
|
|
1222
|
+
if (
|
|
1223
|
+
TS_TYPE_NODE_TYPES.has(parent.type) &&
|
|
1224
|
+
currNode === parent.typeAnnotation
|
|
1225
|
+
) {
|
|
1226
|
+
return true;
|
|
1227
|
+
}
|
|
1228
|
+
currNode = parent;
|
|
1229
|
+
}
|
|
1230
|
+
return false;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
needsPrecedingSemicolon = function (sourceCode, node) {
|
|
1234
|
+
const prevToken = sourceCode.getTokenBefore(node);
|
|
1235
|
+
|
|
1236
|
+
if (
|
|
1237
|
+
!prevToken ||
|
|
1238
|
+
(prevToken.type === "Punctuator" &&
|
|
1239
|
+
PUNCTUATORS.has(prevToken.value))
|
|
1240
|
+
) {
|
|
1241
|
+
return false;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
|
|
1245
|
+
|
|
1246
|
+
if (
|
|
1247
|
+
prevNode.type === "TSDeclareFunction" ||
|
|
1248
|
+
prevNode.parent.type === "TSImportEqualsDeclaration" ||
|
|
1249
|
+
prevNode.parent.parent?.type === "TSImportEqualsDeclaration" ||
|
|
1250
|
+
TS_TYPE_NODE_TYPES.has(prevNode.type) ||
|
|
1251
|
+
isInType(prevNode)
|
|
1252
|
+
) {
|
|
1253
|
+
return false;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
if (isClosingParenToken(prevToken)) {
|
|
1257
|
+
return !STATEMENTS.has(prevNode.type);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
if (isClosingBraceToken(prevToken)) {
|
|
1261
|
+
return (
|
|
1262
|
+
(prevNode.type === "BlockStatement" &&
|
|
1263
|
+
prevNode.parent.type === "FunctionExpression" &&
|
|
1264
|
+
prevNode.parent.parent.type !== "MethodDefinition") ||
|
|
1265
|
+
(prevNode.type === "ClassBody" &&
|
|
1266
|
+
prevNode.parent.type === "ClassExpression") ||
|
|
1267
|
+
prevNode.type === "ObjectExpression"
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) {
|
|
1272
|
+
if (
|
|
1273
|
+
prevNode.parent.type === "VariableDeclarator" &&
|
|
1274
|
+
!prevNode.parent.init
|
|
1275
|
+
) {
|
|
1276
|
+
return false;
|
|
1277
|
+
}
|
|
1278
|
+
if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) {
|
|
1279
|
+
return false;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
const keyword = prevToken.value;
|
|
1283
|
+
const nodeType = NODE_TYPES_BY_KEYWORD[keyword];
|
|
1284
|
+
|
|
1285
|
+
return prevNode.type !== nodeType;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
if (prevToken.type === "String") {
|
|
1289
|
+
return !DECLARATIONS.has(prevNode.parent.type);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
return true;
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* Checks if a node is used as an import attribute key, either in a static or dynamic import.
|
|
1298
|
+
* @param {ASTNode} node The node to check.
|
|
1299
|
+
* @returns {boolean} Whether the node is used as an import attribute key.
|
|
1300
|
+
*/
|
|
1301
|
+
function isImportAttributeKey(node) {
|
|
1302
|
+
const { parent } = node;
|
|
1303
|
+
|
|
1304
|
+
// static import/re-export
|
|
1305
|
+
if (parent.type === "ImportAttribute" && parent.key === node) {
|
|
1306
|
+
return true;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// dynamic import
|
|
1310
|
+
if (
|
|
1311
|
+
parent.type === "Property" &&
|
|
1312
|
+
!parent.computed &&
|
|
1313
|
+
(parent.key === node ||
|
|
1314
|
+
(parent.value === node && parent.shorthand && !parent.method)) &&
|
|
1315
|
+
parent.parent.type === "ObjectExpression"
|
|
1316
|
+
) {
|
|
1317
|
+
const objectExpression = parent.parent;
|
|
1318
|
+
const objectExpressionParent = objectExpression.parent;
|
|
1319
|
+
|
|
1320
|
+
if (
|
|
1321
|
+
objectExpressionParent.type === "ImportExpression" &&
|
|
1322
|
+
objectExpressionParent.options === objectExpression
|
|
1323
|
+
) {
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// nested key
|
|
1328
|
+
if (
|
|
1329
|
+
objectExpressionParent.type === "Property" &&
|
|
1330
|
+
objectExpressionParent.value === objectExpression
|
|
1331
|
+
) {
|
|
1332
|
+
return isImportAttributeKey(objectExpressionParent.key);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
return false;
|
|
1124
1337
|
}
|
|
1125
1338
|
|
|
1126
1339
|
//------------------------------------------------------------------------------
|
|
@@ -1128,1155 +1341,1393 @@ let needsPrecedingSemicolon;
|
|
|
1128
1341
|
//------------------------------------------------------------------------------
|
|
1129
1342
|
|
|
1130
1343
|
module.exports = {
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
1344
|
+
COMMENTS_IGNORE_PATTERN,
|
|
1345
|
+
LINEBREAKS,
|
|
1346
|
+
LINEBREAK_MATCHER: lineBreakPattern,
|
|
1347
|
+
SHEBANG_MATCHER: shebangPattern,
|
|
1348
|
+
STATEMENT_LIST_PARENTS,
|
|
1349
|
+
ECMASCRIPT_GLOBALS,
|
|
1350
|
+
|
|
1351
|
+
/**
|
|
1352
|
+
* Determines whether two adjacent tokens are on the same line.
|
|
1353
|
+
* @param {Object} left The left token object.
|
|
1354
|
+
* @param {Object} right The right token object.
|
|
1355
|
+
* @returns {boolean} Whether or not the tokens are on the same line.
|
|
1356
|
+
* @public
|
|
1357
|
+
*/
|
|
1358
|
+
isTokenOnSameLine(left, right) {
|
|
1359
|
+
return left.loc.end.line === right.loc.start.line;
|
|
1360
|
+
},
|
|
1361
|
+
|
|
1362
|
+
isNullOrUndefined,
|
|
1363
|
+
isCallee,
|
|
1364
|
+
isES5Constructor,
|
|
1365
|
+
getUpperFunction,
|
|
1366
|
+
isFunction,
|
|
1367
|
+
isLoop,
|
|
1368
|
+
isInLoop,
|
|
1369
|
+
isArrayFromMethod,
|
|
1370
|
+
isParenthesised,
|
|
1371
|
+
createGlobalLinebreakMatcher,
|
|
1372
|
+
equalTokens,
|
|
1373
|
+
|
|
1374
|
+
isArrowToken,
|
|
1375
|
+
isClosingBraceToken,
|
|
1376
|
+
isClosingBracketToken,
|
|
1377
|
+
isClosingParenToken,
|
|
1378
|
+
isColonToken,
|
|
1379
|
+
isCommaToken,
|
|
1380
|
+
isCommentToken,
|
|
1381
|
+
isDotToken,
|
|
1382
|
+
isQuestionDotToken,
|
|
1383
|
+
isKeywordToken,
|
|
1384
|
+
isNotClosingBraceToken: negate(isClosingBraceToken),
|
|
1385
|
+
isNotClosingBracketToken: negate(isClosingBracketToken),
|
|
1386
|
+
isNotClosingParenToken: negate(isClosingParenToken),
|
|
1387
|
+
isNotColonToken: negate(isColonToken),
|
|
1388
|
+
isNotCommaToken: negate(isCommaToken),
|
|
1389
|
+
isNotDotToken: negate(isDotToken),
|
|
1390
|
+
isNotQuestionDotToken: negate(isQuestionDotToken),
|
|
1391
|
+
isNotOpeningBraceToken: negate(isOpeningBraceToken),
|
|
1392
|
+
isNotOpeningBracketToken: negate(isOpeningBracketToken),
|
|
1393
|
+
isNotOpeningParenToken: negate(isOpeningParenToken),
|
|
1394
|
+
isNotSemicolonToken: negate(isSemicolonToken),
|
|
1395
|
+
isOpeningBraceToken,
|
|
1396
|
+
isOpeningBracketToken,
|
|
1397
|
+
isOpeningParenToken,
|
|
1398
|
+
isSemicolonToken,
|
|
1399
|
+
isEqToken,
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* Checks whether or not a given node is a string literal.
|
|
1403
|
+
* @param {ASTNode} node A node to check.
|
|
1404
|
+
* @returns {boolean} `true` if the node is a string literal.
|
|
1405
|
+
*/
|
|
1406
|
+
isStringLiteral(node) {
|
|
1407
|
+
return (
|
|
1408
|
+
(node.type === "Literal" && typeof node.value === "string") ||
|
|
1409
|
+
node.type === "TemplateLiteral"
|
|
1410
|
+
);
|
|
1411
|
+
},
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Checks whether a given node is a breakable statement or not.
|
|
1415
|
+
* The node is breakable if the node is one of the following type:
|
|
1416
|
+
*
|
|
1417
|
+
* - DoWhileStatement
|
|
1418
|
+
* - ForInStatement
|
|
1419
|
+
* - ForOfStatement
|
|
1420
|
+
* - ForStatement
|
|
1421
|
+
* - SwitchStatement
|
|
1422
|
+
* - WhileStatement
|
|
1423
|
+
* @param {ASTNode} node A node to check.
|
|
1424
|
+
* @returns {boolean} `true` if the node is breakable.
|
|
1425
|
+
*/
|
|
1426
|
+
isBreakableStatement(node) {
|
|
1427
|
+
return breakableTypePattern.test(node.type);
|
|
1428
|
+
},
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* Gets references which are non initializer and writable.
|
|
1432
|
+
* @param {Reference[]} references An array of references.
|
|
1433
|
+
* @returns {Reference[]} An array of only references which are non initializer and writable.
|
|
1434
|
+
* @public
|
|
1435
|
+
*/
|
|
1436
|
+
getModifyingReferences(references) {
|
|
1437
|
+
return references.filter(isModifyingReference);
|
|
1438
|
+
},
|
|
1439
|
+
|
|
1440
|
+
/**
|
|
1441
|
+
* Validate that a string passed in is surrounded by the specified character
|
|
1442
|
+
* @param {string} val The text to check.
|
|
1443
|
+
* @param {string} character The character to see if it's surrounded by.
|
|
1444
|
+
* @returns {boolean} True if the text is surrounded by the character, false if not.
|
|
1445
|
+
* @private
|
|
1446
|
+
*/
|
|
1447
|
+
isSurroundedBy(val, character) {
|
|
1448
|
+
return val[0] === character && val.at(-1) === character;
|
|
1449
|
+
},
|
|
1450
|
+
|
|
1451
|
+
/**
|
|
1452
|
+
* Returns whether the provided node is an ESLint directive comment or not
|
|
1453
|
+
* @param {Line|Block} node The comment token to be checked
|
|
1454
|
+
* @returns {boolean} `true` if the node is an ESLint directive comment
|
|
1455
|
+
*/
|
|
1456
|
+
isDirectiveComment(node) {
|
|
1457
|
+
const comment = node.value.trim();
|
|
1458
|
+
|
|
1459
|
+
return (
|
|
1460
|
+
(node.type === "Line" && comment.startsWith("eslint-")) ||
|
|
1461
|
+
(node.type === "Block" && ESLINT_DIRECTIVE_PATTERN.test(comment))
|
|
1462
|
+
);
|
|
1463
|
+
},
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* Gets the trailing statement of a given node.
|
|
1467
|
+
*
|
|
1468
|
+
* if (code)
|
|
1469
|
+
* consequent;
|
|
1470
|
+
*
|
|
1471
|
+
* When taking this `IfStatement`, returns `consequent;` statement.
|
|
1472
|
+
* @param {ASTNode} A node to get.
|
|
1473
|
+
* @returns {ASTNode|null} The trailing statement's node.
|
|
1474
|
+
*/
|
|
1475
|
+
getTrailingStatement: esutils.ast.trailingStatement,
|
|
1476
|
+
|
|
1477
|
+
/**
|
|
1478
|
+
* Finds the variable by a given name in a given scope and its upper scopes.
|
|
1479
|
+
* @param {eslint-scope.Scope} initScope A scope to start find.
|
|
1480
|
+
* @param {string} name A variable name to find.
|
|
1481
|
+
* @returns {eslint-scope.Variable|null} A found variable or `null`.
|
|
1482
|
+
*/
|
|
1483
|
+
getVariableByName(initScope, name) {
|
|
1484
|
+
let scope = initScope;
|
|
1485
|
+
|
|
1486
|
+
while (scope) {
|
|
1487
|
+
const variable = scope.set.get(name);
|
|
1488
|
+
|
|
1489
|
+
if (variable) {
|
|
1490
|
+
return variable;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
scope = scope.upper;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
return null;
|
|
1497
|
+
},
|
|
1498
|
+
|
|
1499
|
+
/**
|
|
1500
|
+
* Checks whether or not a given function node is the default `this` binding.
|
|
1501
|
+
*
|
|
1502
|
+
* First, this checks the node:
|
|
1503
|
+
*
|
|
1504
|
+
* - The given node is not in `PropertyDefinition#value` position.
|
|
1505
|
+
* - The given node is not `StaticBlock`.
|
|
1506
|
+
* - The function name does not start with uppercase. It's a convention to capitalize the names
|
|
1507
|
+
* of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
|
|
1508
|
+
* - The function does not have a JSDoc comment that has a @this tag.
|
|
1509
|
+
*
|
|
1510
|
+
* Next, this checks the location of the node.
|
|
1511
|
+
* If the location is below, this judges `this` is valid.
|
|
1512
|
+
*
|
|
1513
|
+
* - The location is not on an object literal.
|
|
1514
|
+
* - The location is not assigned to a variable which starts with an uppercase letter. Applies to anonymous
|
|
1515
|
+
* functions only, as the name of the variable is considered to be the name of the function in this case.
|
|
1516
|
+
* This check is not performed if `capIsConstructor` is set to `false`.
|
|
1517
|
+
* - The location is not on an ES2015 class.
|
|
1518
|
+
* - Its `bind`/`call`/`apply` method is not called directly.
|
|
1519
|
+
* - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
|
|
1520
|
+
* @param {ASTNode} node A function node to check. It also can be an implicit function, like `StaticBlock`
|
|
1521
|
+
* or any expression that is `PropertyDefinition#value` node.
|
|
1522
|
+
* @param {SourceCode} sourceCode A SourceCode instance to get comments.
|
|
1523
|
+
* @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
|
|
1524
|
+
* with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
|
|
1525
|
+
* @returns {boolean} The function node is the default `this` binding.
|
|
1526
|
+
*/
|
|
1527
|
+
isDefaultThisBinding(node, sourceCode, { capIsConstructor = true } = {}) {
|
|
1528
|
+
/*
|
|
1529
|
+
* Class field initializers are implicit functions, but ESTree doesn't have the AST node of field initializers.
|
|
1530
|
+
* Therefore, A expression node at `PropertyDefinition#value` is a function.
|
|
1531
|
+
* In this case, `this` is always not default binding.
|
|
1532
|
+
*/
|
|
1533
|
+
if (
|
|
1534
|
+
node.parent.type === "PropertyDefinition" &&
|
|
1535
|
+
node.parent.value === node
|
|
1536
|
+
) {
|
|
1537
|
+
return false;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
// Class static blocks are implicit functions. In this case, `this` is always not default binding.
|
|
1541
|
+
if (node.type === "StaticBlock") {
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// Check if the function has a parameter named `this`.
|
|
1546
|
+
if (
|
|
1547
|
+
(node.type === "FunctionDeclaration" ||
|
|
1548
|
+
node.type === "FunctionExpression") &&
|
|
1549
|
+
node.params.some(
|
|
1550
|
+
param => param.type === "Identifier" && param.name === "this",
|
|
1551
|
+
)
|
|
1552
|
+
) {
|
|
1553
|
+
return false;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
if (
|
|
1557
|
+
(capIsConstructor && isES5Constructor(node)) ||
|
|
1558
|
+
hasJSDocThisTag(node, sourceCode)
|
|
1559
|
+
) {
|
|
1560
|
+
return false;
|
|
1561
|
+
}
|
|
1562
|
+
const isAnonymous = node.id === null;
|
|
1563
|
+
let currentNode = node;
|
|
1564
|
+
|
|
1565
|
+
while (currentNode) {
|
|
1566
|
+
const parent = currentNode.parent;
|
|
1567
|
+
|
|
1568
|
+
switch (parent.type) {
|
|
1569
|
+
/*
|
|
1570
|
+
* Looks up the destination.
|
|
1571
|
+
* e.g., obj.foo = nativeFoo || function foo() { ... };
|
|
1572
|
+
*/
|
|
1573
|
+
case "LogicalExpression":
|
|
1574
|
+
case "ConditionalExpression":
|
|
1575
|
+
case "ChainExpression":
|
|
1576
|
+
currentNode = parent;
|
|
1577
|
+
break;
|
|
1578
|
+
|
|
1579
|
+
/*
|
|
1580
|
+
* If the upper function is IIFE, checks the destination of the return value.
|
|
1581
|
+
* e.g.
|
|
1582
|
+
* obj.foo = (function() {
|
|
1583
|
+
* // setup...
|
|
1584
|
+
* return function foo() { ... };
|
|
1585
|
+
* })();
|
|
1586
|
+
* obj.foo = (() =>
|
|
1587
|
+
* function foo() { ... }
|
|
1588
|
+
* )();
|
|
1589
|
+
*/
|
|
1590
|
+
case "ReturnStatement": {
|
|
1591
|
+
const func = getUpperFunction(parent);
|
|
1592
|
+
|
|
1593
|
+
if (func === null || !isCallee(func)) {
|
|
1594
|
+
return true;
|
|
1595
|
+
}
|
|
1596
|
+
currentNode = func.parent;
|
|
1597
|
+
break;
|
|
1598
|
+
}
|
|
1599
|
+
case "ArrowFunctionExpression":
|
|
1600
|
+
if (currentNode !== parent.body || !isCallee(parent)) {
|
|
1601
|
+
return true;
|
|
1602
|
+
}
|
|
1603
|
+
currentNode = parent.parent;
|
|
1604
|
+
break;
|
|
1605
|
+
|
|
1606
|
+
/*
|
|
1607
|
+
* e.g.
|
|
1608
|
+
* var obj = { foo() { ... } };
|
|
1609
|
+
* var obj = { foo: function() { ... } };
|
|
1610
|
+
* class A { constructor() { ... } }
|
|
1611
|
+
* class A { foo() { ... } }
|
|
1612
|
+
* class A { get foo() { ... } }
|
|
1613
|
+
* class A { set foo() { ... } }
|
|
1614
|
+
* class A { static foo() { ... } }
|
|
1615
|
+
* class A { foo = function() { ... } }
|
|
1616
|
+
*/
|
|
1617
|
+
case "Property":
|
|
1618
|
+
case "PropertyDefinition":
|
|
1619
|
+
case "MethodDefinition":
|
|
1620
|
+
return parent.value !== currentNode;
|
|
1621
|
+
|
|
1622
|
+
/*
|
|
1623
|
+
* e.g.
|
|
1624
|
+
* obj.foo = function foo() { ... };
|
|
1625
|
+
* Foo = function() { ... };
|
|
1626
|
+
* [obj.foo = function foo() { ... }] = a;
|
|
1627
|
+
* [Foo = function() { ... }] = a;
|
|
1628
|
+
*/
|
|
1629
|
+
case "AssignmentExpression":
|
|
1630
|
+
case "AssignmentPattern":
|
|
1631
|
+
if (parent.left.type === "MemberExpression") {
|
|
1632
|
+
return false;
|
|
1633
|
+
}
|
|
1634
|
+
if (
|
|
1635
|
+
capIsConstructor &&
|
|
1636
|
+
isAnonymous &&
|
|
1637
|
+
parent.left.type === "Identifier" &&
|
|
1638
|
+
startsWithUpperCase(parent.left.name)
|
|
1639
|
+
) {
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
return true;
|
|
1643
|
+
|
|
1644
|
+
/*
|
|
1645
|
+
* e.g.
|
|
1646
|
+
* var Foo = function() { ... };
|
|
1647
|
+
*/
|
|
1648
|
+
case "VariableDeclarator":
|
|
1649
|
+
return !(
|
|
1650
|
+
capIsConstructor &&
|
|
1651
|
+
isAnonymous &&
|
|
1652
|
+
parent.init === currentNode &&
|
|
1653
|
+
parent.id.type === "Identifier" &&
|
|
1654
|
+
startsWithUpperCase(parent.id.name)
|
|
1655
|
+
);
|
|
1656
|
+
|
|
1657
|
+
/*
|
|
1658
|
+
* e.g.
|
|
1659
|
+
* var foo = function foo() { ... }.bind(obj);
|
|
1660
|
+
* (function foo() { ... }).call(obj);
|
|
1661
|
+
* (function foo() { ... }).apply(obj, []);
|
|
1662
|
+
*/
|
|
1663
|
+
case "MemberExpression":
|
|
1664
|
+
if (
|
|
1665
|
+
parent.object === currentNode &&
|
|
1666
|
+
isSpecificMemberAccess(
|
|
1667
|
+
parent,
|
|
1668
|
+
null,
|
|
1669
|
+
bindOrCallOrApplyPattern,
|
|
1670
|
+
)
|
|
1671
|
+
) {
|
|
1672
|
+
const maybeCalleeNode =
|
|
1673
|
+
parent.parent.type === "ChainExpression"
|
|
1674
|
+
? parent.parent
|
|
1675
|
+
: parent;
|
|
1676
|
+
|
|
1677
|
+
return !(
|
|
1678
|
+
isCallee(maybeCalleeNode) &&
|
|
1679
|
+
maybeCalleeNode.parent.arguments.length >= 1 &&
|
|
1680
|
+
!isNullOrUndefined(
|
|
1681
|
+
maybeCalleeNode.parent.arguments[0],
|
|
1682
|
+
)
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
return true;
|
|
1686
|
+
|
|
1687
|
+
/*
|
|
1688
|
+
* e.g.
|
|
1689
|
+
* Reflect.apply(function() {}, obj, []);
|
|
1690
|
+
* Array.from([], function() {}, obj);
|
|
1691
|
+
* list.forEach(function() {}, obj);
|
|
1692
|
+
*/
|
|
1693
|
+
case "CallExpression":
|
|
1694
|
+
if (isReflectApply(parent.callee)) {
|
|
1695
|
+
return (
|
|
1696
|
+
parent.arguments.length !== 3 ||
|
|
1697
|
+
parent.arguments[0] !== currentNode ||
|
|
1698
|
+
isNullOrUndefined(parent.arguments[1])
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
if (isArrayFromMethod(parent.callee)) {
|
|
1702
|
+
return (
|
|
1703
|
+
parent.arguments.length !== 3 ||
|
|
1704
|
+
parent.arguments[1] !== currentNode ||
|
|
1705
|
+
isNullOrUndefined(parent.arguments[2])
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
if (isMethodWhichHasThisArg(parent.callee)) {
|
|
1709
|
+
return (
|
|
1710
|
+
parent.arguments.length !== 2 ||
|
|
1711
|
+
parent.arguments[0] !== currentNode ||
|
|
1712
|
+
isNullOrUndefined(parent.arguments[1])
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
return true;
|
|
1716
|
+
|
|
1717
|
+
// Otherwise `this` is default.
|
|
1718
|
+
default:
|
|
1719
|
+
return true;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/* c8 ignore next */
|
|
1724
|
+
return true;
|
|
1725
|
+
},
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* Get the precedence level based on the node type
|
|
1729
|
+
* @param {ASTNode} node node to evaluate
|
|
1730
|
+
* @returns {number} precedence level
|
|
1731
|
+
* @private
|
|
1732
|
+
*/
|
|
1733
|
+
getPrecedence(node) {
|
|
1734
|
+
switch (node.type) {
|
|
1735
|
+
case "SequenceExpression":
|
|
1736
|
+
return 0;
|
|
1737
|
+
|
|
1738
|
+
case "AssignmentExpression":
|
|
1739
|
+
case "ArrowFunctionExpression":
|
|
1740
|
+
case "YieldExpression":
|
|
1741
|
+
return 1;
|
|
1742
|
+
|
|
1743
|
+
case "ConditionalExpression":
|
|
1744
|
+
return 3;
|
|
1745
|
+
|
|
1746
|
+
case "LogicalExpression":
|
|
1747
|
+
switch (node.operator) {
|
|
1748
|
+
case "||":
|
|
1749
|
+
case "??":
|
|
1750
|
+
return 4;
|
|
1751
|
+
case "&&":
|
|
1752
|
+
return 5;
|
|
1753
|
+
|
|
1754
|
+
// no default
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
/* falls through */
|
|
1758
|
+
|
|
1759
|
+
case "BinaryExpression":
|
|
1760
|
+
switch (node.operator) {
|
|
1761
|
+
case "|":
|
|
1762
|
+
return 6;
|
|
1763
|
+
case "^":
|
|
1764
|
+
return 7;
|
|
1765
|
+
case "&":
|
|
1766
|
+
return 8;
|
|
1767
|
+
case "==":
|
|
1768
|
+
case "!=":
|
|
1769
|
+
case "===":
|
|
1770
|
+
case "!==":
|
|
1771
|
+
return 9;
|
|
1772
|
+
case "<":
|
|
1773
|
+
case "<=":
|
|
1774
|
+
case ">":
|
|
1775
|
+
case ">=":
|
|
1776
|
+
case "in":
|
|
1777
|
+
case "instanceof":
|
|
1778
|
+
return 10;
|
|
1779
|
+
case "<<":
|
|
1780
|
+
case ">>":
|
|
1781
|
+
case ">>>":
|
|
1782
|
+
return 11;
|
|
1783
|
+
case "+":
|
|
1784
|
+
case "-":
|
|
1785
|
+
return 12;
|
|
1786
|
+
case "*":
|
|
1787
|
+
case "/":
|
|
1788
|
+
case "%":
|
|
1789
|
+
return 13;
|
|
1790
|
+
case "**":
|
|
1791
|
+
return 15;
|
|
1792
|
+
|
|
1793
|
+
// no default
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
/* falls through */
|
|
1797
|
+
|
|
1798
|
+
case "UnaryExpression":
|
|
1799
|
+
case "AwaitExpression":
|
|
1800
|
+
return 16;
|
|
1801
|
+
|
|
1802
|
+
case "UpdateExpression":
|
|
1803
|
+
return 17;
|
|
1804
|
+
|
|
1805
|
+
case "CallExpression":
|
|
1806
|
+
case "ChainExpression":
|
|
1807
|
+
case "ImportExpression":
|
|
1808
|
+
return 18;
|
|
1809
|
+
|
|
1810
|
+
case "NewExpression":
|
|
1811
|
+
return 19;
|
|
1812
|
+
|
|
1813
|
+
default:
|
|
1814
|
+
if (node.type in eslintVisitorKeys) {
|
|
1815
|
+
return 20;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
/*
|
|
1819
|
+
* if the node is not a standard node that we know about, then assume it has the lowest precedence
|
|
1820
|
+
* this will mean that rules will wrap unknown nodes in parentheses where applicable instead of
|
|
1821
|
+
* unwrapping them and potentially changing the meaning of the code or introducing a syntax error.
|
|
1822
|
+
*/
|
|
1823
|
+
return -1;
|
|
1824
|
+
}
|
|
1825
|
+
},
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Checks whether the given node is an empty block node or not.
|
|
1829
|
+
* @param {ASTNode|null} node The node to check.
|
|
1830
|
+
* @returns {boolean} `true` if the node is an empty block.
|
|
1831
|
+
*/
|
|
1832
|
+
isEmptyBlock(node) {
|
|
1833
|
+
return Boolean(
|
|
1834
|
+
node && node.type === "BlockStatement" && node.body.length === 0,
|
|
1835
|
+
);
|
|
1836
|
+
},
|
|
1837
|
+
|
|
1838
|
+
/**
|
|
1839
|
+
* Checks whether the given node is an empty function node or not.
|
|
1840
|
+
* @param {ASTNode|null} node The node to check.
|
|
1841
|
+
* @returns {boolean} `true` if the node is an empty function.
|
|
1842
|
+
*/
|
|
1843
|
+
isEmptyFunction(node) {
|
|
1844
|
+
return isFunction(node) && module.exports.isEmptyBlock(node.body);
|
|
1845
|
+
},
|
|
1846
|
+
|
|
1847
|
+
/**
|
|
1848
|
+
* Get directives from directive prologue of a Program or Function node.
|
|
1849
|
+
* @param {ASTNode} node The node to check.
|
|
1850
|
+
* @returns {ASTNode[]} The directives found in the directive prologue.
|
|
1851
|
+
*/
|
|
1852
|
+
getDirectivePrologue(node) {
|
|
1853
|
+
const directives = [];
|
|
1854
|
+
|
|
1855
|
+
// Directive prologues only occur at the top of files or functions.
|
|
1856
|
+
if (
|
|
1857
|
+
node.type === "Program" ||
|
|
1858
|
+
node.type === "FunctionDeclaration" ||
|
|
1859
|
+
node.type === "FunctionExpression" ||
|
|
1860
|
+
/*
|
|
1861
|
+
* Do not check arrow functions with implicit return.
|
|
1862
|
+
* `() => "use strict";` returns the string `"use strict"`.
|
|
1863
|
+
*/
|
|
1864
|
+
(node.type === "ArrowFunctionExpression" &&
|
|
1865
|
+
node.body.type === "BlockStatement")
|
|
1866
|
+
) {
|
|
1867
|
+
const statements =
|
|
1868
|
+
node.type === "Program" ? node.body : node.body.body;
|
|
1869
|
+
|
|
1870
|
+
for (const statement of statements) {
|
|
1871
|
+
if (
|
|
1872
|
+
statement.type === "ExpressionStatement" &&
|
|
1873
|
+
statement.expression.type === "Literal"
|
|
1874
|
+
) {
|
|
1875
|
+
directives.push(statement);
|
|
1876
|
+
} else {
|
|
1877
|
+
break;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
return directives;
|
|
1883
|
+
},
|
|
1884
|
+
|
|
1885
|
+
/**
|
|
1886
|
+
* Determines whether this node is a decimal integer literal. If a node is a decimal integer literal, a dot added
|
|
1887
|
+
* after the node will be parsed as a decimal point, rather than a property-access dot.
|
|
1888
|
+
* @param {ASTNode} node The node to check.
|
|
1889
|
+
* @returns {boolean} `true` if this node is a decimal integer.
|
|
1890
|
+
* @example
|
|
1891
|
+
*
|
|
1892
|
+
* 0 // true
|
|
1893
|
+
* 5 // true
|
|
1894
|
+
* 50 // true
|
|
1895
|
+
* 5_000 // true
|
|
1896
|
+
* 1_234_56 // true
|
|
1897
|
+
* 08 // true
|
|
1898
|
+
* 0192 // true
|
|
1899
|
+
* 5. // false
|
|
1900
|
+
* .5 // false
|
|
1901
|
+
* 5.0 // false
|
|
1902
|
+
* 5.00_00 // false
|
|
1903
|
+
* 05 // false
|
|
1904
|
+
* 0x5 // false
|
|
1905
|
+
* 0b101 // false
|
|
1906
|
+
* 0b11_01 // false
|
|
1907
|
+
* 0o5 // false
|
|
1908
|
+
* 5e0 // false
|
|
1909
|
+
* 5e1_000 // false
|
|
1910
|
+
* 5n // false
|
|
1911
|
+
* 1_000n // false
|
|
1912
|
+
* "5" // false
|
|
1913
|
+
*
|
|
1914
|
+
*/
|
|
1915
|
+
isDecimalInteger(node) {
|
|
1916
|
+
return (
|
|
1917
|
+
node.type === "Literal" &&
|
|
1918
|
+
typeof node.value === "number" &&
|
|
1919
|
+
DECIMAL_INTEGER_PATTERN.test(node.raw)
|
|
1920
|
+
);
|
|
1921
|
+
},
|
|
1922
|
+
|
|
1923
|
+
/**
|
|
1924
|
+
* Determines whether this token is a decimal integer numeric token.
|
|
1925
|
+
* This is similar to isDecimalInteger(), but for tokens.
|
|
1926
|
+
* @param {Token} token The token to check.
|
|
1927
|
+
* @returns {boolean} `true` if this token is a decimal integer.
|
|
1928
|
+
*/
|
|
1929
|
+
isDecimalIntegerNumericToken(token) {
|
|
1930
|
+
return (
|
|
1931
|
+
token.type === "Numeric" &&
|
|
1932
|
+
DECIMAL_INTEGER_PATTERN.test(token.value)
|
|
1933
|
+
);
|
|
1934
|
+
},
|
|
1935
|
+
|
|
1936
|
+
/**
|
|
1937
|
+
* Gets the name and kind of the given function node.
|
|
1938
|
+
*
|
|
1939
|
+
* - `function foo() {}` .................... `function 'foo'`
|
|
1940
|
+
* - `(function foo() {})` .................. `function 'foo'`
|
|
1941
|
+
* - `(function() {})` ...................... `function`
|
|
1942
|
+
* - `function* foo() {}` ................... `generator function 'foo'`
|
|
1943
|
+
* - `(function* foo() {})` ................. `generator function 'foo'`
|
|
1944
|
+
* - `(function*() {})` ..................... `generator function`
|
|
1945
|
+
* - `() => {}` ............................. `arrow function`
|
|
1946
|
+
* - `async () => {}` ....................... `async arrow function`
|
|
1947
|
+
* - `({ foo: function foo() {} })` ......... `method 'foo'`
|
|
1948
|
+
* - `({ foo: function() {} })` ............. `method 'foo'`
|
|
1949
|
+
* - `({ ['foo']: function() {} })` ......... `method 'foo'`
|
|
1950
|
+
* - `({ [foo]: function() {} })` ........... `method`
|
|
1951
|
+
* - `({ foo() {} })` ....................... `method 'foo'`
|
|
1952
|
+
* - `({ foo: function* foo() {} })` ........ `generator method 'foo'`
|
|
1953
|
+
* - `({ foo: function*() {} })` ............ `generator method 'foo'`
|
|
1954
|
+
* - `({ ['foo']: function*() {} })` ........ `generator method 'foo'`
|
|
1955
|
+
* - `({ [foo]: function*() {} })` .......... `generator method`
|
|
1956
|
+
* - `({ *foo() {} })` ...................... `generator method 'foo'`
|
|
1957
|
+
* - `({ foo: async function foo() {} })` ... `async method 'foo'`
|
|
1958
|
+
* - `({ foo: async function() {} })` ....... `async method 'foo'`
|
|
1959
|
+
* - `({ ['foo']: async function() {} })` ... `async method 'foo'`
|
|
1960
|
+
* - `({ [foo]: async function() {} })` ..... `async method`
|
|
1961
|
+
* - `({ async foo() {} })` ................. `async method 'foo'`
|
|
1962
|
+
* - `({ get foo() {} })` ................... `getter 'foo'`
|
|
1963
|
+
* - `({ set foo(a) {} })` .................. `setter 'foo'`
|
|
1964
|
+
* - `class A { constructor() {} }` ......... `constructor`
|
|
1965
|
+
* - `class A { foo() {} }` ................. `method 'foo'`
|
|
1966
|
+
* - `class A { *foo() {} }` ................ `generator method 'foo'`
|
|
1967
|
+
* - `class A { async foo() {} }` ........... `async method 'foo'`
|
|
1968
|
+
* - `class A { ['foo']() {} }` ............. `method 'foo'`
|
|
1969
|
+
* - `class A { *['foo']() {} }` ............ `generator method 'foo'`
|
|
1970
|
+
* - `class A { async ['foo']() {} }` ....... `async method 'foo'`
|
|
1971
|
+
* - `class A { [foo]() {} }` ............... `method`
|
|
1972
|
+
* - `class A { *[foo]() {} }` .............. `generator method`
|
|
1973
|
+
* - `class A { async [foo]() {} }` ......... `async method`
|
|
1974
|
+
* - `class A { get foo() {} }` ............. `getter 'foo'`
|
|
1975
|
+
* - `class A { set foo(a) {} }` ............ `setter 'foo'`
|
|
1976
|
+
* - `class A { static foo() {} }` .......... `static method 'foo'`
|
|
1977
|
+
* - `class A { static *foo() {} }` ......... `static generator method 'foo'`
|
|
1978
|
+
* - `class A { static async foo() {} }` .... `static async method 'foo'`
|
|
1979
|
+
* - `class A { static get foo() {} }` ...... `static getter 'foo'`
|
|
1980
|
+
* - `class A { static set foo(a) {} }` ..... `static setter 'foo'`
|
|
1981
|
+
* - `class A { foo = () => {}; }` .......... `method 'foo'`
|
|
1982
|
+
* - `class A { foo = function() {}; }` ..... `method 'foo'`
|
|
1983
|
+
* - `class A { foo = function bar() {}; }` . `method 'foo'`
|
|
1984
|
+
* - `class A { static foo = () => {}; }` ... `static method 'foo'`
|
|
1985
|
+
* - `class A { '#foo' = () => {}; }` ....... `method '#foo'`
|
|
1986
|
+
* - `class A { #foo = () => {}; }` ......... `private method #foo`
|
|
1987
|
+
* - `class A { static #foo = () => {}; }` .. `static private method #foo`
|
|
1988
|
+
* - `class A { '#foo'() {} }` .............. `method '#foo'`
|
|
1989
|
+
* - `class A { #foo() {} }` ................ `private method #foo`
|
|
1990
|
+
* - `class A { static #foo() {} }` ......... `static private method #foo`
|
|
1991
|
+
* @param {ASTNode} node The function node to get.
|
|
1992
|
+
* @returns {string} The name and kind of the function node.
|
|
1993
|
+
*/
|
|
1994
|
+
getFunctionNameWithKind(node) {
|
|
1995
|
+
const parent = node.parent;
|
|
1996
|
+
const tokens = [];
|
|
1997
|
+
|
|
1998
|
+
if (
|
|
1999
|
+
parent.type === "MethodDefinition" ||
|
|
2000
|
+
parent.type === "PropertyDefinition" ||
|
|
2001
|
+
node.type === "TSPropertySignature" ||
|
|
2002
|
+
node.type === "TSMethodSignature"
|
|
2003
|
+
) {
|
|
2004
|
+
// The proposal uses `static` word consistently before visibility words: https://github.com/tc39/proposal-static-class-features
|
|
2005
|
+
if (parent.static) {
|
|
2006
|
+
tokens.push("static");
|
|
2007
|
+
}
|
|
2008
|
+
if (!parent.computed && parent.key?.type === "PrivateIdentifier") {
|
|
2009
|
+
tokens.push("private");
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
if (node.async) {
|
|
2013
|
+
tokens.push("async");
|
|
2014
|
+
}
|
|
2015
|
+
if (node.generator) {
|
|
2016
|
+
tokens.push("generator");
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
if (parent.type === "Property" || parent.type === "MethodDefinition") {
|
|
2020
|
+
if (parent.kind === "constructor") {
|
|
2021
|
+
return "constructor";
|
|
2022
|
+
}
|
|
2023
|
+
if (parent.kind === "get") {
|
|
2024
|
+
tokens.push("getter");
|
|
2025
|
+
} else if (parent.kind === "set") {
|
|
2026
|
+
tokens.push("setter");
|
|
2027
|
+
} else {
|
|
2028
|
+
tokens.push("method");
|
|
2029
|
+
}
|
|
2030
|
+
} else if (node.type === "TSMethodSignature") {
|
|
2031
|
+
if (node.kind === "get") {
|
|
2032
|
+
tokens.push("getter");
|
|
2033
|
+
} else if (node.kind === "set") {
|
|
2034
|
+
tokens.push("setter");
|
|
2035
|
+
} else {
|
|
2036
|
+
tokens.push("method");
|
|
2037
|
+
}
|
|
2038
|
+
} else if (parent.type === "PropertyDefinition") {
|
|
2039
|
+
tokens.push("method");
|
|
2040
|
+
} else {
|
|
2041
|
+
if (node.type === "ArrowFunctionExpression") {
|
|
2042
|
+
tokens.push("arrow");
|
|
2043
|
+
}
|
|
2044
|
+
tokens.push("function");
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
if (
|
|
2048
|
+
parent.type === "Property" ||
|
|
2049
|
+
parent.type === "MethodDefinition" ||
|
|
2050
|
+
parent.type === "PropertyDefinition"
|
|
2051
|
+
) {
|
|
2052
|
+
if (!parent.computed && parent.key.type === "PrivateIdentifier") {
|
|
2053
|
+
tokens.push(`#${parent.key.name}`);
|
|
2054
|
+
} else {
|
|
2055
|
+
const name = getStaticPropertyName(parent);
|
|
2056
|
+
|
|
2057
|
+
if (name !== null) {
|
|
2058
|
+
tokens.push(`'${name}'`);
|
|
2059
|
+
} else if (node.id) {
|
|
2060
|
+
tokens.push(`'${node.id.name}'`);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
} else if (node.type === "TSMethodSignature") {
|
|
2064
|
+
tokens.push(`'${getStaticPropertyName(node)}'`);
|
|
2065
|
+
} else if (node.id) {
|
|
2066
|
+
tokens.push(`'${node.id.name}'`);
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
return tokens.join(" ");
|
|
2070
|
+
},
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Gets the location of the given function node for reporting.
|
|
2074
|
+
*
|
|
2075
|
+
* - `function foo() {}`
|
|
2076
|
+
* ^^^^^^^^^^^^
|
|
2077
|
+
* - `(function foo() {})`
|
|
2078
|
+
* ^^^^^^^^^^^^
|
|
2079
|
+
* - `(function() {})`
|
|
2080
|
+
* ^^^^^^^^
|
|
2081
|
+
* - `function* foo() {}`
|
|
2082
|
+
* ^^^^^^^^^^^^^
|
|
2083
|
+
* - `(function* foo() {})`
|
|
2084
|
+
* ^^^^^^^^^^^^^
|
|
2085
|
+
* - `(function*() {})`
|
|
2086
|
+
* ^^^^^^^^^
|
|
2087
|
+
* - `() => {}`
|
|
2088
|
+
* ^^
|
|
2089
|
+
* - `async () => {}`
|
|
2090
|
+
* ^^
|
|
2091
|
+
* - `({ foo: function foo() {} })`
|
|
2092
|
+
* ^^^^^^^^^^^^^^^^^
|
|
2093
|
+
* - `({ foo: function() {} })`
|
|
2094
|
+
* ^^^^^^^^^^^^^
|
|
2095
|
+
* - `({ ['foo']: function() {} })`
|
|
2096
|
+
* ^^^^^^^^^^^^^^^^^
|
|
2097
|
+
* - `({ [foo]: function() {} })`
|
|
2098
|
+
* ^^^^^^^^^^^^^^^
|
|
2099
|
+
* - `({ foo() {} })`
|
|
2100
|
+
* ^^^
|
|
2101
|
+
* - `({ foo: function* foo() {} })`
|
|
2102
|
+
* ^^^^^^^^^^^^^^^^^^
|
|
2103
|
+
* - `({ foo: function*() {} })`
|
|
2104
|
+
* ^^^^^^^^^^^^^^
|
|
2105
|
+
* - `({ ['foo']: function*() {} })`
|
|
2106
|
+
* ^^^^^^^^^^^^^^^^^^
|
|
2107
|
+
* - `({ [foo]: function*() {} })`
|
|
2108
|
+
* ^^^^^^^^^^^^^^^^
|
|
2109
|
+
* - `({ *foo() {} })`
|
|
2110
|
+
* ^^^^
|
|
2111
|
+
* - `({ foo: async function foo() {} })`
|
|
2112
|
+
* ^^^^^^^^^^^^^^^^^^^^^^^
|
|
2113
|
+
* - `({ foo: async function() {} })`
|
|
2114
|
+
* ^^^^^^^^^^^^^^^^^^^
|
|
2115
|
+
* - `({ ['foo']: async function() {} })`
|
|
2116
|
+
* ^^^^^^^^^^^^^^^^^^^^^^^
|
|
2117
|
+
* - `({ [foo]: async function() {} })`
|
|
2118
|
+
* ^^^^^^^^^^^^^^^^^^^^^
|
|
2119
|
+
* - `({ async foo() {} })`
|
|
2120
|
+
* ^^^^^^^^^
|
|
2121
|
+
* - `({ get foo() {} })`
|
|
2122
|
+
* ^^^^^^^
|
|
2123
|
+
* - `({ set foo(a) {} })`
|
|
2124
|
+
* ^^^^^^^
|
|
2125
|
+
* - `class A { constructor() {} }`
|
|
2126
|
+
* ^^^^^^^^^^^
|
|
2127
|
+
* - `class A { foo() {} }`
|
|
2128
|
+
* ^^^
|
|
2129
|
+
* - `class A { *foo() {} }`
|
|
2130
|
+
* ^^^^
|
|
2131
|
+
* - `class A { async foo() {} }`
|
|
2132
|
+
* ^^^^^^^^^
|
|
2133
|
+
* - `class A { ['foo']() {} }`
|
|
2134
|
+
* ^^^^^^^
|
|
2135
|
+
* - `class A { *['foo']() {} }`
|
|
2136
|
+
* ^^^^^^^^
|
|
2137
|
+
* - `class A { async ['foo']() {} }`
|
|
2138
|
+
* ^^^^^^^^^^^^^
|
|
2139
|
+
* - `class A { [foo]() {} }`
|
|
2140
|
+
* ^^^^^
|
|
2141
|
+
* - `class A { *[foo]() {} }`
|
|
2142
|
+
* ^^^^^^
|
|
2143
|
+
* - `class A { async [foo]() {} }`
|
|
2144
|
+
* ^^^^^^^^^^^
|
|
2145
|
+
* - `class A { get foo() {} }`
|
|
2146
|
+
* ^^^^^^^
|
|
2147
|
+
* - `class A { set foo(a) {} }`
|
|
2148
|
+
* ^^^^^^^
|
|
2149
|
+
* - `class A { static foo() {} }`
|
|
2150
|
+
* ^^^^^^^^^^
|
|
2151
|
+
* - `class A { static *foo() {} }`
|
|
2152
|
+
* ^^^^^^^^^^^
|
|
2153
|
+
* - `class A { static async foo() {} }`
|
|
2154
|
+
* ^^^^^^^^^^^^^^^^
|
|
2155
|
+
* - `class A { static get foo() {} }`
|
|
2156
|
+
* ^^^^^^^^^^^^^^
|
|
2157
|
+
* - `class A { static set foo(a) {} }`
|
|
2158
|
+
* ^^^^^^^^^^^^^^
|
|
2159
|
+
* - `class A { foo = function() {} }`
|
|
2160
|
+
* ^^^^^^^^^^^^^^
|
|
2161
|
+
* - `class A { static foo = function() {} }`
|
|
2162
|
+
* ^^^^^^^^^^^^^^^^^^^^^
|
|
2163
|
+
* - `class A { foo = (a, b) => {} }`
|
|
2164
|
+
* ^^^^^^
|
|
2165
|
+
* @param {ASTNode} node The function node to get.
|
|
2166
|
+
* @param {SourceCode} sourceCode The source code object to get tokens.
|
|
2167
|
+
* @returns {string} The location of the function node for reporting.
|
|
2168
|
+
*/
|
|
2169
|
+
getFunctionHeadLoc(node, sourceCode) {
|
|
2170
|
+
const parent = node.parent;
|
|
2171
|
+
let start;
|
|
2172
|
+
let end;
|
|
2173
|
+
|
|
2174
|
+
if (
|
|
2175
|
+
parent.type === "Property" ||
|
|
2176
|
+
parent.type === "MethodDefinition" ||
|
|
2177
|
+
parent.type === "PropertyDefinition" ||
|
|
2178
|
+
parent.type === "TSPropertySignature" ||
|
|
2179
|
+
parent.type === "TSMethodSignature"
|
|
2180
|
+
) {
|
|
2181
|
+
start = parent.loc.start;
|
|
2182
|
+
end = getOpeningParenOfParams(node, sourceCode).loc.start;
|
|
2183
|
+
} else if (node.type === "ArrowFunctionExpression") {
|
|
2184
|
+
const arrowToken = sourceCode.getTokenBefore(
|
|
2185
|
+
node.body,
|
|
2186
|
+
isArrowToken,
|
|
2187
|
+
);
|
|
2188
|
+
|
|
2189
|
+
start = arrowToken.loc.start;
|
|
2190
|
+
end = arrowToken.loc.end;
|
|
2191
|
+
} else {
|
|
2192
|
+
start = node.loc.start;
|
|
2193
|
+
end = getOpeningParenOfParams(node, sourceCode).loc.start;
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
return {
|
|
2197
|
+
start: Object.assign({}, start),
|
|
2198
|
+
end: Object.assign({}, end),
|
|
2199
|
+
};
|
|
2200
|
+
},
|
|
2201
|
+
|
|
2202
|
+
/**
|
|
2203
|
+
* Gets next location when the result is not out of bound, otherwise returns null.
|
|
2204
|
+
*
|
|
2205
|
+
* Assumptions:
|
|
2206
|
+
*
|
|
2207
|
+
* - The given location represents a valid location in the given source code.
|
|
2208
|
+
* - Columns are 0-based.
|
|
2209
|
+
* - Lines are 1-based.
|
|
2210
|
+
* - Column immediately after the last character in a line (not incl. linebreaks) is considered to be a valid location.
|
|
2211
|
+
* - If the source code ends with a linebreak, `sourceCode.lines` array will have an extra element (empty string) at the end.
|
|
2212
|
+
* The start (column 0) of that extra line is considered to be a valid location.
|
|
2213
|
+
*
|
|
2214
|
+
* Examples of successive locations (line, column):
|
|
2215
|
+
*
|
|
2216
|
+
* code: foo
|
|
2217
|
+
* locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> null
|
|
2218
|
+
*
|
|
2219
|
+
* code: foo<LF>
|
|
2220
|
+
* locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
|
|
2221
|
+
*
|
|
2222
|
+
* code: foo<CR><LF>
|
|
2223
|
+
* locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
|
|
2224
|
+
*
|
|
2225
|
+
* code: a<LF>b
|
|
2226
|
+
* locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> null
|
|
2227
|
+
*
|
|
2228
|
+
* code: a<LF>b<LF>
|
|
2229
|
+
* locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
|
|
2230
|
+
*
|
|
2231
|
+
* code: a<CR><LF>b<CR><LF>
|
|
2232
|
+
* locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
|
|
2233
|
+
*
|
|
2234
|
+
* code: a<LF><LF>
|
|
2235
|
+
* locations: (1, 0) -> (1, 1) -> (2, 0) -> (3, 0) -> null
|
|
2236
|
+
*
|
|
2237
|
+
* code: <LF>
|
|
2238
|
+
* locations: (1, 0) -> (2, 0) -> null
|
|
2239
|
+
*
|
|
2240
|
+
* code:
|
|
2241
|
+
* locations: (1, 0) -> null
|
|
2242
|
+
* @param {SourceCode} sourceCode The sourceCode
|
|
2243
|
+
* @param {{line: number, column: number}} location The location
|
|
2244
|
+
* @returns {{line: number, column: number} | null} Next location
|
|
2245
|
+
*/
|
|
2246
|
+
getNextLocation(sourceCode, { line, column }) {
|
|
2247
|
+
if (column < sourceCode.lines[line - 1].length) {
|
|
2248
|
+
return {
|
|
2249
|
+
line,
|
|
2250
|
+
column: column + 1,
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
if (line < sourceCode.lines.length) {
|
|
2255
|
+
return {
|
|
2256
|
+
line: line + 1,
|
|
2257
|
+
column: 0,
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
return null;
|
|
2262
|
+
},
|
|
2263
|
+
|
|
2264
|
+
/**
|
|
2265
|
+
* Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
|
|
2266
|
+
* surrounding the node.
|
|
2267
|
+
* @param {SourceCode} sourceCode The source code object
|
|
2268
|
+
* @param {ASTNode} node An expression node
|
|
2269
|
+
* @returns {string} The text representing the node, with all surrounding parentheses included
|
|
2270
|
+
*/
|
|
2271
|
+
getParenthesisedText(sourceCode, node) {
|
|
2272
|
+
let leftToken = sourceCode.getFirstToken(node);
|
|
2273
|
+
let rightToken = sourceCode.getLastToken(node);
|
|
2274
|
+
|
|
2275
|
+
while (
|
|
2276
|
+
sourceCode.getTokenBefore(leftToken) &&
|
|
2277
|
+
sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
|
|
2278
|
+
sourceCode.getTokenBefore(leftToken).value === "(" &&
|
|
2279
|
+
sourceCode.getTokenAfter(rightToken) &&
|
|
2280
|
+
sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
|
|
2281
|
+
sourceCode.getTokenAfter(rightToken).value === ")"
|
|
2282
|
+
) {
|
|
2283
|
+
leftToken = sourceCode.getTokenBefore(leftToken);
|
|
2284
|
+
rightToken = sourceCode.getTokenAfter(rightToken);
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
return sourceCode
|
|
2288
|
+
.getText()
|
|
2289
|
+
.slice(leftToken.range[0], rightToken.range[1]);
|
|
2290
|
+
},
|
|
2291
|
+
|
|
2292
|
+
/**
|
|
2293
|
+
* Determine if a node has a possibility to be an Error object
|
|
2294
|
+
* @param {ASTNode} node ASTNode to check
|
|
2295
|
+
* @returns {boolean} True if there is a chance it contains an Error obj
|
|
2296
|
+
*/
|
|
2297
|
+
couldBeError(node) {
|
|
2298
|
+
switch (node.type) {
|
|
2299
|
+
case "Identifier":
|
|
2300
|
+
case "CallExpression":
|
|
2301
|
+
case "NewExpression":
|
|
2302
|
+
case "MemberExpression":
|
|
2303
|
+
case "TaggedTemplateExpression":
|
|
2304
|
+
case "YieldExpression":
|
|
2305
|
+
case "AwaitExpression":
|
|
2306
|
+
case "ChainExpression":
|
|
2307
|
+
return true; // possibly an error object.
|
|
2308
|
+
|
|
2309
|
+
case "AssignmentExpression":
|
|
2310
|
+
if (["=", "&&="].includes(node.operator)) {
|
|
2311
|
+
return module.exports.couldBeError(node.right);
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
if (["||=", "??="].includes(node.operator)) {
|
|
2315
|
+
return (
|
|
2316
|
+
module.exports.couldBeError(node.left) ||
|
|
2317
|
+
module.exports.couldBeError(node.right)
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
/**
|
|
2322
|
+
* All other assignment operators are mathematical assignment operators (arithmetic or bitwise).
|
|
2323
|
+
* An assignment expression with a mathematical operator can either evaluate to a primitive value,
|
|
2324
|
+
* or throw, depending on the operands. Thus, it cannot evaluate to an `Error` object.
|
|
2325
|
+
*/
|
|
2326
|
+
return false;
|
|
2327
|
+
|
|
2328
|
+
case "SequenceExpression": {
|
|
2329
|
+
const exprs = node.expressions;
|
|
2330
|
+
|
|
2331
|
+
return (
|
|
2332
|
+
exprs.length !== 0 &&
|
|
2333
|
+
module.exports.couldBeError(exprs.at(-1))
|
|
2334
|
+
);
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
case "LogicalExpression":
|
|
2338
|
+
/*
|
|
2339
|
+
* If the && operator short-circuits, the left side was falsy and therefore not an error, and if it
|
|
2340
|
+
* doesn't short-circuit, it takes the value from the right side, so the right side must always be
|
|
2341
|
+
* a plausible error. A future improvement could verify that the left side could be truthy by
|
|
2342
|
+
* excluding falsy literals.
|
|
2343
|
+
*/
|
|
2344
|
+
if (node.operator === "&&") {
|
|
2345
|
+
return module.exports.couldBeError(node.right);
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
return (
|
|
2349
|
+
module.exports.couldBeError(node.left) ||
|
|
2350
|
+
module.exports.couldBeError(node.right)
|
|
2351
|
+
);
|
|
2352
|
+
|
|
2353
|
+
case "ConditionalExpression":
|
|
2354
|
+
return (
|
|
2355
|
+
module.exports.couldBeError(node.consequent) ||
|
|
2356
|
+
module.exports.couldBeError(node.alternate)
|
|
2357
|
+
);
|
|
2358
|
+
|
|
2359
|
+
default:
|
|
2360
|
+
return false;
|
|
2361
|
+
}
|
|
2362
|
+
},
|
|
2363
|
+
|
|
2364
|
+
/**
|
|
2365
|
+
* Check if a given node is a numeric literal or not.
|
|
2366
|
+
* @param {ASTNode} node The node to check.
|
|
2367
|
+
* @returns {boolean} `true` if the node is a number or bigint literal.
|
|
2368
|
+
*/
|
|
2369
|
+
isNumericLiteral(node) {
|
|
2370
|
+
return (
|
|
2371
|
+
node.type === "Literal" &&
|
|
2372
|
+
(typeof node.value === "number" || Boolean(node.bigint))
|
|
2373
|
+
);
|
|
2374
|
+
},
|
|
2375
|
+
|
|
2376
|
+
/**
|
|
2377
|
+
* Determines whether two tokens can safely be placed next to each other without merging into a single token
|
|
2378
|
+
* @param {Token|string} leftValue The left token. If this is a string, it will be tokenized and the last token will be used.
|
|
2379
|
+
* @param {Token|string} rightValue The right token. If this is a string, it will be tokenized and the first token will be used.
|
|
2380
|
+
* @returns {boolean} If the tokens cannot be safely placed next to each other, returns `false`. If the tokens can be placed
|
|
2381
|
+
* next to each other, behavior is undefined (although it should return `true` in most cases).
|
|
2382
|
+
*/
|
|
2383
|
+
canTokensBeAdjacent(leftValue, rightValue) {
|
|
2384
|
+
const espreeOptions = {
|
|
2385
|
+
ecmaVersion: espree.latestEcmaVersion,
|
|
2386
|
+
comment: true,
|
|
2387
|
+
range: true,
|
|
2388
|
+
};
|
|
2389
|
+
|
|
2390
|
+
let leftToken;
|
|
2391
|
+
|
|
2392
|
+
if (typeof leftValue === "string") {
|
|
2393
|
+
let tokens;
|
|
2394
|
+
|
|
2395
|
+
try {
|
|
2396
|
+
tokens = espree.tokenize(leftValue, espreeOptions);
|
|
2397
|
+
} catch {
|
|
2398
|
+
return false;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
const comments = tokens.comments;
|
|
2402
|
+
|
|
2403
|
+
leftToken = tokens.at(-1);
|
|
2404
|
+
if (comments.length) {
|
|
2405
|
+
const lastComment = comments.at(-1);
|
|
2406
|
+
|
|
2407
|
+
if (!leftToken || lastComment.range[0] > leftToken.range[0]) {
|
|
2408
|
+
leftToken = lastComment;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
} else {
|
|
2412
|
+
leftToken = leftValue;
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
/*
|
|
2416
|
+
* If a hashbang comment was passed as a token object from SourceCode,
|
|
2417
|
+
* its type will be "Shebang" because of the way ESLint itself handles hashbangs.
|
|
2418
|
+
* If a hashbang comment was passed in a string and then tokenized in this function,
|
|
2419
|
+
* its type will be "Hashbang" because of the way Espree tokenizes hashbangs.
|
|
2420
|
+
*/
|
|
2421
|
+
if (leftToken.type === "Shebang" || leftToken.type === "Hashbang") {
|
|
2422
|
+
return false;
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
let rightToken;
|
|
2426
|
+
|
|
2427
|
+
if (typeof rightValue === "string") {
|
|
2428
|
+
let tokens;
|
|
2429
|
+
|
|
2430
|
+
try {
|
|
2431
|
+
tokens = espree.tokenize(rightValue, espreeOptions);
|
|
2432
|
+
} catch {
|
|
2433
|
+
return false;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
const comments = tokens.comments;
|
|
2437
|
+
|
|
2438
|
+
rightToken = tokens[0];
|
|
2439
|
+
if (comments.length) {
|
|
2440
|
+
const firstComment = comments[0];
|
|
2441
|
+
|
|
2442
|
+
if (
|
|
2443
|
+
!rightToken ||
|
|
2444
|
+
firstComment.range[0] < rightToken.range[0]
|
|
2445
|
+
) {
|
|
2446
|
+
rightToken = firstComment;
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
} else {
|
|
2450
|
+
rightToken = rightValue;
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
if (
|
|
2454
|
+
leftToken.type === "Punctuator" ||
|
|
2455
|
+
rightToken.type === "Punctuator"
|
|
2456
|
+
) {
|
|
2457
|
+
if (
|
|
2458
|
+
leftToken.type === "Punctuator" &&
|
|
2459
|
+
rightToken.type === "Punctuator"
|
|
2460
|
+
) {
|
|
2461
|
+
const PLUS_TOKENS = new Set(["+", "++"]);
|
|
2462
|
+
const MINUS_TOKENS = new Set(["-", "--"]);
|
|
2463
|
+
|
|
2464
|
+
return !(
|
|
2465
|
+
(PLUS_TOKENS.has(leftToken.value) &&
|
|
2466
|
+
PLUS_TOKENS.has(rightToken.value)) ||
|
|
2467
|
+
(MINUS_TOKENS.has(leftToken.value) &&
|
|
2468
|
+
MINUS_TOKENS.has(rightToken.value))
|
|
2469
|
+
);
|
|
2470
|
+
}
|
|
2471
|
+
if (leftToken.type === "Punctuator" && leftToken.value === "/") {
|
|
2472
|
+
return !["Block", "Line", "RegularExpression"].includes(
|
|
2473
|
+
rightToken.type,
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2476
|
+
return true;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
if (
|
|
2480
|
+
leftToken.type === "String" ||
|
|
2481
|
+
rightToken.type === "String" ||
|
|
2482
|
+
leftToken.type === "Template" ||
|
|
2483
|
+
rightToken.type === "Template"
|
|
2484
|
+
) {
|
|
2485
|
+
return true;
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
if (
|
|
2489
|
+
leftToken.type !== "Numeric" &&
|
|
2490
|
+
rightToken.type === "Numeric" &&
|
|
2491
|
+
rightToken.value.startsWith(".")
|
|
2492
|
+
) {
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
if (
|
|
2497
|
+
leftToken.type === "Block" ||
|
|
2498
|
+
rightToken.type === "Block" ||
|
|
2499
|
+
rightToken.type === "Line"
|
|
2500
|
+
) {
|
|
2501
|
+
return true;
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
if (rightToken.type === "PrivateIdentifier") {
|
|
2505
|
+
return true;
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
return false;
|
|
2509
|
+
},
|
|
2510
|
+
|
|
2511
|
+
/**
|
|
2512
|
+
* Get the `loc` object of a given name in a `/*globals` directive comment.
|
|
2513
|
+
* @param {SourceCode} sourceCode The source code to convert index to loc.
|
|
2514
|
+
* @param {Comment} comment The `/*globals` directive comment which include the name.
|
|
2515
|
+
* @param {string} name The name to find.
|
|
2516
|
+
* @returns {SourceLocation} The `loc` object.
|
|
2517
|
+
*/
|
|
2518
|
+
getNameLocationInGlobalDirectiveComment(sourceCode, comment, name) {
|
|
2519
|
+
const namePattern = new RegExp(
|
|
2520
|
+
`[\\s,]${escapeRegExp(name)}(?:$|[\\s,:])`,
|
|
2521
|
+
"gu",
|
|
2522
|
+
);
|
|
2523
|
+
|
|
2524
|
+
// To ignore the first text "global".
|
|
2525
|
+
namePattern.lastIndex = comment.value.indexOf("global") + 6;
|
|
2526
|
+
|
|
2527
|
+
// Search a given variable name.
|
|
2528
|
+
const match = namePattern.exec(comment.value);
|
|
2529
|
+
|
|
2530
|
+
// Convert the index to loc.
|
|
2531
|
+
const start = sourceCode.getLocFromIndex(
|
|
2532
|
+
comment.range[0] + "/*".length + (match ? match.index + 1 : 0),
|
|
2533
|
+
);
|
|
2534
|
+
const end = {
|
|
2535
|
+
line: start.line,
|
|
2536
|
+
column: start.column + (match ? name.length : 1),
|
|
2537
|
+
};
|
|
2538
|
+
|
|
2539
|
+
return { start, end };
|
|
2540
|
+
},
|
|
2541
|
+
|
|
2542
|
+
/**
|
|
2543
|
+
* Determines whether the given raw string contains an octal escape sequence
|
|
2544
|
+
* or a non-octal decimal escape sequence ("\8", "\9").
|
|
2545
|
+
*
|
|
2546
|
+
* "\1", "\2" ... "\7", "\8", "\9"
|
|
2547
|
+
* "\00", "\01" ... "\07", "\08", "\09"
|
|
2548
|
+
*
|
|
2549
|
+
* "\0", when not followed by a digit, is not an octal escape sequence.
|
|
2550
|
+
* @param {string} rawString A string in its raw representation.
|
|
2551
|
+
* @returns {boolean} `true` if the string contains at least one octal escape sequence
|
|
2552
|
+
* or at least one non-octal decimal escape sequence.
|
|
2553
|
+
*/
|
|
2554
|
+
hasOctalOrNonOctalDecimalEscapeSequence(rawString) {
|
|
2555
|
+
return OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN.test(rawString);
|
|
2556
|
+
},
|
|
2557
|
+
|
|
2558
|
+
/**
|
|
2559
|
+
* Determines whether the given node is a template literal without expressions.
|
|
2560
|
+
* @param {ASTNode} node Node to check.
|
|
2561
|
+
* @returns {boolean} True if the node is a template literal without expressions.
|
|
2562
|
+
*/
|
|
2563
|
+
isStaticTemplateLiteral(node) {
|
|
2564
|
+
return node.type === "TemplateLiteral" && node.expressions.length === 0;
|
|
2565
|
+
},
|
|
2566
|
+
|
|
2567
|
+
/**
|
|
2568
|
+
* Determines whether the existing curly braces around the single statement are necessary to preserve the semantics of the code.
|
|
2569
|
+
* The braces, which make the given block body, are necessary in either of the following situations:
|
|
2570
|
+
*
|
|
2571
|
+
* 1. The statement is a lexical declaration.
|
|
2572
|
+
* 2. Without the braces, an `if` within the statement would become associated with an `else` after the closing brace:
|
|
2573
|
+
*
|
|
2574
|
+
* if (a) {
|
|
2575
|
+
* if (b)
|
|
2576
|
+
* foo();
|
|
2577
|
+
* }
|
|
2578
|
+
* else
|
|
2579
|
+
* bar();
|
|
2580
|
+
*
|
|
2581
|
+
* if (a)
|
|
2582
|
+
* while (b)
|
|
2583
|
+
* while (c) {
|
|
2584
|
+
* while (d)
|
|
2585
|
+
* if (e)
|
|
2586
|
+
* while(f)
|
|
2587
|
+
* foo();
|
|
2588
|
+
* }
|
|
2589
|
+
* else
|
|
2590
|
+
* bar();
|
|
2591
|
+
* @param {ASTNode} node `BlockStatement` body with exactly one statement directly inside. The statement can have its own nested statements.
|
|
2592
|
+
* @param {SourceCode} sourceCode The source code
|
|
2593
|
+
* @returns {boolean} `true` if the braces are necessary - removing them (replacing the given `BlockStatement` body with its single statement content)
|
|
2594
|
+
* would change the semantics of the code or produce a syntax error.
|
|
2595
|
+
*/
|
|
2596
|
+
areBracesNecessary(node, sourceCode) {
|
|
2597
|
+
/**
|
|
2598
|
+
* Determines if the given node is a lexical declaration (let, const, using, await using, function, or class)
|
|
2599
|
+
* @param {ASTNode} nodeToCheck The node to check
|
|
2600
|
+
* @returns {boolean} True if the node is a lexical declaration
|
|
2601
|
+
* @private
|
|
2602
|
+
*/
|
|
2603
|
+
function isLexicalDeclaration(nodeToCheck) {
|
|
2604
|
+
if (nodeToCheck.type === "VariableDeclaration") {
|
|
2605
|
+
return LEXICAL_DECLARATION_KINDS.has(nodeToCheck.kind);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
return (
|
|
2609
|
+
nodeToCheck.type === "FunctionDeclaration" ||
|
|
2610
|
+
nodeToCheck.type === "ClassDeclaration"
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
/**
|
|
2615
|
+
* Checks if the given token is an `else` token or not.
|
|
2616
|
+
* @param {Token} token The token to check.
|
|
2617
|
+
* @returns {boolean} `true` if the token is an `else` token.
|
|
2618
|
+
*/
|
|
2619
|
+
function isElseKeywordToken(token) {
|
|
2620
|
+
return token.value === "else" && token.type === "Keyword";
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
/**
|
|
2624
|
+
* Determines whether the given node has an `else` keyword token as the first token after.
|
|
2625
|
+
* @param {ASTNode} nodeToCheck The node to check.
|
|
2626
|
+
* @returns {boolean} `true` if the node is followed by an `else` keyword token.
|
|
2627
|
+
*/
|
|
2628
|
+
function isFollowedByElseKeyword(nodeToCheck) {
|
|
2629
|
+
const nextToken = sourceCode.getTokenAfter(nodeToCheck);
|
|
2630
|
+
|
|
2631
|
+
return Boolean(nextToken) && isElseKeywordToken(nextToken);
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
/**
|
|
2635
|
+
* Determines whether the code represented by the given node contains an `if` statement
|
|
2636
|
+
* that would become associated with an `else` keyword directly appended to that code.
|
|
2637
|
+
*
|
|
2638
|
+
* Examples where it returns `true`:
|
|
2639
|
+
*
|
|
2640
|
+
* if (a)
|
|
2641
|
+
* foo();
|
|
2642
|
+
*
|
|
2643
|
+
* if (a) {
|
|
2644
|
+
* foo();
|
|
2645
|
+
* }
|
|
2646
|
+
*
|
|
2647
|
+
* if (a)
|
|
2648
|
+
* foo();
|
|
2649
|
+
* else if (b)
|
|
2650
|
+
* bar();
|
|
2651
|
+
*
|
|
2652
|
+
* while (a)
|
|
2653
|
+
* if (b)
|
|
2654
|
+
* if(c)
|
|
2655
|
+
* foo();
|
|
2656
|
+
* else
|
|
2657
|
+
* bar();
|
|
2658
|
+
*
|
|
2659
|
+
* Examples where it returns `false`:
|
|
2660
|
+
*
|
|
2661
|
+
* if (a)
|
|
2662
|
+
* foo();
|
|
2663
|
+
* else
|
|
2664
|
+
* bar();
|
|
2665
|
+
*
|
|
2666
|
+
* while (a) {
|
|
2667
|
+
* if (b)
|
|
2668
|
+
* if(c)
|
|
2669
|
+
* foo();
|
|
2670
|
+
* else
|
|
2671
|
+
* bar();
|
|
2672
|
+
* }
|
|
2673
|
+
*
|
|
2674
|
+
* while (a)
|
|
2675
|
+
* if (b) {
|
|
2676
|
+
* if(c)
|
|
2677
|
+
* foo();
|
|
2678
|
+
* }
|
|
2679
|
+
* else
|
|
2680
|
+
* bar();
|
|
2681
|
+
* @param {ASTNode} nodeToCheck Node representing the code to check.
|
|
2682
|
+
* @returns {boolean} `true` if an `if` statement within the code would become associated with an `else` appended to that code.
|
|
2683
|
+
*/
|
|
2684
|
+
function hasUnsafeIf(nodeToCheck) {
|
|
2685
|
+
switch (nodeToCheck.type) {
|
|
2686
|
+
case "IfStatement":
|
|
2687
|
+
if (!nodeToCheck.alternate) {
|
|
2688
|
+
return true;
|
|
2689
|
+
}
|
|
2690
|
+
return hasUnsafeIf(nodeToCheck.alternate);
|
|
2691
|
+
case "ForStatement":
|
|
2692
|
+
case "ForInStatement":
|
|
2693
|
+
case "ForOfStatement":
|
|
2694
|
+
case "LabeledStatement":
|
|
2695
|
+
case "WithStatement":
|
|
2696
|
+
case "WhileStatement":
|
|
2697
|
+
return hasUnsafeIf(nodeToCheck.body);
|
|
2698
|
+
default:
|
|
2699
|
+
return false;
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
const statement = node.body[0];
|
|
2704
|
+
|
|
2705
|
+
return (
|
|
2706
|
+
isLexicalDeclaration(statement) ||
|
|
2707
|
+
(hasUnsafeIf(statement) && isFollowedByElseKeyword(node))
|
|
2708
|
+
);
|
|
2709
|
+
},
|
|
2710
|
+
|
|
2711
|
+
isReferenceToGlobalVariable,
|
|
2712
|
+
isLogicalExpression,
|
|
2713
|
+
isCoalesceExpression,
|
|
2714
|
+
isMixedLogicalAndCoalesceExpressions,
|
|
2715
|
+
isNullLiteral,
|
|
2716
|
+
getStaticStringValue,
|
|
2717
|
+
getStaticPropertyName,
|
|
2718
|
+
skipChainExpression,
|
|
2719
|
+
isSpecificId,
|
|
2720
|
+
isSpecificMemberAccess,
|
|
2721
|
+
equalLiteralValue,
|
|
2722
|
+
isSameReference,
|
|
2723
|
+
isLogicalAssignmentOperator,
|
|
2724
|
+
getSwitchCaseColonToken,
|
|
2725
|
+
getModuleExportName,
|
|
2726
|
+
isConstant,
|
|
2727
|
+
isTopLevelExpressionStatement,
|
|
2728
|
+
isDirective,
|
|
2729
|
+
isStartOfExpressionStatement,
|
|
2730
|
+
needsPrecedingSemicolon,
|
|
2731
|
+
isImportAttributeKey,
|
|
2732
|
+
getOpeningParenOfParams,
|
|
2282
2733
|
};
|