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
@@ -17,26 +17,24 @@ const { Linter } = require("../linter");
17
17
  const { getRuleFromConfig } = require("../config/flat-config-helpers");
18
18
  const { defaultConfig } = require("../config/default-config");
19
19
  const {
20
- Legacy: {
21
- ConfigOps: {
22
- getRuleSeverity
23
- },
24
- ModuleResolver,
25
- naming
26
- }
20
+ Legacy: {
21
+ ConfigOps: { getRuleSeverity },
22
+ ModuleResolver,
23
+ naming,
24
+ },
27
25
  } = require("@eslint/eslintrc");
28
26
 
29
27
  const {
30
- findFiles,
31
- getCacheFile,
28
+ findFiles,
29
+ getCacheFile,
32
30
 
33
- isNonEmptyString,
34
- isArrayOfNonEmptyString,
31
+ isNonEmptyString,
32
+ isArrayOfNonEmptyString,
35
33
 
36
- createIgnoreResult,
37
- isErrorMessage,
34
+ createIgnoreResult,
35
+ isErrorMessage,
38
36
 
39
- processOptions
37
+ processOptions,
40
38
  } = require("./eslint-helpers");
41
39
  const { pathToFileURL } = require("node:url");
42
40
  const LintResultCache = require("../cli-engine/lint-result-cache");
@@ -101,15 +99,15 @@ const { ConfigLoader, LegacyConfigLoader } = require("../config/config-loader");
101
99
  const debug = require("debug")("eslint:eslint");
102
100
  const privateMembers = new WeakMap();
103
101
  const removedFormatters = new Set([
104
- "checkstyle",
105
- "codeframe",
106
- "compact",
107
- "jslint-xml",
108
- "junit",
109
- "table",
110
- "tap",
111
- "unix",
112
- "visualstudio"
102
+ "checkstyle",
103
+ "codeframe",
104
+ "compact",
105
+ "jslint-xml",
106
+ "junit",
107
+ "table",
108
+ "tap",
109
+ "unix",
110
+ "visualstudio",
113
111
  ]);
114
112
 
115
113
  /**
@@ -119,33 +117,33 @@ const removedFormatters = new Set([
119
117
  * @private
120
118
  */
121
119
  function calculateStatsPerFile(messages) {
122
- const stat = {
123
- errorCount: 0,
124
- fatalErrorCount: 0,
125
- warningCount: 0,
126
- fixableErrorCount: 0,
127
- fixableWarningCount: 0
128
- };
129
-
130
- for (let i = 0; i < messages.length; i++) {
131
- const message = messages[i];
132
-
133
- if (message.fatal || message.severity === 2) {
134
- stat.errorCount++;
135
- if (message.fatal) {
136
- stat.fatalErrorCount++;
137
- }
138
- if (message.fix) {
139
- stat.fixableErrorCount++;
140
- }
141
- } else {
142
- stat.warningCount++;
143
- if (message.fix) {
144
- stat.fixableWarningCount++;
145
- }
146
- }
147
- }
148
- return stat;
120
+ const stat = {
121
+ errorCount: 0,
122
+ fatalErrorCount: 0,
123
+ warningCount: 0,
124
+ fixableErrorCount: 0,
125
+ fixableWarningCount: 0,
126
+ };
127
+
128
+ for (let i = 0; i < messages.length; i++) {
129
+ const message = messages[i];
130
+
131
+ if (message.fatal || message.severity === 2) {
132
+ stat.errorCount++;
133
+ if (message.fatal) {
134
+ stat.fatalErrorCount++;
135
+ }
136
+ if (message.fix) {
137
+ stat.fixableErrorCount++;
138
+ }
139
+ } else {
140
+ stat.warningCount++;
141
+ if (message.fix) {
142
+ stat.fixableWarningCount++;
143
+ }
144
+ }
145
+ }
146
+ return stat;
149
147
  }
150
148
 
151
149
  /**
@@ -154,10 +152,10 @@ function calculateStatsPerFile(messages) {
154
152
  * @returns {Object} metadata for all enabled rules.
155
153
  */
156
154
  function createRulesMeta(rules) {
157
- return Array.from(rules).reduce((retVal, [id, rule]) => {
158
- retVal[id] = rule.meta;
159
- return retVal;
160
- }, {});
155
+ return Array.from(rules).reduce((retVal, [id, rule]) => {
156
+ retVal[id] = rule.meta;
157
+ return retVal;
158
+ }, {});
161
159
  }
162
160
 
163
161
  /**
@@ -167,7 +165,7 @@ function createRulesMeta(rules) {
167
165
  * @returns {string} The absolute path of a file named `"__placeholder__.js"` in the given directory.
168
166
  */
169
167
  function getPlaceholderPath(cwd) {
170
- return path.join(cwd, "__placeholder__.js");
168
+ return path.join(cwd, "__placeholder__.js");
171
169
  }
172
170
 
173
171
  /** @type {WeakMap<ExtractedConfig, DeprecatedRuleInfo[]>} */
@@ -180,45 +178,49 @@ const usedDeprecatedRulesCache = new WeakMap();
180
178
  * @returns {DeprecatedRuleInfo[]} The used deprecated rule list.
181
179
  */
182
180
  function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
183
- const {
184
- options: { cwd },
185
- configLoader
186
- } = privateMembers.get(eslint);
187
- const filePath = path.isAbsolute(maybeFilePath)
188
- ? maybeFilePath
189
- : getPlaceholderPath(cwd);
190
- const configs = configLoader.getCachedConfigArrayForFile(filePath);
191
- const config = configs.getConfig(filePath);
192
-
193
- // Most files use the same config, so cache it.
194
- if (config && !usedDeprecatedRulesCache.has(config)) {
195
- const retv = [];
196
-
197
- if (config.rules) {
198
- for (const [ruleId, ruleConf] of Object.entries(config.rules)) {
199
- if (getRuleSeverity(ruleConf) === 0) {
200
- continue;
201
- }
202
- const rule = getRuleFromConfig(ruleId, config);
203
- const meta = rule && rule.meta;
204
-
205
- if (meta && meta.deprecated) {
206
- const usesNewFormat = typeof meta.deprecated === "object";
207
-
208
- retv.push({
209
- ruleId,
210
- replacedBy: usesNewFormat ? meta.deprecated.replacedBy?.map(replacement => `${replacement.plugin?.name !== void 0 ? `${naming.getShorthandName(replacement.plugin.name, "eslint-plugin")}/` : ""}${replacement.rule?.name ?? ""}`) ?? [] : meta.replacedBy || [],
211
- info: usesNewFormat ? meta.deprecated : void 0
212
- });
213
- }
214
- }
215
- }
216
-
217
-
218
- usedDeprecatedRulesCache.set(config, Object.freeze(retv));
219
- }
220
-
221
- return config ? usedDeprecatedRulesCache.get(config) : Object.freeze([]);
181
+ const {
182
+ options: { cwd },
183
+ configLoader,
184
+ } = privateMembers.get(eslint);
185
+ const filePath = path.isAbsolute(maybeFilePath)
186
+ ? maybeFilePath
187
+ : getPlaceholderPath(cwd);
188
+ const configs = configLoader.getCachedConfigArrayForFile(filePath);
189
+ const config = configs.getConfig(filePath);
190
+
191
+ // Most files use the same config, so cache it.
192
+ if (config && !usedDeprecatedRulesCache.has(config)) {
193
+ const retv = [];
194
+
195
+ if (config.rules) {
196
+ for (const [ruleId, ruleConf] of Object.entries(config.rules)) {
197
+ if (getRuleSeverity(ruleConf) === 0) {
198
+ continue;
199
+ }
200
+ const rule = getRuleFromConfig(ruleId, config);
201
+ const meta = rule && rule.meta;
202
+
203
+ if (meta && meta.deprecated) {
204
+ const usesNewFormat = typeof meta.deprecated === "object";
205
+
206
+ retv.push({
207
+ ruleId,
208
+ replacedBy: usesNewFormat
209
+ ? (meta.deprecated.replacedBy?.map(
210
+ replacement =>
211
+ `${replacement.plugin?.name !== void 0 ? `${naming.getShorthandName(replacement.plugin.name, "eslint-plugin")}/` : ""}${replacement.rule?.name ?? ""}`,
212
+ ) ?? [])
213
+ : meta.replacedBy || [],
214
+ info: usesNewFormat ? meta.deprecated : void 0,
215
+ });
216
+ }
217
+ }
218
+ }
219
+
220
+ usedDeprecatedRulesCache.set(config, Object.freeze(retv));
221
+ }
222
+
223
+ return config ? usedDeprecatedRulesCache.get(config) : Object.freeze([]);
222
224
  }
