eslint 9.21.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.
Files changed (425) hide show
  1. package/README.md +52 -48
  2. package/bin/eslint.js +92 -90
  3. package/conf/default-cli-options.js +22 -22
  4. package/conf/ecma-version.js +1 -1
  5. package/conf/globals.js +97 -98
  6. package/conf/replacements.json +24 -20
  7. package/conf/rule-type-list.json +88 -92
  8. package/lib/api.js +12 -12
  9. package/lib/cli-engine/cli-engine.js +828 -808
  10. package/lib/cli-engine/file-enumerator.js +381 -387
  11. package/lib/cli-engine/formatters/formatters-meta.json +16 -16
  12. package/lib/cli-engine/formatters/html.js +107 -99
  13. package/lib/cli-engine/formatters/json-with-metadata.js +5 -5
  14. package/lib/cli-engine/formatters/json.js +2 -2
  15. package/lib/cli-engine/formatters/stylish.js +96 -75
  16. package/lib/cli-engine/hash.js +1 -1
  17. package/lib/cli-engine/index.js +1 -1
  18. package/lib/cli-engine/lint-result-cache.js +144 -145
  19. package/lib/cli-engine/load-rules.js +16 -16
  20. package/lib/cli.js +541 -457
  21. package/lib/config/config-loader.js +648 -618
  22. package/lib/config/config.js +247 -221
  23. package/lib/config/default-config.js +54 -45
  24. package/lib/config/flat-config-array.js +167 -172
  25. package/lib/config/flat-config-helpers.js +65 -68
  26. package/lib/config/flat-config-schema.js +375 -368
  27. package/lib/config/rule-validator.js +139 -144
  28. package/lib/config-api.js +12 -0
  29. package/lib/eslint/eslint-helpers.js +709 -679
  30. package/lib/eslint/eslint.js +944 -886
  31. package/lib/eslint/index.js +2 -2
  32. package/lib/eslint/legacy-eslint.js +576 -532
  33. package/lib/languages/js/index.js +263 -264
  34. package/lib/languages/js/source-code/index.js +1 -1
  35. package/lib/languages/js/source-code/source-code.js +1129 -1054
  36. package/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js +39 -35
  37. package/lib/languages/js/source-code/token-store/backward-token-cursor.js +35 -36
  38. package/lib/languages/js/source-code/token-store/cursor.js +36 -36
  39. package/lib/languages/js/source-code/token-store/cursors.js +80 -52
  40. package/lib/languages/js/source-code/token-store/decorative-cursor.js +17 -18
  41. package/lib/languages/js/source-code/token-store/filter-cursor.js +19 -20
  42. package/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js +40 -32
  43. package/lib/languages/js/source-code/token-store/forward-token-cursor.js +40 -41
  44. package/lib/languages/js/source-code/token-store/index.js +592 -498
  45. package/lib/languages/js/source-code/token-store/limit-cursor.js +17 -18
  46. package/lib/languages/js/source-code/token-store/padded-token-cursor.js +23 -16
  47. package/lib/languages/js/source-code/token-store/skip-cursor.js +19 -20
  48. package/lib/languages/js/source-code/token-store/utils.js +63 -60
  49. package/lib/languages/js/validate-language-options.js +104 -89
  50. package/lib/linter/apply-disable-directives.js +467 -383
  51. package/lib/linter/code-path-analysis/code-path-analyzer.js +650 -672
  52. package/lib/linter/code-path-analysis/code-path-segment.js +215 -216
  53. package/lib/linter/code-path-analysis/code-path-state.js +2118 -2096
  54. package/lib/linter/code-path-analysis/code-path.js +307 -319
  55. package/lib/linter/code-path-analysis/debug-helpers.js +183 -163
  56. package/lib/linter/code-path-analysis/fork-context.js +296 -271
  57. package/lib/linter/code-path-analysis/id-generator.js +22 -23
  58. package/lib/linter/file-context.js +119 -120
  59. package/lib/linter/index.js +3 -3
  60. package/lib/linter/interpolate.js +16 -16
  61. package/lib/linter/linter.js +2402 -2044
  62. package/lib/linter/node-event-generator.js +284 -225
  63. package/lib/linter/report-translator.js +256 -219
  64. package/lib/linter/rule-fixer.js +122 -124
  65. package/lib/linter/rules.js +35 -35
  66. package/lib/linter/safe-emitter.js +18 -18
  67. package/lib/linter/source-code-fixer.js +94 -92
  68. package/lib/linter/timing.js +104 -101
  69. package/lib/linter/vfile.js +70 -73
  70. package/lib/options.js +375 -361
  71. package/lib/rule-tester/index.js +1 -1
  72. package/lib/rule-tester/rule-tester.js +1307 -1045
  73. package/lib/rules/accessor-pairs.js +297 -262
  74. package/lib/rules/array-bracket-newline.js +249 -237
  75. package/lib/rules/array-bracket-spacing.js +262 -223
  76. package/lib/rules/array-callback-return.js +401 -355
  77. package/lib/rules/array-element-newline.js +357 -312
  78. package/lib/rules/arrow-body-style.js +399 -280
  79. package/lib/rules/arrow-parens.js +205 -172
  80. package/lib/rules/arrow-spacing.js +168 -162
  81. package/lib/rules/block-scoped-var.js +124 -122
  82. package/lib/rules/block-spacing.js +185 -175
  83. package/lib/rules/brace-style.js +261 -198
  84. package/lib/rules/callback-return.js +202 -189
  85. package/lib/rules/camelcase.js +402 -391
  86. package/lib/rules/capitalized-comments.js +252 -231
  87. package/lib/rules/class-methods-use-this.js +179 -171
  88. package/lib/rules/comma-dangle.js +378 -345
  89. package/lib/rules/comma-spacing.js +192 -194
  90. package/lib/rules/comma-style.js +374 -315
  91. package/lib/rules/complexity.js +172 -168
  92. package/lib/rules/computed-property-spacing.js +235 -210
  93. package/lib/rules/consistent-return.js +180 -169
  94. package/lib/rules/consistent-this.js +166 -146
  95. package/lib/rules/constructor-super.js +411 -403
  96. package/lib/rules/curly.js +406 -331
  97. package/lib/rules/default-case-last.js +37 -30
  98. package/lib/rules/default-case.js +88 -84
  99. package/lib/rules/default-param-last.js +68 -53
  100. package/lib/rules/dot-location.js +121 -109
  101. package/lib/rules/dot-notation.js +191 -155
  102. package/lib/rules/eol-last.js +121 -119
  103. package/lib/rules/eqeqeq.js +167 -154
  104. package/lib/rules/for-direction.js +145 -120
  105. package/lib/rules/func-call-spacing.js +260 -230
  106. package/lib/rules/func-name-matching.js +292 -208
  107. package/lib/rules/func-names.js +164 -163
  108. package/lib/rules/func-style.js +158 -126
  109. package/lib/rules/function-call-argument-newline.js +151 -128
  110. package/lib/rules/function-paren-newline.js +348 -290
  111. package/lib/rules/generator-star-spacing.js +228 -209
  112. package/lib/rules/getter-return.js +207 -171
  113. package/lib/rules/global-require.js +84 -73
  114. package/lib/rules/grouped-accessor-pairs.js +169 -149
  115. package/lib/rules/guard-for-in.js +71 -62
  116. package/lib/rules/handle-callback-err.js +107 -102
  117. package/lib/rules/id-blacklist.js +181 -198
  118. package/lib/rules/id-denylist.js +167 -186
  119. package/lib/rules/id-length.js +196 -170
  120. package/lib/rules/id-match.js +343 -288
  121. package/lib/rules/implicit-arrow-linebreak.js +101 -78
  122. package/lib/rules/indent-legacy.js +1343 -1117
  123. package/lib/rules/indent.js +2271 -1758
  124. package/lib/rules/index.js +317 -292
  125. package/lib/rules/init-declarations.js +115 -106
  126. package/lib/rules/jsx-quotes.js +93 -81
  127. package/lib/rules/key-spacing.js +749 -632
  128. package/lib/rules/keyword-spacing.js +647 -604
  129. package/lib/rules/line-comment-position.js +141 -127
  130. package/lib/rules/linebreak-style.js +106 -105
  131. package/lib/rules/lines-around-comment.js +539 -447
  132. package/lib/rules/lines-around-directive.js +232 -202
  133. package/lib/rules/lines-between-class-members.js +304 -233
  134. package/lib/rules/logical-assignment-operators.js +581 -398
  135. package/lib/rules/max-classes-per-file.js +68 -67
  136. package/lib/rules/max-depth.js +145 -142
  137. package/lib/rules/max-len.js +472 -433
  138. package/lib/rules/max-lines-per-function.js +200 -175
  139. package/lib/rules/max-lines.js +157 -161
  140. package/lib/rules/max-nested-callbacks.js +101 -103
  141. package/lib/rules/max-params.js +77 -75
  142. package/lib/rules/max-statements-per-line.js +204 -197
  143. package/lib/rules/max-statements.js +167 -163
  144. package/lib/rules/multiline-comment-style.js +636 -478
  145. package/lib/rules/multiline-ternary.js +240 -175
  146. package/lib/rules/new-cap.js +232 -212
  147. package/lib/rules/new-parens.js +87 -78
  148. package/lib/rules/newline-after-var.js +286 -249
  149. package/lib/rules/newline-before-return.js +228 -221
  150. package/lib/rules/newline-per-chained-call.js +141 -126
  151. package/lib/rules/no-alert.js +89 -78
  152. package/lib/rules/no-array-constructor.js +121 -112
  153. package/lib/rules/no-async-promise-executor.js +29 -23
  154. package/lib/rules/no-await-in-loop.js +68 -70
  155. package/lib/rules/no-bitwise.js +123 -99
  156. package/lib/rules/no-buffer-constructor.js +54 -46
  157. package/lib/rules/no-caller.js +38 -32
  158. package/lib/rules/no-case-declarations.js +60 -56
  159. package/lib/rules/no-catch-shadow.js +75 -72
  160. package/lib/rules/no-class-assign.js +50 -47
  161. package/lib/rules/no-compare-neg-zero.js +61 -47
  162. package/lib/rules/no-cond-assign.js +147 -131
  163. package/lib/rules/no-confusing-arrow.js +97 -80
  164. package/lib/rules/no-console.js +201 -190
  165. package/lib/rules/no-const-assign.js +46 -40
  166. package/lib/rules/no-constant-binary-expression.js +499 -404
  167. package/lib/rules/no-constant-condition.js +157 -142
  168. package/lib/rules/no-constructor-return.js +48 -48
  169. package/lib/rules/no-continue.js +24 -26
  170. package/lib/rules/no-control-regex.js +124 -120
  171. package/lib/rules/no-debugger.js +27 -29
  172. package/lib/rules/no-delete-var.js +28 -28
  173. package/lib/rules/no-div-regex.js +46 -40
  174. package/lib/rules/no-dupe-args.js +67 -68
  175. package/lib/rules/no-dupe-class-members.js +92 -88
  176. package/lib/rules/no-dupe-else-if.js +99 -76
  177. package/lib/rules/no-dupe-keys.js +132 -109
  178. package/lib/rules/no-duplicate-case.js +49 -42
  179. package/lib/rules/no-duplicate-imports.js +178 -175
  180. package/lib/rules/no-else-return.js +429 -384
  181. package/lib/rules/no-empty-character-class.js +56 -49
  182. package/lib/rules/no-empty-function.js +126 -127
  183. package/lib/rules/no-empty-pattern.js +62 -57
  184. package/lib/rules/no-empty-static-block.js +36 -34
  185. package/lib/rules/no-empty.js +97 -85
  186. package/lib/rules/no-eq-null.js +36 -31
  187. package/lib/rules/no-eval.js +255 -249
  188. package/lib/rules/no-ex-assign.js +41 -38
  189. package/lib/rules/no-extend-native.js +160 -158
  190. package/lib/rules/no-extra-bind.js +200 -189
  191. package/lib/rules/no-extra-boolean-cast.js +397 -347
  192. package/lib/rules/no-extra-label.js +149 -130
  193. package/lib/rules/no-extra-parens.js +1653 -1324
  194. package/lib/rules/no-extra-semi.js +145 -143
  195. package/lib/rules/no-fallthrough.js +198 -156
  196. package/lib/rules/no-floating-decimal.js +73 -65
  197. package/lib/rules/no-func-assign.js +53 -54
  198. package/lib/rules/no-global-assign.js +77 -72
  199. package/lib/rules/no-implicit-coercion.js +348 -292
  200. package/lib/rules/no-implicit-globals.js +157 -134
  201. package/lib/rules/no-implied-eval.js +139 -111
  202. package/lib/rules/no-import-assign.js +144 -158
  203. package/lib/rules/no-inline-comments.js +100 -94
  204. package/lib/rules/no-inner-declarations.js +114 -100
  205. package/lib/rules/no-invalid-regexp.js +221 -189
  206. package/lib/rules/no-invalid-this.js +122 -116
  207. package/lib/rules/no-irregular-whitespace.js +265 -251
  208. package/lib/rules/no-iterator.js +28 -32
  209. package/lib/rules/no-label-var.js +58 -61
  210. package/lib/rules/no-labels.js +137 -132
  211. package/lib/rules/no-lone-blocks.js +126 -122
  212. package/lib/rules/no-lonely-if.js +107 -76
  213. package/lib/rules/no-loop-func.js +233 -212
  214. package/lib/rules/no-loss-of-precision.js +215 -200
  215. package/lib/rules/no-magic-numbers.js +245 -217
  216. package/lib/rules/no-misleading-character-class.js +498 -445
  217. package/lib/rules/no-mixed-operators.js +187 -181
  218. package/lib/rules/no-mixed-requires.js +252 -239
  219. package/lib/rules/no-mixed-spaces-and-tabs.js +133 -120
  220. package/lib/rules/no-multi-assign.js +45 -43
  221. package/lib/rules/no-multi-spaces.js +162 -142
  222. package/lib/rules/no-multi-str.js +41 -40
  223. package/lib/rules/no-multiple-empty-lines.js +195 -157
  224. package/lib/rules/no-native-reassign.js +89 -84
  225. package/lib/rules/no-negated-condition.js +78 -74
  226. package/lib/rules/no-negated-in-lhs.js +44 -42
  227. package/lib/rules/no-nested-ternary.js +32 -31
  228. package/lib/rules/no-new-func.js +70 -61
  229. package/lib/rules/no-new-native-nonconstructor.js +42 -38
  230. package/lib/rules/no-new-object.js +47 -47
  231. package/lib/rules/no-new-require.js +47 -46
  232. package/lib/rules/no-new-symbol.js +51 -49
  233. package/lib/rules/no-new-wrappers.js +42 -40
  234. package/lib/rules/no-new.js +27 -28
  235. package/lib/rules/no-nonoctal-decimal-escape.js +140 -120
  236. package/lib/rules/no-obj-calls.js +65 -52
  237. package/lib/rules/no-object-constructor.js +103 -96
  238. package/lib/rules/no-octal-escape.js +39 -42
  239. package/lib/rules/no-octal.js +31 -31
  240. package/lib/rules/no-param-reassign.js +234 -216
  241. package/lib/rules/no-path-concat.js +65 -66
  242. package/lib/rules/no-plusplus.js +59 -60
  243. package/lib/rules/no-process-env.js +48 -47
  244. package/lib/rules/no-process-exit.js +53 -49
  245. package/lib/rules/no-promise-executor-return.js +213 -181
  246. package/lib/rules/no-proto.js +25 -28
  247. package/lib/rules/no-prototype-builtins.js +145 -123
  248. package/lib/rules/no-redeclare.js +153 -151
  249. package/lib/rules/no-regex-spaces.js +182 -160
  250. package/lib/rules/no-restricted-exports.js +207 -184
  251. package/lib/rules/no-restricted-globals.js +110 -111
  252. package/lib/rules/no-restricted-imports.js +656 -536
  253. package/lib/rules/no-restricted-modules.js +221 -201
  254. package/lib/rules/no-restricted-properties.js +180 -152
  255. package/lib/rules/no-restricted-syntax.js +55 -51
  256. package/lib/rules/no-return-assign.js +54 -49
  257. package/lib/rules/no-return-await.js +147 -123
  258. package/lib/rules/no-script-url.js +51 -44
  259. package/lib/rules/no-self-assign.js +147 -145
  260. package/lib/rules/no-self-compare.js +62 -45
  261. package/lib/rules/no-sequences.js +134 -115
  262. package/lib/rules/no-setter-return.js +184 -151
  263. package/lib/rules/no-shadow-restricted-names.js +60 -45
  264. package/lib/rules/no-shadow.js +341 -315
  265. package/lib/rules/no-spaced-func.js +81 -76
  266. package/lib/rules/no-sparse-arrays.js +53 -58
  267. package/lib/rules/no-sync.js +60 -59
  268. package/lib/rules/no-tabs.js +82 -71
  269. package/lib/rules/no-template-curly-in-string.js +32 -31
  270. package/lib/rules/no-ternary.js +24 -28
  271. package/lib/rules/no-this-before-super.js +320 -318
  272. package/lib/rules/no-throw-literal.js +30 -35
  273. package/lib/rules/no-trailing-spaces.js +198 -190
  274. package/lib/rules/no-undef-init.js +75 -60
  275. package/lib/rules/no-undef.js +50 -47
  276. package/lib/rules/no-undefined.js +72 -74
  277. package/lib/rules/no-underscore-dangle.js +369 -326
  278. package/lib/rules/no-unexpected-multiline.js +111 -101
  279. package/lib/rules/no-unmodified-loop-condition.js +253 -253
  280. package/lib/rules/no-unneeded-ternary.js +211 -146
  281. package/lib/rules/no-unreachable-loop.js +144 -141
  282. package/lib/rules/no-unreachable.js +254 -247
  283. package/lib/rules/no-unsafe-finally.js +92 -84
  284. package/lib/rules/no-unsafe-negation.js +104 -82
  285. package/lib/rules/no-unsafe-optional-chaining.js +191 -177
  286. package/lib/rules/no-unused-expressions.js +177 -161
  287. package/lib/rules/no-unused-labels.js +138 -123
  288. package/lib/rules/no-unused-private-class-members.js +205 -181
  289. package/lib/rules/no-unused-vars.js +1668 -1448
  290. package/lib/rules/no-use-before-define.js +228 -230
  291. package/lib/rules/no-useless-assignment.js +589 -510
  292. package/lib/rules/no-useless-backreference.js +211 -192
  293. package/lib/rules/no-useless-call.js +57 -52
  294. package/lib/rules/no-useless-catch.js +39 -39
  295. package/lib/rules/no-useless-computed-key.js +143 -114
  296. package/lib/rules/no-useless-concat.js +64 -59
  297. package/lib/rules/no-useless-constructor.js +157 -110
  298. package/lib/rules/no-useless-escape.js +341 -290
  299. package/lib/rules/no-useless-rename.js +182 -155
  300. package/lib/rules/no-useless-return.js +343 -311
  301. package/lib/rules/no-var.js +232 -211
  302. package/lib/rules/no-void.js +49 -47
  303. package/lib/rules/no-warning-comments.js +190 -185
  304. package/lib/rules/no-whitespace-before-property.js +130 -114
  305. package/lib/rules/no-with.js +23 -25
  306. package/lib/rules/nonblock-statement-body-position.js +148 -129
  307. package/lib/rules/object-curly-newline.js +305 -264
  308. package/lib/rules/object-curly-spacing.js +359 -313
  309. package/lib/rules/object-property-newline.js +136 -105
  310. package/lib/rules/object-shorthand.js +606 -501
  311. package/lib/rules/one-var-declaration-per-line.js +103 -99
  312. package/lib/rules/one-var.js +652 -536
  313. package/lib/rules/operator-assignment.js +218 -160
  314. package/lib/rules/operator-linebreak.js +294 -250
  315. package/lib/rules/padded-blocks.js +345 -307
  316. package/lib/rules/padding-line-between-statements.js +442 -438
  317. package/lib/rules/prefer-arrow-callback.js +361 -312
  318. package/lib/rules/prefer-const.js +417 -376
  319. package/lib/rules/prefer-destructuring.js +300 -278
  320. package/lib/rules/prefer-exponentiation-operator.js +175 -132
  321. package/lib/rules/prefer-named-capture-group.js +152 -139
  322. package/lib/rules/prefer-numeric-literals.js +120 -112
  323. package/lib/rules/prefer-object-has-own.js +115 -81
  324. package/lib/rules/prefer-object-spread.js +212 -192
  325. package/lib/rules/prefer-promise-reject-errors.js +139 -121
  326. package/lib/rules/prefer-reflect.js +126 -106
  327. package/lib/rules/prefer-regex-literals.js +577 -465
  328. package/lib/rules/prefer-rest-params.js +78 -79
  329. package/lib/rules/prefer-spread.js +46 -43
  330. package/lib/rules/prefer-template.js +265 -194
  331. package/lib/rules/quote-props.js +372 -306
  332. package/lib/rules/quotes.js +373 -325
  333. package/lib/rules/radix.js +151 -135
  334. package/lib/rules/require-atomic-updates.js +315 -284
  335. package/lib/rules/require-await.js +143 -115
  336. package/lib/rules/require-unicode-regexp.js +281 -176
  337. package/lib/rules/require-yield.js +52 -53
  338. package/lib/rules/rest-spread-spacing.js +127 -115
  339. package/lib/rules/semi-spacing.js +280 -249
  340. package/lib/rules/semi-style.js +175 -133
  341. package/lib/rules/semi.js +455 -435
  342. package/lib/rules/sort-imports.js +305 -232
  343. package/lib/rules/sort-keys.js +218 -187
  344. package/lib/rules/sort-vars.js +126 -92
  345. package/lib/rules/space-before-blocks.js +198 -188
  346. package/lib/rules/space-before-function-paren.js +185 -165
  347. package/lib/rules/space-in-parens.js +358 -287
  348. package/lib/rules/space-infix-ops.js +236 -200
  349. package/lib/rules/space-unary-ops.js +355 -297
  350. package/lib/rules/spaced-comment.js +362 -318
  351. package/lib/rules/strict.js +264 -229
  352. package/lib/rules/switch-colon-spacing.js +129 -121
  353. package/lib/rules/symbol-description.js +44 -47
  354. package/lib/rules/template-curly-spacing.js +147 -141
  355. package/lib/rules/template-tag-spacing.js +97 -87
  356. package/lib/rules/unicode-bom.js +53 -55
  357. package/lib/rules/use-isnan.js +236 -205
  358. package/lib/rules/utils/ast-utils.js +2039 -1860
  359. package/lib/rules/utils/char-source.js +162 -155
  360. package/lib/rules/utils/fix-tracker.js +83 -80
  361. package/lib/rules/utils/keywords.js +59 -59
  362. package/lib/rules/utils/lazy-loading-rule-map.js +79 -76
  363. package/lib/rules/utils/regular-expressions.js +32 -24
  364. package/lib/rules/utils/unicode/index.js +4 -4
  365. package/lib/rules/utils/unicode/is-combining-character.js +1 -1
  366. package/lib/rules/utils/unicode/is-emoji-modifier.js +1 -1
  367. package/lib/rules/utils/unicode/is-regional-indicator-symbol.js +1 -1
  368. package/lib/rules/utils/unicode/is-surrogate-pair.js +1 -1
  369. package/lib/rules/valid-typeof.js +152 -110
  370. package/lib/rules/vars-on-top.js +151 -144
  371. package/lib/rules/wrap-iife.js +203 -190
  372. package/lib/rules/wrap-regex.js +69 -57
  373. package/lib/rules/yield-star-spacing.js +144 -133
  374. package/lib/rules/yoda.js +282 -271
  375. package/lib/services/parser-service.js +35 -35
  376. package/lib/services/processor-service.js +66 -73
  377. package/lib/shared/ajv.js +14 -14
  378. package/lib/shared/assert.js +3 -4
  379. package/lib/shared/ast-utils.js +7 -6
  380. package/lib/shared/deep-merge-arrays.js +24 -22
  381. package/lib/shared/directives.js +3 -2
  382. package/lib/shared/flags.js +46 -17
  383. package/lib/shared/logging.js +24 -25
  384. package/lib/shared/option-utils.js +43 -36
  385. package/lib/shared/runtime-info.js +136 -127
  386. package/lib/shared/serialization.js +27 -27
  387. package/lib/shared/severity.js +22 -22
  388. package/lib/shared/stats.js +5 -5
  389. package/lib/shared/string-utils.js +16 -16
  390. package/lib/shared/text-table.js +28 -27
  391. package/lib/shared/traverser.js +153 -146
  392. package/lib/types/config-api.d.ts +8 -0
  393. package/lib/types/index.d.ts +2010 -1559
  394. package/lib/types/rules.d.ts +5312 -0
  395. package/lib/types/use-at-your-own-risk.d.ts +32 -30
  396. package/lib/unsupported-api.js +5 -5
  397. package/messages/all-files-ignored.js +3 -3
  398. package/messages/all-matched-files-ignored.js +3 -3
  399. package/messages/config-file-missing.js +2 -2
  400. package/messages/config-plugin-missing.js +3 -3
  401. package/messages/config-serialize-function.js +9 -7
  402. package/messages/eslintrc-incompat.js +13 -15
  403. package/messages/eslintrc-plugins.js +3 -4
  404. package/messages/extend-config-missing.js +3 -3
  405. package/messages/failed-to-read-json.js +3 -3
  406. package/messages/file-not-found.js +3 -3
  407. package/messages/invalid-rule-options.js +2 -2
  408. package/messages/invalid-rule-severity.js +2 -2
  409. package/messages/no-config-found.js +3 -3
  410. package/messages/plugin-conflict.js +8 -8
  411. package/messages/plugin-invalid.js +3 -3
  412. package/messages/plugin-missing.js +3 -3
  413. package/messages/print-config-with-directory-path.js +2 -2
  414. package/messages/shared.js +6 -1
  415. package/messages/whitespace-found.js +3 -3
  416. package/package.json +22 -20
  417. package/lib/types/rules/best-practices.d.ts +0 -1143
  418. package/lib/types/rules/deprecated.d.ts +0 -252
  419. package/lib/types/rules/ecmascript-6.d.ts +0 -647
  420. package/lib/types/rules/index.d.ts +0 -50
  421. package/lib/types/rules/node-commonjs.d.ts +0 -171
  422. package/lib/types/rules/possible-errors.d.ts +0 -685
  423. package/lib/types/rules/strict-mode.d.ts +0 -38
  424. package/lib/types/rules/stylistic-issues.d.ts +0 -2043
  425. package/lib/types/rules/variables.d.ts +0 -234
