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