223
225
 
224
226
  /**
@@ -229,19 +231,19 @@ function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
229
231
  * @returns {LintResult[]} The processed linting results.
230
232
  */
231
233
  function processLintReport(eslint, { results }) {
232
- const descriptor = {
233
- configurable: true,
234
- enumerable: true,
235
- get() {
236
- return getOrFindUsedDeprecatedRules(eslint, this.filePath);
237
- }
238
- };
239
-
240
- for (const result of results) {
241
- Object.defineProperty(result, "usedDeprecatedRules", descriptor);
242
- }
243
-
244
- return results;
234
+ const descriptor = {
235
+ configurable: true,
236
+ enumerable: true,
237
+ get() {
238
+ return getOrFindUsedDeprecatedRules(eslint, this.filePath);
239
+ },
240
+ };
241
+
242
+ for (const result of results) {
243
+ Object.defineProperty(result, "usedDeprecatedRules", descriptor);
244
+ }
245
+
246
+ return results;
245
247
  }
246
248
 
247
249
  /**
@@ -251,18 +253,17 @@ function processLintReport(eslint, { results }) {
251
253
  * @returns {number} An integer representing the order in which the two results should occur.
252
254
  */
253
255
  function compareResultsByFilePath(a, b) {
254
- if (a.filePath < b.filePath) {
255
- return -1;
256
- }
256
+ if (a.filePath < b.filePath) {
257
+ return -1;
258
+ }
257
259
 
258
- if (a.filePath > b.filePath) {
259
- return 1;
260
- }
260
+ if (a.filePath > b.filePath) {
261
+ return 1;
262
+ }
261
263
 
262
- return 0;
264
+ return 0;
263
265
  }
264
266
 
265
-
266
267
  /**
267
268
  * Determines which config file to use. This is determined by seeing if an
268
269
  * override config file was passed, and if so, using it; otherwise, as long
@@ -276,22 +277,23 @@ function compareResultsByFilePath(a, b) {
276
277
  * the config file.
277
278
  */
278
279
  async function locateConfigFileToUse({ configFile, cwd }) {
279
-
280
- const configLoader = new ConfigLoader({
281
- cwd,
282
- configFile
283
- });
284
-
285
- const configFilePath = await configLoader.findConfigFileForPath(path.join(cwd, "__placeholder__.js"));
286
-
287
- if (!configFilePath) {
288
- throw new Error("No ESLint configuration file was found.");
289
- }
290
-
291
- return {
292
- configFilePath,
293
- basePath: configFile ? cwd : path.dirname(configFilePath)
294
- };
280
+ const configLoader = new ConfigLoader({
281
+ cwd,
282
+ configFile,
283
+ });
284
+
285
+ const configFilePath = await configLoader.findConfigFileForPath(
286
+ path.join(cwd, "__placeholder__.js"),
287
+ );
288
+
289
+ if (!configFilePath) {
290
+ throw new Error("No ESLint configuration file was found.");
291
+ }
292
+
293
+ return {
294
+ configFilePath,
295
+ basePath: configFile ? cwd : path.dirname(configFilePath),
296
+ };
295
297
  }
296
298
 
297
299
  /**
@@ -310,74 +312,71 @@ async function locateConfigFileToUse({ configFile, cwd }) {
310
312
  * @private
311
313
  */
312
314
  function verifyText({
313
- text,
314
- cwd,
315
- filePath: providedFilePath,
316
- configs,
317
- fix,
318
- allowInlineConfig,
319
- ruleFilter,
320
- stats,
321
- linter
315
+ text,
316
+ cwd,
317
+ filePath: providedFilePath,
318
+ configs,
319
+ fix,
320
+ allowInlineConfig,
321
+ ruleFilter,
322
+ stats,
323
+ linter,
322
324
  }) {
323
- const filePath = providedFilePath || "<text>";
324
-
325
- debug(`Lint ${filePath}`);
326
-
327
- /*
328
- * Verify.
329
- * `config.extractConfig(filePath)` requires an absolute path, but `linter`
330
- * doesn't know CWD, so it gives `linter` an absolute path always.
331
- */
332
- const filePathToVerify = filePath === "<text>" ? getPlaceholderPath(cwd) : filePath;
333
- const { fixed, messages, output } = linter.verifyAndFix(
334
- text,
335
- configs,
336
- {
337
- allowInlineConfig,
338
- filename: filePathToVerify,
339
- fix,
340
- ruleFilter,
341
- stats,
342
-
343
- /**
344
- * Check if the linter should adopt a given code block or not.
345
- * @param {string} blockFilename The virtual filename of a code block.
346
- * @returns {boolean} `true` if the linter should adopt the code block.
347
- */
348
- filterCodeBlock(blockFilename) {
349
- return configs.getConfig(blockFilename) !== void 0;
350
- }
351
- }
352
- );
353
-
354
- // Tweak and return.
355
- const result = {
356
- filePath: filePath === "<text>" ? filePath : path.resolve(filePath),
357
- messages,
358
- suppressedMessages: linter.getSuppressedMessages(),
359
- ...calculateStatsPerFile(messages)
360
- };
361
-
362
- if (fixed) {
363
- result.output = output;
364
- }
365
-
366
- if (
367
- result.errorCount + result.warningCount > 0 &&
368
- typeof result.output === "undefined"
369
- ) {
370
- result.source = text;
371
- }
372
-
373
- if (stats) {
374
- result.stats = {
375
- times: linter.getTimes(),
376
- fixPasses: linter.getFixPassCount()
377
- };
378
- }
379
-
380
- return result;
325
+ const filePath = providedFilePath || "<text>";
326
+
327
+ debug(`Lint ${filePath}`);
328
+
329
+ /*
330
+ * Verify.
331
+ * `config.extractConfig(filePath)` requires an absolute path, but `linter`
332
+ * doesn't know CWD, so it gives `linter` an absolute path always.
333
+ */
334
+ const filePathToVerify =
335
+ filePath === "<text>" ? getPlaceholderPath(cwd) : filePath;
336
+ const { fixed, messages, output } = linter.verifyAndFix(text, configs, {
337
+ allowInlineConfig,
338
+ filename: filePathToVerify,
339
+ fix,
340
+ ruleFilter,
341
+ stats,
342
+
343
+ /**
344
+ * Check if the linter should adopt a given code block or not.
345
+ * @param {string} blockFilename The virtual filename of a code block.
346
+ * @returns {boolean} `true` if the linter should adopt the code block.
347
+ */
348
+ filterCodeBlock(blockFilename) {
349
+ return configs.getConfig(blockFilename) !== void 0;
350
+ },
351
+ });
352
+
353
+ // Tweak and return.
354
+ const result = {
355
+ filePath: filePath === "<text>" ? filePath : path.resolve(filePath),
356
+ messages,
357
+ suppressedMessages: linter.getSuppressedMessages(),
358
+ ...calculateStatsPerFile(messages),
359
+ };
360
+
361
+ if (fixed) {
362
+ result.output = output;
363
+ }
364
+
365
+ if (
366
+ result.errorCount + result.warningCount > 0 &&
367
+ typeof result.output === "undefined"
368
+ ) {
369
+ result.source = text;
370
+ }
371
+
372
+ if (stats) {
373
+ result.stats = {
374
+ times: linter.getTimes(),
375
+ fixPasses: linter.getFixPassCount(),
376
+ };
377
+ }
378
+
379
+ return result;
381
380
  }
382
381
 
383
382
  /**
@@ -388,13 +387,13 @@ function verifyText({
388
387
  * @returns {boolean} Whether the message should be fixed.
389
388
  */
390
389
  function shouldMessageBeFixed(message, config, fixTypes) {
391
- if (!message.ruleId) {
392
- return fixTypes.has("directive");
393
- }
390
+ if (!message.ruleId) {
391
+ return fixTypes.has("directive");
392
+ }
394
393
 
395
- const rule = message.ruleId && getRuleFromConfig(message.ruleId, config);
394
+ const rule = message.ruleId && getRuleFromConfig(message.ruleId, config);
396
395
 
397
- return Boolean(rule && rule.meta && fixTypes.has(rule.meta.type));
396
+ return Boolean(rule && rule.meta && fixTypes.has(rule.meta.type));
398
397
  }