@@ -10,46 +10,55 @@
10
10
  // Requirements
11
11
  //------------------------------------------------------------------------------
12
12
 
13
- const
14
- path = require("node:path"),
15
- eslintScope = require("eslint-scope"),
16
- evk = require("eslint-visitor-keys"),
17
- espree = require("espree"),
18
- merge = require("lodash.merge"),
19
- pkg = require("../../package.json"),
20
- {
21
- Legacy: {
22
- ConfigOps,
23
- ConfigValidator,
24
- environments: BuiltInEnvironments
25
- }
26
- } = require("@eslint/eslintrc/universal"),
27
- Traverser = require("../shared/traverser"),
28
- { SourceCode } = require("../languages/js/source-code"),
29
- applyDisableDirectives = require("./apply-disable-directives"),
30
- { ConfigCommentParser } = require("@eslint/plugin-kit"),
31
- NodeEventGenerator = require("./node-event-generator"),
32
- createReportTranslator = require("./report-translator"),
33
- Rules = require("./rules"),
34
- createEmitter = require("./safe-emitter"),
35
- SourceCodeFixer = require("./source-code-fixer"),
36
- timing = require("./timing"),
37
- ruleReplacements = require("../../conf/replacements.json");
13
+ const path = require("node:path"),
14
+ eslintScope = require("eslint-scope"),
15
+ evk = require("eslint-visitor-keys"),
16
+ espree = require("espree"),
17
+ merge = require("lodash.merge"),
18
+ pkg = require("../../package.json"),
19
+ {
20
+ Legacy: {
21
+ ConfigOps,
22
+ ConfigValidator,
23
+ environments: BuiltInEnvironments,
24
+ },
25
+ } = require("@eslint/eslintrc/universal"),
26
+ Traverser = require("../shared/traverser"),
27
+ { SourceCode } = require("../languages/js/source-code"),
28
+ applyDisableDirectives = require("./apply-disable-directives"),
29
+ { ConfigCommentParser } = require("@eslint/plugin-kit"),
30
+ NodeEventGenerator = require("./node-event-generator"),
31
+ createReportTranslator = require("./report-translator"),
32
+ Rules = require("./rules"),
33
+ createEmitter = require("./safe-emitter"),
34
+ SourceCodeFixer = require("./source-code-fixer"),
35
+ timing = require("./timing"),
36
+ ruleReplacements = require("../../conf/replacements.json");
38
37
  const { getRuleFromConfig } = require("../config/flat-config-helpers");
39
38
  const { FlatConfigArray } = require("../config/flat-config-array");
40
39
  const { startTime, endTime } = require("../shared/stats");
41
40
  const { RuleValidator } = require("../config/rule-validator");
42
41
  const { assertIsRuleSeverity } = require("../config/flat-config-schema");
43
- const { normalizeSeverityToString, normalizeSeverityToNumber } = require("../shared/severity");
42
+ const {
43
+ normalizeSeverityToString,
44
+ normalizeSeverityToNumber,
45
+ } = require("../shared/severity");
44
46
  const { deepMergeArrays } = require("../shared/deep-merge-arrays");
45
47
  const jslang = require("../languages/js");
46
- const { activeFlags, inactiveFlags, getInactivityReasonMessage } = require("../shared/flags");
48
+ const {
49
+ activeFlags,
50
+ inactiveFlags,
51
+ getInactivityReasonMessage,
52
+ } = require("../shared/flags");
47
53
  const debug = require("debug")("eslint:linter");
48
54
  const MAX_AUTOFIX_PASSES = 10;
49
55
  const DEFAULT_PARSER_NAME = "espree";
50
56
  const DEFAULT_ECMA_VERSION = 5;
51
57
  const commentParser = new ConfigCommentParser();
52
- const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };
58
+ const DEFAULT_ERROR_LOC = {
59
+ start: { line: 1, column: 0 },
60
+ end: { line: 1, column: 1 },
61
+ };
53
62
  const parserSymbol = Symbol.for("eslint.RuleTester.parser");
54
63
  const { LATEST_ECMA_VERSION } = require("../../conf/ecma-version");
55
64
  const { VFile } = require("./vfile");
@@ -79,7 +88,6 @@ const STEP_KIND_CALL = 2;
79
88
  /** @typedef {import("@eslint/core").RuleConfig} RuleConfig */
80
89
  /** @typedef {import("../types").Linter.StringSeverity} StringSeverity */
81
90
 
82
-
83
91
  /* eslint-disable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
84
92
  /**
85
93
  * @template T
@@ -157,7 +165,7 @@ const STEP_KIND_CALL = 2;
157
165
  * @returns {boolean} True if the parser is Espree or false if not.
158
166
  */
159
167
  function isEspree(parser) {
160
- return !!(parser === espree || parser[parserSymbol] === espree);
168
+ return !!(parser === espree || parser[parserSymbol] === espree);
161
169
  }
162
170
 
163
171
  /**
@@ -169,72 +177,80 @@ function isEspree(parser) {
169
177
  * @param {{exportedVariables: Object, enabledGlobals: Object}} commentDirectives Directives from comment configuration
170
178
  * @returns {void}
171
179
  */
172
- function addDeclaredGlobals(globalScope, configGlobals, { exportedVariables, enabledGlobals }) {
173
-
174
- // Define configured global variables.
175
- for (const id of new Set([...Object.keys(configGlobals), ...Object.keys(enabledGlobals)])) {
176
-
177
- /*
178
- * `ConfigOps.normalizeConfigGlobal` will throw an error if a configured global value is invalid. However, these errors would
179
- * typically be caught when validating a config anyway (validity for inline global comments is checked separately).
180
- */
181
- const configValue = configGlobals[id] === void 0 ? void 0 : ConfigOps.normalizeConfigGlobal(configGlobals[id]);
182
- const commentValue = enabledGlobals[id] && enabledGlobals[id].value;
183
- const value = commentValue || configValue;
184
- const sourceComments = enabledGlobals[id] && enabledGlobals[id].comments;
185
-
186
- if (value === "off") {
187
- continue;
188
- }
189
-
190
- let variable = globalScope.set.get(id);
191
-
192
- if (!variable) {
193
- variable = new eslintScope.Variable(id, globalScope);
194
-
195
- globalScope.variables.push(variable);
196
- globalScope.set.set(id, variable);
197
- }
198
-
199
- variable.eslintImplicitGlobalSetting = configValue;
200
- variable.eslintExplicitGlobal = sourceComments !== void 0;
201
- variable.eslintExplicitGlobalComments = sourceComments;
202
- variable.writeable = (value === "writable");
203
- }
204
-
205
- // mark all exported variables as such
206
- Object.keys(exportedVariables).forEach(name => {
207
- const variable = globalScope.set.get(name);
208
-
209
- if (variable) {
210
- variable.eslintUsed = true;
211
- variable.eslintExported = true;
212
- }
213
- });
214
-
215
- /*
216
- * "through" contains all references which definitions cannot be found.
217
- * Since we augment the global scope using configuration, we need to update
218
- * references and remove the ones that were added by configuration.
219
- */
220
- globalScope.through = globalScope.through.filter(reference => {
221
- const name = reference.identifier.name;
222
- const variable = globalScope.set.get(name);
223
-
224
- if (variable) {
225
-
226
- /*
227
- * Links the variable and the reference.
228
- * And this reference is removed from `Scope#through`.
229
- */
230
- reference.resolved = variable;
231
- variable.references.push(reference);
232
-
233
- return false;
234
- }
235
-
236
- return true;
237
- });
180
+ function addDeclaredGlobals(
181
+ globalScope,
182
+ configGlobals,
183
+ { exportedVariables, enabledGlobals },
184
+ ) {
185
+ // Define configured global variables.
186
+ for (const id of new Set([
187
+ ...Object.keys(configGlobals),
188
+ ...Object.keys(enabledGlobals),
189
+ ])) {
190
+ /*
191
+ * `ConfigOps.normalizeConfigGlobal` will throw an error if a configured global value is invalid. However, these errors would
192
+ * typically be caught when validating a config anyway (validity for inline global comments is checked separately).
193
+ */
194
+ const configValue =
195
+ configGlobals[id] === void 0
196
+ ? void 0
197
+ : ConfigOps.normalizeConfigGlobal(configGlobals[id]);
198
+ const commentValue = enabledGlobals[id] && enabledGlobals[id].value;
199
+ const value = commentValue || configValue;
200
+ const sourceComments =
201
+ enabledGlobals[id] && enabledGlobals[id].comments;
202
+
203
+ if (value === "off") {
204
+ continue;
205
+ }
206
+
207
+ let variable = globalScope.set.get(id);
208
+
209
+ if (!variable) {
210
+ variable = new eslintScope.Variable(id, globalScope);
211
+
212
+ globalScope.variables.push(variable);
213
+ globalScope.set.set(id, variable);
214
+ }
215
+
216
+ variable.eslintImplicitGlobalSetting = configValue;
217
+ variable.eslintExplicitGlobal = sourceComments !== void 0;
218
+ variable.eslintExplicitGlobalComments = sourceComments;
219
+ variable.writeable = value === "writable";
220
+ }
221
+
222
+ // mark all exported variables as such
223
+ Object.keys(exportedVariables).forEach(name => {
224
+ const variable = globalScope.set.get(name);
225
+
226
+ if (variable) {
227
+ variable.eslintUsed = true;
228
+ variable.eslintExported = true;
229
+ }
230
+ });
231
+
232
+ /*
233
+ * "through" contains all references which definitions cannot be found.
234
+ * Since we augment the global scope using configuration, we need to update
235
+ * references and remove the ones that were added by configuration.
236
+ */
237
+ globalScope.through = globalScope.through.filter(reference => {
238
+ const name = reference.identifier.name;
239
+ const variable = globalScope.set.get(name);
240
+
241
+ if (variable) {
242
+ /*
243
+ * Links the variable and the reference.
244
+ * And this reference is removed from `Scope#through`.
245
+ */
246
+ reference.resolved = variable;
247
+ variable.references.push(reference);
248
+
249
+ return false;
250
+ }
251
+
252
+ return true;
253
+ });
238
254
  }
239
255
 
240
256
  /**
@@ -244,9 +260,9 @@ function addDeclaredGlobals(globalScope, configGlobals, { exportedVariables, ena
244
260
  * @private
245
261
  */
246
262
  function createMissingRuleMessage(ruleId) {
247
- return Object.hasOwn(ruleReplacements.rules, ruleId)
248
- ? `Rule '${ruleId}' was removed and replaced by: ${ruleReplacements.rules[ruleId].join(", ")}`
249
- : `Definition for rule '${ruleId}' was not found.`;
263
+ return Object.hasOwn(ruleReplacements.rules, ruleId)
264
+ ? `Rule '${ruleId}' was removed and replaced by: ${ruleReplacements.rules[ruleId].join(", ")}`
265
+ : `Definition for rule '${ruleId}' was not found.`;
250
266
  }
251
267
 
252
268
  /**
@@ -261,21 +277,24 @@ function createMissingRuleMessage(ruleId) {
261
277
  * @param {Language} language The language to use to adjust the location information.
262
278
  * @returns {Object} The updated location.
263
279
  */
264
- function updateLocationInformation({ line, column, endLine, endColumn }, language) {
265
-
266
- const columnOffset = language.columnStart === 1 ? 0 : 1;
267
- const lineOffset = language.lineStart === 1 ? 0 : 1;
268
-
269
- // calculate separately to account for undefined
270
- const finalEndLine = endLine === void 0 ? endLine : endLine + lineOffset;
271
- const finalEndColumn = endColumn === void 0 ? endColumn : endColumn + columnOffset;
272
-
273
- return {
274
- line: line + lineOffset,
275
- column: column + columnOffset,
276
- endLine: finalEndLine,
277
- endColumn: finalEndColumn
278
- };
280
+ function updateLocationInformation(
281
+ { line, column, endLine, endColumn },
282
+ language,
283
+ ) {
284
+ const columnOffset = language.columnStart === 1 ? 0 : 1;
285
+ const lineOffset = language.lineStart === 1 ? 0 : 1;
286
+
287
+ // calculate separately to account for undefined
288
+ const finalEndLine = endLine === void 0 ? endLine : endLine + lineOffset;
289
+ const finalEndColumn =
290
+ endColumn === void 0 ? endColumn : endColumn + columnOffset;
291
+
292
+ return {
293
+ line: line + lineOffset,
294
+ column: column + columnOffset,
295
+ endLine: finalEndLine,
296
+ endColumn: finalEndColumn,
297
+ };
279
298
  }
280
299
 
281
300
  /**
@@ -290,31 +309,34 @@ function updateLocationInformation({ line, column, endLine, endColumn }, languag
290
309
  * @private
291
310
  */
292
311
  function createLintingProblem(options) {
293
- const {
294
- ruleId = null,
295
- loc = DEFAULT_ERROR_LOC,
296
- message = createMissingRuleMessage(options.ruleId),
297
- severity = 2,
298
-
299
- // fallback for eslintrc mode
300
- language = {
301
- columnStart: 0,
302
- lineStart: 1
303
- }
304
- } = options;
305
-
306
- return {
307
- ruleId,
308
- message,
309
- ...updateLocationInformation({
310
- line: loc.start.line,
311
- column: loc.start.column,
312
- endLine: loc.end.line,
313
- endColumn: loc.end.column
314
- }, language),
315
- severity,
316
- nodeType: null
317
- };
312
+ const {
313
+ ruleId = null,
314
+ loc = DEFAULT_ERROR_LOC,
315
+ message = createMissingRuleMessage(options.ruleId),
316
+ severity = 2,
317
+
318
+ // fallback for eslintrc mode
319
+ language = {
320
+ columnStart: 0,
321
+ lineStart: 1,
322
+ },
323
+ } = options;
324
+
325
+ return {
326
+ ruleId,
327
+ message,
328
+ ...updateLocationInformation(
329
+ {
330
+ line: loc.start.line,
331
+ column: loc.start.column,
332
+ endLine: loc.end.line,
333
+ endColumn: loc.end.column,
334
+ },
335
+ language,
336
+ ),
337
+ severity,
338
+ nodeType: null,
339
+ };
318
340
  }
319
341
 
320
342
  /**
@@ -324,7 +346,7 @@ function createLintingProblem(options) {
324
346
  * @returns {Array} The value as an array.
325
347
  */
326
348
  function asArray(value) {
327
- return Array.isArray(value) ? value : [value];
349
+ return Array.isArray(value) ? value : [value];
328
350
  }
329
351
 
330
352
  /**
@@ -338,39 +360,60 @@ function asArray(value) {
338
360
  * @param {"error"|"warn"} severity The severity to report.
339
361
  * @returns {void}
340
362
  */
341
- function addProblemIfSameSeverityAndOptions(config, loc, problems, ruleId, ruleOptions, ruleOptionsInline, severity) {
342
- const existingConfigRaw = config.rules?.[ruleId];
343
- const existingConfig = existingConfigRaw ? asArray(existingConfigRaw) : ["off"];
344
- const existingSeverity = normalizeSeverityToString(existingConfig[0]);
345
- const inlineSeverity = normalizeSeverityToString(ruleOptions[0]);
346
- const sameSeverity = existingSeverity === inlineSeverity;
347
-
348
- if (!sameSeverity) {
349
- return;
350
- }
351
-
352
- const alreadyConfigured = existingConfigRaw
353
- ? `is already configured to '${existingSeverity}'`
354
- : "is not enabled so can't be turned off";
355
- let message;
356
-
357
- if ((existingConfig.length === 1 && ruleOptions.length === 1) || existingSeverity === "off") {
358
- message = `Unused inline config ('${ruleId}' ${alreadyConfigured}).`;
359
- } else if (!containsDifferentProperty(ruleOptions.slice(1), existingConfig.slice(1))) {
360
- message = ruleOptionsInline.length === 1
361
- ? `Unused inline config ('${ruleId}' ${alreadyConfigured}).`
362
- : `Unused inline config ('${ruleId}' ${alreadyConfigured} with the same options).`;
363
- }
364
-
365
- if (message) {
366
- problems.push(createLintingProblem({
367
- ruleId: null,
368
- message,
369
- loc,
370
- language: config.language,
371
- severity: normalizeSeverityToNumber(severity)
372
- }));
373
- }
363
+ function addProblemIfSameSeverityAndOptions(
364
+ config,
365
+ loc,
366
+ problems,
367
+ ruleId,
368
+ ruleOptions,
369
+ ruleOptionsInline,
370
+ severity,
371
+ ) {
372
+ const existingConfigRaw = config.rules?.[ruleId];
373
+ const existingConfig = existingConfigRaw
374
+ ? asArray(existingConfigRaw)
375
+ : ["off"];
376
+ const existingSeverity = normalizeSeverityToString(existingConfig[0]);
377
+ const inlineSeverity = normalizeSeverityToString(ruleOptions[0]);
378
+ const sameSeverity = existingSeverity === inlineSeverity;
379
+
380
+ if (!sameSeverity) {
381
+ return;
382
+ }
383
+
384
+ const alreadyConfigured = existingConfigRaw
385
+ ? `is already configured to '${existingSeverity}'`
386
+ : "is not enabled so can't be turned off";
387
+ let message;
388
+
389
+ if (
390
+ (existingConfig.length === 1 && ruleOptions.length === 1) ||
391
+ existingSeverity === "off"
392
+ ) {
393
+ message = `Unused inline config ('${ruleId}' ${alreadyConfigured}).`;
394
+ } else if (
395
+ !containsDifferentProperty(
396
+ ruleOptions.slice(1),
397
+ existingConfig.slice(1),
398
+ )
399
+ ) {
400
+ message =
401
+ ruleOptionsInline.length === 1
402
+ ? `Unused inline config ('${ruleId}' ${alreadyConfigured}).`
403
+ : `Unused inline config ('${ruleId}' ${alreadyConfigured} with the same options).`;
404
+ }
405
+
406
+ if (message) {
407
+ problems.push(
408
+ createLintingProblem({
409
+ ruleId: null,
410
+ message,
411
+ loc,
412
+ language: config.language,
413
+ severity: normalizeSeverityToNumber(severity),
414
+ }),
415
+ );
416
+ }
374
417
  }
375
418
 
376
419
  /**
@@ -386,57 +429,61 @@ function addProblemIfSameSeverityAndOptions(config, loc, problems, ruleId, ruleO
386
429
  * @param {SourceCode} sourceCode The SourceCode object to get comments from.
387
430
  * @returns {Object} Directives and problems from the comment
388
431
  */
389
- function createDisableDirectives({ type, value, justification, node }, ruleMapper, language, sourceCode) {
390
- const ruleIds = Object.keys(commentParser.parseListConfig(value));
391
- const directiveRules = ruleIds.length ? ruleIds : [null];
392
- const result = {
393
- directives: [], // valid disable directives
394
- directiveProblems: [] // problems in directives
395
- };
396
- const parentDirective = { node, value, ruleIds };
397
-
398
- for (const ruleId of directiveRules) {
399
-
400
- const loc = sourceCode.getLoc(node);
401
-
402
- // push to directives, if the rule is defined(including null, e.g. /*eslint enable*/)
403
- if (ruleId === null || !!ruleMapper(ruleId)) {
404
-
405
-
406
- if (type === "disable-next-line") {
407
- const { line, column } = updateLocationInformation(
408
- loc.end,
409
- language
410
- );
411
-
412
- result.directives.push({
413
- parentDirective,
414
- type,
415
- line,
416
- column,
417
- ruleId,
418
- justification
419
- });
420
- } else {
421
- const { line, column } = updateLocationInformation(
422
- loc.start,
423
- language
424
- );
425
-
426
- result.directives.push({
427
- parentDirective,
428
- type,
429
- line,
430
- column,
431
- ruleId,
432
- justification
433
- });
434
- }
435
- } else {
436
- result.directiveProblems.push(createLintingProblem({ ruleId, loc, language }));
437
- }
438
- }
439
- return result;
432
+ function createDisableDirectives(
433
+ { type, value, justification, node },
434
+ ruleMapper,
435
+ language,
436
+ sourceCode,
437
+ ) {
438
+ const ruleIds = Object.keys(commentParser.parseListConfig(value));
439
+ const directiveRules = ruleIds.length ? ruleIds : [null];
440
+ const result = {
441
+ directives: [], // valid disable directives
442
+ directiveProblems: [], // problems in directives
443
+ };
444
+ const parentDirective = { node, value, ruleIds };
445
+
446
+ for (const ruleId of directiveRules) {
447
+ const loc = sourceCode.getLoc(node);
448
+
449
+ // push to directives, if the rule is defined(including null, e.g. /*eslint enable*/)
450
+ if (ruleId === null || !!ruleMapper(ruleId)) {
451
+ if (type === "disable-next-line") {
452
+ const { line, column } = updateLocationInformation(
453
+ loc.end,
454
+ language,
455
+ );
456
+
457
+ result.directives.push({
458
+ parentDirective,
459
+ type,
460
+ line,
461
+ column,
462
+ ruleId,
463
+ justification,
464
+ });
465
+ } else {
466
+ const { line, column } = updateLocationInformation(
467
+ loc.start,
468
+ language,
469
+ );
470
+
471
+ result.directives.push({
472
+ parentDirective,
473
+ type,
474
+ line,
475
+ column,
476
+ ruleId,
477
+ justification,
478
+ });
479
+ }
480
+ } else {
481
+ result.directiveProblems.push(
482
+ createLintingProblem({ ruleId, loc, language }),
483
+ );
484
+ }
485
+ }
486
+ return result;
440
487
  }
441
488
 
442
489
  /**
@@ -450,223 +497,265 @@ function createDisableDirectives({ type, value, justification, node }, ruleMappe
450
497
  * @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: LintMessage[], disableDirectives: DisableDirective[]}}
451
498
  * A collection of the directive comments that were found, along with any problems that occurred when parsing
452
499
  */
453
- function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config) {
454
- const configuredRules = {};
455
- const enabledGlobals = Object.create(null);
456
- const exportedVariables = {};
457
- const problems = [];
458
- const disableDirectives = [];
459
- const validator = new ConfigValidator({
460
- builtInRules: Rules
461
- });
462
-
463
- sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
464
-
465
- const directive = commentParser.parseDirective(comment.value);
466
-
467
- if (!directive) {
468
- return;
469
- }
470
-
471
- const {
472
- label,
473
- value,
474
- justification: justificationPart
475
- } = directive;
476
-
477
- const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(label);
478
-
479
- if (comment.type === "Line" && !lineCommentSupported) {
480
- return;
481
- }
482
-
483
- const loc = sourceCode.getLoc(comment);
484
-
485
- if (warnInlineConfig) {
486
- const kind = comment.type === "Block" ? `/*${label}*/` : `//${label}`;
487
-
488
- problems.push(createLintingProblem({
489
- ruleId: null,
490
- message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`,
491
- loc,
492
- severity: 1
493
- }));
494
- return;
495
- }
496
-
497
- if (label === "eslint-disable-line" && loc.start.line !== loc.end.line) {
498
- const message = `${label} comment should not span multiple lines.`;
499
-
500
- problems.push(createLintingProblem({
501
- ruleId: null,
502
- message,
503
- loc
504
- }));
505
- return;
506
- }
507
-
508
- switch (label) {
509
- case "eslint-disable":
510
- case "eslint-enable":
511
- case "eslint-disable-next-line":
512
- case "eslint-disable-line": {
513
- const directiveType = label.slice("eslint-".length);
514
- const { directives, directiveProblems } = createDisableDirectives({
515
- type: directiveType,
516
- value,
517
- justification: justificationPart,
518
- node: comment
519
- }, ruleMapper, jslang, sourceCode);
520
-
521
- disableDirectives.push(...directives);
522
- problems.push(...directiveProblems);
523
- break;
524
- }
525
-
526
- case "exported":
527
- Object.assign(exportedVariables, commentParser.parseListConfig(value));
528
- break;
529
-
530
- case "globals":
531
- case "global":
532
- for (const [id, idSetting] of Object.entries(commentParser.parseStringConfig(value))) {
533
- let normalizedValue;
534
-
535
- try {
536
- normalizedValue = ConfigOps.normalizeConfigGlobal(idSetting);
537
- } catch (err) {
538
- problems.push(createLintingProblem({
539
- ruleId: null,
540
- loc,
541
- message: err.message
542
- }));
543
- continue;
544
- }
545
-
546
- if (enabledGlobals[id]) {
547
- enabledGlobals[id].comments.push(comment);
548
- enabledGlobals[id].value = normalizedValue;
549
- } else {
550
- enabledGlobals[id] = {
551
- comments: [comment],
552
- value: normalizedValue
553
- };
554
- }
555
- }
556
- break;
557
-
558
- case "eslint": {
559
- const parseResult = commentParser.parseJSONLikeConfig(value);
560
-
561
- if (parseResult.ok) {
562
- Object.keys(parseResult.config).forEach(name => {
563
- const rule = ruleMapper(name);
564
- const ruleValue = parseResult.config[name];
565
-
566
- if (!rule) {
567
- problems.push(createLintingProblem({ ruleId: name, loc }));
568
- return;
569
- }
570
-
571
- if (Object.hasOwn(configuredRules, name)) {
572
- problems.push(createLintingProblem({
573
- message: `Rule "${name}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
574
- loc
575
- }));
576
- return;
577
- }
578
-
579
- let ruleOptions = asArray(ruleValue);
580
-
581
- /*
582
- * If the rule was already configured, inline rule configuration that
583
- * only has severity should retain options from the config and just override the severity.
584
- *
585
- * Example:
586
- *
587
- * {
588
- * rules: {
589
- * curly: ["error", "multi"]
590
- * }
591
- * }
592
- *
593
- * /* eslint curly: ["warn"] * /
594
- *
595
- * Results in:
596
- *
597
- * curly: ["warn", "multi"]
598
- */
599
- if (
600
-
601
- /*
602
- * If inline config for the rule has only severity
603
- */
604
- ruleOptions.length === 1 &&
605
-
606
- /*
607
- * And the rule was already configured
608
- */
609
- config.rules && Object.hasOwn(config.rules, name)
610
- ) {
611
-
612
- /*
613
- * Then use severity from the inline config and options from the provided config
614
- */
615
- ruleOptions = [
616
- ruleOptions[0], // severity from the inline config
617
- ...asArray(config.rules[name]).slice(1) // options from the provided config
618
- ];
619
- }
620
-
621
- try {
622
- validator.validateRuleOptions(rule, name, ruleOptions);
623
- } catch (err) {
624
-
625
- /*
626
- * If the rule has invalid `meta.schema`, throw the error because
627
- * this is not an invalid inline configuration but an invalid rule.
628
- */
629
- if (err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA") {
630
- throw err;
631
- }
632
-
633
- problems.push(createLintingProblem({
634
- ruleId: name,
635
- message: err.message,
636
- loc
637
- }));
638
-
639
- // do not apply the config, if found invalid options.
640
- return;
641
- }
642
-
643
- configuredRules[name] = ruleOptions;
644
- });
645
- } else {
646
- const problem = createLintingProblem({
647
- ruleId: null,
648
- loc,
649
- message: parseResult.error.message
650
- });
651
-
652
- problem.fatal = true;
653
- problems.push(problem);
654
- }
655
-
656
- break;
657
- }
658
-
659
- // no default
660
- }
661
- });
662
-
663
- return {
664
- configuredRules,
665
- enabledGlobals,
666
- exportedVariables,
667
- problems,
668
- disableDirectives
669
- };
500
+ function getDirectiveComments(
501
+ sourceCode,
502
+ ruleMapper,
503
+ warnInlineConfig,
504
+ config,
505
+ ) {
506
+ const configuredRules = {};
507
+ const enabledGlobals = Object.create(null);
508
+ const exportedVariables = {};
509
+ const problems = [];
510
+ const disableDirectives = [];
511
+ const validator = new ConfigValidator({
512
+ builtInRules: Rules,
513
+ });
514
+
515
+ sourceCode
516
+ .getInlineConfigNodes()
517
+ .filter(token => token.type !== "Shebang")
518
+ .forEach(comment => {
519
+ const directive = commentParser.parseDirective(comment.value);
520
+
521
+ if (!directive) {
522
+ return;
523
+ }
524
+
525
+ const {
526
+ label,
527
+ value,
528
+ justification: justificationPart,
529
+ } = directive;
530
+
531
+ const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(
532
+ label,
533
+ );
534
+
535
+ if (comment.type === "Line" && !lineCommentSupported) {
536
+ return;
537
+ }
538
+
539
+ const loc = sourceCode.getLoc(comment);
540
+
541
+ if (warnInlineConfig) {
542
+ const kind =
543
+ comment.type === "Block" ? `/*${label}*/` : `//${label}`;
544
+
545
+ problems.push(
546
+ createLintingProblem({
547
+ ruleId: null,
548
+ message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`,
549
+ loc,
550
+ severity: 1,
551
+ }),
552
+ );
553
+ return;
554
+ }
555
+
556
+ if (
557
+ label === "eslint-disable-line" &&
558
+ loc.start.line !== loc.end.line
559
+ ) {
560
+ const message = `${label} comment should not span multiple lines.`;
561
+
562
+ problems.push(
563
+ createLintingProblem({
564
+ ruleId: null,
565
+ message,
566
+ loc,
567
+ }),
568
+ );
569
+ return;
570
+ }
571
+
572
+ switch (label) {
573
+ case "eslint-disable":
574
+ case "eslint-enable":
575
+ case "eslint-disable-next-line":
576
+ case "eslint-disable-line": {
577
+ const directiveType = label.slice("eslint-".length);
578
+ const { directives, directiveProblems } =
579
+ createDisableDirectives(
580
+ {
581
+ type: directiveType,
582
+ value,
583
+ justification: justificationPart,
584
+ node: comment,
585
+ },
586
+ ruleMapper,
587
+ jslang,
588
+ sourceCode,
589
+ );
590
+
591
+ disableDirectives.push(...directives);
592
+ problems.push(...directiveProblems);
593
+ break;
594
+ }
595
+
596
+ case "exported":
597
+ Object.assign(
598
+ exportedVariables,
599
+ commentParser.parseListConfig(value),
600
+ );
601
+ break;
602
+
603
+ case "globals":
604
+ case "global":
605
+ for (const [id, idSetting] of Object.entries(
606
+ commentParser.parseStringConfig(value),
607
+ )) {
608
+ let normalizedValue;
609
+
610
+ try {
611
+ normalizedValue =
612
+ ConfigOps.normalizeConfigGlobal(idSetting);
613
+ } catch (err) {
614
+ problems.push(
615
+ createLintingProblem({
616
+ ruleId: null,
617
+ loc,
618
+ message: err.message,
619
+ }),
620
+ );
621
+ continue;
622
+ }
623
+
624
+ if (enabledGlobals[id]) {
625
+ enabledGlobals[id].comments.push(comment);
626
+ enabledGlobals[id].value = normalizedValue;
627
+ } else {
628
+ enabledGlobals[id] = {
629
+ comments: [comment],
630
+ value: normalizedValue,
631
+ };
632
+ }
633
+ }
634
+ break;
635
+
636
+ case "eslint": {
637
+ const parseResult =
638
+ commentParser.parseJSONLikeConfig(value);
639
+
640
+ if (parseResult.ok) {
641
+ Object.keys(parseResult.config).forEach(name => {
642
+ const rule = ruleMapper(name);
643
+ const ruleValue = parseResult.config[name];
644
+
645
+ if (!rule) {
646
+ problems.push(
647
+ createLintingProblem({ ruleId: name, loc }),
648
+ );
649
+ return;
650
+ }
651
+
652
+ if (Object.hasOwn(configuredRules, name)) {
653
+ problems.push(
654
+ createLintingProblem({
655
+ message: `Rule "${name}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
656
+ loc,
657
+ }),
658
+ );
659
+ return;
660
+ }
661
+
662
+ let ruleOptions = asArray(ruleValue);
663
+
664
+ /*
665
+ * If the rule was already configured, inline rule configuration that
666
+ * only has severity should retain options from the config and just override the severity.
667
+ *
668
+ * Example:
669
+ *
670
+ * {
671
+ * rules: {
672
+ * curly: ["error", "multi"]
673
+ * }
674
+ * }
675
+ *
676
+ * /* eslint curly: ["warn"] * /
677
+ *
678
+ * Results in:
679
+ *
680
+ * curly: ["warn", "multi"]
681
+ */
682
+ if (
683
+ /*
684
+ * If inline config for the rule has only severity
685
+ */
686
+ ruleOptions.length === 1 &&
687
+ /*
688
+ * And the rule was already configured
689
+ */
690
+ config.rules &&
691
+ Object.hasOwn(config.rules, name)
692
+ ) {
693
+ /*
694
+ * Then use severity from the inline config and options from the provided config
695
+ */
696
+ ruleOptions = [
697
+ ruleOptions[0], // severity from the inline config
698
+ ...asArray(config.rules[name]).slice(1), // options from the provided config
699
+ ];
700
+ }
701
+
702
+ try {
703
+ validator.validateRuleOptions(
704
+ rule,
705
+ name,
706
+ ruleOptions,
707
+ );
708
+ } catch (err) {
709
+ /*
710
+ * If the rule has invalid `meta.schema`, throw the error because
711
+ * this is not an invalid inline configuration but an invalid rule.
712
+ */
713
+ if (
714
+ err.code ===
715
+ "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
716
+ ) {
717
+ throw err;
718
+ }
719
+
720
+ problems.push(
721
+ createLintingProblem({
722
+ ruleId: name,
723
+ message: err.message,
724
+ loc,
725
+ }),
726
+ );
727
+
728
+ // do not apply the config, if found invalid options.
729
+ return;
730
+ }
731
+
732
+ configuredRules[name] = ruleOptions;
733
+ });
734
+ } else {
735
+ const problem = createLintingProblem({
736
+ ruleId: null,
737
+ loc,
738
+ message: parseResult.error.message,
739
+ });
740
+
741
+ problem.fatal = true;
742
+ problems.push(problem);
743
+ }
744
+
745
+ break;
746
+ }
747
+
748
+ // no default
749
+ }
750
+ });
751
+
752
+ return {
753
+ configuredRules,
754
+ enabledGlobals,
755
+ exportedVariables,
756
+ problems,
757
+ disableDirectives,
758
+ };
670
759
  }