399
398
 
400
399
  /**
@@ -402,7 +401,9 @@ function shouldMessageBeFixed(message, config, fixTypes) {
402
401
  * @returns {TypeError} An error object.
403
402
  */
404
403
  function createExtraneousResultsError() {
405
- return new TypeError("Results object was not created from this ESLint instance.");
404
+ return new TypeError(
405
+ "Results object was not created from this ESLint instance.",
406
+ );
406
407
  }
407
408
 
408
409
  /**
@@ -413,13 +414,15 @@ function createExtraneousResultsError() {
413
414
  * @returns {Function|boolean} The fixer function or the original fix value.
414
415
  */
415
416
  function getFixerForFixTypes(fix, fixTypesSet, config) {
416
- if (!fix || !fixTypesSet) {
417
- return fix;
418
- }
417
+ if (!fix || !fixTypesSet) {
418
+ return fix;
419
+ }
419
420
 
420
- const originalFix = (typeof fix === "function") ? fix : () => true;
421
+ const originalFix = typeof fix === "function" ? fix : () => true;
421
422
 
422
- return message => shouldMessageBeFixed(message, config, fixTypesSet) && originalFix(message);
423
+ return message =>
424
+ shouldMessageBeFixed(message, config, fixTypesSet) &&
425
+ originalFix(message);
423
426
  }
424
427
 
425
428
  //-----------------------------------------------------------------------------
@@ -430,679 +433,734 @@ function getFixerForFixTypes(fix, fixTypesSet, config) {
430
433
  * Primary Node.js API for ESLint.
431
434
  */
432
435
  class ESLint {
433
-
434
- /**
435
- * The type of configuration used by this class.
436
- * @type {string}
437
- */
438
- static configType = "flat";
439
-
440
- /**
441
- * The loader to use for finding config files.
442
- * @type {ConfigLoader|LegacyConfigLoader}
443
- */
444
- #configLoader;
445
-
446
- /**
447
- * Creates a new instance of the main ESLint API.
448
- * @param {ESLintOptions} options The options for this instance.
449
- */
450
- constructor(options = {}) {
451
-
452
- const defaultConfigs = [];
453
- const processedOptions = processOptions(options);
454
- const linter = new Linter({
455
- cwd: processedOptions.cwd,
456
- configType: "flat",
457
- flags: processedOptions.flags
458
- });
459
-
460
- const cacheFilePath = getCacheFile(
461
- processedOptions.cacheLocation,
462
- processedOptions.cwd
463
- );
464
-
465
- const lintResultCache = processedOptions.cache
466
- ? new LintResultCache(cacheFilePath, processedOptions.cacheStrategy)
467
- : null;
468
-
469
- const configLoaderOptions = {
470
- cwd: processedOptions.cwd,
471
- baseConfig: processedOptions.baseConfig,
472
- overrideConfig: processedOptions.overrideConfig,
473
- configFile: processedOptions.configFile,
474
- ignoreEnabled: processedOptions.ignore,
475
- ignorePatterns: processedOptions.ignorePatterns,
476
- defaultConfigs
477
- };
478
-
479
- this.#configLoader = linter.hasFlag("unstable_config_lookup_from_file")
480
- ? new ConfigLoader(configLoaderOptions)
481
- : new LegacyConfigLoader(configLoaderOptions);
482
-
483
- debug(`Using config loader ${this.#configLoader.constructor.name}`);
484
-
485
- privateMembers.set(this, {
486
- options: processedOptions,
487
- linter,
488
- cacheFilePath,
489
- lintResultCache,
490
- defaultConfigs,
491
- configs: null,
492
- configLoader: this.#configLoader
493
- });
494
-
495
-
496
- /**
497
- * If additional plugins are passed in, add that to the default
498
- * configs for this instance.
499
- */
500
- if (options.plugins) {
501
-
502
- const plugins = {};
503
-
504
- for (const [pluginName, plugin] of Object.entries(options.plugins)) {
505
- plugins[naming.getShorthandName(pluginName, "eslint-plugin")] = plugin;
506
- }
507
-
508
- defaultConfigs.push({
509
- plugins
510
- });
511
- }
512
-
513
- // Check for the .eslintignore file, and warn if it's present.
514
- if (existsSync(path.resolve(processedOptions.cwd, ".eslintignore"))) {
515
- process.emitWarning(
516
- "The \".eslintignore\" file is no longer supported. Switch to using the \"ignores\" property in \"eslint.config.js\": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files",
517
- "ESLintIgnoreWarning"
518
- );
519
- }
520
- }
521
-
522
- /**
523
- * The version text.
524
- * @type {string}
525
- */
526
- static get version() {
527
- return version;
528
- }
529
-
530
- /**
531
- * The default configuration that ESLint uses internally. This is provided for tooling that wants to calculate configurations using the same defaults as ESLint.
532
- * Keep in mind that the default configuration may change from version to version, so you shouldn't rely on any particular keys or values to be present.
533
- * @type {ConfigArray}
534
- */
535
- static get defaultConfig() {
536
- return defaultConfig;
537
- }
538
-
539
- /**
540
- * Outputs fixes from the given results to files.
541
- * @param {LintResult[]} results The lint results.
542
- * @returns {Promise<void>} Returns a promise that is used to track side effects.
543
- */
544
- static async outputFixes(results) {
545
- if (!Array.isArray(results)) {
546
- throw new Error("'results' must be an array");
547
- }
548
-
549
- await Promise.all(
550
- results
551
- .filter(result => {
552
- if (typeof result !== "object" || result === null) {
553
- throw new Error("'results' must include only objects");
554
- }
555
- return (
556
- typeof result.output === "string" &&
557
- path.isAbsolute(result.filePath)
558
- );
559
- })
560
- .map(r => fs.writeFile(r.filePath, r.output))
561
- );
562
- }
563
-
564
- /**
565
- * Returns results that only contains errors.
566
- * @param {LintResult[]} results The results to filter.
567
- * @returns {LintResult[]} The filtered results.
568
- */
569
- static getErrorResults(results) {
570
- const filtered = [];
571
-
572
- results.forEach(result => {
573
- const filteredMessages = result.messages.filter(isErrorMessage);
574
- const filteredSuppressedMessages = result.suppressedMessages.filter(isErrorMessage);
575
-
576
- if (filteredMessages.length > 0) {
577
- filtered.push({
578
- ...result,
579
- messages: filteredMessages,
580
- suppressedMessages: filteredSuppressedMessages,
581
- errorCount: filteredMessages.length,
582
- warningCount: 0,
583
- fixableErrorCount: result.fixableErrorCount,
584
- fixableWarningCount: 0
585
- });
586
- }
587
- });
588
-
589
- return filtered;
590
- }
591
-
592
- /**
593
- * Returns meta objects for each rule represented in the lint results.
594
- * @param {LintResult[]} results The results to fetch rules meta for.
595
- * @returns {Object} A mapping of ruleIds to rule meta objects.
596
- * @throws {TypeError} When the results object wasn't created from this ESLint instance.
597
- * @throws {TypeError} When a plugin or rule is missing.
598
- */
599
- getRulesMetaForResults(results) {
600
-
601
- // short-circuit simple case
602
- if (results.length === 0) {
603
- return {};
604
- }
605
-
606
- const resultRules = new Map();
607
- const {
608
- configLoader,
609
- options: { cwd }
610
- } = privateMembers.get(this);
611
-
612
- for (const result of results) {
613
-
614
- /*
615
- * Normalize filename for <text>.
616
- */
617
- const filePath = result.filePath === "<text>"
618
- ? getPlaceholderPath(cwd) : result.filePath;
619
- const allMessages = result.messages.concat(result.suppressedMessages);
620
-
621
- for (const { ruleId } of allMessages) {
622
- if (!ruleId) {
623
- continue;
624
- }
625
-
626
- /*
627
- * All of the plugin and rule information is contained within the
628
- * calculated config for the given file.
629
- */
630
- let configs;
631
-
632
- try {
633
- configs = configLoader.getCachedConfigArrayForFile(filePath);
634
- } catch {
635
- throw createExtraneousResultsError();
636
- }
637
-
638
- const config = configs.getConfig(filePath);
639
-
640
- if (!config) {
641
- throw createExtraneousResultsError();
642
- }
643
- const rule = getRuleFromConfig(ruleId, config);
644
-
645
- // ignore unknown rules
646
- if (rule) {
647
- resultRules.set(ruleId, rule);
648
- }
649
- }
650
- }
651
-
652
- return createRulesMeta(resultRules);
653
- }
654
-
655
- /**
656
- * Indicates if the given feature flag is enabled for this instance.
657
- * @param {string} flag The feature flag to check.
658
- * @returns {boolean} `true` if the feature flag is enabled, `false` if not.
659
- */
660
- hasFlag(flag) {
661
-
662
- // note: Linter does validation of the flags
663
- return privateMembers.get(this).linter.hasFlag(flag);
664
- }
665
-
666
- /**
667
- * Executes the current configuration on an array of file and directory names.
668
- * @param {string|string[]} patterns An array of file and directory names.
669
- * @returns {Promise<LintResult[]>} The results of linting the file patterns given.
670
- */
671
- async lintFiles(patterns) {
672
-
673
- let normalizedPatterns = patterns;
674
- const {
675
- cacheFilePath,
676
- lintResultCache,
677
- linter,
678
- options: eslintOptions
679
- } = privateMembers.get(this);
680
-
681
- /*
682
- * Special cases:
683
- * 1. `patterns` is an empty string
684
- * 2. `patterns` is an empty array
685
- *
686
- * In both cases, we use the cwd as the directory to lint.
687
- */
688
- if (patterns === "" || Array.isArray(patterns) && patterns.length === 0) {
689
-
690
- /*
691
- * Special case: If `passOnNoPatterns` is true, then we just exit
692
- * without doing any work.
693
- */
694
- if (eslintOptions.passOnNoPatterns) {
695
- return [];
696
- }
697
-
698
- normalizedPatterns = ["."];
699
- } else {
700
-
701
- if (!isNonEmptyString(patterns) && !isArrayOfNonEmptyString(patterns)) {
702
- throw new Error("'patterns' must be a non-empty string or an array of non-empty strings");
703
- }
704
-
705
- if (typeof patterns === "string") {
706
- normalizedPatterns = [patterns];
707
- }
708
- }
709
-
710
- debug(`Using file patterns: ${normalizedPatterns}`);
711
-
712
- const {
713
- allowInlineConfig,
714
- cache,
715
- cwd,
716
- fix,
717
- fixTypes,
718
- ruleFilter,
719
- stats,
720
- globInputPaths,
721
- errorOnUnmatchedPattern,
722
- warnIgnored
723
- } = eslintOptions;
724
- const startTime = Date.now();
725
- const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
726
-
727
- // Delete cache file; should this be done here?
728
- if (!cache && cacheFilePath) {
729
- debug(`Deleting cache file at ${cacheFilePath}`);
730
-
731
- try {
732
- await fs.unlink(cacheFilePath);
733
- } catch (error) {
734
- const errorCode = error && error.code;
735
-
736
- // Ignore errors when no such file exists or file system is read only (and cache file does not exist)
737
- if (errorCode !== "ENOENT" && !(errorCode === "EROFS" && !existsSync(cacheFilePath))) {
738
- throw error;
739
- }
740
- }
741
- }
742
-
743
- const filePaths = await findFiles({
744
- patterns: normalizedPatterns,
745
- cwd,
746
- globInputPaths,
747
- configLoader: this.#configLoader,
748
- errorOnUnmatchedPattern
749
- });
750
- const controller = new AbortController();
751
- const retryCodes = new Set(["ENFILE", "EMFILE"]);
752
- const retrier = new Retrier(error => retryCodes.has(error.code), { concurrency: 100 });
753
-
754
- debug(`${filePaths.length} files found in: ${Date.now() - startTime}ms`);
755
-
756
- /*
757
- * Because we need to process multiple files, including reading from disk,
758
- * it is most efficient to start by reading each file via promises so that
759
- * they can be done in parallel. Then, we can lint the returned text. This
760
- * ensures we are waiting the minimum amount of time in between lints.
761
- */
762
- const results = await Promise.all(
763
-
764
- filePaths.map(async filePath => {
765
-
766
- const configs = await this.#configLoader.loadConfigArrayForFile(filePath);
767
- const config = configs.getConfig(filePath);
768
-
769
- /*
770
- * If a filename was entered that cannot be matched
771
- * to a config, then notify the user.
772
- */
773
- if (!config) {
774
- if (warnIgnored) {
775
- const configStatus = configs.getConfigStatus(filePath);
776
-
777
- return createIgnoreResult(filePath, cwd, configStatus);
778
- }
779
-
780
- return void 0;
781
- }
782
-
783
- // Skip if there is cached result.
784
- if (lintResultCache) {
785
- const cachedResult =
786
- lintResultCache.getCachedLintResults(filePath, config);
787
-
788
- if (cachedResult) {
789
- const hadMessages =
790
- cachedResult.messages &&
791
- cachedResult.messages.length > 0;
792
-
793
- if (hadMessages && fix) {
794
- debug(`Reprocessing cached file to allow autofix: ${filePath}`);
795
- } else {
796
- debug(`Skipping file since it hasn't changed: ${filePath}`);
797
- return cachedResult;
798
- }
799
- }
800
- }
801
-
802
-
803
- // set up fixer for fixTypes if necessary
804
- const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
805
-
806
- return retrier.retry(() => fs.readFile(filePath, { encoding: "utf8", signal: controller.signal })
807
- .then(text => {
808
-
809
- // fail immediately if an error occurred in another file
810
- controller.signal.throwIfAborted();
811
-
812
- // do the linting
813
- const result = verifyText({
814
- text,
815
- filePath,
816
- configs,
817
- cwd,
818
- fix: fixer,
819
- allowInlineConfig,
820
- ruleFilter,
821
- stats,
822
- linter
823
- });
824
-
825
- /*
826
- * Store the lint result in the LintResultCache.
827
- * NOTE: The LintResultCache will remove the file source and any
828
- * other properties that are difficult to serialize, and will
829
- * hydrate those properties back in on future lint runs.
830
- */
831
- if (lintResultCache) {
832
- lintResultCache.setCachedLintResults(filePath, config, result);
833
- }
834
-
835
- return result;
836
- }), { signal: controller.signal })
837
- .catch(error => {
838
- controller.abort(error);
839
- throw error;
840
- });
841
- })
842
- );
843
-
844
- // Persist the cache to disk.
845
- if (lintResultCache) {
846
- lintResultCache.reconcile();
847
- }
848
-
849
- const finalResults = results.filter(result => !!result);
850
-
851
- return processLintReport(this, {
852
- results: finalResults
853
- });
854
- }
855
-
856
- /**
857
- * Executes the current configuration on text.
858
- * @param {string} code A string of JavaScript code to lint.
859
- * @param {Object} [options] The options.
860
- * @param {string} [options.filePath] The path to the file of the source code.
861
- * @param {boolean} [options.warnIgnored] When set to true, warn if given filePath is an ignored path.
862
- * @returns {Promise<LintResult[]>} The results of linting the string of code given.
863
- */
864
- async lintText(code, options = {}) {
865
-
866
- // Parameter validation
867
-
868
- if (typeof code !== "string") {
869
- throw new Error("'code' must be a string");
870
- }
871
-
872
- if (typeof options !== "object") {
873
- throw new Error("'options' must be an object, null, or undefined");
874
- }
875
-
876
- // Options validation
877
-
878
- const {
879
- filePath,
880
- warnIgnored,
881
- ...unknownOptions
882
- } = options || {};
883
-
884
- const unknownOptionKeys = Object.keys(unknownOptions);
885
-
886
- if (unknownOptionKeys.length > 0) {
887
- throw new Error(`'options' must not include the unknown option(s): ${unknownOptionKeys.join(", ")}`);
888
- }
889
-
890
- if (filePath !== void 0 && !isNonEmptyString(filePath)) {
891
- throw new Error("'options.filePath' must be a non-empty string or undefined");
892
- }
893
-
894
- if (typeof warnIgnored !== "boolean" && typeof warnIgnored !== "undefined") {
895
- throw new Error("'options.warnIgnored' must be a boolean or undefined");
896
- }
897
-
898
- // Now we can get down to linting
899
-
900
- const {
901
- linter,
902
- options: eslintOptions
903
- } = privateMembers.get(this);
904
- const {
905
- allowInlineConfig,
906
- cwd,
907
- fix,
908
- fixTypes,
909
- warnIgnored: constructorWarnIgnored,
910
- ruleFilter,
911
- stats
912
- } = eslintOptions;
913
- const results = [];
914
- const startTime = Date.now();
915
- const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
916
- const resolvedFilename = path.resolve(cwd, filePath || "__placeholder__.js");
917
- const configs = await this.#configLoader.loadConfigArrayForFile(resolvedFilename);
918
- const configStatus = configs?.getConfigStatus(resolvedFilename) ?? "unconfigured";
919
-
920
- // Clear the last used config arrays.
921
- if (resolvedFilename && configStatus !== "matched") {
922
- const shouldWarnIgnored = typeof warnIgnored === "boolean" ? warnIgnored : constructorWarnIgnored;
923
-
924
- if (shouldWarnIgnored) {
925
- results.push(createIgnoreResult(resolvedFilename, cwd, configStatus));
926
- }
927
- } else {
928
-
929
- const config = configs.getConfig(resolvedFilename);
930
- const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
931
-
932
- // Do lint.
933
- results.push(verifyText({
934
- text: code,
935
- filePath: resolvedFilename.endsWith("__placeholder__.js") ? "<text>" : resolvedFilename,
936
- configs,
937
- cwd,
938
- fix: fixer,
939
- allowInlineConfig,
940
- ruleFilter,
941
- stats,
942
- linter
943
- }));
944
- }
945
-
946
- debug(`Linting complete in: ${Date.now() - startTime}ms`);
947
-
948
- return processLintReport(this, {
949
- results
950
- });
951
-
952
- }
953
-
954
- /**
955
- * Returns the formatter representing the given formatter name.
956
- * @param {string} [name] The name of the formatter to load.
957
- * The following values are allowed:
958
- * - `undefined` ... Load `stylish` builtin formatter.
959
- * - A builtin formatter name ... Load the builtin formatter.
960
- * - A third-party formatter name:
961
- * - `foo` → `eslint-formatter-foo`
962
- * - `@foo` → `@foo/eslint-formatter`
963
- * - `@foo/bar` → `@foo/eslint-formatter-bar`
964
- * - A file path ... Load the file.
965
- * @returns {Promise<Formatter>} A promise resolving to the formatter object.
966
- * This promise will be rejected if the given formatter was not found or not
967
- * a function.
968
- */
969
- async loadFormatter(name = "stylish") {
970
- if (typeof name !== "string") {
971
- throw new Error("'name' must be a string");
972
- }
973
-
974
- // replace \ with / for Windows compatibility
975
- const normalizedFormatName = name.replace(/\\/gu, "/");
976
- const namespace = naming.getNamespaceFromTerm(normalizedFormatName);
977
-
978
- // grab our options
979
- const { cwd } = privateMembers.get(this).options;
980
-
981
-
982
- let formatterPath;
983
-
984
- // if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
985
- if (!namespace && normalizedFormatName.includes("/")) {
986
- formatterPath = path.resolve(cwd, normalizedFormatName);
987
- } else {
988
- try {
989
- const npmFormat = naming.normalizePackageName(normalizedFormatName, "eslint-formatter");
990
-
991
- // TODO: This is pretty dirty...would be nice to clean up at some point.
992
- formatterPath = ModuleResolver.resolve(npmFormat, getPlaceholderPath(cwd));
993
- } catch {
994
- formatterPath = path.resolve(__dirname, "../", "cli-engine", "formatters", `${normalizedFormatName}.js`);
995
- }
996
- }
997
-
998
- let formatter;
999
-
1000
- try {
1001
- formatter = (await import(pathToFileURL(formatterPath))).default;
1002
- } catch (ex) {
1003
-
1004
- // check for formatters that have been removed
1005
- if (removedFormatters.has(name)) {
1006
- ex.message = `The ${name} formatter is no longer part of core ESLint. Install it manually with \`npm install -D eslint-formatter-${name}\``;
1007
- } else {
1008
- ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
1009
- }
1010
-
1011
- throw ex;
1012
- }
1013
-
1014
-
1015
- if (typeof formatter !== "function") {
1016
- throw new TypeError(`Formatter must be a function, but got a ${typeof formatter}.`);
1017
- }
1018
-
1019
- const eslint = this;
1020
-
1021
- return {
1022
-
1023
- /**
1024
- * The main formatter method.
1025
- * @param {LintResult[]} results The lint results to format.
1026
- * @param {ResultsMeta} resultsMeta Warning count and max threshold.
1027
- * @returns {string} The formatted lint results.
1028
- */
1029
- format(results, resultsMeta) {
1030
- let rulesMeta = null;
1031
-
1032
- results.sort(compareResultsByFilePath);
1033
-
1034
- return formatter(results, {
1035
- ...resultsMeta,
1036
- cwd,
1037
- get rulesMeta() {
1038
- if (!rulesMeta) {
1039
- rulesMeta = eslint.getRulesMetaForResults(results);
1040
- }
1041
-
1042
- return rulesMeta;
1043
- }
1044
- });
1045
- }
1046
- };
1047
- }
1048
-
1049
- /**
1050
- * Returns a configuration object for the given file based on the CLI options.
1051
- * This is the same logic used by the ESLint CLI executable to determine
1052
- * configuration for each file it processes.
1053
- * @param {string} filePath The path of the file to retrieve a config object for.
1054
- * @returns {Promise<ConfigData|undefined>} A configuration object for the file
1055
- * or `undefined` if there is no configuration data for the object.
1056
- */
1057
- async calculateConfigForFile(filePath) {
1058
- if (!isNonEmptyString(filePath)) {
1059
- throw new Error("'filePath' must be a non-empty string");
1060
- }
1061
- const options = privateMembers.get(this).options;
1062
- const absolutePath = path.resolve(options.cwd, filePath);
1063
- const configs = await this.#configLoader.loadConfigArrayForFile(absolutePath);
1064
-
1065
- if (!configs) {
1066
- const error = new Error("Could not find config file.");
1067
-
1068
- error.messageTemplate = "config-file-missing";
1069
- throw error;
1070
- }
1071
-
1072
- return configs.getConfig(absolutePath);
1073
- }
1074
-
1075
- /**
1076
- * Finds the config file being used by this instance based on the options
1077
- * passed to the constructor.
1078
- * @param {string} [filePath] The path of the file to find the config file for.
1079
- * @returns {Promise<string|undefined>} The path to the config file being used or
1080
- * `undefined` if no config file is being used.
1081
- */
1082
- findConfigFile(filePath) {
1083
- const options = privateMembers.get(this).options;
1084
-
1085
- /*
1086
- * Because the new config lookup scheme skips the current directory
1087
- * and looks into the parent directories, we need to use a placeholder
1088
- * directory to ensure the file in cwd is checked.
1089
- */
1090
- const fakeCwd = path.join(options.cwd, "__placeholder__");
1091
-
1092
- return this.#configLoader.findConfigFileForPath(filePath ?? fakeCwd)
1093
- .catch(() => void 0);
1094
- }
1095
-
1096
- /**
1097
- * Checks if a given path is ignored by ESLint.
1098
- * @param {string} filePath The path of the file to check.
1099
- * @returns {Promise<boolean>} Whether or not the given path is ignored.
1100
- */
1101
- async isPathIgnored(filePath) {
1102
- const config = await this.calculateConfigForFile(filePath);
1103
-
1104
- return config === void 0;
1105
- }
436
+ /**
437
+ * The type of configuration used by this class.
438
+ * @type {string}
439
+ */
440
+ static configType = "flat";
441
+
442
+ /**
443
+ * The loader to use for finding config files.
444
+ * @type {ConfigLoader|LegacyConfigLoader}
445
+ */
446
+ #configLoader;
447
+
448
+ /**
449
+ * Creates a new instance of the main ESLint API.
450
+ * @param {ESLintOptions} options The options for this instance.
451
+ */
452
+ constructor(options = {}) {
453
+ const defaultConfigs = [];
454
+ const processedOptions = processOptions(options);
455
+ const linter = new Linter({
456
+ cwd: processedOptions.cwd,
457
+ configType: "flat",
458
+ flags: processedOptions.flags,
459
+ });
460
+
461
+ const cacheFilePath = getCacheFile(
462
+ processedOptions.cacheLocation,
463
+ processedOptions.cwd,
464
+ );
465
+
466
+ const lintResultCache = processedOptions.cache
467
+ ? new LintResultCache(cacheFilePath, processedOptions.cacheStrategy)
468
+ : null;
469
+
470
+ const configLoaderOptions = {
471
+ cwd: processedOptions.cwd,
472
+ baseConfig: processedOptions.baseConfig,
473
+ overrideConfig: processedOptions.overrideConfig,
474
+ configFile: processedOptions.configFile,
475
+ ignoreEnabled: processedOptions.ignore,
476
+ ignorePatterns: processedOptions.ignorePatterns,
477
+ defaultConfigs,
478
+ };
479
+
480
+ this.#configLoader = linter.hasFlag("unstable_config_lookup_from_file")
481
+ ? new ConfigLoader(configLoaderOptions)
482
+ : new LegacyConfigLoader(configLoaderOptions);
483
+
484
+ debug(`Using config loader ${this.#configLoader.constructor.name}`);
485
+
486
+ privateMembers.set(this, {
487
+ options: processedOptions,
488
+ linter,
489
+ cacheFilePath,
490
+ lintResultCache,
491
+ defaultConfigs,
492
+ configs: null,
493
+ configLoader: this.#configLoader,
494
+ });
495
+
496
+ /**
497
+ * If additional plugins are passed in, add that to the default
498
+ * configs for this instance.
499
+ */
500
+ if (options.plugins) {
501
+ const plugins = {};
502
+
503
+ for (const [pluginName, plugin] of Object.entries(
504
+ options.plugins,
505
+ )) {
506
+ plugins[naming.getShorthandName(pluginName, "eslint-plugin")] =
507
+ plugin;
508
+ }
509
+
510
+ defaultConfigs.push({
511
+ plugins,
512
+ });
513
+ }
514
+
515
+ // Check for the .eslintignore file, and warn if it's present.
516
+ if (existsSync(path.resolve(processedOptions.cwd, ".eslintignore"))) {
517
+ process.emitWarning(
518
+ 'The ".eslintignore" file is no longer supported. Switch to using the "ignores" property in "eslint.config.js": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files',
519
+ "ESLintIgnoreWarning",
520
+ );
521
+ }
522
+ }
523
+
524
+ /**
525
+ * The version text.
526
+ * @type {string}
527
+ */
528
+ static get version() {
529
+ return version;
530
+ }
531
+
532
+ /**
533
+ * The default configuration that ESLint uses internally. This is provided for tooling that wants to calculate configurations using the same defaults as ESLint.
534
+ * Keep in mind that the default configuration may change from version to version, so you shouldn't rely on any particular keys or values to be present.
535
+ * @type {ConfigArray}
536
+ */
537
+ static get defaultConfig() {
538
+ return defaultConfig;
539
+ }
540
+
541
+ /**
542
+ * Outputs fixes from the given results to files.
543
+ * @param {LintResult[]} results The lint results.
544
+ * @returns {Promise<void>} Returns a promise that is used to track side effects.
545
+ */
546
+ static async outputFixes(results) {
547
+ if (!Array.isArray(results)) {
548
+ throw new Error("'results' must be an array");
549
+ }
550
+
551
+ await Promise.all(
552
+ results
553
+ .filter(result => {
554
+ if (typeof result !== "object" || result === null) {
555
+ throw new Error("'results' must include only objects");
556
+ }
557
+ return (
558
+ typeof result.output === "string" &&
559
+ path.isAbsolute(result.filePath)
560
+ );
561
+ })
562
+ .map(r => fs.writeFile(r.filePath, r.output)),
563
+ );
564
+ }
565
+
566
+ /**
567
+ * Returns results that only contains errors.
568
+ * @param {LintResult[]} results The results to filter.
569
+ * @returns {LintResult[]} The filtered results.
570
+ */
571
+ static getErrorResults(results) {
572
+ const filtered = [];
573
+
574
+ results.forEach(result => {
575
+ const filteredMessages = result.messages.filter(isErrorMessage);
576
+ const filteredSuppressedMessages =
577
+ result.suppressedMessages.filter(isErrorMessage);
578
+
579
+ if (filteredMessages.length > 0) {
580
+ filtered.push({
581
+ ...result,
582
+ messages: filteredMessages,
583
+ suppressedMessages: filteredSuppressedMessages,
584
+ errorCount: filteredMessages.length,
585
+ warningCount: 0,
586
+ fixableErrorCount: result.fixableErrorCount,
587
+ fixableWarningCount: 0,
588
+ });
589
+ }
590
+ });
591
+
592
+ return filtered;
593
+ }
594
+
595
+ /**
596
+ * Returns meta objects for each rule represented in the lint results.
597
+ * @param {LintResult[]} results The results to fetch rules meta for.
598
+ * @returns {Object} A mapping of ruleIds to rule meta objects.
599
+ * @throws {TypeError} When the results object wasn't created from this ESLint instance.
600
+ * @throws {TypeError} When a plugin or rule is missing.
601
+ */
602
+ getRulesMetaForResults(results) {
603
+ // short-circuit simple case
604
+ if (results.length === 0) {
605
+ return {};
606
+ }
607
+
608
+ const resultRules = new Map();
609
+ const {
610
+ configLoader,
611
+ options: { cwd },
612
+ } = privateMembers.get(this);
613
+
614
+ for (const result of results) {
615
+ /*
616
+ * Normalize filename for <text>.
617
+ */
618
+ const filePath =
619
+ result.filePath === "<text>"
620
+ ? getPlaceholderPath(cwd)
621
+ : result.filePath;
622
+ const allMessages = result.messages.concat(
623
+ result.suppressedMessages,
624
+ );
625
+
626
+ for (const { ruleId } of allMessages) {
627
+ if (!ruleId) {
628
+ continue;
629
+ }
630
+
631
+ /*
632
+ * All of the plugin and rule information is contained within the
633
+ * calculated config for the given file.
634
+ */
635
+ let configs;
636
+
637
+ try {
638
+ configs =
639
+ configLoader.getCachedConfigArrayForFile(filePath);
640
+ } catch {
641
+ throw createExtraneousResultsError();
642
+ }
643
+
644
+ const config = configs.getConfig(filePath);
645
+
646
+ if (!config) {
647
+ throw createExtraneousResultsError();
648
+ }
649
+ const rule = getRuleFromConfig(ruleId, config);
650
+
651
+ // ignore unknown rules
652
+ if (rule) {
653
+ resultRules.set(ruleId, rule);
654
+ }
655
+ }
656
+ }
657
+
658
+ return createRulesMeta(resultRules);
659
+ }
660
+
661
+ /**
662
+ * Indicates if the given feature flag is enabled for this instance.
663
+ * @param {string} flag The feature flag to check.
664
+ * @returns {boolean} `true` if the feature flag is enabled, `false` if not.
665
+ */
666
+ hasFlag(flag) {
667
+ // note: Linter does validation of the flags
668
+ return privateMembers.get(this).linter.hasFlag(flag);
669
+ }
670
+
671
+ /**
672
+ * Executes the current configuration on an array of file and directory names.
673
+ * @param {string|string[]} patterns An array of file and directory names.
674
+ * @returns {Promise<LintResult[]>} The results of linting the file patterns given.
675
+ */
676
+ async lintFiles(patterns) {
677
+ let normalizedPatterns = patterns;
678
+ const {
679
+ cacheFilePath,
680
+ lintResultCache,
681
+ linter,
682
+ options: eslintOptions,
683
+ } = privateMembers.get(this);
684
+
685
+ /*
686
+ * Special cases:
687
+ * 1. `patterns` is an empty string
688
+ * 2. `patterns` is an empty array
689
+ *
690
+ * In both cases, we use the cwd as the directory to lint.
691
+ */
692
+ if (
693
+ patterns === "" ||
694
+ (Array.isArray(patterns) && patterns.length === 0)
695
+ ) {
696
+ /*
697
+ * Special case: If `passOnNoPatterns` is true, then we just exit
698
+ * without doing any work.
699
+ */
700
+ if (eslintOptions.passOnNoPatterns) {
701
+ return [];
702
+ }
703
+
704
+ normalizedPatterns = ["."];
705
+ } else {
706
+ if (
707
+ !isNonEmptyString(patterns) &&
708
+ !isArrayOfNonEmptyString(patterns)
709
+ ) {
710
+ throw new Error(
711
+ "'patterns' must be a non-empty string or an array of non-empty strings",
712
+ );
713
+ }
714
+
715
+ if (typeof patterns === "string") {
716
+ normalizedPatterns = [patterns];
717
+ }
718
+ }
719
+
720
+ debug(`Using file patterns: ${normalizedPatterns}`);
721
+
722
+ const {
723
+ allowInlineConfig,
724
+ cache,
725
+ cwd,
726
+ fix,
727
+ fixTypes,
728
+ ruleFilter,
729
+ stats,
730
+ globInputPaths,
731
+ errorOnUnmatchedPattern,
732
+ warnIgnored,
733
+ } = eslintOptions;
734
+ const startTime = Date.now();
735
+ const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
736
+
737
+ // Delete cache file; should this be done here?
738
+ if (!cache && cacheFilePath) {
739
+ debug(`Deleting cache file at ${cacheFilePath}`);
740
+
741
+ try {
742
+ await fs.unlink(cacheFilePath);
743
+ } catch (error) {
744
+ const errorCode = error && error.code;
745
+
746
+ // Ignore errors when no such file exists or file system is read only (and cache file does not exist)
747
+ if (
748
+ errorCode !== "ENOENT" &&
749
+ !(errorCode === "EROFS" && !existsSync(cacheFilePath))
750
+ ) {
751
+ throw error;
752
+ }
753
+ }
754
+ }
755
+
756
+ const filePaths = await findFiles({
757
+ patterns: normalizedPatterns,
758
+ cwd,
759
+ globInputPaths,
760
+ configLoader: this.#configLoader,
761
+ errorOnUnmatchedPattern,
762
+ });
763
+ const controller = new AbortController();
764
+ const retryCodes = new Set(["ENFILE", "EMFILE"]);
765
+ const retrier = new Retrier(error => retryCodes.has(error.code), {
766
+ concurrency: 100,
767
+ });
768
+
769
+ debug(
770
+ `${filePaths.length} files found in: ${Date.now() - startTime}ms`,
771
+ );
772
+
773
+ /*
774
+ * Because we need to process multiple files, including reading from disk,
775
+ * it is most efficient to start by reading each file via promises so that
776
+ * they can be done in parallel. Then, we can lint the returned text. This
777
+ * ensures we are waiting the minimum amount of time in between lints.
778
+ */
779
+ const results = await Promise.all(
780
+ filePaths.map(async filePath => {
781
+ const configs =
782
+ await this.#configLoader.loadConfigArrayForFile(filePath);
783
+ const config = configs.getConfig(filePath);
784
+
785
+ /*
786
+ * If a filename was entered that cannot be matched
787
+ * to a config, then notify the user.
788
+ */
789
+ if (!config) {
790
+ if (warnIgnored) {
791
+ const configStatus = configs.getConfigStatus(filePath);
792
+
793
+ return createIgnoreResult(filePath, cwd, configStatus);
794
+ }
795
+
796
+ return void 0;
797
+ }
798
+
799
+ // Skip if there is cached result.
800
+ if (lintResultCache) {
801
+ const cachedResult = lintResultCache.getCachedLintResults(
802
+ filePath,
803
+ config,
804
+ );
805
+
806
+ if (cachedResult) {
807
+ const hadMessages =
808
+ cachedResult.messages &&
809
+ cachedResult.messages.length > 0;
810
+
811
+ if (hadMessages && fix) {
812
+ debug(
813
+ `Reprocessing cached file to allow autofix: ${filePath}`,
814
+ );
815
+ } else {
816
+ debug(
817
+ `Skipping file since it hasn't changed: ${filePath}`,
818
+ );
819
+ return cachedResult;
820
+ }
821
+ }
822
+ }
823
+
824
+ // set up fixer for fixTypes if necessary
825
+ const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
826
+
827
+ return retrier
828
+ .retry(
829
+ () =>
830
+ fs
831
+ .readFile(filePath, {
832
+ encoding: "utf8",
833
+ signal: controller.signal,
834
+ })
835
+ .then(text => {
836
+ // fail immediately if an error occurred in another file
837
+ controller.signal.throwIfAborted();
838
+
839
+ // do the linting
840
+ const result = verifyText({
841
+ text,
842
+ filePath,
843
+ configs,
844
+ cwd,
845
+ fix: fixer,
846
+ allowInlineConfig,
847
+ ruleFilter,
848
+ stats,
849
+ linter,
850
+ });
851
+
852
+ /*
853
+ * Store the lint result in the LintResultCache.
854
+ * NOTE: The LintResultCache will remove the file source and any
855
+ * other properties that are difficult to serialize, and will
856
+ * hydrate those properties back in on future lint runs.
857
+ */
858
+ if (lintResultCache) {
859
+ lintResultCache.setCachedLintResults(
860
+ filePath,
861
+ config,
862
+ result,
863
+ );
864
+ }
865
+
866
+ return result;
867
+ }),
868
+ { signal: controller.signal },
869
+ )
870
+ .catch(error => {
871
+ controller.abort(error);
872
+ throw error;
873
+ });
874
+ }),
875
+ );
876
+
877
+ // Persist the cache to disk.
878
+ if (lintResultCache) {
879
+ lintResultCache.reconcile();
880
+ }
881
+
882
+ const finalResults = results.filter(result => !!result);
883
+
884
+ return processLintReport(this, {
885
+ results: finalResults,
886
+ });
887
+ }
888
+
889
+ /**
890
+ * Executes the current configuration on text.
891
+ * @param {string} code A string of JavaScript code to lint.
892
+ * @param {Object} [options] The options.
893
+ * @param {string} [options.filePath] The path to the file of the source code.
894
+ * @param {boolean} [options.warnIgnored] When set to true, warn if given filePath is an ignored path.
895
+ * @returns {Promise<LintResult[]>} The results of linting the string of code given.
896
+ */
897
+ async lintText(code, options = {}) {
898
+ // Parameter validation
899
+
900
+ if (typeof code !== "string") {
901
+ throw new Error("'code' must be a string");
902
+ }
903
+
904
+ if (typeof options !== "object") {
905
+ throw new Error("'options' must be an object, null, or undefined");
906
+ }
907
+
908
+ // Options validation
909
+
910
+ const { filePath, warnIgnored, ...unknownOptions } = options || {};
911
+
912
+ const unknownOptionKeys = Object.keys(unknownOptions);
913
+
914
+ if (unknownOptionKeys.length > 0) {
915
+ throw new Error(
916
+ `'options' must not include the unknown option(s): ${unknownOptionKeys.join(", ")}`,
917
+ );
918
+ }
919
+
920
+ if (filePath !== void 0 && !isNonEmptyString(filePath)) {
921
+ throw new Error(
922
+ "'options.filePath' must be a non-empty string or undefined",
923
+ );
924
+ }
925
+
926
+ if (
927
+ typeof warnIgnored !== "boolean" &&
928
+ typeof warnIgnored !== "undefined"
929
+ ) {
930
+ throw new Error(
931
+ "'options.warnIgnored' must be a boolean or undefined",
932
+ );
933
+ }
934
+
935
+ // Now we can get down to linting
936
+
937
+ const { linter, options: eslintOptions } = privateMembers.get(this);
938
+ const {
939
+ allowInlineConfig,
940
+ cwd,
941
+ fix,
942
+ fixTypes,
943
+ warnIgnored: constructorWarnIgnored,
944
+ ruleFilter,
945
+ stats,
946
+ } = eslintOptions;
947
+ const results = [];
948
+ const startTime = Date.now();
949
+ const fixTypesSet = fixTypes ? new Set(fixTypes) : null;
950
+ const resolvedFilename = path.resolve(
951
+ cwd,
952
+ filePath || "__placeholder__.js",
953
+ );
954
+ const configs =
955
+ await this.#configLoader.loadConfigArrayForFile(resolvedFilename);
956
+ const configStatus =
957
+ configs?.getConfigStatus(resolvedFilename) ?? "unconfigured";
958
+
959
+ // Clear the last used config arrays.
960
+ if (resolvedFilename && configStatus !== "matched") {
961
+ const shouldWarnIgnored =
962
+ typeof warnIgnored === "boolean"
963
+ ? warnIgnored
964
+ : constructorWarnIgnored;
965
+
966
+ if (shouldWarnIgnored) {
967
+ results.push(
968
+ createIgnoreResult(resolvedFilename, cwd, configStatus),
969
+ );
970
+ }
971
+ } else {
972
+ const config = configs.getConfig(resolvedFilename);
973
+ const fixer = getFixerForFixTypes(fix, fixTypesSet, config);
974
+
975
+ // Do lint.
976
+ results.push(
977
+ verifyText({
978
+ text: code,
979
+ filePath: resolvedFilename.endsWith("__placeholder__.js")
980
+ ? "<text>"
981
+ : resolvedFilename,
982
+ configs,
983
+ cwd,
984
+ fix: fixer,
985
+ allowInlineConfig,
986
+ ruleFilter,
987
+ stats,
988
+ linter,
989
+ }),
990
+ );
991
+ }
992
+
993
+ debug(`Linting complete in: ${Date.now() - startTime}ms`);
994
+
995
+ return processLintReport(this, {
996
+ results,
997
+ });
998
+ }
999
+
1000
+ /**
1001
+ * Returns the formatter representing the given formatter name.
1002
+ * @param {string} [name] The name of the formatter to load.
1003
+ * The following values are allowed:
1004
+ * - `undefined` ... Load `stylish` builtin formatter.
1005
+ * - A builtin formatter name ... Load the builtin formatter.
1006
+ * - A third-party formatter name:
1007
+ * - `foo` `eslint-formatter-foo`
1008
+ * - `@foo` → `@foo/eslint-formatter`
1009
+ * - `@foo/bar` `@foo/eslint-formatter-bar`
1010
+ * - A file path ... Load the file.
1011
+ * @returns {Promise<Formatter>} A promise resolving to the formatter object.
1012
+ * This promise will be rejected if the given formatter was not found or not
1013
+ * a function.
1014
+ */
1015
+ async loadFormatter(name = "stylish") {
1016
+ if (typeof name !== "string") {
1017
+ throw new Error("'name' must be a string");
1018
+ }
1019
+
1020
+ // replace \ with / for Windows compatibility
1021
+ const normalizedFormatName = name.replace(/\\/gu, "/");
1022
+ const namespace = naming.getNamespaceFromTerm(normalizedFormatName);
1023
+
1024
+ // grab our options
1025
+ const { cwd } = privateMembers.get(this).options;
1026
+
1027
+ let formatterPath;
1028
+
1029
+ // if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
1030
+ if (!namespace && normalizedFormatName.includes("/")) {
1031
+ formatterPath = path.resolve(cwd, normalizedFormatName);
1032
+ } else {
1033
+ try {
1034
+ const npmFormat = naming.normalizePackageName(
1035
+ normalizedFormatName,
1036
+ "eslint-formatter",
1037
+ );
1038
+
1039
+ // TODO: This is pretty dirty...would be nice to clean up at some point.
1040
+ formatterPath = ModuleResolver.resolve(
1041
+ npmFormat,
1042
+ getPlaceholderPath(cwd),
1043
+ );
1044
+ } catch {
1045
+ formatterPath = path.resolve(
1046
+ __dirname,
1047
+ "../",
1048
+ "cli-engine",
1049
+ "formatters",
1050
+ `${normalizedFormatName}.js`,
1051
+ );
1052
+ }
1053
+ }
1054
+
1055
+ let formatter;
1056
+
1057
+ try {
1058
+ formatter = (await import(pathToFileURL(formatterPath))).default;
1059
+ } catch (ex) {
1060
+ // check for formatters that have been removed
1061
+ if (removedFormatters.has(name)) {
1062
+ ex.message = `The ${name} formatter is no longer part of core ESLint. Install it manually with \`npm install -D eslint-formatter-${name}\``;
1063
+ } else {
1064
+ ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
1065
+ }
1066
+
1067
+ throw ex;
1068
+ }
1069
+
1070
+ if (typeof formatter !== "function") {
1071
+ throw new TypeError(
1072
+ `Formatter must be a function, but got a ${typeof formatter}.`,
1073
+ );
1074
+ }
1075
+
1076
+ const eslint = this;
1077
+
1078
+ return {
1079
+ /**
1080
+ * The main formatter method.
1081
+ * @param {LintResult[]} results The lint results to format.
1082
+ * @param {ResultsMeta} resultsMeta Warning count and max threshold.
1083
+ * @returns {string} The formatted lint results.
1084
+ */
1085
+ format(results, resultsMeta) {
1086
+ let rulesMeta = null;
1087
+
1088
+ results.sort(compareResultsByFilePath);
1089
+
1090
+ return formatter(results, {
1091
+ ...resultsMeta,
1092
+ cwd,
1093
+ get rulesMeta() {
1094
+ if (!rulesMeta) {
1095
+ rulesMeta = eslint.getRulesMetaForResults(results);
1096
+ }
1097
+
1098
+ return rulesMeta;
1099
+ },
1100
+ });
1101
+ },
1102
+ };
1103
+ }
1104
+
1105
+ /**
1106
+ * Returns a configuration object for the given file based on the CLI options.
1107
+ * This is the same logic used by the ESLint CLI executable to determine
1108
+ * configuration for each file it processes.
1109
+ * @param {string} filePath The path of the file to retrieve a config object for.
1110
+ * @returns {Promise<ConfigData|undefined>} A configuration object for the file
1111
+ * or `undefined` if there is no configuration data for the object.
1112
+ */
1113
+ async calculateConfigForFile(filePath) {
1114
+ if (!isNonEmptyString(filePath)) {
1115
+ throw new Error("'filePath' must be a non-empty string");
1116
+ }
1117
+ const options = privateMembers.get(this).options;
1118
+ const absolutePath = path.resolve(options.cwd, filePath);
1119
+ const configs =
1120
+ await this.#configLoader.loadConfigArrayForFile(absolutePath);
1121
+
1122
+ if (!configs) {
1123
+ const error = new Error("Could not find config file.");
1124
+
1125
+ error.messageTemplate = "config-file-missing";
1126
+ throw error;
1127
+ }
1128
+
1129
+ return configs.getConfig(absolutePath);
1130
+ }
1131
+
1132
+ /**
1133
+ * Finds the config file being used by this instance based on the options
1134
+ * passed to the constructor.
1135
+ * @param {string} [filePath] The path of the file to find the config file for.
1136
+ * @returns {Promise<string|undefined>} The path to the config file being used or
1137
+ * `undefined` if no config file is being used.
1138
+ */
1139
+ findConfigFile(filePath) {
1140
+ const options = privateMembers.get(this).options;
1141
+
1142
+ /*
1143
+ * Because the new config lookup scheme skips the current directory
1144
+ * and looks into the parent directories, we need to use a placeholder
1145
+ * directory to ensure the file in cwd is checked.
1146
+ */
1147
+ const fakeCwd = path.join(options.cwd, "__placeholder__");
1148
+
1149
+ return this.#configLoader
1150
+ .findConfigFileForPath(filePath ?? fakeCwd)
1151
+ .catch(() => void 0);
1152
+ }
1153
+
1154
+ /**
1155
+ * Checks if a given path is ignored by ESLint.
1156
+ * @param {string} filePath The path of the file to check.
1157
+ * @returns {Promise<boolean>} Whether or not the given path is ignored.
1158
+ */
1159
+ async isPathIgnored(filePath) {
1160
+ const config = await this.calculateConfigForFile(filePath);
1161
+
1162
+ return config === void 0;
1163
+ }
1106
1164
  }
1107
1165
 
1108
1166
  /**
@@ -1110,7 +1168,7 @@ class ESLint {
1110
1168
  * @returns {Promise<boolean>} Whether flat config should be used.
1111
1169
  */
1112
1170
  async function shouldUseFlatConfig() {
1113
- return (process.env.ESLINT_USE_FLAT_CONFIG !== "false");
1171
+ return process.env.ESLINT_USE_FLAT_CONFIG !== "false";
1114
1172
  }
1115
1173
 
1116
1174
  //------------------------------------------------------------------------------
@@ -1118,7 +1176,7 @@ async function shouldUseFlatConfig() {
1118
1176
  //------------------------------------------------------------------------------
1119
1177
 
1120
1178
  module.exports = {
1121
- ESLint,
1122
- shouldUseFlatConfig,
1123
- locateConfigFileToUse
1179
+ ESLint,
1180
+ shouldUseFlatConfig,
1181
+ locateConfigFileToUse,
1124
1182
  };