671
760
 
672
761
  /**
@@ -678,32 +767,39 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config)
678
767
  * A collection of the directive comments that were found, along with any problems that occurred when parsing
679
768
  */
680
769
  function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper, language) {
681
- const disableDirectives = [];
682
- const problems = [];
683
-
684
- if (sourceCode.getDisableDirectives) {
685
- const {
686
- directives: directivesSources,
687
- problems: directivesProblems
688
- } = sourceCode.getDisableDirectives();
689
-
690
- problems.push(...directivesProblems.map(directiveProblem => createLintingProblem({
691
- ...directiveProblem,
692
- language
693
- })));
694
-
695
- directivesSources.forEach(directive => {
696
- const { directives, directiveProblems } = createDisableDirectives(directive, ruleMapper, language, sourceCode);
697
-
698
- disableDirectives.push(...directives);
699
- problems.push(...directiveProblems);
700
- });
701
- }
702
-
703
- return {
704
- problems,
705
- disableDirectives
706
- };
770
+ const disableDirectives = [];
771
+ const problems = [];
772
+
773
+ if (sourceCode.getDisableDirectives) {
774
+ const { directives: directivesSources, problems: directivesProblems } =
775
+ sourceCode.getDisableDirectives();
776
+
777
+ problems.push(
778
+ ...directivesProblems.map(directiveProblem =>
779
+ createLintingProblem({
780
+ ...directiveProblem,
781
+ language,
782
+ }),
783
+ ),
784
+ );
785
+
786
+ directivesSources.forEach(directive => {
787
+ const { directives, directiveProblems } = createDisableDirectives(
788
+ directive,
789
+ ruleMapper,
790
+ language,
791
+ sourceCode,
792
+ );
793
+
794
+ disableDirectives.push(...directives);
795
+ problems.push(...directiveProblems);
796
+ });
797
+ }
798
+
799
+ return {
800
+ problems,
801
+ disableDirectives,
802
+ };
707
803
  }
708
804
 
709
805
  /**
@@ -713,18 +809,17 @@ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper, language) {
713
809
  * @returns {number} normalized ECMAScript version
714
810
  */
715
811
  function normalizeEcmaVersion(parser, ecmaVersion) {
716
-
717
- if (isEspree(parser)) {
718
- if (ecmaVersion === "latest") {
719
- return espree.latestEcmaVersion;
720
- }
721
- }
722
-
723
- /*
724
- * Calculate ECMAScript edition number from official year version starting with
725
- * ES2015, which corresponds with ES6 (or a difference of 2009).
726
- */
727
- return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
812
+ if (isEspree(parser)) {
813
+ if (ecmaVersion === "latest") {
814
+ return espree.latestEcmaVersion;
815
+ }
816
+ }
817
+
818
+ /*
819
+ * Calculate ECMAScript edition number from official year version starting with
820
+ * ES2015, which corresponds with ES6 (or a difference of 2009).
821
+ */
822
+ return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
728
823
  }
729
824
 
730
825
  /**
@@ -734,29 +829,28 @@ function normalizeEcmaVersion(parser, ecmaVersion) {
734
829
  * @returns {number} normalized ECMAScript version
735
830
  */
736
831
  function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
737
-
738
- switch (ecmaVersion) {
739
- case 3:
740
- return 3;
741
-
742
- // void 0 = no ecmaVersion specified so use the default
743
- case 5:
744
- case void 0:
745
- return 5;
746
-
747
- default:
748
- if (typeof ecmaVersion === "number") {
749
- return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
750
- }
751
- }
752
-
753
- /*
754
- * We default to the latest supported ecmaVersion for everything else.
755
- * Remember, this is for languageOptions.ecmaVersion, which sets the version
756
- * that is used for a number of processes inside of ESLint. It's normally
757
- * safe to assume people want the latest unless otherwise specified.
758
- */
759
- return LATEST_ECMA_VERSION;
832
+ switch (ecmaVersion) {
833
+ case 3:
834
+ return 3;
835
+
836
+ // void 0 = no ecmaVersion specified so use the default
837
+ case 5:
838
+ case void 0:
839
+ return 5;
840
+
841
+ default:
842
+ if (typeof ecmaVersion === "number") {
843
+ return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
844
+ }
845
+ }
846
+
847
+ /*
848
+ * We default to the latest supported ecmaVersion for everything else.
849
+ * Remember, this is for languageOptions.ecmaVersion, which sets the version
850
+ * that is used for a number of processes inside of ESLint. It's normally
851
+ * safe to assume people want the latest unless otherwise specified.
852
+ */
853
+ return LATEST_ECMA_VERSION;
760
854
  }
761
855
 
762
856
  const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)(?:\*\/|$)/gsu;
@@ -767,20 +861,22 @@ const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)(?:\*\/|$)/gsu;
767
861
  * @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment.
768
862
  */
769
863
  function findEslintEnv(text) {
770
- let match, retv;
771
-
772
- eslintEnvPattern.lastIndex = 0;
773
-
774
- while ((match = eslintEnvPattern.exec(text)) !== null) {
775
- if (match[0].endsWith("*/")) {
776
- retv = Object.assign(
777
- retv || {},
778
- commentParser.parseListConfig(commentParser.parseDirective(match[0].slice(2, -2)).value)
779
- );
780
- }
781
- }
782
-
783
- return retv;
864
+ let match, retv;
865
+
866
+ eslintEnvPattern.lastIndex = 0;
867
+
868
+ while ((match = eslintEnvPattern.exec(text)) !== null) {
869
+ if (match[0].endsWith("*/")) {
870
+ retv = Object.assign(
871
+ retv || {},
872
+ commentParser.parseListConfig(
873
+ commentParser.parseDirective(match[0].slice(2, -2)).value,
874
+ ),
875
+ );
876
+ }
877
+ }
878
+
879
+ return retv;
784
880
  }
785
881
 
786
882
  /**
@@ -796,10 +892,10 @@ function findEslintEnv(text) {
796
892
  * @returns {string} The normalized filename.
797
893
  */
798
894
  function normalizeFilename(filename) {
799
- const parts = filename.split(path.sep);
800
- const index = parts.lastIndexOf("<text>");
895
+ const parts = filename.split(path.sep);
896
+ const index = parts.lastIndexOf("<text>");
801
897
 
802
- return index === -1 ? filename : parts.slice(index).join(path.sep);
898
+ return index === -1 ? filename : parts.slice(index).join(path.sep);
803
899
  }
804
900
 
805
901
  /**
@@ -810,49 +906,63 @@ function normalizeFilename(filename) {
810
906
  * @returns {Required<VerifyOptions> & InternalOptions} Normalized options
811
907
  */
812
908
  function normalizeVerifyOptions(providedOptions, config) {
813
-
814
- const linterOptions = config.linterOptions || config;
815
-
816
- // .noInlineConfig for eslintrc, .linterOptions.noInlineConfig for flat
817
- const disableInlineConfig = linterOptions.noInlineConfig === true;
818
- const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
819
- const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
820
- ? ` (${config.configNameOfNoInlineConfig})`
821
- : "";
822
-
823
- let reportUnusedDisableDirectives = providedOptions.reportUnusedDisableDirectives;
824
-
825
- if (typeof reportUnusedDisableDirectives === "boolean") {
826
- reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
827
- }
828
- if (typeof reportUnusedDisableDirectives !== "string") {
829
- if (typeof linterOptions.reportUnusedDisableDirectives === "boolean") {
830
- reportUnusedDisableDirectives = linterOptions.reportUnusedDisableDirectives ? "warn" : "off";
831
- } else {
832
- reportUnusedDisableDirectives = linterOptions.reportUnusedDisableDirectives === void 0 ? "off" : normalizeSeverityToString(linterOptions.reportUnusedDisableDirectives);
833
- }
834
- }
835
-
836
- const reportUnusedInlineConfigs = linterOptions.reportUnusedInlineConfigs === void 0 ? "off" : normalizeSeverityToString(linterOptions.reportUnusedInlineConfigs);
837
-
838
- let ruleFilter = providedOptions.ruleFilter;
839
-
840
- if (typeof ruleFilter !== "function") {
841
- ruleFilter = () => true;
842
- }
843
-
844
- return {
845
- filename: normalizeFilename(providedOptions.filename || "<input>"),
846
- allowInlineConfig: !ignoreInlineConfig,
847
- warnInlineConfig: disableInlineConfig && !ignoreInlineConfig
848
- ? `your config${configNameOfNoInlineConfig}`
849
- : null,
850
- reportUnusedDisableDirectives,
851
- reportUnusedInlineConfigs,
852
- disableFixes: Boolean(providedOptions.disableFixes),
853
- stats: providedOptions.stats,
854
- ruleFilter
855
- };
909
+ const linterOptions = config.linterOptions || config;
910
+
911
+ // .noInlineConfig for eslintrc, .linterOptions.noInlineConfig for flat
912
+ const disableInlineConfig = linterOptions.noInlineConfig === true;
913
+ const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
914
+ const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
915
+ ? ` (${config.configNameOfNoInlineConfig})`
916
+ : "";
917
+
918
+ let reportUnusedDisableDirectives =
919
+ providedOptions.reportUnusedDisableDirectives;
920
+
921
+ if (typeof reportUnusedDisableDirectives === "boolean") {
922
+ reportUnusedDisableDirectives = reportUnusedDisableDirectives
923
+ ? "error"
924
+ : "off";
925
+ }
926
+ if (typeof reportUnusedDisableDirectives !== "string") {
927
+ if (typeof linterOptions.reportUnusedDisableDirectives === "boolean") {
928
+ reportUnusedDisableDirectives =
929
+ linterOptions.reportUnusedDisableDirectives ? "warn" : "off";
930
+ } else {
931
+ reportUnusedDisableDirectives =
932
+ linterOptions.reportUnusedDisableDirectives === void 0
933
+ ? "off"
934
+ : normalizeSeverityToString(
935
+ linterOptions.reportUnusedDisableDirectives,
936
+ );
937
+ }
938
+ }
939
+
940
+ const reportUnusedInlineConfigs =
941
+ linterOptions.reportUnusedInlineConfigs === void 0
942
+ ? "off"
943
+ : normalizeSeverityToString(
944
+ linterOptions.reportUnusedInlineConfigs,
945
+ );
946
+
947
+ let ruleFilter = providedOptions.ruleFilter;
948
+
949
+ if (typeof ruleFilter !== "function") {
950
+ ruleFilter = () => true;
951
+ }
952
+
953
+ return {
954
+ filename: normalizeFilename(providedOptions.filename || "<input>"),
955
+ allowInlineConfig: !ignoreInlineConfig,
956
+ warnInlineConfig:
957
+ disableInlineConfig && !ignoreInlineConfig
958
+ ? `your config${configNameOfNoInlineConfig}`
959
+ : null,
960
+ reportUnusedDisableDirectives,
961
+ reportUnusedInlineConfigs,
962
+ disableFixes: Boolean(providedOptions.disableFixes),
963
+ stats: providedOptions.stats,
964
+ ruleFilter,
965
+ };
856
966
  }
857
967
 
858
968
  /**
@@ -863,25 +973,36 @@ function normalizeVerifyOptions(providedOptions, config) {
863
973
  * @returns {ParserOptions} Resulting parser options after merge
864
974
  */
865
975
  function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
866
-
867
- const parserOptionsFromEnv = enabledEnvironments
868
- .filter(env => env.parserOptions)
869
- .reduce((parserOptions, env) => merge(parserOptions, env.parserOptions), {});
870
- const mergedParserOptions = merge(parserOptionsFromEnv, providedOptions || {});
871
- const isModule = mergedParserOptions.sourceType === "module";
872
-
873
- if (isModule) {
874
-
875
- /*
876
- * can't have global return inside of modules
877
- * TODO: espree validate parserOptions.globalReturn when sourceType is setting to module.(@aladdin-add)
878
- */
879
- mergedParserOptions.ecmaFeatures = Object.assign({}, mergedParserOptions.ecmaFeatures, { globalReturn: false });
880
- }
881
-
882
- mergedParserOptions.ecmaVersion = normalizeEcmaVersion(parser, mergedParserOptions.ecmaVersion);
883
-
884
- return mergedParserOptions;
976
+ const parserOptionsFromEnv = enabledEnvironments
977
+ .filter(env => env.parserOptions)
978
+ .reduce(
979
+ (parserOptions, env) => merge(parserOptions, env.parserOptions),
980
+ {},
981
+ );
982
+ const mergedParserOptions = merge(
983
+ parserOptionsFromEnv,
984
+ providedOptions || {},
985
+ );
986
+ const isModule = mergedParserOptions.sourceType === "module";
987
+
988
+ if (isModule) {
989
+ /*
990
+ * can't have global return inside of modules
991
+ * TODO: espree validate parserOptions.globalReturn when sourceType is setting to module.(@aladdin-add)
992
+ */
993
+ mergedParserOptions.ecmaFeatures = Object.assign(
994
+ {},
995
+ mergedParserOptions.ecmaFeatures,
996
+ { globalReturn: false },
997
+ );
998
+ }
999
+
1000
+ mergedParserOptions.ecmaVersion = normalizeEcmaVersion(
1001
+ parser,
1002
+ mergedParserOptions.ecmaVersion,
1003
+ );
1004
+
1005
+ return mergedParserOptions;
885
1006
  }
886
1007
 
887
1008
  /**
@@ -892,20 +1013,20 @@ function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
892
1013
  * @param {ParserOptions} config.parserOptions The parserOptions to use.
893
1014
  * @returns {LanguageOptions} The languageOptions equivalent.
894
1015
  */
895
- function createLanguageOptions({ globals: configuredGlobals, parser, parserOptions }) {
896
-
897
- const {
898
- ecmaVersion,
899
- sourceType
900
- } = parserOptions;
901
-
902
- return {
903
- globals: configuredGlobals,
904
- ecmaVersion: normalizeEcmaVersionForLanguageOptions(ecmaVersion),
905
- sourceType,
906
- parser,
907
- parserOptions
908
- };
1016
+ function createLanguageOptions({
1017
+ globals: configuredGlobals,
1018
+ parser,
1019
+ parserOptions,
1020
+ }) {
1021
+ const { ecmaVersion, sourceType } = parserOptions;
1022
+
1023
+ return {
1024
+ globals: configuredGlobals,
1025
+ ecmaVersion: normalizeEcmaVersionForLanguageOptions(ecmaVersion),
1026
+ sourceType,
1027
+ parser,
1028
+ parserOptions,
1029
+ };
909
1030
  }
910
1031
 
911
1032
  /**
@@ -915,11 +1036,13 @@ function createLanguageOptions({ globals: configuredGlobals, parser, parserOptio
915
1036
  * @returns {Record<string, GlobalConf>} The resolved globals object
916
1037
  */
917
1038
  function resolveGlobals(providedGlobals, enabledEnvironments) {
918
- return Object.assign(
919
- Object.create(null),
920
- ...enabledEnvironments.filter(env => env.globals).map(env => env.globals),
921
- providedGlobals
922
- );
1039
+ return Object.assign(
1040
+ Object.create(null),
1041
+ ...enabledEnvironments
1042
+ .filter(env => env.globals)
1043
+ .map(env => env.globals),
1044
+ providedGlobals,
1045
+ );
923
1046
  }
924
1047
 
925
1048
  /**
@@ -930,26 +1053,26 @@ function resolveGlobals(providedGlobals, enabledEnvironments) {
930
1053
  * @returns {void}
931
1054
  */
932
1055
  function storeTime(time, timeOpts, slots) {
933
- const { type, key } = timeOpts;
934
-
935
- if (!slots.times) {
936
- slots.times = { passes: [{}] };
937
- }
938
-
939
- const passIndex = slots.fixPasses;
940
-
941
- if (passIndex > slots.times.passes.length - 1) {
942
- slots.times.passes.push({});
943
- }
944
-
945
- if (key) {
946
- slots.times.passes[passIndex][type] ??= {};
947
- slots.times.passes[passIndex][type][key] ??= { total: 0 };
948
- slots.times.passes[passIndex][type][key].total += time;
949
- } else {
950
- slots.times.passes[passIndex][type] ??= { total: 0 };
951
- slots.times.passes[passIndex][type].total += time;
952
- }
1056
+ const { type, key } = timeOpts;
1057
+
1058
+ if (!slots.times) {
1059
+ slots.times = { passes: [{}] };
1060
+ }
1061
+
1062
+ const passIndex = slots.fixPasses;
1063
+
1064
+ if (passIndex > slots.times.passes.length - 1) {
1065
+ slots.times.passes.push({});
1066
+ }
1067
+
1068
+ if (key) {
1069
+ slots.times.passes[passIndex][type] ??= {};
1070
+ slots.times.passes[passIndex][type][key] ??= { total: 0 };
1071
+ slots.times.passes[passIndex][type][key].total += time;
1072
+ } else {
1073
+ slots.times.passes[passIndex][type] ??= { total: 0 };
1074
+ slots.times.passes[passIndex][type].total += time;
1075
+ }
953
1076
  }
954
1077
 
955
1078
  /**
@@ -959,10 +1082,10 @@ function storeTime(time, timeOpts, slots) {
959
1082
  * @returns {Array} of rule options, empty Array if none
960
1083
  */
961
1084
  function getRuleOptions(ruleConfig, defaultOptions) {
962
- if (Array.isArray(ruleConfig)) {
963
- return deepMergeArrays(defaultOptions, ruleConfig.slice(1));
964
- }
965
- return defaultOptions ?? [];
1085
+ if (Array.isArray(ruleConfig)) {
1086
+ return deepMergeArrays(defaultOptions, ruleConfig.slice(1));
1087
+ }
1088
+ return defaultOptions ?? [];
966
1089
  }
967
1090
 
968
1091
  /**
@@ -973,19 +1096,19 @@ function getRuleOptions(ruleConfig, defaultOptions) {
973
1096
  * @returns {ScopeManager} The analysis result.
974
1097
  */
975
1098
  function analyzeScope(ast, languageOptions, visitorKeys) {
976
- const parserOptions = languageOptions.parserOptions;
977
- const ecmaFeatures = parserOptions.ecmaFeatures || {};
978
- const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
979
-
980
- return eslintScope.analyze(ast, {
981
- ignoreEval: true,
982
- nodejsScope: ecmaFeatures.globalReturn,
983
- impliedStrict: ecmaFeatures.impliedStrict,
984
- ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
985
- sourceType: languageOptions.sourceType || "script",
986
- childVisitorKeys: visitorKeys || evk.KEYS,
987
- fallback: Traverser.getKeys
988
- });
1099
+ const parserOptions = languageOptions.parserOptions;
1100
+ const ecmaFeatures = parserOptions.ecmaFeatures || {};
1101
+ const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
1102
+
1103
+ return eslintScope.analyze(ast, {
1104
+ ignoreEval: true,
1105
+ nodejsScope: ecmaFeatures.globalReturn,
1106
+ impliedStrict: ecmaFeatures.impliedStrict,
1107
+ ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
1108
+ sourceType: languageOptions.sourceType || "script",
1109
+ childVisitorKeys: visitorKeys || evk.KEYS,
1110
+ fallback: Traverser.getKeys,
1111
+ });
989
1112
  }
990
1113
 
991
1114
  /**
@@ -997,17 +1120,22 @@ function analyzeScope(ast, languageOptions, visitorKeys) {
997
1120
  * @returns {Object} A map of selector listeners provided by the rule
998
1121
  */
999
1122
  function createRuleListeners(rule, ruleContext) {
1000
-
1001
- if (!rule || typeof rule !== "object" || typeof rule.create !== "function") {
1002
- throw new TypeError(`Error while loading rule '${ruleContext.id}': Rule must be an object with a \`create\` method`);
1003
- }
1004
-
1005
- try {
1006
- return rule.create(ruleContext);
1007
- } catch (ex) {
1008
- ex.message = `Error while loading rule '${ruleContext.id}': ${ex.message}`;
1009
- throw ex;
1010
- }
1123
+ if (
1124
+ !rule ||
1125
+ typeof rule !== "object" ||
1126
+ typeof rule.create !== "function"
1127
+ ) {
1128
+ throw new TypeError(
1129
+ `Error while loading rule '${ruleContext.id}': Rule must be an object with a \`create\` method`,
1130
+ );
1131
+ }
1132
+
1133
+ try {
1134
+ return rule.create(ruleContext);
1135
+ } catch (ex) {
1136
+ ex.message = `Error while loading rule '${ruleContext.id}': ${ex.message}`;
1137
+ throw ex;
1138
+ }
1011
1139
  }
1012
1140
 
1013
1141
  /**
@@ -1031,199 +1159,230 @@ function createRuleListeners(rule, ruleContext) {
1031
1159
  * @throws {Error} If traversal into a node fails.
1032
1160
  */
1033
1161
  function runRules(
1034
- sourceCode,
1035
- configuredRules,
1036
- ruleMapper,
1037
- parserName,
1038
- language,
1039
- languageOptions,
1040
- settings,
1041
- filename,
1042
- applyDefaultOptions,
1043
- disableFixes,
1044
- cwd,
1045
- physicalFilename,
1046
- ruleFilter,
1047
- stats,
1048
- slots
1162
+ sourceCode,
1163
+ configuredRules,
1164
+ ruleMapper,
1165
+ parserName,
1166
+ language,
1167
+ languageOptions,
1168
+ settings,
1169
+ filename,
1170
+ applyDefaultOptions,
1171
+ disableFixes,
1172
+ cwd,
1173
+ physicalFilename,
1174
+ ruleFilter,
1175
+ stats,
1176
+ slots,
1049
1177
  ) {
1050
- const emitter = createEmitter();
1051
-
1052
- // must happen first to assign all node.parent properties
1053
- const eventQueue = sourceCode.traverse();
1054
-
1055
- /*
1056
- * Create a frozen object with the ruleContext properties and methods that are shared by all rules.
1057
- * All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
1058
- * properties once for each rule.
1059
- */
1060
- const sharedTraversalContext = new FileContext({
1061
- cwd,
1062
- filename,
1063
- physicalFilename: physicalFilename || filename,
1064
- sourceCode,
1065
- parserOptions: {
1066
- ...languageOptions.parserOptions
1067
- },
1068
- parserPath: parserName,
1069
- languageOptions,
1070
- settings
1071
- });
1072
-
1073
- const lintingProblems = [];
1074
-
1075
- Object.keys(configuredRules).forEach(ruleId => {
1076
- const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
1077
-
1078
- // not load disabled rules
1079
- if (severity === 0) {
1080
- return;
1081
- }
1082
-
1083
- if (ruleFilter && !ruleFilter({ ruleId, severity })) {
1084
- return;
1085
- }
1086
-
1087
- const rule = ruleMapper(ruleId);
1088
-
1089
- if (!rule) {
1090
- lintingProblems.push(createLintingProblem({ ruleId, language }));
1091
- return;
1092
- }
1093
-
1094
- const messageIds = rule.meta && rule.meta.messages;
1095
- let reportTranslator = null;
1096
- const ruleContext = Object.freeze(
1097
- Object.assign(
1098
- Object.create(sharedTraversalContext),
1099
- {
1100
- id: ruleId,
1101
- options: getRuleOptions(configuredRules[ruleId], applyDefaultOptions ? rule.meta?.defaultOptions : void 0),
1102
- report(...args) {
1103
-
1104
- /*
1105
- * Create a report translator lazily.
1106
- * In a vast majority of cases, any given rule reports zero errors on a given
1107
- * piece of code. Creating a translator lazily avoids the performance cost of
1108
- * creating a new translator function for each rule that usually doesn't get
1109
- * called.
1110
- *
1111
- * Using lazy report translators improves end-to-end performance by about 3%
1112
- * with Node 8.4.0.
1113
- */
1114
- if (reportTranslator === null) {
1115
- reportTranslator = createReportTranslator({
1116
- ruleId,
1117
- severity,
1118
- sourceCode,
1119
- messageIds,
1120
- disableFixes,
1121
- language
1122
- });
1123
- }
1124
- const problem = reportTranslator(...args);
1125
-
1126
- if (problem.fix && !(rule.meta && rule.meta.fixable)) {
1127
- throw new Error("Fixable rules must set the `meta.fixable` property to \"code\" or \"whitespace\".");
1128
- }
1129
- if (problem.suggestions && !(rule.meta && rule.meta.hasSuggestions === true)) {
1130
- if (rule.meta && rule.meta.docs && typeof rule.meta.docs.suggestion !== "undefined") {
1131
-
1132
- // Encourage migration from the former property name.
1133
- throw new Error("Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.");
1134
- }
1135
- throw new Error("Rules with suggestions must set the `meta.hasSuggestions` property to `true`.");
1136
- }
1137
- lintingProblems.push(problem);
1138
- }
1139
- }
1140
- )
1141
- );
1142
-
1143
- const ruleListenersReturn = (timing.enabled || stats)
1144
- ? timing.time(ruleId, createRuleListeners, stats)(rule, ruleContext) : createRuleListeners(rule, ruleContext);
1145
-
1146
- const ruleListeners = stats ? ruleListenersReturn.result : ruleListenersReturn;
1147
-
1148
- if (stats) {
1149
- storeTime(ruleListenersReturn.tdiff, { type: "rules", key: ruleId }, slots);
1150
- }
1151
-
1152
- /**
1153
- * Include `ruleId` in error logs
1154
- * @param {Function} ruleListener A rule method that listens for a node.
1155
- * @returns {Function} ruleListener wrapped in error handler
1156
- */
1157
- function addRuleErrorHandler(ruleListener) {
1158
- return function ruleErrorHandler(...listenerArgs) {
1159
- try {
1160
- const ruleListenerReturn = ruleListener(...listenerArgs);
1161
-
1162
- const ruleListenerResult = stats ? ruleListenerReturn.result : ruleListenerReturn;
1163
-
1164
- if (stats) {
1165
- storeTime(ruleListenerReturn.tdiff, { type: "rules", key: ruleId }, slots);
1166
- }
1167
-
1168
- return ruleListenerResult;
1169
- } catch (e) {
1170
- e.ruleId = ruleId;
1171
- throw e;
1172
- }
1173
- };
1174
- }
1175
-
1176
- if (typeof ruleListeners === "undefined" || ruleListeners === null) {
1177
- throw new Error(`The create() function for rule '${ruleId}' did not return an object.`);
1178
- }
1179
-
1180
- // add all the selectors from the rule as listeners
1181
- Object.keys(ruleListeners).forEach(selector => {
1182
- const ruleListener = (timing.enabled || stats)
1183
- ? timing.time(ruleId, ruleListeners[selector], stats) : ruleListeners[selector];
1184
-
1185
- emitter.on(
1186
- selector,
1187
- addRuleErrorHandler(ruleListener)
1188
- );
1189
- });
1190
- });
1191
-
1192
- const eventGenerator = new NodeEventGenerator(emitter, {
1193
- visitorKeys: sourceCode.visitorKeys ?? language.visitorKeys,
1194
- fallback: Traverser.getKeys,
1195
- matchClass: language.matchesSelectorClass ?? (() => false),
1196
- nodeTypeKey: language.nodeTypeKey
1197
- });
1198
-
1199
- for (const step of eventQueue) {
1200
- switch (step.kind) {
1201
- case STEP_KIND_VISIT: {
1202
- try {
1203
- if (step.phase === 1) {
1204
- eventGenerator.enterNode(step.target);
1205
- } else {
1206
- eventGenerator.leaveNode(step.target);
1207
- }
1208
- } catch (err) {
1209
- err.currentNode = step.target;
1210
- throw err;
1211
- }
1212
- break;
1213
- }
1214
-
1215
- case STEP_KIND_CALL: {
1216
- emitter.emit(step.target, ...step.args);
1217
- break;
1218
- }
1219
-
1220
- default:
1221
- throw new Error(`Invalid traversal step found: "${step.type}".`);
1222
- }
1223
-
1224
- }
1225
-
1226
- return lintingProblems;
1178
+ const emitter = createEmitter();
1179
+
1180
+ // must happen first to assign all node.parent properties
1181
+ const eventQueue = sourceCode.traverse();
1182
+
1183
+ /*
1184
+ * Create a frozen object with the ruleContext properties and methods that are shared by all rules.
1185
+ * All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
1186
+ * properties once for each rule.
1187
+ */
1188
+ const sharedTraversalContext = new FileContext({
1189
+ cwd,
1190
+ filename,
1191
+ physicalFilename: physicalFilename || filename,
1192
+ sourceCode,
1193
+ parserOptions: {
1194
+ ...languageOptions.parserOptions,
1195
+ },
1196
+ parserPath: parserName,
1197
+ languageOptions,
1198
+ settings,
1199
+ });
1200
+
1201
+ const lintingProblems = [];
1202
+
1203
+ Object.keys(configuredRules).forEach(ruleId => {
1204
+ const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
1205
+
1206
+ // not load disabled rules
1207
+ if (severity === 0) {
1208
+ return;
1209
+ }
1210
+
1211
+ if (ruleFilter && !ruleFilter({ ruleId, severity })) {
1212
+ return;
1213
+ }
1214
+
1215
+ const rule = ruleMapper(ruleId);
1216
+
1217
+ if (!rule) {
1218
+ lintingProblems.push(createLintingProblem({ ruleId, language }));
1219
+ return;
1220
+ }
1221
+
1222
+ const messageIds = rule.meta && rule.meta.messages;
1223
+ let reportTranslator = null;
1224
+ const ruleContext = Object.freeze(
1225
+ Object.assign(Object.create(sharedTraversalContext), {
1226
+ id: ruleId,
1227
+ options: getRuleOptions(
1228
+ configuredRules[ruleId],
1229
+ applyDefaultOptions ? rule.meta?.defaultOptions : void 0,
1230
+ ),
1231
+ report(...args) {
1232
+ /*
1233
+ * Create a report translator lazily.
1234
+ * In a vast majority of cases, any given rule reports zero errors on a given
1235
+ * piece of code. Creating a translator lazily avoids the performance cost of
1236
+ * creating a new translator function for each rule that usually doesn't get
1237
+ * called.
1238
+ *
1239
+ * Using lazy report translators improves end-to-end performance by about 3%
1240
+ * with Node 8.4.0.
1241
+ */
1242
+ if (reportTranslator === null) {
1243
+ reportTranslator = createReportTranslator({
1244
+ ruleId,
1245
+ severity,
1246
+ sourceCode,
1247
+ messageIds,
1248
+ disableFixes,
1249
+ language,
1250
+ });
1251
+ }
1252
+ const problem = reportTranslator(...args);
1253
+
1254
+ if (problem.fix && !(rule.meta && rule.meta.fixable)) {
1255
+ throw new Error(
1256
+ 'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".',
1257
+ );
1258
+ }
1259
+ if (
1260
+ problem.suggestions &&
1261
+ !(rule.meta && rule.meta.hasSuggestions === true)
1262
+ ) {
1263
+ if (
1264
+ rule.meta &&
1265
+ rule.meta.docs &&
1266
+ typeof rule.meta.docs.suggestion !== "undefined"
1267
+ ) {
1268
+ // Encourage migration from the former property name.
1269
+ throw new Error(
1270
+ "Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
1271
+ );
1272
+ }
1273
+ throw new Error(
1274
+ "Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
1275
+ );
1276
+ }
1277
+ lintingProblems.push(problem);
1278
+ },
1279
+ }),
1280
+ );
1281
+
1282
+ const ruleListenersReturn =
1283
+ timing.enabled || stats
1284
+ ? timing.time(
1285
+ ruleId,
1286
+ createRuleListeners,
1287
+ stats,
1288
+ )(rule, ruleContext)
1289
+ : createRuleListeners(rule, ruleContext);
1290
+
1291
+ const ruleListeners = stats
1292
+ ? ruleListenersReturn.result
1293
+ : ruleListenersReturn;
1294
+
1295
+ if (stats) {
1296
+ storeTime(
1297
+ ruleListenersReturn.tdiff,
1298
+ { type: "rules", key: ruleId },
1299
+ slots,
1300
+ );
1301
+ }
1302
+
1303
+ /**
1304
+ * Include `ruleId` in error logs
1305
+ * @param {Function} ruleListener A rule method that listens for a node.
1306
+ * @returns {Function} ruleListener wrapped in error handler
1307
+ */
1308
+ function addRuleErrorHandler(ruleListener) {
1309
+ return function ruleErrorHandler(...listenerArgs) {
1310
+ try {
1311
+ const ruleListenerReturn = ruleListener(...listenerArgs);
1312
+
1313
+ const ruleListenerResult = stats
1314
+ ? ruleListenerReturn.result
1315
+ : ruleListenerReturn;
1316
+
1317
+ if (stats) {
1318
+ storeTime(
1319
+ ruleListenerReturn.tdiff,
1320
+ { type: "rules", key: ruleId },
1321
+ slots,
1322
+ );
1323
+ }
1324
+
1325
+ return ruleListenerResult;
1326
+ } catch (e) {
1327
+ e.ruleId = ruleId;
1328
+ throw e;
1329
+ }
1330
+ };
1331
+ }
1332
+
1333
+ if (typeof ruleListeners === "undefined" || ruleListeners === null) {
1334
+ throw new Error(
1335
+ `The create() function for rule '${ruleId}' did not return an object.`,
1336
+ );
1337
+ }
1338
+
1339
+ // add all the selectors from the rule as listeners
1340
+ Object.keys(ruleListeners).forEach(selector => {
1341
+ const ruleListener =
1342
+ timing.enabled || stats
1343
+ ? timing.time(ruleId, ruleListeners[selector], stats)
1344
+ : ruleListeners[selector];
1345
+
1346
+ emitter.on(selector, addRuleErrorHandler(ruleListener));
1347
+ });
1348
+ });
1349
+
1350
+ const eventGenerator = new NodeEventGenerator(emitter, {
1351
+ visitorKeys: sourceCode.visitorKeys ?? language.visitorKeys,
1352
+ fallback: Traverser.getKeys,
1353
+ matchClass: language.matchesSelectorClass ?? (() => false),
1354
+ nodeTypeKey: language.nodeTypeKey,
1355
+ });
1356
+
1357
+ for (const step of eventQueue) {
1358
+ switch (step.kind) {
1359
+ case STEP_KIND_VISIT: {
1360
+ try {
1361
+ if (step.phase === 1) {
1362
+ eventGenerator.enterNode(step.target);
1363
+ } else {
1364
+ eventGenerator.leaveNode(step.target);
1365
+ }
1366
+ } catch (err) {
1367
+ err.currentNode = step.target;
1368
+ throw err;
1369
+ }
1370
+ break;
1371
+ }
1372
+
1373
+ case STEP_KIND_CALL: {
1374
+ emitter.emit(step.target, ...step.args);
1375
+ break;
1376
+ }
1377
+
1378
+ default:
1379
+ throw new Error(
1380
+ `Invalid traversal step found: "${step.type}".`,
1381
+ );
1382
+ }
1383
+ }
1384
+
1385
+ return lintingProblems;
1227
1386
  }
1228
1387
 
1229
1388
  /**
@@ -1232,14 +1391,14 @@ function runRules(
1232
1391
  * @returns {string} The source code text.
1233
1392
  */
1234
1393
  function ensureText(textOrSourceCode) {
1235
- if (typeof textOrSourceCode === "object") {
1236
- const { hasBOM, text } = textOrSourceCode;
1237
- const bom = hasBOM ? "\uFEFF" : "";
1394
+ if (typeof textOrSourceCode === "object") {
1395
+ const { hasBOM, text } = textOrSourceCode;
1396
+ const bom = hasBOM ? "\uFEFF" : "";
1238
1397
 
1239
- return bom + text;
1240
- }
1398
+ return bom + text;
1399
+ }
1241
1400
 
1242
- return String(textOrSourceCode);
1401
+ return String(textOrSourceCode);
1243
1402
  }
1244
1403
 
1245
1404
  /**
@@ -1249,11 +1408,12 @@ function ensureText(textOrSourceCode) {
1249
1408
  * @returns {Environment|null} The environment.
1250
1409
  */
1251
1410
  function getEnv(slots, envId) {
1252
- return (
1253
- (slots.lastConfigArray && slots.lastConfigArray.pluginEnvironments.get(envId)) ||
1254
- BuiltInEnvironments.get(envId) ||
1255
- null
1256
- );
1411
+ return (
1412
+ (slots.lastConfigArray &&
1413
+ slots.lastConfigArray.pluginEnvironments.get(envId)) ||
1414
+ BuiltInEnvironments.get(envId) ||
1415
+ null
1416
+ );
1257
1417
  }
1258
1418
 
1259
1419
  /**
@@ -1263,10 +1423,11 @@ function getEnv(slots, envId) {
1263
1423
  * @returns {Rule|null} The rule.
1264
1424
  */
1265
1425
  function getRule(slots, ruleId) {
1266
- return (
1267
- (slots.lastConfigArray && slots.lastConfigArray.pluginRules.get(ruleId)) ||
1268
- slots.ruleMap.get(ruleId)
1269
- );
1426
+ return (
1427
+ (slots.lastConfigArray &&
1428
+ slots.lastConfigArray.pluginRules.get(ruleId)) ||
1429
+ slots.ruleMap.get(ruleId)
1430
+ );
1270
1431
  }
1271
1432
 
1272
1433
  /**
@@ -1275,16 +1436,16 @@ function getRule(slots, ruleId) {
1275
1436
  * @returns {string | undefined} normalized cwd
1276
1437
  */
1277
1438
  function normalizeCwd(cwd) {
1278
- if (cwd) {
1279
- return cwd;
1280
- }
1281
- if (typeof process === "object") {
1282
- return process.cwd();
1283
- }
1284
-
1285
- // It's more explicit to assign the undefined
1286
- // eslint-disable-next-line no-undefined -- Consistently returning a value
1287
- return undefined;
1439
+ if (cwd) {
1440
+ return cwd;
1441
+ }
1442
+ if (typeof process === "object") {
1443
+ return process.cwd();
1444
+ }
1445
+
1446
+ // It's more explicit to assign the undefined
1447
+ // eslint-disable-next-line no-undefined -- Consistently returning a value
1448
+ return undefined;
1288
1449
  }
1289
1450
 
1290
1451
  /**
@@ -1300,11 +1461,13 @@ const internalSlotsMap = new WeakMap();
1300
1461
  * @throws {Error} If the linter is in flat config mode.
1301
1462
  */
1302
1463
  function assertEslintrcConfig(linter) {
1303
- const { configType } = internalSlotsMap.get(linter);
1464
+ const { configType } = internalSlotsMap.get(linter);
1304
1465
 
1305
- if (configType === "flat") {
1306
- throw new Error("This method cannot be used with flat config. Add your entries directly into the config array.");
1307
- }
1466
+ if (configType === "flat") {
1467
+ throw new Error(
1468
+ "This method cannot be used with flat config. Add your entries directly into the config array.",
1469
+ );
1470
+ }
1308
1471
  }
1309
1472
 
1310
1473
  //------------------------------------------------------------------------------
@@ -1316,1182 +1479,1377 @@ function assertEslintrcConfig(linter) {
1316
1479
  * @name Linter
1317
1480
  */
1318
1481
  class Linter {
1319
-
1320
- /**
1321
- * Initialize the Linter.
1322
- * @param {Object} [config] the config object
1323
- * @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
1324
- * @param {Array<string>} [config.flags] the feature flags to enable.
1325
- * @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
1326
- */
1327
- constructor({ cwd, configType = "flat", flags = [] } = {}) {
1328
-
1329
- const processedFlags = [];
1330
-
1331
- flags.forEach(flag => {
1332
- if (inactiveFlags.has(flag)) {
1333
- const inactiveFlagData = inactiveFlags.get(flag);
1334
- const inactivityReason = getInactivityReasonMessage(inactiveFlagData);
1335
-
1336
- if (typeof inactiveFlagData.replacedBy === "undefined") {
1337
- throw new Error(`The flag '${flag}' is inactive: ${inactivityReason}`);
1338
- }
1339
-
1340
- // if there's a replacement, enable it instead of original
1341
- if (typeof inactiveFlagData.replacedBy === "string") {
1342
- processedFlags.push(inactiveFlagData.replacedBy);
1343
- }
1344
-
1345
- globalThis.process?.emitWarning?.(
1346
- `The flag '${flag}' is inactive: ${inactivityReason}`,
1347
- `ESLintInactiveFlag_${flag}`
1348
- );
1349
-
1350
- return;
1351
- }
1352
-
1353
- if (!activeFlags.has(flag)) {
1354
- throw new Error(`Unknown flag '${flag}'.`);
1355
- }
1356
-
1357
- processedFlags.push(flag);
1358
- });
1359
-
1360
- internalSlotsMap.set(this, {
1361
- cwd: normalizeCwd(cwd),
1362
- flags: processedFlags,
1363
- lastConfigArray: null,
1364
- lastSourceCode: null,
1365
- lastSuppressedMessages: [],
1366
- configType, // TODO: Remove after flat config conversion
1367
- parserMap: new Map([["espree", espree]]),
1368
- ruleMap: new Rules()
1369
- });
1370
-
1371
- this.version = pkg.version;
1372
- }
1373
-
1374
- /**
1375
- * Getter for package version.
1376
- * @static
1377
- * @returns {string} The version from package.json.
1378
- */
1379
- static get version() {
1380
- return pkg.version;
1381
- }
1382
-
1383
- /**
1384
- * Indicates if the given feature flag is enabled for this instance.
1385
- * @param {string} flag The feature flag to check.
1386
- * @returns {boolean} `true` if the feature flag is enabled, `false` if not.
1387
- */
1388
- hasFlag(flag) {
1389
- return internalSlotsMap.get(this).flags.includes(flag);
1390
- }
1391
-
1392
- /**
1393
- * Lint using eslintrc and without processors.
1394
- * @param {VFile} file The file to lint.
1395
- * @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
1396
- * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1397
- * @throws {Error} If during rule execution.
1398
- * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
1399
- */
1400
- #eslintrcVerifyWithoutProcessors(file, providedConfig, providedOptions) {
1401
-
1402
- const slots = internalSlotsMap.get(this);
1403
- const config = providedConfig || {};
1404
- const options = normalizeVerifyOptions(providedOptions, config);
1405
-
1406
- // Resolve parser.
1407
- let parserName = DEFAULT_PARSER_NAME;
1408
- let parser = espree;
1409
-
1410
- if (typeof config.parser === "object" && config.parser !== null) {
1411
- parserName = config.parser.filePath;
1412
- parser = config.parser.definition;
1413
- } else if (typeof config.parser === "string") {
1414
- if (!slots.parserMap.has(config.parser)) {
1415
- return [{
1416
- ruleId: null,
1417
- fatal: true,
1418
- severity: 2,
1419
- message: `Configured parser '${config.parser}' was not found.`,
1420
- line: 0,
1421
- column: 0,
1422
- nodeType: null
1423
- }];
1424
- }
1425
- parserName = config.parser;
1426
- parser = slots.parserMap.get(config.parser);
1427
- }
1428
-
1429
- // search and apply "eslint-env *".
1430
- const envInFile = options.allowInlineConfig && !options.warnInlineConfig
1431
- ? findEslintEnv(file.body)
1432
- : {};
1433
- const resolvedEnvConfig = Object.assign({ builtin: true }, config.env, envInFile);
1434
- const enabledEnvs = Object.keys(resolvedEnvConfig)
1435
- .filter(envName => resolvedEnvConfig[envName])
1436
- .map(envName => getEnv(slots, envName))
1437
- .filter(env => env);
1438
-
1439
- const parserOptions = resolveParserOptions(parser, config.parserOptions || {}, enabledEnvs);
1440
- const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
1441
- const settings = config.settings || {};
1442
- const languageOptions = createLanguageOptions({
1443
- globals: config.globals,
1444
- parser,
1445
- parserOptions
1446
- });
1447
-
1448
- if (!slots.lastSourceCode) {
1449
- let t;
1450
-
1451
- if (options.stats) {
1452
- t = startTime();
1453
- }
1454
-
1455
- const parserService = new ParserService();
1456
- const parseResult = parserService.parseSync(
1457
- file,
1458
- {
1459
- language: jslang,
1460
- languageOptions
1461
- }
1462
- );
1463
-
1464
- if (options.stats) {
1465
- const time = endTime(t);
1466
- const timeOpts = { type: "parse" };
1467
-
1468
- storeTime(time, timeOpts, slots);
1469
- }
1470
-
1471
- if (!parseResult.ok) {
1472
- return parseResult.errors;
1473
- }
1474
-
1475
- slots.lastSourceCode = parseResult.sourceCode;
1476
- } else {
1477
-
1478
- /*
1479
- * If the given source code object as the first argument does not have scopeManager, analyze the scope.
1480
- * This is for backward compatibility (SourceCode is frozen so it cannot rebind).
1481
- */
1482
- if (!slots.lastSourceCode.scopeManager) {
1483
- slots.lastSourceCode = new SourceCode({
1484
- text: slots.lastSourceCode.text,
1485
- ast: slots.lastSourceCode.ast,
1486
- hasBOM: slots.lastSourceCode.hasBOM,
1487
- parserServices: slots.lastSourceCode.parserServices,
1488
- visitorKeys: slots.lastSourceCode.visitorKeys,
1489
- scopeManager: analyzeScope(slots.lastSourceCode.ast, languageOptions)
1490
- });
1491
- }
1492
- }
1493
-
1494
- const sourceCode = slots.lastSourceCode;
1495
- const commentDirectives = options.allowInlineConfig
1496
- ? getDirectiveComments(sourceCode, ruleId => getRule(slots, ruleId), options.warnInlineConfig, config)
1497
- : { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
1498
-
1499
- addDeclaredGlobals(
1500
- sourceCode.scopeManager.scopes[0],
1501
- configuredGlobals,
1502
- { exportedVariables: commentDirectives.exportedVariables, enabledGlobals: commentDirectives.enabledGlobals }
1503
- );
1504
-
1505
- const configuredRules = Object.assign({}, config.rules, commentDirectives.configuredRules);
1506
-
1507
- let lintingProblems;
1508
-
1509
- try {
1510
- lintingProblems = runRules(
1511
- sourceCode,
1512
- configuredRules,
1513
- ruleId => getRule(slots, ruleId),
1514
- parserName,
1515
- jslang,
1516
- languageOptions,
1517
- settings,
1518
- options.filename,
1519
- true,
1520
- options.disableFixes,
1521
- slots.cwd,
1522
- providedOptions.physicalFilename,
1523
- null,
1524
- options.stats,
1525
- slots
1526
- );
1527
- } catch (err) {
1528
- err.message += `\nOccurred while linting ${options.filename}`;
1529
- debug("An error occurred while traversing");
1530
- debug("Filename:", options.filename);
1531
- if (err.currentNode) {
1532
- const { line } = sourceCode.getLoc(err.currentNode).start;
1533
-
1534
- debug("Line:", line);
1535
- err.message += `:${line}`;
1536
- }
1537
- debug("Parser Options:", parserOptions);
1538
- debug("Parser Path:", parserName);
1539
- debug("Settings:", settings);
1540
-
1541
- if (err.ruleId) {
1542
- err.message += `\nRule: "${err.ruleId}"`;
1543
- }
1544
-
1545
- throw err;
1546
- }
1547
-
1548
- return applyDisableDirectives({
1549
- language: jslang,
1550
- sourceCode,
1551
- directives: commentDirectives.disableDirectives,
1552
- disableFixes: options.disableFixes,
1553
- problems: lintingProblems
1554
- .concat(commentDirectives.problems)
1555
- .sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
1556
- reportUnusedDisableDirectives: options.reportUnusedDisableDirectives
1557
- });
1558
-
1559
- }
1560
-
1561
- /**
1562
- * Same as linter.verify, except without support for processors.
1563
- * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
1564
- * @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
1565
- * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1566
- * @throws {Error} If during rule execution.
1567
- * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
1568
- */
1569
- _verifyWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
1570
- const slots = internalSlotsMap.get(this);
1571
- const filename = normalizeFilename(providedOptions.filename || "<input>");
1572
- let text;
1573
-
1574
- // evaluate arguments
1575
- if (typeof textOrSourceCode === "string") {
1576
- slots.lastSourceCode = null;
1577
- text = textOrSourceCode;
1578
- } else {
1579
- slots.lastSourceCode = textOrSourceCode;
1580
- text = textOrSourceCode.text;
1581
- }
1582
-
1583
- const file = new VFile(filename, text, {
1584
- physicalPath: providedOptions.physicalFilename
1585
- });
1586
-
1587
- return this.#eslintrcVerifyWithoutProcessors(file, providedConfig, providedOptions);
1588
- }
1589
-
1590
- /**
1591
- * Verifies the text against the rules specified by the second argument.
1592
- * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
1593
- * @param {ConfigData|ConfigArray} config An ESLintConfig instance to configure everything.
1594
- * @param {(string|(VerifyOptions&ProcessorOptions))} [filenameOrOptions] The optional filename of the file being checked.
1595
- * If this is not set, the filename will default to '<input>' in the rule context. If
1596
- * an object, then it has "filename", "allowInlineConfig", and some properties.
1597
- * @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
1598
- */
1599
- verify(textOrSourceCode, config, filenameOrOptions) {
1600
- debug("Verify");
1601
-
1602
- const { configType, cwd } = internalSlotsMap.get(this);
1603
-
1604
- const options = typeof filenameOrOptions === "string"
1605
- ? { filename: filenameOrOptions }
1606
- : filenameOrOptions || {};
1607
-
1608
- const configToUse = config ?? {};
1609
-
1610
- if (configType !== "eslintrc") {
1611
-
1612
- /*
1613
- * Because of how Webpack packages up the files, we can't
1614
- * compare directly to `FlatConfigArray` using `instanceof`
1615
- * because it's not the same `FlatConfigArray` as in the tests.
1616
- * So, we work around it by assuming an array is, in fact, a
1617
- * `FlatConfigArray` if it has a `getConfig()` method.
1618
- */
1619
- let configArray = configToUse;
1620
-
1621
- if (!Array.isArray(configToUse) || typeof configToUse.getConfig !== "function") {
1622
- configArray = new FlatConfigArray(configToUse, { basePath: cwd });
1623
- configArray.normalizeSync();
1624
- }
1625
-
1626
- return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
1627
- }
1628
-
1629
- if (typeof configToUse.extractConfig === "function") {
1630
- return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, configToUse, options));
1631
- }
1632
-
1633
- /*
1634
- * If we get to here, it means `config` is just an object rather
1635
- * than a config array so we can go right into linting.
1636
- */
1637
-
1638
- /*
1639
- * `Linter` doesn't support `overrides` property in configuration.
1640
- * So we cannot apply multiple processors.
1641
- */
1642
- if (options.preprocess || options.postprocess) {
1643
- return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, configToUse, options));
1644
- }
1645
- return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, configToUse, options));
1646
- }
1647
-
1648
- /**
1649
- * Verify with a processor.
1650
- * @param {string|SourceCode} textOrSourceCode The source code.
1651
- * @param {FlatConfig} config The config array.
1652
- * @param {VerifyOptions&ProcessorOptions} options The options.
1653
- * @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
1654
- * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
1655
- */
1656
- _verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options, configForRecursive) {
1657
- const slots = internalSlotsMap.get(this);
1658
- const filename = options.filename || "<input>";
1659
- const filenameToExpose = normalizeFilename(filename);
1660
- const physicalFilename = options.physicalFilename || filenameToExpose;
1661
- const text = ensureText(textOrSourceCode);
1662
- const file = new VFile(filenameToExpose, text, {
1663
- physicalPath: physicalFilename
1664
- });
1665
-
1666
- const preprocess = options.preprocess || (rawText => [rawText]);
1667
- const postprocess = options.postprocess || (messagesList => messagesList.flat());
1668
-
1669
- const processorService = new ProcessorService();
1670
- const preprocessResult = processorService.preprocessSync(file, {
1671
- processor: {
1672
- preprocess,
1673
- postprocess
1674
- }
1675
- });
1676
-
1677
- if (!preprocessResult.ok) {
1678
- return preprocessResult.errors;
1679
- }
1680
-
1681
- const filterCodeBlock =
1682
- options.filterCodeBlock ||
1683
- (blockFilename => blockFilename.endsWith(".js"));
1684
- const originalExtname = path.extname(filename);
1685
- const { files } = preprocessResult;
1686
-
1687
- const messageLists = files.map(block => {
1688
- debug("A code block was found: %o", block.path || "(unnamed)");
1689
-
1690
- // Keep the legacy behavior.
1691
- if (typeof block === "string") {
1692
- return this._verifyWithFlatConfigArrayAndWithoutProcessors(block, config, options);
1693
- }
1694
-
1695
- // Skip this block if filtered.
1696
- if (!filterCodeBlock(block.path, block.body)) {
1697
- debug("This code block was skipped.");
1698
- return [];
1699
- }
1700
-
1701
- // Resolve configuration again if the file content or extension was changed.
1702
- if (configForRecursive && (text !== block.rawBody || path.extname(block.path) !== originalExtname)) {
1703
- debug("Resolving configuration again because the file content or extension was changed.");
1704
- return this._verifyWithFlatConfigArray(
1705
- block.rawBody,
1706
- configForRecursive,
1707
- { ...options, filename: block.path, physicalFilename: block.physicalPath }
1708
- );
1709
- }
1710
-
1711
- slots.lastSourceCode = null;
1712
-
1713
- // Does lint.
1714
- return this.#flatVerifyWithoutProcessors(
1715
- block,
1716
- config,
1717
- { ...options, filename: block.path, physicalFilename: block.physicalPath }
1718
- );
1719
- });
1720
-
1721
- return processorService.postprocessSync(file, messageLists, {
1722
- processor: {
1723
- preprocess,
1724
- postprocess
1725
- }
1726
- });
1727
- }
1728
-
1729
- /**
1730
- * Verify using flat config and without any processors.
1731
- * @param {VFile} file The file to lint.
1732
- * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
1733
- * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1734
- * @throws {Error} If during rule execution.
1735
- * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
1736
- */
1737
- #flatVerifyWithoutProcessors(file, providedConfig, providedOptions) {
1738
-
1739
- const slots = internalSlotsMap.get(this);
1740
- const config = providedConfig || {};
1741
- const { settings = {}, languageOptions } = config;
1742
- const options = normalizeVerifyOptions(providedOptions, config);
1743
-
1744
- if (!slots.lastSourceCode) {
1745
- let t;
1746
-
1747
- if (options.stats) {
1748
- t = startTime();
1749
- }
1750
-
1751
- const parserService = new ParserService();
1752
- const parseResult = parserService.parseSync(
1753
- file,
1754
- config
1755
- );
1756
-
1757
- if (options.stats) {
1758
- const time = endTime(t);
1759
-
1760
- storeTime(time, { type: "parse" }, slots);
1761
- }
1762
-
1763
- if (!parseResult.ok) {
1764
- return parseResult.errors;
1765
- }
1766
-
1767
- slots.lastSourceCode = parseResult.sourceCode;
1768
- } else {
1769
-
1770
- /*
1771
- * If the given source code object as the first argument does not have scopeManager, analyze the scope.
1772
- * This is for backward compatibility (SourceCode is frozen so it cannot rebind).
1773
- *
1774
- * We check explicitly for `null` to ensure that this is a JS-flavored language.
1775
- * For non-JS languages we don't want to do this.
1776
- *
1777
- * TODO: Remove this check when we stop exporting the `SourceCode` object.
1778
- */
1779
- if (slots.lastSourceCode.scopeManager === null) {
1780
- slots.lastSourceCode = new SourceCode({
1781
- text: slots.lastSourceCode.text,
1782
- ast: slots.lastSourceCode.ast,
1783
- hasBOM: slots.lastSourceCode.hasBOM,
1784
- parserServices: slots.lastSourceCode.parserServices,
1785
- visitorKeys: slots.lastSourceCode.visitorKeys,
1786
- scopeManager: analyzeScope(slots.lastSourceCode.ast, languageOptions)
1787
- });
1788
- }
1789
- }
1790
-
1791
- const sourceCode = slots.lastSourceCode;
1792
-
1793
- /*
1794
- * Make adjustments based on the language options. For JavaScript,
1795
- * this is primarily about adding variables into the global scope
1796
- * to account for ecmaVersion and configured globals.
1797
- */
1798
- sourceCode.applyLanguageOptions?.(languageOptions);
1799
-
1800
- const mergedInlineConfig = {
1801
- rules: {}
1802
- };
1803
- const inlineConfigProblems = [];
1804
-
1805
- /*
1806
- * Inline config can be either enabled or disabled. If disabled, it's possible
1807
- * to detect the inline config and emit a warning (though this is not required).
1808
- * So we first check to see if inline config is allowed at all, and if so, we
1809
- * need to check if it's a warning or not.
1810
- */
1811
- if (options.allowInlineConfig) {
1812
-
1813
- // if inline config should warn then add the warnings
1814
- if (options.warnInlineConfig) {
1815
- if (sourceCode.getInlineConfigNodes) {
1816
- sourceCode.getInlineConfigNodes().forEach(node => {
1817
-
1818
- const loc = sourceCode.getLoc(node);
1819
- const range = sourceCode.getRange(node);
1820
-
1821
- inlineConfigProblems.push(createLintingProblem({
1822
- ruleId: null,
1823
- message: `'${sourceCode.text.slice(range[0], range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`,
1824
- loc,
1825
- severity: 1,
1826
- language: config.language
1827
- }));
1828
-
1829
- });
1830
- }
1831
- } else {
1832
- const inlineConfigResult = sourceCode.applyInlineConfig?.();
1833
-
1834
- if (inlineConfigResult) {
1835
- inlineConfigProblems.push(
1836
- ...inlineConfigResult.problems
1837
- .map(problem => createLintingProblem({ ...problem, language: config.language }))
1838
- .map(problem => {
1839
- problem.fatal = true;
1840
- return problem;
1841
- })
1842
- );
1843
-
1844
- // next we need to verify information about the specified rules
1845
- const ruleValidator = new RuleValidator();
1846
-
1847
- for (const { config: inlineConfig, loc } of inlineConfigResult.configs) {
1848
-
1849
- Object.keys(inlineConfig.rules).forEach(ruleId => {
1850
- const rule = getRuleFromConfig(ruleId, config);
1851
- const ruleValue = inlineConfig.rules[ruleId];
1852
-
1853
- if (!rule) {
1854
- inlineConfigProblems.push(createLintingProblem({
1855
- ruleId,
1856
- loc,
1857
- language: config.language
1858
- }));
1859
- return;
1860
- }
1861
-
1862
- if (Object.hasOwn(mergedInlineConfig.rules, ruleId)) {
1863
- inlineConfigProblems.push(createLintingProblem({
1864
- message: `Rule "${ruleId}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
1865
- loc,
1866
- language: config.language
1867
- }));
1868
- return;
1869
- }
1870
-
1871
- try {
1872
-
1873
- const ruleOptionsInline = asArray(ruleValue);
1874
- let ruleOptions = ruleOptionsInline;
1875
-
1876
- assertIsRuleSeverity(ruleId, ruleOptions[0]);
1877
-
1878
- /*
1879
- * If the rule was already configured, inline rule configuration that
1880
- * only has severity should retain options from the config and just override the severity.
1881
- *
1882
- * Example:
1883
- *
1884
- * {
1885
- * rules: {
1886
- * curly: ["error", "multi"]
1887
- * }
1888
- * }
1889
- *
1890
- * /* eslint curly: ["warn"] * /
1891
- *
1892
- * Results in:
1893
- *
1894
- * curly: ["warn", "multi"]
1895
- */
1896
-
1897
- let shouldValidateOptions = true;
1898
-
1899
- if (
1900
-
1901
- /*
1902
- * If inline config for the rule has only severity
1903
- */
1904
- ruleOptions.length === 1 &&
1905
-
1906
- /*
1907
- * And the rule was already configured
1908
- */
1909
- config.rules && Object.hasOwn(config.rules, ruleId)
1910
- ) {
1911
-
1912
- /*
1913
- * Then use severity from the inline config and options from the provided config
1914
- */
1915
- ruleOptions = [
1916
- ruleOptions[0], // severity from the inline config
1917
- ...config.rules[ruleId].slice(1) // options from the provided config
1918
- ];
1919
-
1920
- // if the rule was enabled, the options have already been validated
1921
- if (config.rules[ruleId][0] > 0) {
1922
- shouldValidateOptions = false;
1923
- }
1924
- } else {
1925
-
1926
- /**
1927
- * Since we know the user provided options, apply defaults on top of them
1928
- */
1929
- const slicedOptions = ruleOptions.slice(1);
1930
- const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, slicedOptions);
1931
-
1932
- if (mergedOptions.length) {
1933
- ruleOptions = [ruleOptions[0], ...mergedOptions];
1934
- }
1935
- }
1936
-
1937
- if (options.reportUnusedInlineConfigs !== "off") {
1938
- addProblemIfSameSeverityAndOptions(
1939
- config, loc, inlineConfigProblems, ruleId, ruleOptions, ruleOptionsInline, options.reportUnusedInlineConfigs
1940
- );
1941
- }
1942
-
1943
- if (shouldValidateOptions) {
1944
- ruleValidator.validate({
1945
- plugins: config.plugins,
1946
- rules: {
1947
- [ruleId]: ruleOptions
1948
- }
1949
- });
1950
- }
1951
-
1952
- mergedInlineConfig.rules[ruleId] = ruleOptions;
1953
- } catch (err) {
1954
-
1955
- /*
1956
- * If the rule has invalid `meta.schema`, throw the error because
1957
- * this is not an invalid inline configuration but an invalid rule.
1958
- */
1959
- if (err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA") {
1960
- throw err;
1961
- }
1962
-
1963
- let baseMessage = err.message.slice(
1964
- err.message.startsWith("Key \"rules\":")
1965
- ? err.message.indexOf(":", 12) + 1
1966
- : err.message.indexOf(":") + 1
1967
- ).trim();
1968
-
1969
- if (err.messageTemplate) {
1970
- baseMessage += ` You passed "${ruleValue}".`;
1971
- }
1972
-
1973
- inlineConfigProblems.push(createLintingProblem({
1974
- ruleId,
1975
- message: `Inline configuration for rule "${ruleId}" is invalid:\n\t${baseMessage}\n`,
1976
- loc,
1977
- language: config.language
1978
- }));
1979
- }
1980
- });
1981
- }
1982
- }
1983
- }
1984
- }
1985
-
1986
- const commentDirectives = options.allowInlineConfig && !options.warnInlineConfig
1987
- ? getDirectiveCommentsForFlatConfig(
1988
- sourceCode,
1989
- ruleId => getRuleFromConfig(ruleId, config),
1990
- config.language
1991
- )
1992
- : { problems: [], disableDirectives: [] };
1993
-
1994
- const configuredRules = Object.assign({}, config.rules, mergedInlineConfig.rules);
1995
-
1996
- let lintingProblems;
1997
-
1998
- sourceCode.finalize?.();
1999
-
2000
- try {
2001
- lintingProblems = runRules(
2002
- sourceCode,
2003
- configuredRules,
2004
- ruleId => getRuleFromConfig(ruleId, config),
2005
- void 0,
2006
- config.language,
2007
- languageOptions,
2008
- settings,
2009
- options.filename,
2010
- false,
2011
- options.disableFixes,
2012
- slots.cwd,
2013
- providedOptions.physicalFilename,
2014
- options.ruleFilter,
2015
- options.stats,
2016
- slots
2017
- );
2018
- } catch (err) {
2019
- err.message += `\nOccurred while linting ${options.filename}`;
2020
- debug("An error occurred while traversing");
2021
- debug("Filename:", options.filename);
2022
- if (err.currentNode) {
2023
- const { line } = sourceCode.getLoc(err.currentNode).start;
2024
-
2025
- debug("Line:", line);
2026
- err.message += `:${line}`;
2027
- }
2028
- debug("Parser Options:", languageOptions.parserOptions);
2029
-
2030
- // debug("Parser Path:", parserName);
2031
- debug("Settings:", settings);
2032
-
2033
- if (err.ruleId) {
2034
- err.message += `\nRule: "${err.ruleId}"`;
2035
- }
2036
-
2037
- throw err;
2038
- }
2039
-
2040
- return applyDisableDirectives({
2041
- language: config.language,
2042
- sourceCode,
2043
- directives: commentDirectives.disableDirectives,
2044
- disableFixes: options.disableFixes,
2045
- problems: lintingProblems
2046
- .concat(commentDirectives.problems)
2047
- .concat(inlineConfigProblems)
2048
- .sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
2049
- reportUnusedDisableDirectives: options.reportUnusedDisableDirectives,
2050
- ruleFilter: options.ruleFilter,
2051
- configuredRules
2052
- });
2053
-
2054
-
2055
- }
2056
-
2057
- /**
2058
- * Same as linter.verify, except without support for processors.
2059
- * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
2060
- * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
2061
- * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
2062
- * @throws {Error} If during rule execution.
2063
- * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
2064
- */
2065
- _verifyWithFlatConfigArrayAndWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
2066
- const slots = internalSlotsMap.get(this);
2067
- const filename = normalizeFilename(providedOptions.filename || "<input>");
2068
- let text;
2069
-
2070
- // evaluate arguments
2071
- if (typeof textOrSourceCode === "string") {
2072
- slots.lastSourceCode = null;
2073
- text = textOrSourceCode;
2074
- } else {
2075
- slots.lastSourceCode = textOrSourceCode;
2076
- text = textOrSourceCode.text;
2077
- }
2078
-
2079
- const file = new VFile(filename, text, {
2080
- physicalPath: providedOptions.physicalFilename
2081
- });
2082
-
2083
- return this.#flatVerifyWithoutProcessors(file, providedConfig, providedOptions);
2084
- }
2085
-
2086
- /**
2087
- * Verify a given code with `ConfigArray`.
2088
- * @param {string|SourceCode} textOrSourceCode The source code.
2089
- * @param {ConfigArray} configArray The config array.
2090
- * @param {VerifyOptions&ProcessorOptions} options The options.
2091
- * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
2092
- */
2093
- _verifyWithConfigArray(textOrSourceCode, configArray, options) {
2094
- debug("With ConfigArray: %s", options.filename);
2095
-
2096
- // Store the config array in order to get plugin envs and rules later.
2097
- internalSlotsMap.get(this).lastConfigArray = configArray;
2098
-
2099
- // Extract the final config for this file.
2100
- const config = configArray.extractConfig(options.filename);
2101
- const processor =
2102
- config.processor &&
2103
- configArray.pluginProcessors.get(config.processor);
2104
-
2105
- // Verify.
2106
- if (processor) {
2107
- debug("Apply the processor: %o", config.processor);
2108
- const { preprocess, postprocess, supportsAutofix } = processor;
2109
- const disableFixes = options.disableFixes || !supportsAutofix;
2110
-
2111
- return this._verifyWithProcessor(
2112
- textOrSourceCode,
2113
- config,
2114
- { ...options, disableFixes, postprocess, preprocess },
2115
- configArray
2116
- );
2117
- }
2118
- return this._verifyWithoutProcessors(textOrSourceCode, config, options);
2119
- }
2120
-
2121
- /**
2122
- * Verify a given code with a flat config.
2123
- * @param {string|SourceCode} textOrSourceCode The source code.
2124
- * @param {FlatConfigArray} configArray The config array.
2125
- * @param {VerifyOptions&ProcessorOptions} options The options.
2126
- * @param {boolean} [firstCall=false] Indicates if this is being called directly
2127
- * from verify(). (TODO: Remove once eslintrc is removed.)
2128
- * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
2129
- */
2130
- _verifyWithFlatConfigArray(textOrSourceCode, configArray, options, firstCall = false) {
2131
- debug("With flat config: %s", options.filename);
2132
-
2133
- // we need a filename to match configs against
2134
- const filename = options.filename || "__placeholder__.js";
2135
-
2136
- // Store the config array in order to get plugin envs and rules later.
2137
- internalSlotsMap.get(this).lastConfigArray = configArray;
2138
- const config = configArray.getConfig(filename);
2139
-
2140
- if (!config) {
2141
- return [
2142
- {
2143
- ruleId: null,
2144
- severity: 1,
2145
- message: `No matching configuration found for ${filename}.`,
2146
- line: 0,
2147
- column: 0,
2148
- nodeType: null
2149
- }
2150
- ];
2151
- }
2152
-
2153
- // Verify.
2154
- if (config.processor) {
2155
- debug("Apply the processor: %o", config.processor);
2156
- const { preprocess, postprocess, supportsAutofix } = config.processor;
2157
- const disableFixes = options.disableFixes || !supportsAutofix;
2158
-
2159
- return this._verifyWithFlatConfigArrayAndProcessor(
2160
- textOrSourceCode,
2161
- config,
2162
- { ...options, filename, disableFixes, postprocess, preprocess },
2163
- configArray
2164
- );
2165
- }
2166
-
2167
- // check for options-based processing
2168
- if (firstCall && (options.preprocess || options.postprocess)) {
2169
- return this._verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options);
2170
- }
2171
-
2172
- return this._verifyWithFlatConfigArrayAndWithoutProcessors(textOrSourceCode, config, options);
2173
- }
2174
-
2175
- /**
2176
- * Verify with a processor.
2177
- * @param {string|SourceCode} textOrSourceCode The source code.
2178
- * @param {ConfigData|ExtractedConfig} config The config array.
2179
- * @param {VerifyOptions&ProcessorOptions} options The options.
2180
- * @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
2181
- * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
2182
- */
2183
- _verifyWithProcessor(textOrSourceCode, config, options, configForRecursive) {
2184
- const slots = internalSlotsMap.get(this);
2185
- const filename = options.filename || "<input>";
2186
- const filenameToExpose = normalizeFilename(filename);
2187
- const physicalFilename = options.physicalFilename || filenameToExpose;
2188
- const text = ensureText(textOrSourceCode);
2189
- const file = new VFile(filenameToExpose, text, {
2190
- physicalPath: physicalFilename
2191
- });
2192
-
2193
- const preprocess = options.preprocess || (rawText => [rawText]);
2194
- const postprocess = options.postprocess || (messagesList => messagesList.flat());
2195
-
2196
- const processorService = new ProcessorService();
2197
- const preprocessResult = processorService.preprocessSync(file, {
2198
- processor: {
2199
- preprocess,
2200
- postprocess
2201
- }
2202
- });
2203
-
2204
- if (!preprocessResult.ok) {
2205
- return preprocessResult.errors;
2206
- }
2207
-
2208
- const filterCodeBlock =
2209
- options.filterCodeBlock ||
2210
- (blockFilePath => blockFilePath.endsWith(".js"));
2211
- const originalExtname = path.extname(filename);
2212
-
2213
- const { files } = preprocessResult;
2214
-
2215
- const messageLists = files.map(block => {
2216
- debug("A code block was found: %o", block.path ?? "(unnamed)");
2217
-
2218
- // Keep the legacy behavior.
2219
- if (typeof block === "string") {
2220
- return this._verifyWithoutProcessors(block, config, options);
2221
- }
2222
-
2223
- // Skip this block if filtered.
2224
- if (!filterCodeBlock(block.path, block.body)) {
2225
- debug("This code block was skipped.");
2226
- return [];
2227
- }
2228
-
2229
- // Resolve configuration again if the file content or extension was changed.
2230
- if (configForRecursive && (text !== block.rawBody || path.extname(block.path) !== originalExtname)) {
2231
- debug("Resolving configuration again because the file content or extension was changed.");
2232
- return this._verifyWithConfigArray(
2233
- block.rawBody,
2234
- configForRecursive,
2235
- { ...options, filename: block.path, physicalFilename: block.physicalPath }
2236
- );
2237
- }
2238
-
2239
- slots.lastSourceCode = null;
2240
-
2241
- // Does lint.
2242
- return this.#eslintrcVerifyWithoutProcessors(
2243
- block,
2244
- config,
2245
- { ...options, filename: block.path, physicalFilename: block.physicalPath }
2246
- );
2247
- });
2248
-
2249
- return processorService.postprocessSync(file, messageLists, {
2250
- processor: {
2251
- preprocess,
2252
- postprocess
2253
- }
2254
- });
2255
-
2256
- }
2257
-
2258
- /**
2259
- * Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
2260
- * The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
2261
- * @param {Array<LintMessage|SuppressedLintMessage>} problems A list of reported problems.
2262
- * @returns {LintMessage[]} A list of LintMessage.
2263
- */
2264
- _distinguishSuppressedMessages(problems) {
2265
- const messages = [];
2266
- const suppressedMessages = [];
2267
- const slots = internalSlotsMap.get(this);
2268
-
2269
- for (const problem of problems) {
2270
- if (problem.suppressions) {
2271
- suppressedMessages.push(problem);
2272
- } else {
2273
- messages.push(problem);
2274
- }
2275
- }
2276
-
2277
- slots.lastSuppressedMessages = suppressedMessages;
2278
-
2279
- return messages;
2280
- }
2281
-
2282
- /**
2283
- * Gets the SourceCode object representing the parsed source.
2284
- * @returns {SourceCode} The SourceCode object.
2285
- */
2286
- getSourceCode() {
2287
- return internalSlotsMap.get(this).lastSourceCode;
2288
- }
2289
-
2290
- /**
2291
- * Gets the times spent on (parsing, fixing, linting) a file.
2292
- * @returns {LintTimes} The times.
2293
- */
2294
- getTimes() {
2295
- return internalSlotsMap.get(this).times ?? { passes: [] };
2296
- }
2297
-
2298
- /**
2299
- * Gets the number of autofix passes that were made in the last run.
2300
- * @returns {number} The number of autofix passes.
2301
- */
2302
- getFixPassCount() {
2303
- return internalSlotsMap.get(this).fixPasses ?? 0;
2304
- }
2305
-
2306
- /**
2307
- * Gets the list of SuppressedLintMessage produced in the last running.
2308
- * @returns {SuppressedLintMessage[]} The list of SuppressedLintMessage
2309
- */
2310
- getSuppressedMessages() {
2311
- return internalSlotsMap.get(this).lastSuppressedMessages;
2312
- }
2313
-
2314
- /**
2315
- * Defines a new linting rule.
2316
- * @param {string} ruleId A unique rule identifier
2317
- * @param {Rule} rule A rule object
2318
- * @returns {void}
2319
- */
2320
- defineRule(ruleId, rule) {
2321
- assertEslintrcConfig(this);
2322
- internalSlotsMap.get(this).ruleMap.define(ruleId, rule);
2323
- }
2324
-
2325
- /**
2326
- * Defines many new linting rules.
2327
- * @param {Record<string, Rule>} rulesToDefine map from unique rule identifier to rule
2328
- * @returns {void}
2329
- */
2330
- defineRules(rulesToDefine) {
2331
- assertEslintrcConfig(this);
2332
- Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => {
2333
- this.defineRule(ruleId, rulesToDefine[ruleId]);
2334
- });
2335
- }
2336
-
2337
- /**
2338
- * Gets an object with all loaded rules.
2339
- * @returns {Map<string, Rule>} All loaded rules
2340
- */
2341
- getRules() {
2342
- assertEslintrcConfig(this);
2343
- const { lastConfigArray, ruleMap } = internalSlotsMap.get(this);
2344
-
2345
- return new Map(function *() {
2346
- yield* ruleMap;
2347
-
2348
- if (lastConfigArray) {
2349
- yield* lastConfigArray.pluginRules;
2350
- }
2351
- }());
2352
- }
2353
-
2354
- /**
2355
- * Define a new parser module
2356
- * @param {string} parserId Name of the parser
2357
- * @param {Parser} parserModule The parser object
2358
- * @returns {void}
2359
- */
2360
- defineParser(parserId, parserModule) {
2361
- assertEslintrcConfig(this);
2362
- internalSlotsMap.get(this).parserMap.set(parserId, parserModule);
2363
- }
2364
-
2365
- /**
2366
- * Performs multiple autofix passes over the text until as many fixes as possible
2367
- * have been applied.
2368
- * @param {string} text The source text to apply fixes to.
2369
- * @param {ConfigData|ConfigArray|FlatConfigArray} config The ESLint config object to use.
2370
- * @param {VerifyOptions&ProcessorOptions&FixOptions} options The ESLint options object to use.
2371
- * @returns {{fixed:boolean,messages:LintMessage[],output:string}} The result of the fix operation as returned from the
2372
- * SourceCodeFixer.
2373
- */
2374
- verifyAndFix(text, config, options) {
2375
- let messages,
2376
- fixedResult,
2377
- fixed = false,
2378
- passNumber = 0,
2379
- currentText = text;
2380
- const debugTextDescription = options && options.filename || `${text.slice(0, 10)}...`;
2381
- const shouldFix = options && typeof options.fix !== "undefined" ? options.fix : true;
2382
- const stats = options?.stats;
2383
-
2384
- /**
2385
- * This loop continues until one of the following is true:
2386
- *
2387
- * 1. No more fixes have been applied.
2388
- * 2. Ten passes have been made.
2389
- *
2390
- * That means anytime a fix is successfully applied, there will be another pass.
2391
- * Essentially, guaranteeing a minimum of two passes.
2392
- */
2393
- const slots = internalSlotsMap.get(this);
2394
-
2395
- // Remove lint times from the last run.
2396
- if (stats) {
2397
- delete slots.times;
2398
- slots.fixPasses = 0;
2399
- }
2400
-
2401
- do {
2402
- passNumber++;
2403
- let tTotal;
2404
-
2405
- if (stats) {
2406
- tTotal = startTime();
2407
- }
2408
-
2409
- debug(`Linting code for ${debugTextDescription} (pass ${passNumber})`);
2410
- messages = this.verify(currentText, config, options);
2411
-
2412
- debug(`Generating fixed text for ${debugTextDescription} (pass ${passNumber})`);
2413
- let t;
2414
-
2415
- if (stats) {
2416
- t = startTime();
2417
- }
2418
-
2419
- fixedResult = SourceCodeFixer.applyFixes(currentText, messages, shouldFix);
2420
-
2421
- if (stats) {
2422
-
2423
- if (fixedResult.fixed) {
2424
- const time = endTime(t);
2425
-
2426
- storeTime(time, { type: "fix" }, slots);
2427
- slots.fixPasses++;
2428
- } else {
2429
- storeTime(0, { type: "fix" }, slots);
2430
- }
2431
- }
2432
-
2433
- /*
2434
- * stop if there are any syntax errors.
2435
- * 'fixedResult.output' is a empty string.
2436
- */
2437
- if (messages.length === 1 && messages[0].fatal) {
2438
- break;
2439
- }
2440
-
2441
- // keep track if any fixes were ever applied - important for return value
2442
- fixed = fixed || fixedResult.fixed;
2443
-
2444
- // update to use the fixed output instead of the original text
2445
- currentText = fixedResult.output;
2446
-
2447
- if (stats) {
2448
- tTotal = endTime(tTotal);
2449
- const passIndex = slots.times.passes.length - 1;
2450
-
2451
- slots.times.passes[passIndex].total = tTotal;
2452
- }
2453
-
2454
- } while (
2455
- fixedResult.fixed &&
2456
- passNumber < MAX_AUTOFIX_PASSES
2457
- );
2458
-
2459
- /*
2460
- * If the last result had fixes, we need to lint again to be sure we have
2461
- * the most up-to-date information.
2462
- */
2463
- if (fixedResult.fixed) {
2464
- let tTotal;
2465
-
2466
- if (stats) {
2467
- tTotal = startTime();
2468
- }
2469
-
2470
- fixedResult.messages = this.verify(currentText, config, options);
2471
-
2472
- if (stats) {
2473
- storeTime(0, { type: "fix" }, slots);
2474
- slots.times.passes.at(-1).total = endTime(tTotal);
2475
- }
2476
- }
2477
-
2478
- // ensure the last result properly reflects if fixes were done
2479
- fixedResult.fixed = fixed;
2480
- fixedResult.output = currentText;
2481
-
2482
- return fixedResult;
2483
- }
1482
+ /**
1483
+ * Initialize the Linter.
1484
+ * @param {Object} [config] the config object
1485
+ * @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
1486
+ * @param {Array<string>} [config.flags] the feature flags to enable.
1487
+ * @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
1488
+ */
1489
+ constructor({ cwd, configType = "flat", flags = [] } = {}) {
1490
+ const processedFlags = [];
1491
+
1492
+ flags.forEach(flag => {
1493
+ if (inactiveFlags.has(flag)) {
1494
+ const inactiveFlagData = inactiveFlags.get(flag);
1495
+ const inactivityReason =
1496
+ getInactivityReasonMessage(inactiveFlagData);
1497
+
1498
+ if (typeof inactiveFlagData.replacedBy === "undefined") {
1499
+ throw new Error(
1500
+ `The flag '${flag}' is inactive: ${inactivityReason}`,
1501
+ );
1502
+ }
1503
+
1504
+ // if there's a replacement, enable it instead of original
1505
+ if (typeof inactiveFlagData.replacedBy === "string") {
1506
+ processedFlags.push(inactiveFlagData.replacedBy);
1507
+ }
1508
+
1509
+ globalThis.process?.emitWarning?.(
1510
+ `The flag '${flag}' is inactive: ${inactivityReason}`,
1511
+ `ESLintInactiveFlag_${flag}`,
1512
+ );
1513
+
1514
+ return;
1515
+ }
1516
+
1517
+ if (!activeFlags.has(flag)) {
1518
+ throw new Error(`Unknown flag '${flag}'.`);
1519
+ }
1520
+
1521
+ processedFlags.push(flag);
1522
+ });
1523
+
1524
+ internalSlotsMap.set(this, {
1525
+ cwd: normalizeCwd(cwd),
1526
+ flags: processedFlags,
1527
+ lastConfigArray: null,
1528
+ lastSourceCode: null,
1529
+ lastSuppressedMessages: [],
1530
+ configType, // TODO: Remove after flat config conversion
1531
+ parserMap: new Map([["espree", espree]]),
1532
+ ruleMap: new Rules(),
1533
+ });
1534
+
1535
+ this.version = pkg.version;
1536
+ }
1537
+
1538
+ /**
1539
+ * Getter for package version.
1540
+ * @static
1541
+ * @returns {string} The version from package.json.
1542
+ */
1543
+ static get version() {
1544
+ return pkg.version;
1545
+ }
1546
+
1547
+ /**
1548
+ * Indicates if the given feature flag is enabled for this instance.
1549
+ * @param {string} flag The feature flag to check.
1550
+ * @returns {boolean} `true` if the feature flag is enabled, `false` if not.
1551
+ */
1552
+ hasFlag(flag) {
1553
+ return internalSlotsMap.get(this).flags.includes(flag);
1554
+ }
1555
+
1556
+ /**
1557
+ * Lint using eslintrc and without processors.
1558
+ * @param {VFile} file The file to lint.
1559
+ * @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
1560
+ * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1561
+ * @throws {Error} If during rule execution.
1562
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
1563
+ */
1564
+ #eslintrcVerifyWithoutProcessors(file, providedConfig, providedOptions) {
1565
+ const slots = internalSlotsMap.get(this);
1566
+ const config = providedConfig || {};
1567
+ const options = normalizeVerifyOptions(providedOptions, config);
1568
+
1569
+ // Resolve parser.
1570
+ let parserName = DEFAULT_PARSER_NAME;
1571
+ let parser = espree;
1572
+
1573
+ if (typeof config.parser === "object" && config.parser !== null) {
1574
+ parserName = config.parser.filePath;
1575
+ parser = config.parser.definition;
1576
+ } else if (typeof config.parser === "string") {
1577
+ if (!slots.parserMap.has(config.parser)) {
1578
+ return [
1579
+ {
1580
+ ruleId: null,
1581
+ fatal: true,
1582
+ severity: 2,
1583
+ message: `Configured parser '${config.parser}' was not found.`,
1584
+ line: 0,
1585
+ column: 0,
1586
+ nodeType: null,
1587
+ },
1588
+ ];
1589
+ }
1590
+ parserName = config.parser;
1591
+ parser = slots.parserMap.get(config.parser);
1592
+ }
1593
+
1594
+ // search and apply "eslint-env *".
1595
+ const envInFile =
1596
+ options.allowInlineConfig && !options.warnInlineConfig
1597
+ ? findEslintEnv(file.body)
1598
+ : {};
1599
+ const resolvedEnvConfig = Object.assign(
1600
+ { builtin: true },
1601
+ config.env,
1602
+ envInFile,
1603
+ );
1604
+ const enabledEnvs = Object.keys(resolvedEnvConfig)
1605
+ .filter(envName => resolvedEnvConfig[envName])
1606
+ .map(envName => getEnv(slots, envName))
1607
+ .filter(env => env);
1608
+
1609
+ const parserOptions = resolveParserOptions(
1610
+ parser,
1611
+ config.parserOptions || {},
1612
+ enabledEnvs,
1613
+ );
1614
+ const configuredGlobals = resolveGlobals(
1615
+ config.globals || {},
1616
+ enabledEnvs,
1617
+ );
1618
+ const settings = config.settings || {};
1619
+ const languageOptions = createLanguageOptions({
1620
+ globals: config.globals,
1621
+ parser,
1622
+ parserOptions,
1623
+ });
1624
+
1625
+ if (!slots.lastSourceCode) {
1626
+ let t;
1627
+
1628
+ if (options.stats) {
1629
+ t = startTime();
1630
+ }
1631
+
1632
+ const parserService = new ParserService();
1633
+ const parseResult = parserService.parseSync(file, {
1634
+ language: jslang,
1635
+ languageOptions,
1636
+ });
1637
+
1638
+ if (options.stats) {
1639
+ const time = endTime(t);
1640
+ const timeOpts = { type: "parse" };
1641
+
1642
+ storeTime(time, timeOpts, slots);
1643
+ }
1644
+
1645
+ if (!parseResult.ok) {
1646
+ return parseResult.errors;
1647
+ }
1648
+
1649
+ slots.lastSourceCode = parseResult.sourceCode;
1650
+ } else {
1651
+ /*
1652
+ * If the given source code object as the first argument does not have scopeManager, analyze the scope.
1653
+ * This is for backward compatibility (SourceCode is frozen so it cannot rebind).
1654
+ */
1655
+ if (!slots.lastSourceCode.scopeManager) {
1656
+ slots.lastSourceCode = new SourceCode({
1657
+ text: slots.lastSourceCode.text,
1658
+ ast: slots.lastSourceCode.ast,
1659
+ hasBOM: slots.lastSourceCode.hasBOM,
1660
+ parserServices: slots.lastSourceCode.parserServices,
1661
+ visitorKeys: slots.lastSourceCode.visitorKeys,
1662
+ scopeManager: analyzeScope(
1663
+ slots.lastSourceCode.ast,
1664
+ languageOptions,
1665
+ ),
1666
+ });
1667
+ }
1668
+ }
1669
+
1670
+ const sourceCode = slots.lastSourceCode;
1671
+ const commentDirectives = options.allowInlineConfig
1672
+ ? getDirectiveComments(
1673
+ sourceCode,
1674
+ ruleId => getRule(slots, ruleId),
1675
+ options.warnInlineConfig,
1676
+ config,
1677
+ )
1678
+ : {
1679
+ configuredRules: {},
1680
+ enabledGlobals: {},
1681
+ exportedVariables: {},
1682
+ problems: [],
1683
+ disableDirectives: [],
1684
+ };
1685
+
1686
+ addDeclaredGlobals(
1687
+ sourceCode.scopeManager.scopes[0],
1688
+ configuredGlobals,
1689
+ {
1690
+ exportedVariables: commentDirectives.exportedVariables,
1691
+ enabledGlobals: commentDirectives.enabledGlobals,
1692
+ },
1693
+ );
1694
+
1695
+ const configuredRules = Object.assign(
1696
+ {},
1697
+ config.rules,
1698
+ commentDirectives.configuredRules,
1699
+ );
1700
+
1701
+ let lintingProblems;
1702
+
1703
+ try {
1704
+ lintingProblems = runRules(
1705
+ sourceCode,
1706
+ configuredRules,
1707
+ ruleId => getRule(slots, ruleId),
1708
+ parserName,
1709
+ jslang,
1710
+ languageOptions,
1711
+ settings,
1712
+ options.filename,
1713
+ true,
1714
+ options.disableFixes,
1715
+ slots.cwd,
1716
+ providedOptions.physicalFilename,
1717
+ null,
1718
+ options.stats,
1719
+ slots,
1720
+ );
1721
+ } catch (err) {
1722
+ err.message += `\nOccurred while linting ${options.filename}`;
1723
+ debug("An error occurred while traversing");
1724
+ debug("Filename:", options.filename);
1725
+ if (err.currentNode) {
1726
+ const { line } = sourceCode.getLoc(err.currentNode).start;
1727
+
1728
+ debug("Line:", line);
1729
+ err.message += `:${line}`;
1730
+ }
1731
+ debug("Parser Options:", parserOptions);
1732
+ debug("Parser Path:", parserName);
1733
+ debug("Settings:", settings);
1734
+
1735
+ if (err.ruleId) {
1736
+ err.message += `\nRule: "${err.ruleId}"`;
1737
+ }
1738
+
1739
+ throw err;
1740
+ }
1741
+
1742
+ return applyDisableDirectives({
1743
+ language: jslang,
1744
+ sourceCode,
1745
+ directives: commentDirectives.disableDirectives,
1746
+ disableFixes: options.disableFixes,
1747
+ problems: lintingProblems
1748
+ .concat(commentDirectives.problems)
1749
+ .sort(
1750
+ (problemA, problemB) =>
1751
+ problemA.line - problemB.line ||
1752
+ problemA.column - problemB.column,
1753
+ ),
1754
+ reportUnusedDisableDirectives:
1755
+ options.reportUnusedDisableDirectives,
1756
+ });
1757
+ }
1758
+
1759
+ /**
1760
+ * Same as linter.verify, except without support for processors.
1761
+ * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
1762
+ * @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
1763
+ * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1764
+ * @throws {Error} If during rule execution.
1765
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
1766
+ */
1767
+ _verifyWithoutProcessors(
1768
+ textOrSourceCode,
1769
+ providedConfig,
1770
+ providedOptions,
1771
+ ) {
1772
+ const slots = internalSlotsMap.get(this);
1773
+ const filename = normalizeFilename(
1774
+ providedOptions.filename || "<input>",
1775
+ );
1776
+ let text;
1777
+
1778
+ // evaluate arguments
1779
+ if (typeof textOrSourceCode === "string") {
1780
+ slots.lastSourceCode = null;
1781
+ text = textOrSourceCode;
1782
+ } else {
1783
+ slots.lastSourceCode = textOrSourceCode;
1784
+ text = textOrSourceCode.text;
1785
+ }
1786
+
1787
+ const file = new VFile(filename, text, {
1788
+ physicalPath: providedOptions.physicalFilename,
1789
+ });
1790
+
1791
+ return this.#eslintrcVerifyWithoutProcessors(
1792
+ file,
1793
+ providedConfig,
1794
+ providedOptions,
1795
+ );
1796
+ }
1797
+
1798
+ /**
1799
+ * Verifies the text against the rules specified by the second argument.
1800
+ * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
1801
+ * @param {ConfigData|ConfigArray} config An ESLintConfig instance to configure everything.
1802
+ * @param {(string|(VerifyOptions&ProcessorOptions))} [filenameOrOptions] The optional filename of the file being checked.
1803
+ * If this is not set, the filename will default to '<input>' in the rule context. If
1804
+ * an object, then it has "filename", "allowInlineConfig", and some properties.
1805
+ * @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
1806
+ */
1807
+ verify(textOrSourceCode, config, filenameOrOptions) {
1808
+ debug("Verify");
1809
+
1810
+ const { configType, cwd } = internalSlotsMap.get(this);
1811
+
1812
+ const options =
1813
+ typeof filenameOrOptions === "string"
1814
+ ? { filename: filenameOrOptions }
1815
+ : filenameOrOptions || {};
1816
+
1817
+ const configToUse = config ?? {};
1818
+
1819
+ if (configType !== "eslintrc") {
1820
+ /*
1821
+ * Because of how Webpack packages up the files, we can't
1822
+ * compare directly to `FlatConfigArray` using `instanceof`
1823
+ * because it's not the same `FlatConfigArray` as in the tests.
1824
+ * So, we work around it by assuming an array is, in fact, a
1825
+ * `FlatConfigArray` if it has a `getConfig()` method.
1826
+ */
1827
+ let configArray = configToUse;
1828
+
1829
+ if (
1830
+ !Array.isArray(configToUse) ||
1831
+ typeof configToUse.getConfig !== "function"
1832
+ ) {
1833
+ configArray = new FlatConfigArray(configToUse, {
1834
+ basePath: cwd,
1835
+ });
1836
+ configArray.normalizeSync();
1837
+ }
1838
+
1839
+ return this._distinguishSuppressedMessages(
1840
+ this._verifyWithFlatConfigArray(
1841
+ textOrSourceCode,
1842
+ configArray,
1843
+ options,
1844
+ true,
1845
+ ),
1846
+ );
1847
+ }
1848
+
1849
+ if (typeof configToUse.extractConfig === "function") {
1850
+ return this._distinguishSuppressedMessages(
1851
+ this._verifyWithConfigArray(
1852
+ textOrSourceCode,
1853
+ configToUse,
1854
+ options,
1855
+ ),
1856
+ );
1857
+ }
1858
+
1859
+ /*
1860
+ * If we get to here, it means `config` is just an object rather
1861
+ * than a config array so we can go right into linting.
1862
+ */
1863
+
1864
+ /*
1865
+ * `Linter` doesn't support `overrides` property in configuration.
1866
+ * So we cannot apply multiple processors.
1867
+ */
1868
+ if (options.preprocess || options.postprocess) {
1869
+ return this._distinguishSuppressedMessages(
1870
+ this._verifyWithProcessor(
1871
+ textOrSourceCode,
1872
+ configToUse,
1873
+ options,
1874
+ ),
1875
+ );
1876
+ }
1877
+ return this._distinguishSuppressedMessages(
1878
+ this._verifyWithoutProcessors(
1879
+ textOrSourceCode,
1880
+ configToUse,
1881
+ options,
1882
+ ),
1883
+ );
1884
+ }
1885
+
1886
+ /**
1887
+ * Verify with a processor.
1888
+ * @param {string|SourceCode} textOrSourceCode The source code.
1889
+ * @param {FlatConfig} config The config array.
1890
+ * @param {VerifyOptions&ProcessorOptions} options The options.
1891
+ * @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
1892
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
1893
+ */
1894
+ _verifyWithFlatConfigArrayAndProcessor(
1895
+ textOrSourceCode,
1896
+ config,
1897
+ options,
1898
+ configForRecursive,
1899
+ ) {
1900
+ const slots = internalSlotsMap.get(this);
1901
+ const filename = options.filename || "<input>";
1902
+ const filenameToExpose = normalizeFilename(filename);
1903
+ const physicalFilename = options.physicalFilename || filenameToExpose;
1904
+ const text = ensureText(textOrSourceCode);
1905
+ const file = new VFile(filenameToExpose, text, {
1906
+ physicalPath: physicalFilename,
1907
+ });
1908
+
1909
+ const preprocess = options.preprocess || (rawText => [rawText]);
1910
+ const postprocess =
1911
+ options.postprocess || (messagesList => messagesList.flat());
1912
+
1913
+ const processorService = new ProcessorService();
1914
+ const preprocessResult = processorService.preprocessSync(file, {
1915
+ processor: {
1916
+ preprocess,
1917
+ postprocess,
1918
+ },
1919
+ });
1920
+
1921
+ if (!preprocessResult.ok) {
1922
+ return preprocessResult.errors;
1923
+ }
1924
+
1925
+ const filterCodeBlock =
1926
+ options.filterCodeBlock ||
1927
+ (blockFilename => blockFilename.endsWith(".js"));
1928
+ const originalExtname = path.extname(filename);
1929
+ const { files } = preprocessResult;
1930
+
1931
+ const messageLists = files.map(block => {
1932
+ debug("A code block was found: %o", block.path || "(unnamed)");
1933
+
1934
+ // Keep the legacy behavior.
1935
+ if (typeof block === "string") {
1936
+ return this._verifyWithFlatConfigArrayAndWithoutProcessors(
1937
+ block,
1938
+ config,
1939
+ options,
1940
+ );
1941
+ }
1942
+
1943
+ // Skip this block if filtered.
1944
+ if (!filterCodeBlock(block.path, block.body)) {
1945
+ debug("This code block was skipped.");
1946
+ return [];
1947
+ }
1948
+
1949
+ // Resolve configuration again if the file content or extension was changed.
1950
+ if (
1951
+ configForRecursive &&
1952
+ (text !== block.rawBody ||
1953
+ path.extname(block.path) !== originalExtname)
1954
+ ) {
1955
+ debug(
1956
+ "Resolving configuration again because the file content or extension was changed.",
1957
+ );
1958
+ return this._verifyWithFlatConfigArray(
1959
+ block.rawBody,
1960
+ configForRecursive,
1961
+ {
1962
+ ...options,
1963
+ filename: block.path,
1964
+ physicalFilename: block.physicalPath,
1965
+ },
1966
+ );
1967
+ }
1968
+
1969
+ slots.lastSourceCode = null;
1970
+
1971
+ // Does lint.
1972
+ return this.#flatVerifyWithoutProcessors(block, config, {
1973
+ ...options,
1974
+ filename: block.path,
1975
+ physicalFilename: block.physicalPath,
1976
+ });
1977
+ });
1978
+
1979
+ return processorService.postprocessSync(file, messageLists, {
1980
+ processor: {
1981
+ preprocess,
1982
+ postprocess,
1983
+ },
1984
+ });
1985
+ }
1986
+
1987
+ /**
1988
+ * Verify using flat config and without any processors.
1989
+ * @param {VFile} file The file to lint.
1990
+ * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
1991
+ * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1992
+ * @throws {Error} If during rule execution.
1993
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
1994
+ */
1995
+ #flatVerifyWithoutProcessors(file, providedConfig, providedOptions) {
1996
+ const slots = internalSlotsMap.get(this);
1997
+ const config = providedConfig || {};
1998
+ const { settings = {}, languageOptions } = config;
1999
+ const options = normalizeVerifyOptions(providedOptions, config);
2000
+
2001
+ if (!slots.lastSourceCode) {
2002
+ let t;
2003
+
2004
+ if (options.stats) {
2005
+ t = startTime();
2006
+ }
2007
+
2008
+ const parserService = new ParserService();
2009
+ const parseResult = parserService.parseSync(file, config);
2010
+
2011
+ if (options.stats) {
2012
+ const time = endTime(t);
2013
+
2014
+ storeTime(time, { type: "parse" }, slots);
2015
+ }
2016
+
2017
+ if (!parseResult.ok) {
2018
+ return parseResult.errors;
2019
+ }
2020
+
2021
+ slots.lastSourceCode = parseResult.sourceCode;
2022
+ } else {
2023
+ /*
2024
+ * If the given source code object as the first argument does not have scopeManager, analyze the scope.
2025
+ * This is for backward compatibility (SourceCode is frozen so it cannot rebind).
2026
+ *
2027
+ * We check explicitly for `null` to ensure that this is a JS-flavored language.
2028
+ * For non-JS languages we don't want to do this.
2029
+ *
2030
+ * TODO: Remove this check when we stop exporting the `SourceCode` object.
2031
+ */
2032
+ if (slots.lastSourceCode.scopeManager === null) {
2033
+ slots.lastSourceCode = new SourceCode({
2034
+ text: slots.lastSourceCode.text,
2035
+ ast: slots.lastSourceCode.ast,
2036
+ hasBOM: slots.lastSourceCode.hasBOM,
2037
+ parserServices: slots.lastSourceCode.parserServices,
2038
+ visitorKeys: slots.lastSourceCode.visitorKeys,
2039
+ scopeManager: analyzeScope(
2040
+ slots.lastSourceCode.ast,
2041
+ languageOptions,
2042
+ ),
2043
+ });
2044
+ }
2045
+ }
2046
+
2047
+ const sourceCode = slots.lastSourceCode;
2048
+
2049
+ /*
2050
+ * Make adjustments based on the language options. For JavaScript,
2051
+ * this is primarily about adding variables into the global scope
2052
+ * to account for ecmaVersion and configured globals.
2053
+ */
2054
+ sourceCode.applyLanguageOptions?.(languageOptions);
2055
+
2056
+ const mergedInlineConfig = {
2057
+ rules: {},
2058
+ };
2059
+ const inlineConfigProblems = [];
2060
+
2061
+ /*
2062
+ * Inline config can be either enabled or disabled. If disabled, it's possible
2063
+ * to detect the inline config and emit a warning (though this is not required).
2064
+ * So we first check to see if inline config is allowed at all, and if so, we
2065
+ * need to check if it's a warning or not.
2066
+ */
2067
+ if (options.allowInlineConfig) {
2068
+ // if inline config should warn then add the warnings
2069
+ if (options.warnInlineConfig) {
2070
+ if (sourceCode.getInlineConfigNodes) {
2071
+ sourceCode.getInlineConfigNodes().forEach(node => {
2072
+ const loc = sourceCode.getLoc(node);
2073
+ const range = sourceCode.getRange(node);
2074
+
2075
+ inlineConfigProblems.push(
2076
+ createLintingProblem({
2077
+ ruleId: null,
2078
+ message: `'${sourceCode.text.slice(range[0], range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`,
2079
+ loc,
2080
+ severity: 1,
2081
+ language: config.language,
2082
+ }),
2083
+ );
2084
+ });
2085
+ }
2086
+ } else {
2087
+ const inlineConfigResult = sourceCode.applyInlineConfig?.();
2088
+
2089
+ if (inlineConfigResult) {
2090
+ inlineConfigProblems.push(
2091
+ ...inlineConfigResult.problems
2092
+ .map(problem =>
2093
+ createLintingProblem({
2094
+ ...problem,
2095
+ language: config.language,
2096
+ }),
2097
+ )
2098
+ .map(problem => {
2099
+ problem.fatal = true;
2100
+ return problem;
2101
+ }),
2102
+ );
2103
+
2104
+ // next we need to verify information about the specified rules
2105
+ const ruleValidator = new RuleValidator();
2106
+
2107
+ for (const {
2108
+ config: inlineConfig,
2109
+ loc,
2110
+ } of inlineConfigResult.configs) {
2111
+ Object.keys(inlineConfig.rules).forEach(ruleId => {
2112
+ const rule = getRuleFromConfig(ruleId, config);
2113
+ const ruleValue = inlineConfig.rules[ruleId];
2114
+
2115
+ if (!rule) {
2116
+ inlineConfigProblems.push(
2117
+ createLintingProblem({
2118
+ ruleId,
2119
+ loc,
2120
+ language: config.language,
2121
+ }),
2122
+ );
2123
+ return;
2124
+ }
2125
+
2126
+ if (
2127
+ Object.hasOwn(mergedInlineConfig.rules, ruleId)
2128
+ ) {
2129
+ inlineConfigProblems.push(
2130
+ createLintingProblem({
2131
+ message: `Rule "${ruleId}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
2132
+ loc,
2133
+ language: config.language,
2134
+ }),
2135
+ );
2136
+ return;
2137
+ }
2138
+
2139
+ try {
2140
+ const ruleOptionsInline = asArray(ruleValue);
2141
+ let ruleOptions = ruleOptionsInline;
2142
+
2143
+ assertIsRuleSeverity(ruleId, ruleOptions[0]);
2144
+
2145
+ /*
2146
+ * If the rule was already configured, inline rule configuration that
2147
+ * only has severity should retain options from the config and just override the severity.
2148
+ *
2149
+ * Example:
2150
+ *
2151
+ * {
2152
+ * rules: {
2153
+ * curly: ["error", "multi"]
2154
+ * }
2155
+ * }
2156
+ *
2157
+ * /* eslint curly: ["warn"] * /
2158
+ *
2159
+ * Results in:
2160
+ *
2161
+ * curly: ["warn", "multi"]
2162
+ */
2163
+
2164
+ let shouldValidateOptions = true;
2165
+
2166
+ if (
2167
+ /*
2168
+ * If inline config for the rule has only severity
2169
+ */
2170
+ ruleOptions.length === 1 &&
2171
+ /*
2172
+ * And the rule was already configured
2173
+ */
2174
+ config.rules &&
2175
+ Object.hasOwn(config.rules, ruleId)
2176
+ ) {
2177
+ /*
2178
+ * Then use severity from the inline config and options from the provided config
2179
+ */
2180
+ ruleOptions = [
2181
+ ruleOptions[0], // severity from the inline config
2182
+ ...config.rules[ruleId].slice(1), // options from the provided config
2183
+ ];
2184
+
2185
+ // if the rule was enabled, the options have already been validated
2186
+ if (config.rules[ruleId][0] > 0) {
2187
+ shouldValidateOptions = false;
2188
+ }
2189
+ } else {
2190
+ /**
2191
+ * Since we know the user provided options, apply defaults on top of them
2192
+ */
2193
+ const slicedOptions = ruleOptions.slice(1);
2194
+ const mergedOptions = deepMergeArrays(
2195
+ rule.meta?.defaultOptions,
2196
+ slicedOptions,
2197
+ );
2198
+
2199
+ if (mergedOptions.length) {
2200
+ ruleOptions = [
2201
+ ruleOptions[0],
2202
+ ...mergedOptions,
2203
+ ];
2204
+ }
2205
+ }
2206
+
2207
+ if (
2208
+ options.reportUnusedInlineConfigs !== "off"
2209
+ ) {
2210
+ addProblemIfSameSeverityAndOptions(
2211
+ config,
2212
+ loc,
2213
+ inlineConfigProblems,
2214
+ ruleId,
2215
+ ruleOptions,
2216
+ ruleOptionsInline,
2217
+ options.reportUnusedInlineConfigs,
2218
+ );
2219
+ }
2220
+
2221
+ if (shouldValidateOptions) {
2222
+ ruleValidator.validate({
2223
+ plugins: config.plugins,
2224
+ rules: {
2225
+ [ruleId]: ruleOptions,
2226
+ },
2227
+ });
2228
+ }
2229
+
2230
+ mergedInlineConfig.rules[ruleId] = ruleOptions;
2231
+ } catch (err) {
2232
+ /*
2233
+ * If the rule has invalid `meta.schema`, throw the error because
2234
+ * this is not an invalid inline configuration but an invalid rule.
2235
+ */
2236
+ if (
2237
+ err.code ===
2238
+ "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
2239
+ ) {
2240
+ throw err;
2241
+ }
2242
+
2243
+ let baseMessage = err.message
2244
+ .slice(
2245
+ err.message.startsWith('Key "rules":')
2246
+ ? err.message.indexOf(":", 12) + 1
2247
+ : err.message.indexOf(":") + 1,
2248
+ )
2249
+ .trim();
2250
+
2251
+ if (err.messageTemplate) {
2252
+ baseMessage += ` You passed "${ruleValue}".`;
2253
+ }
2254
+
2255
+ inlineConfigProblems.push(
2256
+ createLintingProblem({
2257
+ ruleId,
2258
+ message: `Inline configuration for rule "${ruleId}" is invalid:\n\t${baseMessage}\n`,
2259
+ loc,
2260
+ language: config.language,
2261
+ }),
2262
+ );
2263
+ }
2264
+ });
2265
+ }
2266
+ }
2267
+ }
2268
+ }
2269
+
2270
+ const commentDirectives =
2271
+ options.allowInlineConfig && !options.warnInlineConfig
2272
+ ? getDirectiveCommentsForFlatConfig(
2273
+ sourceCode,
2274
+ ruleId => getRuleFromConfig(ruleId, config),
2275
+ config.language,
2276
+ )
2277
+ : { problems: [], disableDirectives: [] };
2278
+
2279
+ const configuredRules = Object.assign(
2280
+ {},
2281
+ config.rules,
2282
+ mergedInlineConfig.rules,
2283
+ );
2284
+
2285
+ let lintingProblems;
2286
+
2287
+ sourceCode.finalize?.();
2288
+
2289
+ try {
2290
+ lintingProblems = runRules(
2291
+ sourceCode,
2292
+ configuredRules,
2293
+ ruleId => getRuleFromConfig(ruleId, config),
2294
+ void 0,
2295
+ config.language,
2296
+ languageOptions,
2297
+ settings,
2298
+ options.filename,
2299
+ false,
2300
+ options.disableFixes,
2301
+ slots.cwd,
2302
+ providedOptions.physicalFilename,
2303
+ options.ruleFilter,
2304
+ options.stats,
2305
+ slots,
2306
+ );
2307
+ } catch (err) {
2308
+ err.message += `\nOccurred while linting ${options.filename}`;
2309
+ debug("An error occurred while traversing");
2310
+ debug("Filename:", options.filename);
2311
+ if (err.currentNode) {
2312
+ const { line } = sourceCode.getLoc(err.currentNode).start;
2313
+
2314
+ debug("Line:", line);
2315
+ err.message += `:${line}`;
2316
+ }
2317
+ debug("Parser Options:", languageOptions.parserOptions);
2318
+
2319
+ // debug("Parser Path:", parserName);
2320
+ debug("Settings:", settings);
2321
+
2322
+ if (err.ruleId) {
2323
+ err.message += `\nRule: "${err.ruleId}"`;
2324
+ }
2325
+
2326
+ throw err;
2327
+ }
2328
+
2329
+ return applyDisableDirectives({
2330
+ language: config.language,
2331
+ sourceCode,
2332
+ directives: commentDirectives.disableDirectives,
2333
+ disableFixes: options.disableFixes,
2334
+ problems: lintingProblems
2335
+ .concat(commentDirectives.problems)
2336
+ .concat(inlineConfigProblems)
2337
+ .sort(
2338
+ (problemA, problemB) =>
2339
+ problemA.line - problemB.line ||
2340
+ problemA.column - problemB.column,
2341
+ ),
2342
+ reportUnusedDisableDirectives:
2343
+ options.reportUnusedDisableDirectives,
2344
+ ruleFilter: options.ruleFilter,
2345
+ configuredRules,
2346
+ });
2347
+ }
2348
+
2349
+ /**
2350
+ * Same as linter.verify, except without support for processors.
2351
+ * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
2352
+ * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
2353
+ * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
2354
+ * @throws {Error} If during rule execution.
2355
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
2356
+ */
2357
+ _verifyWithFlatConfigArrayAndWithoutProcessors(
2358
+ textOrSourceCode,
2359
+ providedConfig,
2360
+ providedOptions,
2361
+ ) {
2362
+ const slots = internalSlotsMap.get(this);
2363
+ const filename = normalizeFilename(
2364
+ providedOptions.filename || "<input>",
2365
+ );
2366
+ let text;
2367
+
2368
+ // evaluate arguments
2369
+ if (typeof textOrSourceCode === "string") {
2370
+ slots.lastSourceCode = null;
2371
+ text = textOrSourceCode;
2372
+ } else {
2373
+ slots.lastSourceCode = textOrSourceCode;
2374
+ text = textOrSourceCode.text;
2375
+ }
2376
+
2377
+ const file = new VFile(filename, text, {
2378
+ physicalPath: providedOptions.physicalFilename,
2379
+ });
2380
+
2381
+ return this.#flatVerifyWithoutProcessors(
2382
+ file,
2383
+ providedConfig,
2384
+ providedOptions,
2385
+ );
2386
+ }
2387
+
2388
+ /**
2389
+ * Verify a given code with `ConfigArray`.
2390
+ * @param {string|SourceCode} textOrSourceCode The source code.
2391
+ * @param {ConfigArray} configArray The config array.
2392
+ * @param {VerifyOptions&ProcessorOptions} options The options.
2393
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
2394
+ */
2395
+ _verifyWithConfigArray(textOrSourceCode, configArray, options) {
2396
+ debug("With ConfigArray: %s", options.filename);
2397
+
2398
+ // Store the config array in order to get plugin envs and rules later.
2399
+ internalSlotsMap.get(this).lastConfigArray = configArray;
2400
+
2401
+ // Extract the final config for this file.
2402
+ const config = configArray.extractConfig(options.filename);
2403
+ const processor =
2404
+ config.processor &&
2405
+ configArray.pluginProcessors.get(config.processor);
2406
+
2407
+ // Verify.
2408
+ if (processor) {
2409
+ debug("Apply the processor: %o", config.processor);
2410
+ const { preprocess, postprocess, supportsAutofix } = processor;
2411
+ const disableFixes = options.disableFixes || !supportsAutofix;
2412
+
2413
+ return this._verifyWithProcessor(
2414
+ textOrSourceCode,
2415
+ config,
2416
+ { ...options, disableFixes, postprocess, preprocess },
2417
+ configArray,
2418
+ );
2419
+ }
2420
+ return this._verifyWithoutProcessors(textOrSourceCode, config, options);
2421
+ }
2422
+
2423
+ /**
2424
+ * Verify a given code with a flat config.
2425
+ * @param {string|SourceCode} textOrSourceCode The source code.
2426
+ * @param {FlatConfigArray} configArray The config array.
2427
+ * @param {VerifyOptions&ProcessorOptions} options The options.
2428
+ * @param {boolean} [firstCall=false] Indicates if this is being called directly
2429
+ * from verify(). (TODO: Remove once eslintrc is removed.)
2430
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
2431
+ */
2432
+ _verifyWithFlatConfigArray(
2433
+ textOrSourceCode,
2434
+ configArray,
2435
+ options,
2436
+ firstCall = false,
2437
+ ) {
2438
+ debug("With flat config: %s", options.filename);
2439
+
2440
+ // we need a filename to match configs against
2441
+ const filename = options.filename || "__placeholder__.js";
2442
+
2443
+ // Store the config array in order to get plugin envs and rules later.
2444
+ internalSlotsMap.get(this).lastConfigArray = configArray;
2445
+ const config = configArray.getConfig(filename);
2446
+
2447
+ if (!config) {
2448
+ return [
2449
+ {
2450
+ ruleId: null,
2451
+ severity: 1,
2452
+ message: `No matching configuration found for ${filename}.`,
2453
+ line: 0,
2454
+ column: 0,
2455
+ nodeType: null,
2456
+ },
2457
+ ];
2458
+ }
2459
+
2460
+ // Verify.
2461
+ if (config.processor) {
2462
+ debug("Apply the processor: %o", config.processor);
2463
+ const { preprocess, postprocess, supportsAutofix } =
2464
+ config.processor;
2465
+ const disableFixes = options.disableFixes || !supportsAutofix;
2466
+
2467
+ return this._verifyWithFlatConfigArrayAndProcessor(
2468
+ textOrSourceCode,
2469
+ config,
2470
+ { ...options, filename, disableFixes, postprocess, preprocess },
2471
+ configArray,
2472
+ );
2473
+ }
2474
+
2475
+ // check for options-based processing
2476
+ if (firstCall && (options.preprocess || options.postprocess)) {
2477
+ return this._verifyWithFlatConfigArrayAndProcessor(
2478
+ textOrSourceCode,
2479
+ config,
2480
+ options,
2481
+ );
2482
+ }
2483
+
2484
+ return this._verifyWithFlatConfigArrayAndWithoutProcessors(
2485
+ textOrSourceCode,
2486
+ config,
2487
+ options,
2488
+ );
2489
+ }
2490
+
2491
+ /**
2492
+ * Verify with a processor.
2493
+ * @param {string|SourceCode} textOrSourceCode The source code.
2494
+ * @param {ConfigData|ExtractedConfig} config The config array.
2495
+ * @param {VerifyOptions&ProcessorOptions} options The options.
2496
+ * @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
2497
+ * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
2498
+ */
2499
+ _verifyWithProcessor(
2500
+ textOrSourceCode,
2501
+ config,
2502
+ options,
2503
+ configForRecursive,
2504
+ ) {
2505
+ const slots = internalSlotsMap.get(this);
2506
+ const filename = options.filename || "<input>";
2507
+ const filenameToExpose = normalizeFilename(filename);
2508
+ const physicalFilename = options.physicalFilename || filenameToExpose;
2509
+ const text = ensureText(textOrSourceCode);
2510
+ const file = new VFile(filenameToExpose, text, {
2511
+ physicalPath: physicalFilename,
2512
+ });
2513
+
2514
+ const preprocess = options.preprocess || (rawText => [rawText]);
2515
+ const postprocess =
2516
+ options.postprocess || (messagesList => messagesList.flat());
2517
+
2518
+ const processorService = new ProcessorService();
2519
+ const preprocessResult = processorService.preprocessSync(file, {
2520
+ processor: {
2521
+ preprocess,
2522
+ postprocess,
2523
+ },
2524
+ });
2525
+
2526
+ if (!preprocessResult.ok) {
2527
+ return preprocessResult.errors;
2528
+ }
2529
+
2530
+ const filterCodeBlock =
2531
+ options.filterCodeBlock ||
2532
+ (blockFilePath => blockFilePath.endsWith(".js"));
2533
+ const originalExtname = path.extname(filename);
2534
+
2535
+ const { files } = preprocessResult;
2536
+
2537
+ const messageLists = files.map(block => {
2538
+ debug("A code block was found: %o", block.path ?? "(unnamed)");
2539
+
2540
+ // Keep the legacy behavior.
2541
+ if (typeof block === "string") {
2542
+ return this._verifyWithoutProcessors(block, config, options);
2543
+ }
2544
+
2545
+ // Skip this block if filtered.
2546
+ if (!filterCodeBlock(block.path, block.body)) {
2547
+ debug("This code block was skipped.");
2548
+ return [];
2549
+ }
2550
+
2551
+ // Resolve configuration again if the file content or extension was changed.
2552
+ if (
2553
+ configForRecursive &&
2554
+ (text !== block.rawBody ||
2555
+ path.extname(block.path) !== originalExtname)
2556
+ ) {
2557
+ debug(
2558
+ "Resolving configuration again because the file content or extension was changed.",
2559
+ );
2560
+ return this._verifyWithConfigArray(
2561
+ block.rawBody,
2562
+ configForRecursive,
2563
+ {
2564
+ ...options,
2565
+ filename: block.path,
2566
+ physicalFilename: block.physicalPath,
2567
+ },
2568
+ );
2569
+ }
2570
+
2571
+ slots.lastSourceCode = null;
2572
+
2573
+ // Does lint.
2574
+ return this.#eslintrcVerifyWithoutProcessors(block, config, {
2575
+ ...options,
2576
+ filename: block.path,
2577
+ physicalFilename: block.physicalPath,
2578
+ });
2579
+ });
2580
+
2581
+ return processorService.postprocessSync(file, messageLists, {
2582
+ processor: {
2583
+ preprocess,
2584
+ postprocess,
2585
+ },
2586
+ });
2587
+ }
2588
+
2589
+ /**
2590
+ * Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
2591
+ * The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
2592
+ * @param {Array<LintMessage|SuppressedLintMessage>} problems A list of reported problems.
2593
+ * @returns {LintMessage[]} A list of LintMessage.
2594
+ */
2595
+ _distinguishSuppressedMessages(problems) {
2596
+ const messages = [];
2597
+ const suppressedMessages = [];
2598
+ const slots = internalSlotsMap.get(this);
2599
+
2600
+ for (const problem of problems) {
2601
+ if (problem.suppressions) {
2602
+ suppressedMessages.push(problem);
2603
+ } else {
2604
+ messages.push(problem);
2605
+ }
2606
+ }
2607
+
2608
+ slots.lastSuppressedMessages = suppressedMessages;
2609
+
2610
+ return messages;
2611
+ }
2612
+
2613
+ /**
2614
+ * Gets the SourceCode object representing the parsed source.
2615
+ * @returns {SourceCode} The SourceCode object.
2616
+ */
2617
+ getSourceCode() {
2618
+ return internalSlotsMap.get(this).lastSourceCode;
2619
+ }
2620
+
2621
+ /**
2622
+ * Gets the times spent on (parsing, fixing, linting) a file.
2623
+ * @returns {LintTimes} The times.
2624
+ */
2625
+ getTimes() {
2626
+ return internalSlotsMap.get(this).times ?? { passes: [] };
2627
+ }
2628
+
2629
+ /**
2630
+ * Gets the number of autofix passes that were made in the last run.
2631
+ * @returns {number} The number of autofix passes.
2632
+ */
2633
+ getFixPassCount() {
2634
+ return internalSlotsMap.get(this).fixPasses ?? 0;
2635
+ }
2636
+
2637
+ /**
2638
+ * Gets the list of SuppressedLintMessage produced in the last running.
2639
+ * @returns {SuppressedLintMessage[]} The list of SuppressedLintMessage
2640
+ */
2641
+ getSuppressedMessages() {
2642
+ return internalSlotsMap.get(this).lastSuppressedMessages;
2643
+ }
2644
+
2645
+ /**
2646
+ * Defines a new linting rule.
2647
+ * @param {string} ruleId A unique rule identifier
2648
+ * @param {Rule} rule A rule object
2649
+ * @returns {void}
2650
+ */
2651
+ defineRule(ruleId, rule) {
2652
+ assertEslintrcConfig(this);
2653
+ internalSlotsMap.get(this).ruleMap.define(ruleId, rule);
2654
+ }
2655
+
2656
+ /**
2657
+ * Defines many new linting rules.
2658
+ * @param {Record<string, Rule>} rulesToDefine map from unique rule identifier to rule
2659
+ * @returns {void}
2660
+ */
2661
+ defineRules(rulesToDefine) {
2662
+ assertEslintrcConfig(this);
2663
+ Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => {
2664
+ this.defineRule(ruleId, rulesToDefine[ruleId]);
2665
+ });
2666
+ }
2667
+
2668
+ /**
2669
+ * Gets an object with all loaded rules.
2670
+ * @returns {Map<string, Rule>} All loaded rules
2671
+ */
2672
+ getRules() {
2673
+ assertEslintrcConfig(this);
2674
+ const { lastConfigArray, ruleMap } = internalSlotsMap.get(this);
2675
+
2676
+ return new Map(
2677
+ (function* () {
2678
+ yield* ruleMap;
2679
+
2680
+ if (lastConfigArray) {
2681
+ yield* lastConfigArray.pluginRules;
2682
+ }
2683
+ })(),
2684
+ );
2685
+ }
2686
+
2687
+ /**
2688
+ * Define a new parser module
2689
+ * @param {string} parserId Name of the parser
2690
+ * @param {Parser} parserModule The parser object
2691
+ * @returns {void}
2692
+ */
2693
+ defineParser(parserId, parserModule) {
2694
+ assertEslintrcConfig(this);
2695
+ internalSlotsMap.get(this).parserMap.set(parserId, parserModule);
2696
+ }
2697
+
2698
+ /**
2699
+ * Performs multiple autofix passes over the text until as many fixes as possible
2700
+ * have been applied.
2701
+ * @param {string} text The source text to apply fixes to.
2702
+ * @param {ConfigData|ConfigArray|FlatConfigArray} config The ESLint config object to use.
2703
+ * @param {VerifyOptions&ProcessorOptions&FixOptions} options The ESLint options object to use.
2704
+ * @returns {{fixed:boolean,messages:LintMessage[],output:string}} The result of the fix operation as returned from the
2705
+ * SourceCodeFixer.
2706
+ */
2707
+ verifyAndFix(text, config, options) {
2708
+ let messages,
2709
+ fixedResult,
2710
+ fixed = false,
2711
+ passNumber = 0,
2712
+ currentText = text,
2713
+ secondPreviousText,
2714
+ previousText;
2715
+ const debugTextDescription =
2716
+ (options && options.filename) || `${text.slice(0, 10)}...`;
2717
+ const shouldFix =
2718
+ options && typeof options.fix !== "undefined" ? options.fix : true;
2719
+ const stats = options?.stats;
2720
+
2721
+ /**
2722
+ * This loop continues until one of the following is true:
2723
+ *
2724
+ * 1. No more fixes have been applied.
2725
+ * 2. Ten passes have been made.
2726
+ *
2727
+ * That means anytime a fix is successfully applied, there will be another pass.
2728
+ * Essentially, guaranteeing a minimum of two passes.
2729
+ */
2730
+ const slots = internalSlotsMap.get(this);
2731
+
2732
+ // Remove lint times from the last run.
2733
+ if (stats) {
2734
+ delete slots.times;
2735
+ slots.fixPasses = 0;
2736
+ }
2737
+
2738
+ do {
2739
+ passNumber++;
2740
+ let tTotal;
2741
+
2742
+ if (stats) {
2743
+ tTotal = startTime();
2744
+ }
2745
+
2746
+ debug(
2747
+ `Linting code for ${debugTextDescription} (pass ${passNumber})`,
2748
+ );
2749
+ messages = this.verify(currentText, config, options);
2750
+
2751
+ debug(
2752
+ `Generating fixed text for ${debugTextDescription} (pass ${passNumber})`,
2753
+ );
2754
+ let t;
2755
+
2756
+ if (stats) {
2757
+ t = startTime();
2758
+ }
2759
+
2760
+ fixedResult = SourceCodeFixer.applyFixes(
2761
+ currentText,
2762
+ messages,
2763
+ shouldFix,
2764
+ );
2765
+
2766
+ if (stats) {
2767
+ if (fixedResult.fixed) {
2768
+ const time = endTime(t);
2769
+
2770
+ storeTime(time, { type: "fix" }, slots);
2771
+ slots.fixPasses++;
2772
+ } else {
2773
+ storeTime(0, { type: "fix" }, slots);
2774
+ }
2775
+ }
2776
+
2777
+ /*
2778
+ * stop if there are any syntax errors.
2779
+ * 'fixedResult.output' is a empty string.
2780
+ */
2781
+ if (messages.length === 1 && messages[0].fatal) {
2782
+ break;
2783
+ }
2784
+
2785
+ // keep track if any fixes were ever applied - important for return value
2786
+ fixed = fixed || fixedResult.fixed;
2787
+
2788
+ // update to use the fixed output instead of the original text
2789
+ secondPreviousText = previousText;
2790
+ previousText = currentText;
2791
+ currentText = fixedResult.output;
2792
+
2793
+ if (stats) {
2794
+ tTotal = endTime(tTotal);
2795
+ const passIndex = slots.times.passes.length - 1;
2796
+
2797
+ slots.times.passes[passIndex].total = tTotal;
2798
+ }
2799
+
2800
+ // Stop if we've made a circular fix
2801
+ if (
2802
+ passNumber > 1 &&
2803
+ currentText.length === secondPreviousText.length &&
2804
+ currentText === secondPreviousText
2805
+ ) {
2806
+ debug(
2807
+ `Circular fixes detected after pass ${passNumber}. Exiting fix loop.`,
2808
+ );
2809
+ globalThis?.process?.emitWarning?.(
2810
+ `Circular fixes detected while fixing ${options?.filename ?? "text"}. It is likely that you have conflicting rules in your configuration.`,
2811
+ "ESLintCircularFixesWarning",
2812
+ );
2813
+ break;
2814
+ }
2815
+ } while (fixedResult.fixed && passNumber < MAX_AUTOFIX_PASSES);
2816
+
2817
+ /*
2818
+ * If the last result had fixes, we need to lint again to be sure we have
2819
+ * the most up-to-date information.
2820
+ */
2821
+ if (fixedResult.fixed) {
2822
+ let tTotal;
2823
+
2824
+ if (stats) {
2825
+ tTotal = startTime();
2826
+ }
2827
+
2828
+ fixedResult.messages = this.verify(currentText, config, options);
2829
+
2830
+ if (stats) {
2831
+ storeTime(0, { type: "fix" }, slots);
2832
+ slots.times.passes.at(-1).total = endTime(tTotal);
2833
+ }
2834
+ }
2835
+
2836
+ // ensure the last result properly reflects if fixes were done
2837
+ fixedResult.fixed = fixed;
2838
+ fixedResult.output = currentText;
2839
+
2840
+ return fixedResult;
2841
+ }
2484
2842
  }
2485
2843
 
2486
2844
  module.exports = {
2487
- Linter,
2488
-
2489
- /**
2490
- * Get the internal slots of a given Linter instance for tests.
2491
- * @param {Linter} instance The Linter instance to get.
2492
- * @returns {LinterInternalSlots} The internal slots.
2493
- */
2494
- getLinterInternalSlots(instance) {
2495
- return internalSlotsMap.get(instance);
2496
- }
2845
+ Linter,
2846
+
2847
+ /**
2848
+ * Get the internal slots of a given Linter instance for tests.
2849
+ * @param {Linter} instance The Linter instance to get.
2850
+ * @returns {LinterInternalSlots} The internal slots.
2851
+ */
2852
+ getLinterInternalSlots(instance) {
2853
+ return internalSlotsMap.get(instance);
2854
+ },
2497
2855
  };