pickier 0.1.28 → 0.1.29

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 (263) hide show
  1. package/dist/ast.d.ts +13 -0
  2. package/dist/bin/cli.js +507 -302
  3. package/dist/plugins/eslint.d.ts +2 -0
  4. package/dist/plugins/general.d.ts +2 -0
  5. package/dist/plugins/index.d.ts +2 -0
  6. package/dist/plugins/lockfile.d.ts +22 -0
  7. package/dist/plugins/markdown.d.ts +2 -0
  8. package/dist/plugins/node.d.ts +2 -0
  9. package/dist/plugins/perfectionist.d.ts +6 -0
  10. package/dist/plugins/pickier.d.ts +2 -0
  11. package/dist/plugins/publint.d.ts +10 -0
  12. package/dist/plugins/quality.d.ts +2 -0
  13. package/dist/plugins/regexp.d.ts +2 -0
  14. package/dist/plugins/shell.d.ts +2 -0
  15. package/dist/plugins/spell.d.ts +3 -0
  16. package/dist/plugins/style.d.ts +2 -0
  17. package/dist/plugins/ts.d.ts +2 -0
  18. package/dist/plugins/unused-imports.d.ts +6 -0
  19. package/dist/plugins/utils.d.ts +4 -0
  20. package/dist/rules/general/_template-tracking.d.ts +31 -0
  21. package/dist/rules/general/array-callback-return.d.ts +2 -0
  22. package/dist/rules/general/constructor-super.d.ts +2 -0
  23. package/dist/rules/general/for-direction.d.ts +2 -0
  24. package/dist/rules/general/getter-return.d.ts +2 -0
  25. package/dist/rules/general/no-async-promise-executor.d.ts +2 -0
  26. package/dist/rules/general/no-compare-neg-zero.d.ts +2 -0
  27. package/dist/rules/general/no-cond-assign.d.ts +2 -0
  28. package/dist/rules/general/no-const-assign.d.ts +2 -0
  29. package/dist/rules/general/no-constant-condition.d.ts +2 -0
  30. package/dist/rules/general/no-constructor-return.d.ts +2 -0
  31. package/dist/rules/general/no-dupe-class-members.d.ts +2 -0
  32. package/dist/rules/general/no-dupe-keys.d.ts +2 -0
  33. package/dist/rules/general/no-duplicate-case.d.ts +2 -0
  34. package/dist/rules/general/no-empty-pattern.d.ts +2 -0
  35. package/dist/rules/general/no-fallthrough.d.ts +2 -0
  36. package/dist/rules/general/no-irregular-whitespace.d.ts +2 -0
  37. package/dist/rules/general/no-loss-of-precision.d.ts +2 -0
  38. package/dist/rules/general/no-new.d.ts +13 -0
  39. package/dist/rules/general/no-promise-executor-return.d.ts +2 -0
  40. package/dist/rules/general/no-redeclare.d.ts +2 -0
  41. package/dist/rules/general/no-regex-spaces.d.ts +10 -0
  42. package/dist/rules/general/no-self-assign.d.ts +2 -0
  43. package/dist/rules/general/no-self-compare.d.ts +2 -0
  44. package/dist/rules/general/no-sparse-arrays.d.ts +2 -0
  45. package/dist/rules/general/no-undef.d.ts +2 -0
  46. package/dist/rules/general/no-unreachable.d.ts +2 -0
  47. package/dist/rules/general/no-unsafe-negation.d.ts +2 -0
  48. package/dist/rules/general/no-unused-vars.d.ts +2 -0
  49. package/dist/rules/general/no-useless-catch.d.ts +2 -0
  50. package/dist/rules/general/prefer-const.d.ts +2 -0
  51. package/dist/rules/general/prefer-object-spread.d.ts +2 -0
  52. package/dist/rules/general/prefer-template.d.ts +2 -0
  53. package/dist/rules/general/use-isnan.d.ts +2 -0
  54. package/dist/rules/general/valid-typeof.d.ts +2 -0
  55. package/dist/rules/imports/first.d.ts +2 -0
  56. package/dist/rules/imports/import-dedupe.d.ts +2 -0
  57. package/dist/rules/imports/named.d.ts +2 -0
  58. package/dist/rules/imports/no-cycle.d.ts +2 -0
  59. package/dist/rules/imports/no-duplicate-imports.d.ts +2 -0
  60. package/dist/rules/imports/no-import-dist.d.ts +2 -0
  61. package/dist/rules/imports/no-import-node-modules-by-path.d.ts +2 -0
  62. package/dist/rules/imports/no-unresolved.d.ts +2 -0
  63. package/dist/rules/lockfile/parser.d.ts +79 -0
  64. package/dist/rules/lockfile/validate-host.d.ts +18 -0
  65. package/dist/rules/lockfile/validate-https.d.ts +14 -0
  66. package/dist/rules/lockfile/validate-integrity.d.ts +19 -0
  67. package/dist/rules/lockfile/validate-package-names.d.ts +23 -0
  68. package/dist/rules/lockfile/validate-scheme.d.ts +17 -0
  69. package/dist/rules/markdown/_fence-tracking.d.ts +32 -0
  70. package/dist/rules/markdown/_shared.d.ts +9 -0
  71. package/dist/rules/markdown/blanks-around-fences.d.ts +5 -0
  72. package/dist/rules/markdown/blanks-around-headings.d.ts +5 -0
  73. package/dist/rules/markdown/blanks-around-lists.d.ts +5 -0
  74. package/dist/rules/markdown/blanks-around-tables.d.ts +5 -0
  75. package/dist/rules/markdown/code-block-style.d.ts +5 -0
  76. package/dist/rules/markdown/code-fence-style.d.ts +5 -0
  77. package/dist/rules/markdown/commands-show-output.d.ts +5 -0
  78. package/dist/rules/markdown/descriptive-link-text.d.ts +5 -0
  79. package/dist/rules/markdown/emphasis-style.d.ts +5 -0
  80. package/dist/rules/markdown/fenced-code-language.d.ts +5 -0
  81. package/dist/rules/markdown/first-line-heading.d.ts +5 -0
  82. package/dist/rules/markdown/heading-increment.d.ts +5 -0
  83. package/dist/rules/markdown/heading-start-left.d.ts +5 -0
  84. package/dist/rules/markdown/heading-style.d.ts +5 -0
  85. package/dist/rules/markdown/hr-style.d.ts +5 -0
  86. package/dist/rules/markdown/line-length.d.ts +5 -0
  87. package/dist/rules/markdown/link-fragments.d.ts +5 -0
  88. package/dist/rules/markdown/link-image-reference-definitions.d.ts +5 -0
  89. package/dist/rules/markdown/link-image-style.d.ts +5 -0
  90. package/dist/rules/markdown/list-indent.d.ts +5 -0
  91. package/dist/rules/markdown/list-marker-space.d.ts +5 -0
  92. package/dist/rules/markdown/no-alt-text.d.ts +5 -0
  93. package/dist/rules/markdown/no-bare-urls.d.ts +5 -0
  94. package/dist/rules/markdown/no-blanks-blockquote.d.ts +5 -0
  95. package/dist/rules/markdown/no-duplicate-heading.d.ts +10 -0
  96. package/dist/rules/markdown/no-emphasis-as-heading.d.ts +9 -0
  97. package/dist/rules/markdown/no-empty-links.d.ts +5 -0
  98. package/dist/rules/markdown/no-hard-tabs.d.ts +5 -0
  99. package/dist/rules/markdown/no-inline-html.d.ts +5 -0
  100. package/dist/rules/markdown/no-missing-space-atx.d.ts +5 -0
  101. package/dist/rules/markdown/no-missing-space-closed-atx.d.ts +5 -0
  102. package/dist/rules/markdown/no-multiple-blanks.d.ts +5 -0
  103. package/dist/rules/markdown/no-multiple-space-atx.d.ts +5 -0
  104. package/dist/rules/markdown/no-multiple-space-blockquote.d.ts +5 -0
  105. package/dist/rules/markdown/no-multiple-space-closed-atx.d.ts +5 -0
  106. package/dist/rules/markdown/no-reversed-links.d.ts +5 -0
  107. package/dist/rules/markdown/no-space-in-code.d.ts +5 -0
  108. package/dist/rules/markdown/no-space-in-emphasis.d.ts +5 -0
  109. package/dist/rules/markdown/no-space-in-links.d.ts +5 -0
  110. package/dist/rules/markdown/no-trailing-punctuation.d.ts +5 -0
  111. package/dist/rules/markdown/no-trailing-spaces.d.ts +5 -0
  112. package/dist/rules/markdown/ol-prefix.d.ts +5 -0
  113. package/dist/rules/markdown/proper-names.d.ts +5 -0
  114. package/dist/rules/markdown/reference-links-images.d.ts +14 -0
  115. package/dist/rules/markdown/required-headings.d.ts +5 -0
  116. package/dist/rules/markdown/single-title.d.ts +5 -0
  117. package/dist/rules/markdown/single-trailing-newline.d.ts +5 -0
  118. package/dist/rules/markdown/strong-style.d.ts +5 -0
  119. package/dist/rules/markdown/table-column-count.d.ts +5 -0
  120. package/dist/rules/markdown/table-column-style.d.ts +5 -0
  121. package/dist/rules/markdown/table-pipe-style.d.ts +5 -0
  122. package/dist/rules/markdown/ul-indent.d.ts +14 -0
  123. package/dist/rules/markdown/ul-style.d.ts +5 -0
  124. package/dist/rules/node/prefer-global-buffer.d.ts +9 -0
  125. package/dist/rules/node/prefer-global-process.d.ts +9 -0
  126. package/dist/rules/quality/complexity.d.ts +2 -0
  127. package/dist/rules/quality/default-case.d.ts +2 -0
  128. package/dist/rules/quality/eqeqeq.d.ts +2 -0
  129. package/dist/rules/quality/max-depth.d.ts +2 -0
  130. package/dist/rules/quality/max-lines-per-function.d.ts +2 -0
  131. package/dist/rules/quality/no-alert.d.ts +2 -0
  132. package/dist/rules/quality/no-await-in-loop.d.ts +2 -0
  133. package/dist/rules/quality/no-caller.d.ts +2 -0
  134. package/dist/rules/quality/no-case-declarations.d.ts +2 -0
  135. package/dist/rules/quality/no-else-return.d.ts +2 -0
  136. package/dist/rules/quality/no-empty-function.d.ts +2 -0
  137. package/dist/rules/quality/no-empty.d.ts +2 -0
  138. package/dist/rules/quality/no-eval.d.ts +2 -0
  139. package/dist/rules/quality/no-extend-native.d.ts +2 -0
  140. package/dist/rules/quality/no-extra-boolean-cast.d.ts +2 -0
  141. package/dist/rules/quality/no-global-assign.d.ts +2 -0
  142. package/dist/rules/quality/no-implied-eval.d.ts +2 -0
  143. package/dist/rules/quality/no-iterator.d.ts +2 -0
  144. package/dist/rules/quality/no-lonely-if.d.ts +2 -0
  145. package/dist/rules/quality/no-new-func.d.ts +2 -0
  146. package/dist/rules/quality/no-new-wrappers.d.ts +2 -0
  147. package/dist/rules/quality/no-new.d.ts +2 -0
  148. package/dist/rules/quality/no-octal.d.ts +2 -0
  149. package/dist/rules/quality/no-param-reassign.d.ts +2 -0
  150. package/dist/rules/quality/no-proto.d.ts +2 -0
  151. package/dist/rules/quality/no-return-assign.d.ts +2 -0
  152. package/dist/rules/quality/no-sequences.d.ts +2 -0
  153. package/dist/rules/quality/no-shadow.d.ts +2 -0
  154. package/dist/rules/quality/no-throw-literal.d.ts +2 -0
  155. package/dist/rules/quality/no-use-before-define.d.ts +2 -0
  156. package/dist/rules/quality/no-useless-call.d.ts +2 -0
  157. package/dist/rules/quality/no-useless-concat.d.ts +2 -0
  158. package/dist/rules/quality/no-useless-escape.d.ts +2 -0
  159. package/dist/rules/quality/no-useless-rename.d.ts +2 -0
  160. package/dist/rules/quality/no-useless-return.d.ts +2 -0
  161. package/dist/rules/quality/no-var.d.ts +2 -0
  162. package/dist/rules/quality/no-with.d.ts +2 -0
  163. package/dist/rules/quality/prefer-arrow-callback.d.ts +2 -0
  164. package/dist/rules/quality/require-await.d.ts +2 -0
  165. package/dist/rules/regexp/no-super-linear-backtracking.d.ts +2 -0
  166. package/dist/rules/regexp/no-unused-capturing-group.d.ts +2 -0
  167. package/dist/rules/regexp/no-useless-lazy.d.ts +9 -0
  168. package/dist/rules/shell/_shared.d.ts +24 -0
  169. package/dist/rules/shell/command-substitution.d.ts +6 -0
  170. package/dist/rules/shell/consistent-case-terminators.d.ts +9 -0
  171. package/dist/rules/shell/function-style.d.ts +6 -0
  172. package/dist/rules/shell/heredoc-indent.d.ts +7 -0
  173. package/dist/rules/shell/indent.d.ts +2 -0
  174. package/dist/rules/shell/keyword-spacing.d.ts +10 -0
  175. package/dist/rules/shell/no-broken-redirect.d.ts +7 -0
  176. package/dist/rules/shell/no-cd-without-check.d.ts +6 -0
  177. package/dist/rules/shell/no-eval.d.ts +6 -0
  178. package/dist/rules/shell/no-exit-in-subshell.d.ts +7 -0
  179. package/dist/rules/shell/no-ls-parsing.d.ts +7 -0
  180. package/dist/rules/shell/no-trailing-semicolons.d.ts +6 -0
  181. package/dist/rules/shell/no-trailing-whitespace.d.ts +5 -0
  182. package/dist/rules/shell/no-useless-cat.d.ts +6 -0
  183. package/dist/rules/shell/no-variable-in-single-quotes.d.ts +7 -0
  184. package/dist/rules/shell/operator-spacing.d.ts +11 -0
  185. package/dist/rules/shell/prefer-double-brackets.d.ts +6 -0
  186. package/dist/rules/shell/prefer-printf.d.ts +6 -0
  187. package/dist/rules/shell/quote-variables.d.ts +2 -0
  188. package/dist/rules/shell/set-options.d.ts +8 -0
  189. package/dist/rules/shell/shebang.d.ts +2 -0
  190. package/dist/rules/sort/exports.d.ts +2 -0
  191. package/dist/rules/sort/heritage-clauses.d.ts +2 -0
  192. package/dist/rules/sort/imports.d.ts +2 -0
  193. package/dist/rules/sort/keys.d.ts +2 -0
  194. package/dist/rules/sort/named-imports.d.ts +2 -0
  195. package/dist/rules/sort/objects.d.ts +2 -0
  196. package/dist/rules/sort/tailwind-classes.d.ts +5 -0
  197. package/dist/rules/style/array-bracket-spacing.d.ts +2 -0
  198. package/dist/rules/style/arrow-parens.d.ts +2 -0
  199. package/dist/rules/style/arrow-spacing.d.ts +2 -0
  200. package/dist/rules/style/block-spacing.d.ts +2 -0
  201. package/dist/rules/style/brace-style.d.ts +10 -0
  202. package/dist/rules/style/comma-dangle.d.ts +2 -0
  203. package/dist/rules/style/comma-spacing.d.ts +2 -0
  204. package/dist/rules/style/comma-style.d.ts +2 -0
  205. package/dist/rules/style/computed-property-spacing.d.ts +2 -0
  206. package/dist/rules/style/consistent-chaining.d.ts +2 -0
  207. package/dist/rules/style/consistent-list-newline.d.ts +2 -0
  208. package/dist/rules/style/curly.d.ts +5 -0
  209. package/dist/rules/style/dot-location.d.ts +2 -0
  210. package/dist/rules/style/function-call-spacing.d.ts +2 -0
  211. package/dist/rules/style/generator-star-spacing.d.ts +2 -0
  212. package/dist/rules/style/if-newline.d.ts +2 -0
  213. package/dist/rules/style/indent-binary-ops.d.ts +2 -0
  214. package/dist/rules/style/indent-unindent.d.ts +2 -0
  215. package/dist/rules/style/key-spacing.d.ts +2 -0
  216. package/dist/rules/style/keyword-spacing.d.ts +2 -0
  217. package/dist/rules/style/lines-between-class-members.d.ts +2 -0
  218. package/dist/rules/style/max-statements-per-line.d.ts +2 -0
  219. package/dist/rules/style/multiline-ternary.d.ts +2 -0
  220. package/dist/rules/style/new-parens.d.ts +2 -0
  221. package/dist/rules/style/no-extra-parens.d.ts +2 -0
  222. package/dist/rules/style/no-floating-decimal.d.ts +2 -0
  223. package/dist/rules/style/no-mixed-operators.d.ts +2 -0
  224. package/dist/rules/style/no-mixed-spaces-and-tabs.d.ts +2 -0
  225. package/dist/rules/style/no-multi-spaces.d.ts +10 -0
  226. package/dist/rules/style/no-multiple-empty-lines.d.ts +9 -0
  227. package/dist/rules/style/no-tabs.d.ts +2 -0
  228. package/dist/rules/style/no-trailing-spaces.d.ts +9 -0
  229. package/dist/rules/style/no-whitespace-before-property.d.ts +2 -0
  230. package/dist/rules/style/object-curly-spacing.d.ts +2 -0
  231. package/dist/rules/style/operator-linebreak.d.ts +2 -0
  232. package/dist/rules/style/padded-blocks.d.ts +2 -0
  233. package/dist/rules/style/quote-props.d.ts +2 -0
  234. package/dist/rules/style/rest-spread-spacing.d.ts +2 -0
  235. package/dist/rules/style/semi-spacing.d.ts +2 -0
  236. package/dist/rules/style/space-before-blocks.d.ts +2 -0
  237. package/dist/rules/style/space-before-function-paren.d.ts +2 -0
  238. package/dist/rules/style/space-in-parens.d.ts +2 -0
  239. package/dist/rules/style/space-infix-ops.d.ts +2 -0
  240. package/dist/rules/style/space-unary-ops.d.ts +2 -0
  241. package/dist/rules/style/spaced-comment.d.ts +2 -0
  242. package/dist/rules/style/switch-colon-spacing.d.ts +2 -0
  243. package/dist/rules/style/template-curly-spacing.d.ts +2 -0
  244. package/dist/rules/style/template-tag-spacing.d.ts +2 -0
  245. package/dist/rules/style/top-level-function.d.ts +6 -0
  246. package/dist/rules/style/wrap-iife.d.ts +2 -0
  247. package/dist/rules/style/yield-star-spacing.d.ts +2 -0
  248. package/dist/rules/ts/member-delimiter-style.d.ts +4 -0
  249. package/dist/rules/ts/no-explicit-any.d.ts +2 -0
  250. package/dist/rules/ts/no-floating-promises.d.ts +2 -0
  251. package/dist/rules/ts/no-misused-promises.d.ts +2 -0
  252. package/dist/rules/ts/no-require-imports.d.ts +2 -0
  253. package/dist/rules/ts/no-top-level-await.d.ts +4 -0
  254. package/dist/rules/ts/no-ts-export-equal.d.ts +2 -0
  255. package/dist/rules/ts/no-unsafe-assignment.d.ts +2 -0
  256. package/dist/rules/ts/prefer-nullish-coalescing.d.ts +2 -0
  257. package/dist/rules/ts/prefer-optional-chain.d.ts +2 -0
  258. package/dist/rules/ts/type-annotation-spacing.d.ts +2 -0
  259. package/dist/rules/ts/type-generic-spacing.d.ts +2 -0
  260. package/dist/rules/ts/type-named-tuple-spacing.d.ts +2 -0
  261. package/dist/src/index.js +481 -289
  262. package/dist/utils.d.ts +12 -3
  263. package/package.json +2 -2
package/dist/src/index.js CHANGED
@@ -9364,6 +9364,16 @@ function unmaskStrings(text, strings) {
9364
9364
  return text;
9365
9365
  return text.replace(/@@S(\d+)@@/g, (_, idx) => strings[Number(idx)] ?? "");
9366
9366
  }
9367
+ function collectIdentifierSet(text) {
9368
+ const identifiers = new Set;
9369
+ const identifierRe = /[$A-Z_][\w$]*/gi;
9370
+ let match = identifierRe.exec(text);
9371
+ while (match !== null) {
9372
+ identifiers.add(match[0]);
9373
+ match = identifierRe.exec(text);
9374
+ }
9375
+ return identifiers;
9376
+ }
9367
9377
  function formatImports(source) {
9368
9378
  const firstChar = source[0];
9369
9379
  if (firstChar !== "i" && firstChar !== " " && firstChar !== "\t" && firstChar !== "/" && firstChar !== `
@@ -9391,17 +9401,8 @@ function formatImports(source) {
9391
9401
  return source;
9392
9402
  const rest = lines.slice(idx).join(`
9393
9403
  `);
9394
- const codeText = rest;
9395
- const isWordChar = (c) => c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c >= "0" && c <= "9" || c === "_" || c === "$";
9396
- const used = (name) => {
9397
- for (let pos = codeText.indexOf(name, 0);pos !== -1; pos = codeText.indexOf(name, pos + name.length)) {
9398
- const before = pos > 0 ? codeText[pos - 1] : " ";
9399
- const after = pos + name.length < codeText.length ? codeText[pos + name.length] : " ";
9400
- if (!isWordChar(before) && !isWordChar(after))
9401
- return true;
9402
- }
9403
- return false;
9404
- };
9404
+ const usedIdentifiers = collectIdentifierSet(rest);
9405
+ const used = (name) => usedIdentifiers.has(name);
9405
9406
  for (const imp of imports) {
9406
9407
  if (imp.kind !== "value")
9407
9408
  continue;
@@ -20322,11 +20323,11 @@ var init_no_unused_vars = __esm(() => {
20322
20323
  }
20323
20324
  };
20324
20325
  computeTemplateLines();
20326
+ const declRe = new RegExp("^\\s*(?:const|let|var)\\s+(.+?)" + ";" + "?\\s*$");
20325
20327
  for (let i = 0;i < lines.length; i++) {
20326
20328
  if (lineStartsInTemplate[i])
20327
20329
  continue;
20328
20330
  const line = lines[i];
20329
- const declRe = new RegExp("^\\s*(?:const|let|var)\\s+(.+?)" + ";" + "?\\s*$");
20330
20331
  const decl = line.match(declRe);
20331
20332
  if (!decl)
20332
20333
  continue;
@@ -21756,6 +21757,90 @@ function findTopLevelEquals(s) {
21756
21757
  }
21757
21758
  return -1;
21758
21759
  }
21760
+ function destructuringReassignsName(text, name) {
21761
+ const re = new RegExp(`\\b${name}\\b`);
21762
+ let i = 0;
21763
+ let inStr = null;
21764
+ let escaped = false;
21765
+ while (i < text.length) {
21766
+ const c = text[i];
21767
+ if (escaped) {
21768
+ escaped = false;
21769
+ i++;
21770
+ continue;
21771
+ }
21772
+ if (c === "\\" && inStr) {
21773
+ escaped = true;
21774
+ i++;
21775
+ continue;
21776
+ }
21777
+ if (inStr) {
21778
+ if (inStr === "single" && c === "'" || inStr === "double" && c === '"' || inStr === "template" && c === "`")
21779
+ inStr = null;
21780
+ i++;
21781
+ continue;
21782
+ }
21783
+ if (c === "'") {
21784
+ inStr = "single";
21785
+ i++;
21786
+ continue;
21787
+ }
21788
+ if (c === '"') {
21789
+ inStr = "double";
21790
+ i++;
21791
+ continue;
21792
+ }
21793
+ if (c === "`") {
21794
+ inStr = "template";
21795
+ i++;
21796
+ continue;
21797
+ }
21798
+ if (c === "[" || c === "{") {
21799
+ const open = c;
21800
+ const close = c === "[" ? "]" : "}";
21801
+ let depth = 1;
21802
+ let j = i + 1;
21803
+ while (j < text.length && depth > 0) {
21804
+ const cj = text[j];
21805
+ if (cj === "\\") {
21806
+ j += 2;
21807
+ continue;
21808
+ }
21809
+ if (cj === open)
21810
+ depth++;
21811
+ else if (cj === close)
21812
+ depth--;
21813
+ if (depth === 0)
21814
+ break;
21815
+ j++;
21816
+ }
21817
+ if (depth === 0 && j < text.length) {
21818
+ let k = j + 1;
21819
+ while (k < text.length && (text[k] === " " || text[k] === "\t" || text[k] === "\r" || text[k] === `
21820
+ `))
21821
+ k++;
21822
+ if (text[k] === "=" && text[k + 1] !== "=" && text[k + 1] !== ">") {
21823
+ const inside = text.slice(i + 1, j);
21824
+ if (re.test(inside)) {
21825
+ const keyOnly = new RegExp(`\\b${name}\\b\\s*:`);
21826
+ const valueAfterColon = new RegExp(`:\\s*\\b${name}\\b`);
21827
+ if (open === "{") {
21828
+ const isKeyOnly = keyOnly.test(inside) && !valueAfterColon.test(inside) && !new RegExp(`(?:^|[\\s,{])\\s*${name}\\s*(?:,|\\s*=|\\s*})`).test(inside);
21829
+ if (!isKeyOnly)
21830
+ return true;
21831
+ } else {
21832
+ return true;
21833
+ }
21834
+ }
21835
+ }
21836
+ }
21837
+ i = j + 1;
21838
+ continue;
21839
+ }
21840
+ i++;
21841
+ }
21842
+ return false;
21843
+ }
21759
21844
  function analyzeLetDecl(line, text) {
21760
21845
  const declRe = new RegExp("^\\s*(?:let|var)\\s+(.+?)" + ";" + "?\\s*$");
21761
21846
  const decl = line.match(declRe);
@@ -21793,7 +21878,8 @@ function analyzeLetDecl(line, text) {
21793
21878
  const assignPattern = `\\b${name}\\s*(?:${assignOps.map((op) => op.replace(/[|\\^$*+?.(){}[\]]/g, (r) => `\\${r}`)).join("|")})`;
21794
21879
  const directAssign = new RegExp(assignPattern).test(rest);
21795
21880
  const incDecChanged = new RegExp(`(?:^|[^$w])(?:\\+\\+|--)\\s*${name}\\b|\\b${name}\\s*(?:\\+\\+|--)`).test(rest);
21796
- result.push({ name, fixable: !directAssign && !incDecChanged });
21881
+ const destructReassigned = destructuringReassignsName(rest, name);
21882
+ result.push({ name, fixable: !directAssign && !incDecChanged && !destructReassigned });
21797
21883
  }
21798
21884
  return result;
21799
21885
  }
@@ -21822,8 +21908,20 @@ var init_prefer_const = __esm(() => {
21822
21908
  },
21823
21909
  fix: (text) => {
21824
21910
  const lines = text.split(/\r?\n/);
21911
+ const disabledLines = new Set;
21912
+ const disableNextRe = /(?:eslint|pickier)-disable-next-line\b([^*\n]*)/;
21913
+ for (let i = 0;i < lines.length; i++) {
21914
+ const m = lines[i].match(disableNextRe);
21915
+ if (!m)
21916
+ continue;
21917
+ const ruleList = m[1].trim();
21918
+ if (ruleList === "" || /\bprefer-const\b/.test(ruleList))
21919
+ disabledLines.add(i + 2);
21920
+ }
21825
21921
  let changed = false;
21826
21922
  for (let i = 0;i < lines.length; i++) {
21923
+ if (disabledLines.has(i + 1))
21924
+ continue;
21827
21925
  const line = lines[i];
21828
21926
  if (!/^\s*let\b/.test(line))
21829
21927
  continue;
@@ -28473,14 +28571,27 @@ function getVariantPriority(cls) {
28473
28571
  }
28474
28572
  return priority;
28475
28573
  }
28574
+ function getClassSortKey(cls) {
28575
+ const cached = sortKeyCache.get(cls);
28576
+ if (cached)
28577
+ return cached;
28578
+ const key = {
28579
+ group: getGroupIndex(cls),
28580
+ variant: getVariantPriority(cls)
28581
+ };
28582
+ sortKeyCache.set(cls, key);
28583
+ return key;
28584
+ }
28476
28585
  function sortClasses(classes) {
28477
28586
  return [...classes].sort((a, b) => {
28478
- const ga = getGroupIndex(a);
28479
- const gb = getGroupIndex(b);
28587
+ const aKey = getClassSortKey(a);
28588
+ const bKey = getClassSortKey(b);
28589
+ const ga = aKey.group;
28590
+ const gb = bKey.group;
28480
28591
  if (ga !== gb)
28481
28592
  return ga - gb;
28482
- const va = getVariantPriority(a);
28483
- const vb = getVariantPriority(b);
28593
+ const va = aKey.variant;
28594
+ const vb = bKey.variant;
28484
28595
  if (va !== vb)
28485
28596
  return va - vb;
28486
28597
  return a.localeCompare(b);
@@ -28499,6 +28610,8 @@ function looksLikeJsExpression(value) {
28499
28610
  }
28500
28611
  function extractClassValues(content) {
28501
28612
  const matches = [];
28613
+ if (!content.includes("class") && !content.includes("clsx") && !content.includes("cn(") && !content.includes("tw(") && !content.includes("cva(") && !content.includes("tv("))
28614
+ return matches;
28502
28615
  for (const re of [ATTR_RE, ATTR_TMPL_RE, UTIL_FN_RE]) {
28503
28616
  re.lastIndex = 0;
28504
28617
  let m;
@@ -28545,7 +28658,7 @@ function isSorted(classes) {
28545
28658
  const sorted = sortClasses(classes);
28546
28659
  return classes.every((c, i) => c === sorted[i]);
28547
28660
  }
28548
- var GROUP_ORDER, VARIANT_RE, ATTR_RE, ATTR_TMPL_RE, UTIL_FN_RE, sortTailwindClassesRule;
28661
+ var GROUP_ORDER, VARIANT_RE, sortKeyCache, ATTR_RE, ATTR_TMPL_RE, UTIL_FN_RE, sortTailwindClassesRule;
28549
28662
  var init_tailwind_classes = __esm(() => {
28550
28663
  GROUP_ORDER = [
28551
28664
  [/^(block|inline|inline-block|flex|inline-flex|grid|inline-grid|flow-root|contents|hidden|table|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row-group|table-row|list-item|subgrid)$/, 0],
@@ -28569,6 +28682,7 @@ var init_tailwind_classes = __esm(() => {
28569
28682
  [/^(sr-only|not-sr-only)$/, 15]
28570
28683
  ];
28571
28684
  VARIANT_RE = /^([a-z0-9][-a-z0-9]{0,50}:)+(?!\[)/;
28685
+ sortKeyCache = new Map;
28572
28686
  ATTR_RE = /\b(?:class|className|:class)\s*=\s*(?:"([^"]*?)"|'([^']*?)')/g;
28573
28687
  ATTR_TMPL_RE = /\b(?:class|className|:class)\s*=\s*\{`([^`]*?)`\}/g;
28574
28688
  UTIL_FN_RE = /\b(?:clsx|cn|tw|cva|tv)\s*\(\s*(?:"([^"]*?)"|'([^']*?)')/g;
@@ -37167,15 +37281,7 @@ function globToRegex(pattern) {
37167
37281
  }
37168
37282
  return new RegExp(`^${src}$`);
37169
37283
  }
37170
- function matchesAnyPattern(filePath, patterns) {
37171
- for (const p of patterns) {
37172
- const re = globToRegex(p);
37173
- if (re.test(filePath) || re.test(filePath.replace(/\\/g, "/")))
37174
- return true;
37175
- }
37176
- return false;
37177
- }
37178
- function* walkDir(dir, ignore, dot, cwd) {
37284
+ function* walkDirWithMatcher(dir, ignoreMatcher, dot) {
37179
37285
  let entries;
37180
37286
  try {
37181
37287
  entries = readdirSync8(dir);
@@ -37186,8 +37292,7 @@ function* walkDir(dir, ignore, dot, cwd) {
37186
37292
  if (!dot && name.startsWith("."))
37187
37293
  continue;
37188
37294
  const full = join10(dir, name);
37189
- const rel = full.startsWith(`${cwd}/`) ? full.slice(cwd.length + 1) : full;
37190
- if (ignore.length && matchesAnyPattern(rel, ignore))
37295
+ if (ignoreMatcher(full))
37191
37296
  continue;
37192
37297
  let st;
37193
37298
  try {
@@ -37196,17 +37301,21 @@ function* walkDir(dir, ignore, dot, cwd) {
37196
37301
  continue;
37197
37302
  }
37198
37303
  if (st.isDirectory()) {
37199
- yield* walkDir(full, ignore, dot, cwd);
37304
+ yield* walkDirWithMatcher(full, ignoreMatcher, dot);
37200
37305
  } else {
37201
37306
  yield full;
37202
37307
  }
37203
37308
  }
37204
37309
  }
37310
+ function* walkDir(dir, ignore, dot, cwd) {
37311
+ yield* walkDirWithMatcher(dir, createIgnoreMatcher(ignore, cwd), dot);
37312
+ }
37205
37313
  async function glob(patterns, opts = {}) {
37206
37314
  const cwd = opts.cwd ?? process21.cwd();
37207
37315
  const ignore = opts.ignore ?? [];
37208
37316
  const dot = opts.dot ?? false;
37209
37317
  const absolute = opts.absolute ?? true;
37318
+ const ignoreMatcher = createIgnoreMatcher(ignore, cwd);
37210
37319
  if (typeof globalThis.Bun?.Glob !== "undefined") {
37211
37320
  const BunGlob = globalThis.Bun.Glob;
37212
37321
  const results2 = [];
@@ -37215,7 +37324,7 @@ async function glob(patterns, opts = {}) {
37215
37324
  for await (const file of g.scan({ cwd, dot, onlyFiles: opts.onlyFiles ?? true, followSymlinks: false })) {
37216
37325
  const full = isAbsolute6(file) ? file : join10(cwd, file);
37217
37326
  const rel = full.startsWith(`${cwd}/`) ? full.slice(cwd.length + 1) : full;
37218
- if (ignore.length && matchesAnyPattern(rel, ignore))
37327
+ if (ignoreMatcher(full))
37219
37328
  continue;
37220
37329
  results2.push(absolute ? full : rel);
37221
37330
  }
@@ -37230,7 +37339,7 @@ async function glob(patterns, opts = {}) {
37230
37339
  const st = statSync5(full);
37231
37340
  if (!st.isDirectory()) {
37232
37341
  const rel = full.startsWith(`${cwd}/`) ? full.slice(cwd.length + 1) : full;
37233
- if (!ignore.length || !matchesAnyPattern(rel, ignore))
37342
+ if (!ignoreMatcher(full))
37234
37343
  results.push(absolute ? full : rel);
37235
37344
  } else {
37236
37345
  for (const f of walkDir(full, ignore, dot, cwd))
@@ -37405,36 +37514,60 @@ function isCodeFile(file, allowedExts) {
37405
37514
  function toPosixPath(p) {
37406
37515
  return p.replace(/\\/g, "/").replace(/\/+/g, "/");
37407
37516
  }
37408
- function shouldIgnorePath(absPath, ignoreGlobs) {
37409
- const isOutsideProject = !absPath.startsWith(process21.cwd());
37410
- const universalIgnores = ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**"];
37411
- const effectiveIgnores = isOutsideProject ? ignoreGlobs.filter((pattern) => universalIgnores.includes(pattern)) : ignoreGlobs;
37412
- const rel = toPosixPath(isOutsideProject ? absPath : absPath.slice(process21.cwd().length));
37413
- for (const g of effectiveIgnores) {
37517
+ function compileIgnoreGlobs(ignoreGlobs) {
37518
+ const compiled = [];
37519
+ for (const g of ignoreGlobs) {
37414
37520
  const gg = toPosixPath(g.trim());
37521
+ if (!gg)
37522
+ continue;
37415
37523
  const filePattern = gg.match(/\*\*\/\*\.(.+)$/);
37416
37524
  if (filePattern) {
37417
- const extension = filePattern[1];
37418
- if (rel.endsWith(`.${extension}`))
37419
- return true;
37525
+ compiled.push({ raw: gg, kind: "extension", value: filePattern[1] });
37420
37526
  continue;
37421
37527
  }
37422
37528
  const m = gg.match(/\*\*\/(.+?)\/\*\*$/);
37423
37529
  if (m) {
37424
- const name = m[1];
37425
- if (rel.includes(`/${name}/`) || rel.endsWith(`/${name}`))
37426
- return true;
37530
+ compiled.push({ raw: gg, kind: "segment", value: m[1] });
37427
37531
  continue;
37428
37532
  }
37429
37533
  const m2 = gg.match(/\*\*\/(.+)$/);
37430
37534
  if (m2) {
37431
- const name = m2[1].replace(/\/$/, "");
37432
- if (rel.includes(`/${name}/`) || rel.endsWith(`/${name}`))
37433
- return true;
37434
- continue;
37535
+ compiled.push({ raw: gg, kind: "suffix", value: m2[1].replace(/\/$/, "") });
37536
+ }
37537
+ }
37538
+ return compiled;
37539
+ }
37540
+ function createIgnoreMatcher(ignoreGlobs, cwd = process21.cwd()) {
37541
+ if (ignoreGlobs.length === 0)
37542
+ return () => false;
37543
+ const compiled = compileIgnoreGlobs(ignoreGlobs);
37544
+ if (compiled.length === 0)
37545
+ return () => false;
37546
+ const universalRaw = new Set(UNIVERSAL_IGNORES);
37547
+ return (absPath) => {
37548
+ const normalizedAbs = toPosixPath(absPath);
37549
+ const normalizedCwd = toPosixPath(cwd).replace(/\/$/, "");
37550
+ const isOutsideProject = !normalizedAbs.startsWith(normalizedCwd);
37551
+ const rel = isOutsideProject ? normalizedAbs : normalizedAbs.slice(normalizedCwd.length);
37552
+ for (const pattern of compiled) {
37553
+ if (isOutsideProject && !universalRaw.has(pattern.raw))
37554
+ continue;
37555
+ if (pattern.kind === "extension") {
37556
+ if (rel.endsWith(`.${pattern.value}`))
37557
+ return true;
37558
+ continue;
37559
+ }
37560
+ if (pattern.kind === "segment" || pattern.kind === "suffix") {
37561
+ const name = pattern.value;
37562
+ if (rel.includes(`/${name}/`) || rel.endsWith(`/${name}`))
37563
+ return true;
37564
+ }
37435
37565
  }
37436
- }
37437
- return false;
37566
+ return false;
37567
+ };
37568
+ }
37569
+ function shouldIgnorePath(absPath, ignoreGlobs) {
37570
+ return createIgnoreMatcher(ignoreGlobs)(absPath);
37438
37571
  }
37439
37572
  var MAX_FIXER_PASSES = 5, ENV, UNIVERSAL_IGNORES, colors, _cachedDefaultConfig = null;
37440
37573
  var init_utils3 = __esm(() => {
@@ -37646,6 +37779,7 @@ async function runFormat(globs, options) {
37646
37779
  return !absBase.startsWith(process23.cwd());
37647
37780
  });
37648
37781
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
37782
+ const ignoreMatcher = createIgnoreMatcher(globIgnores);
37649
37783
  let entries = [];
37650
37784
  const simpleDirPattern = patterns.length === 1 && /\*\*\/\*$/.test(patterns[0]);
37651
37785
  if (simpleDirPattern) {
@@ -37660,7 +37794,7 @@ async function runFormat(globs, options) {
37660
37794
  for (const it of items) {
37661
37795
  const full = join8(dir, it);
37662
37796
  const st = statSync4(full);
37663
- if (shouldIgnorePath(full, globIgnores))
37797
+ if (ignoreMatcher(full))
37664
37798
  continue;
37665
37799
  if (st.isDirectory())
37666
37800
  stack.push(full);
@@ -37686,7 +37820,7 @@ async function runFormat(globs, options) {
37686
37820
  }
37687
37821
  trace("globbed entries", entries.length);
37688
37822
  const files = entries.filter((f) => {
37689
- if (shouldIgnorePath(f, globIgnores))
37823
+ if (ignoreMatcher(f))
37690
37824
  return false;
37691
37825
  const idx = f.lastIndexOf(".");
37692
37826
  if (idx < 0)
@@ -37758,24 +37892,21 @@ function trace2(...args) {
37758
37892
  getLogger2().error("[pickier:trace]", args);
37759
37893
  }
37760
37894
  async function lintText(text, cfg, filePath = "untitled", signal) {
37761
- if (signal?.aborted) {
37895
+ if (signal?.aborted)
37762
37896
  throw new Error("AbortError");
37763
- }
37764
- const cfg2 = cfg;
37765
- cfg2._internalSkipPluginRulesInScan = true;
37766
- const issues = scanContent(filePath, text, cfg);
37897
+ const suppress = parseDisableDirectives(text);
37898
+ const commentLines = getCommentLines(text);
37899
+ const issues = scanContentOptimized(filePath, text, cfg, suppress, commentLines);
37767
37900
  if (signal?.aborted)
37768
37901
  throw new Error("AbortError");
37769
37902
  try {
37770
37903
  const pluginIssues = await applyPlugins(filePath, text, cfg);
37771
- const suppress = parseDisableDirectives(text);
37772
- const commentLines = getCommentLines(text);
37773
37904
  for (const i of pluginIssues) {
37774
37905
  if (signal?.aborted)
37775
37906
  throw new Error("AbortError");
37776
37907
  if (isSuppressed(i.ruleId, i.line, suppress))
37777
37908
  continue;
37778
- if (commentLines.has(i.line))
37909
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
37779
37910
  continue;
37780
37911
  issues.push({
37781
37912
  filePath: i.filePath,
@@ -37809,6 +37940,7 @@ async function runLintProgrammatic(globs, options, signal) {
37809
37940
  return !absBase.startsWith(process25.cwd());
37810
37941
  });
37811
37942
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
37943
+ const ignoreMatcher = createIgnoreMatcher(globIgnores);
37812
37944
  let entries = [];
37813
37945
  const nonGlobSingle = patterns.length === 1 && !/[*?[\]{}()!]/.test(patterns[0]);
37814
37946
  if (nonGlobSingle) {
@@ -37834,7 +37966,7 @@ async function runLintProgrammatic(globs, options, signal) {
37834
37966
  for (const it of items) {
37835
37967
  const full = join11(dir, it);
37836
37968
  const st = statSync6(full);
37837
- if (shouldIgnorePath(full, globIgnores))
37969
+ if (ignoreMatcher(full))
37838
37970
  continue;
37839
37971
  if (st.isDirectory())
37840
37972
  stack.push(full);
@@ -37873,7 +38005,7 @@ async function runLintProgrammatic(globs, options, signal) {
37873
38005
  cntNodeModules++;
37874
38006
  continue;
37875
38007
  }
37876
- if (shouldIgnorePath(f, globIgnores)) {
38008
+ if (ignoreMatcher(f)) {
37877
38009
  cntIgnored++;
37878
38010
  continue;
37879
38011
  }
@@ -37886,15 +38018,12 @@ async function runLintProgrammatic(globs, options, signal) {
37886
38018
  }
37887
38019
  trace2("filter:programmatic", { total: cntTotal, included: cntIncluded, node_modules: cntNodeModules, ignored: cntIgnored, wrongExt: cntWrongExt });
37888
38020
  const concurrency = ENV.CONCURRENCY;
37889
- const limit = createLimiter(concurrency);
37890
38021
  const processFile = async (file) => {
37891
38022
  if (signal?.aborted)
37892
38023
  throw new Error("AbortError");
37893
38024
  const src = readFileSync10(file, "utf8");
37894
38025
  const suppress = parseDisableDirectives(src);
37895
38026
  const commentLines = getCommentLines(src);
37896
- const cfgAny = cfg;
37897
- cfgAny._internalSkipPluginRulesInScan = true;
37898
38027
  let issues = scanContentOptimized(file, src, cfg, suppress, commentLines);
37899
38028
  try {
37900
38029
  const pluginIssues = await applyPlugins(file, src, cfg);
@@ -37903,7 +38032,7 @@ async function runLintProgrammatic(globs, options, signal) {
37903
38032
  throw new Error("AbortError");
37904
38033
  if (isSuppressed(i.ruleId, i.line, suppress))
37905
38034
  continue;
37906
- if (commentLines.has(i.line))
38035
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
37907
38036
  continue;
37908
38037
  issues.push({
37909
38038
  filePath: i.filePath,
@@ -37953,7 +38082,7 @@ async function runLintProgrammatic(globs, options, signal) {
37953
38082
  }
37954
38083
  return issues;
37955
38084
  };
37956
- const issueArrays = await Promise.all(files.map((file) => limit(() => processFile(file))));
38085
+ const issueArrays = await processWithConcurrency(files, concurrency, processFile);
37957
38086
  const allIssues = issueArrays.flat();
37958
38087
  const errors = allIssues.filter((i) => i.severity === "error").length;
37959
38088
  const warnings = allIssues.filter((i) => i.severity === "warning").length;
@@ -37975,10 +38104,10 @@ function parseDisableDirectives(content) {
37975
38104
  for (let i = 0;i < lines.length; i++) {
37976
38105
  const t = lines[i].trim();
37977
38106
  const lineNo = i + 1;
37978
- const nextLineMatch = t.match(/^\/\/\s*(?:eslint|pickier)-disable-next-line\s+(\S.*)$/);
38107
+ const nextLineMatch = t.match(/^\/\/\s*(?:eslint|pickier)-disable-next-line(?:\s+(\S.*))?$/);
37979
38108
  if (nextLineMatch) {
37980
- const ruleText = nextLineMatch[1].replace(/\s+--\s.*$/, "");
37981
- const list = ruleText.split(",").map((s) => s.trim()).filter(Boolean);
38109
+ const ruleText = nextLineMatch[1]?.replace(/\s+--\s.*$/, "");
38110
+ const list = ruleText ? ruleText.split(",").map((s) => s.trim()).filter(Boolean) : ["*"];
37982
38111
  if (list.length > 0) {
37983
38112
  const target = lineNo + 1;
37984
38113
  const set = nextLine.get(target) || new Set;
@@ -38069,23 +38198,6 @@ function parseDisableDirectives(content) {
38069
38198
  const sortedEnableLines = Array.from(rangeEnable.keys()).sort((a, b) => a - b);
38070
38199
  return { nextLine, fileLevel, rangeDisable, rangeEnable, sortedDisableLines, sortedEnableLines };
38071
38200
  }
38072
- function binarySearchLargestLessThan(arr, target) {
38073
- if (arr.length === 0 || arr[0] >= target)
38074
- return -1;
38075
- let left = 0;
38076
- let right = arr.length - 1;
38077
- let result = -1;
38078
- while (left <= right) {
38079
- const mid = Math.floor((left + right) / 2);
38080
- if (arr[mid] < target) {
38081
- result = arr[mid];
38082
- left = mid + 1;
38083
- } else {
38084
- right = mid - 1;
38085
- }
38086
- }
38087
- return result;
38088
- }
38089
38201
  function isSuppressed(ruleId, line, directives) {
38090
38202
  if (directives instanceof Map) {
38091
38203
  const set = directives.get(line);
@@ -38100,14 +38212,28 @@ function isSuppressed(ruleId, line, directives) {
38100
38212
  const nextLineSet = directives.nextLine.get(line);
38101
38213
  if (nextLineSet && matchesRule(ruleId, nextLineSet))
38102
38214
  return true;
38103
- const lastDisableLine = binarySearchLargestLessThan(directives.sortedDisableLines, line);
38104
- const lastEnableLine = binarySearchLargestLessThan(directives.sortedEnableLines, line);
38105
- if (lastDisableLine !== -1 && lastDisableLine > lastEnableLine) {
38106
- const disabledRules = directives.rangeDisable.get(lastDisableLine);
38107
- if (matchesRule(ruleId, disabledRules))
38108
- return true;
38215
+ let disabled = false;
38216
+ let disableIndex = 0;
38217
+ let enableIndex = 0;
38218
+ while (true) {
38219
+ const nextDisable = disableIndex < directives.sortedDisableLines.length ? directives.sortedDisableLines[disableIndex] : Number.POSITIVE_INFINITY;
38220
+ const nextEnable = enableIndex < directives.sortedEnableLines.length ? directives.sortedEnableLines[enableIndex] : Number.POSITIVE_INFINITY;
38221
+ const nextDirectiveLine = Math.min(nextDisable, nextEnable);
38222
+ if (nextDirectiveLine >= line)
38223
+ break;
38224
+ if (nextDisable === nextDirectiveLine) {
38225
+ const disabledRules = directives.rangeDisable.get(nextDisable);
38226
+ if (matchesRule(ruleId, disabledRules))
38227
+ disabled = true;
38228
+ disableIndex++;
38229
+ continue;
38230
+ }
38231
+ const enabledRules = directives.rangeEnable.get(nextEnable);
38232
+ if (enabledRules.has("*") || matchesRule(ruleId, enabledRules))
38233
+ disabled = false;
38234
+ enableIndex++;
38109
38235
  }
38110
- return false;
38236
+ return disabled;
38111
38237
  }
38112
38238
  function matchesRule(ruleId, ruleSet) {
38113
38239
  if (ruleSet.size === 0)
@@ -38127,6 +38253,9 @@ function matchesRule(ruleId, ruleSet) {
38127
38253
  }
38128
38254
  return false;
38129
38255
  }
38256
+ function shouldSkipCommentOnlyPluginIssue(ruleId) {
38257
+ return ruleId !== "spaced-comment" && !ruleId.endsWith("/spaced-comment");
38258
+ }
38130
38259
  function ensureHelpText(issue, ruleId) {
38131
38260
  if (issue.help) {
38132
38261
  return issue;
@@ -38163,8 +38292,22 @@ async function withTimeout2(p, ms, label) {
38163
38292
  throw e;
38164
38293
  }
38165
38294
  }
38166
- async function applyPlugins(filePath, content, cfg) {
38167
- const issues = [];
38295
+ async function processWithConcurrency(items, concurrency, worker) {
38296
+ const results = new Array(items.length);
38297
+ if (items.length === 0)
38298
+ return results;
38299
+ let nextIndex = 0;
38300
+ const workerCount = Math.max(1, Math.min(Math.max(1, concurrency), items.length));
38301
+ async function runWorker() {
38302
+ while (nextIndex < items.length) {
38303
+ const index = nextIndex++;
38304
+ results[index] = await worker(items[index], index);
38305
+ }
38306
+ }
38307
+ await Promise.all(Array.from({ length: workerCount }, runWorker));
38308
+ return results;
38309
+ }
38310
+ function getPluginDefinitions(cfg) {
38168
38311
  let pluginDefs = getAllPlugins();
38169
38312
  if (cfg.plugins && cfg.plugins.length > 0) {
38170
38313
  const coreNames = new Set(["pickier", "style", "regexp", "ts"]);
@@ -38174,6 +38317,9 @@ async function applyPlugins(filePath, content, cfg) {
38174
38317
  for (const p of userPlugins)
38175
38318
  pluginDefs.push(p);
38176
38319
  }
38320
+ return pluginDefs;
38321
+ }
38322
+ function getRulesConfig(cfg, pluginDefs) {
38177
38323
  const rulesConfig = { ...cfg.pluginRules || {} };
38178
38324
  if (cfg.rules?.noUnusedCapturingGroup)
38179
38325
  rulesConfig["regexp/no-unused-capturing-group"] = cfg.rules.noUnusedCapturingGroup;
@@ -38183,115 +38329,168 @@ async function applyPlugins(filePath, content, cfg) {
38183
38329
  "antfu/no-top-level-await": "ts/no-top-level-await"
38184
38330
  };
38185
38331
  for (const [alias, target] of Object.entries(ruleAliases)) {
38186
- if (rulesConfig[alias]) {
38332
+ if (rulesConfig[alias])
38187
38333
  rulesConfig[target] = rulesConfig[alias];
38188
- }
38189
38334
  }
38190
38335
  for (const key of Object.keys(cfg.pluginRules || {})) {
38191
38336
  if (!key.includes("/")) {
38192
38337
  for (const p of pluginDefs) {
38193
- if (p.rules && Object.prototype.hasOwnProperty.call(p.rules, key)) {
38338
+ if (p.rules && Object.prototype.hasOwnProperty.call(p.rules, key))
38194
38339
  rulesConfig[`${p.name}/${key}`] = cfg.pluginRules[key];
38195
- }
38196
38340
  }
38197
38341
  }
38198
38342
  }
38199
- const baseCtx = { filePath, config: cfg };
38343
+ return rulesConfig;
38344
+ }
38345
+ function getPluginPlan(cfg) {
38346
+ const cached = pluginPlanCache.get(cfg);
38347
+ if (cached)
38348
+ return cached;
38349
+ const pluginDefs = getPluginDefinitions(cfg);
38350
+ const rulesConfig = getRulesConfig(cfg, pluginDefs);
38351
+ const checkRules = [];
38352
+ const fixRules = [];
38353
+ const fixableRuleIds = new Set(["no-debugger"]);
38354
+ const fixableBareRuleNames = new Set(["no-debugger"]);
38200
38355
  const executedRules = new Set;
38201
38356
  for (const plugin of pluginDefs) {
38202
- const r = plugin.rules;
38203
- for (const ruleName in r) {
38357
+ for (const ruleName in plugin.rules) {
38204
38358
  const fullRuleId = `${plugin.name}/${ruleName}`;
38205
38359
  const setting = getRuleSetting(rulesConfig, fullRuleId);
38206
38360
  if (!setting.enabled)
38207
38361
  continue;
38208
- if (executedRules.has(ruleName)) {
38362
+ if (executedRules.has(ruleName))
38209
38363
  continue;
38210
- }
38211
38364
  executedRules.add(ruleName);
38212
- const rule = r[ruleName];
38213
- const overrideSeverity = setting.severity;
38214
- if (!rule || typeof rule.check !== "function") {
38215
- if (overrideSeverity === "error") {
38216
- issues.push({
38217
- filePath,
38218
- line: 1,
38219
- column: 1,
38220
- ruleId: `${fullRuleId}-internal`,
38221
- message: "Rule missing implementation (check function is undefined)",
38222
- severity: "error"
38223
- });
38224
- }
38225
- continue;
38365
+ const rule = plugin.rules[ruleName];
38366
+ const planned = {
38367
+ pluginName: plugin.name,
38368
+ ruleName,
38369
+ fullRuleId,
38370
+ rule,
38371
+ severity: setting.severity,
38372
+ options: setting.options
38373
+ };
38374
+ if (typeof rule?.check === "function")
38375
+ checkRules.push(planned);
38376
+ else if (setting.severity === "error") {
38377
+ checkRules.push(planned);
38378
+ }
38379
+ if (typeof rule?.fix === "function") {
38380
+ fixRules.push(planned);
38381
+ fixableRuleIds.add(fullRuleId);
38382
+ fixableBareRuleNames.add(ruleName);
38383
+ }
38384
+ }
38385
+ }
38386
+ const plan = { checkRules, fixRules, fixableRuleIds, fixableBareRuleNames };
38387
+ pluginPlanCache.set(cfg, plan);
38388
+ return plan;
38389
+ }
38390
+ function isShellPath(filePath, content) {
38391
+ return /\.(?:sh|bash|zsh|ksh|dash)$/.test(filePath) || /^#!\s*(?:\/usr\/bin\/env\s+)?(?:ba|z|k|da)?sh\b/.test(content);
38392
+ }
38393
+ function isLockfilePath(filePath) {
38394
+ return /(?:^|[/\\])(?:bun\.lock|bun\.lockb|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|npm-shrinkwrap\.json)$/.test(filePath);
38395
+ }
38396
+ function shouldRunPlannedRule(rule, filePath, content) {
38397
+ switch (rule.pluginName) {
38398
+ case "markdown":
38399
+ return filePath.endsWith(".md");
38400
+ case "shell":
38401
+ return isShellPath(filePath, content);
38402
+ case "publint":
38403
+ return /(?:^|[/\\])package\.json$/.test(filePath);
38404
+ case "lockfile":
38405
+ return isLockfilePath(filePath);
38406
+ case "node":
38407
+ case "ts":
38408
+ case "general":
38409
+ case "quality":
38410
+ case "eslint":
38411
+ case "regexp":
38412
+ case "unused-imports":
38413
+ case "perfectionist":
38414
+ return /\.(?:ts|js|tsx|jsx|mts|mjs|cts|cjs)$/.test(filePath);
38415
+ default:
38416
+ return true;
38417
+ }
38418
+ }
38419
+ async function applyPlugins(filePath, content, cfg) {
38420
+ const issues = [];
38421
+ const plan = getPluginPlan(cfg);
38422
+ const baseCtx = { filePath, config: cfg };
38423
+ for (const planned of plan.checkRules) {
38424
+ if (!shouldRunPlannedRule(planned, filePath, content))
38425
+ continue;
38426
+ const { fullRuleId, rule, severity: overrideSeverity } = planned;
38427
+ if (!rule || typeof rule.check !== "function") {
38428
+ if (overrideSeverity === "error") {
38429
+ issues.push({
38430
+ filePath,
38431
+ line: 1,
38432
+ column: 1,
38433
+ ruleId: `${fullRuleId}-internal`,
38434
+ message: "Rule missing implementation (check function is undefined)",
38435
+ severity: "error"
38436
+ });
38226
38437
  }
38227
- try {
38228
- trace2("rule:start", fullRuleId);
38229
- const ruleTimeoutMs = ENV.RULE_TIMEOUT_MS;
38230
- const ctx = { ...baseCtx, options: setting.options };
38231
- const out = await withTimeout2(Promise.resolve().then(() => rule.check(content, ctx)), ruleTimeoutMs, `rule:${fullRuleId}`);
38232
- trace2("rule:end", fullRuleId, Array.isArray(out) ? out.length : 0);
38233
- for (const i of out) {
38234
- const issueWithHelp = ensureHelpText(i, fullRuleId);
38235
- if (overrideSeverity)
38236
- issues.push({ ...issueWithHelp, severity: overrideSeverity });
38237
- else
38238
- issues.push(issueWithHelp);
38239
- }
38240
- } catch (e) {
38438
+ continue;
38439
+ }
38440
+ try {
38441
+ trace2("rule:start", fullRuleId);
38442
+ const ruleTimeoutMs = ENV.RULE_TIMEOUT_MS;
38443
+ const ctx = { ...baseCtx, options: planned.options };
38444
+ const started = performance.now();
38445
+ const out = await withTimeout2(Promise.resolve().then(() => rule.check(content, ctx)), ruleTimeoutMs, `rule:${fullRuleId}`);
38446
+ const elapsed = performance.now() - started;
38447
+ if (elapsed > ruleTimeoutMs) {
38241
38448
  issues.push({
38242
38449
  filePath,
38243
38450
  line: 1,
38244
38451
  column: 1,
38245
38452
  ruleId: `${fullRuleId}-internal`,
38246
- message: `Rule threw: ${e?.message || e}`,
38453
+ message: `Rule exceeded timeout budget: ${Math.round(elapsed)}ms > ${ruleTimeoutMs}ms`,
38247
38454
  severity: "error"
38248
38455
  });
38249
38456
  }
38457
+ trace2("rule:end", fullRuleId, Array.isArray(out) ? out.length : 0);
38458
+ for (const i of out) {
38459
+ const issueWithHelp = ensureHelpText(i, fullRuleId);
38460
+ if (overrideSeverity)
38461
+ issues.push({ ...issueWithHelp, severity: overrideSeverity });
38462
+ else
38463
+ issues.push(issueWithHelp);
38464
+ }
38465
+ } catch (e) {
38466
+ issues.push({
38467
+ filePath,
38468
+ line: 1,
38469
+ column: 1,
38470
+ ruleId: `${fullRuleId}-internal`,
38471
+ message: `Rule threw: ${e?.message || e}`,
38472
+ severity: "error"
38473
+ });
38250
38474
  }
38251
38475
  }
38252
38476
  return issues;
38253
38477
  }
38254
38478
  function applyPluginFixes(filePath, content, cfg) {
38255
- const pluginDefs = getAllPlugins();
38256
- if (cfg.plugins && cfg.plugins.length > 0) {
38257
- for (const p of cfg.plugins) {
38258
- if (typeof p === "string")
38259
- continue;
38260
- pluginDefs.push(p);
38261
- }
38262
- }
38263
- const rulesConfig = { ...cfg.pluginRules || {} };
38264
- if (cfg.rules?.noUnusedCapturingGroup)
38265
- rulesConfig["regexp/no-unused-capturing-group"] = cfg.rules.noUnusedCapturingGroup;
38266
- for (const key of Object.keys(cfg.pluginRules || {})) {
38267
- if (!key.includes("/")) {
38268
- for (const p of pluginDefs) {
38269
- if (p.rules && Object.prototype.hasOwnProperty.call(p.rules, key))
38270
- rulesConfig[`${p.name}/${key}`] = cfg.pluginRules[key];
38271
- }
38272
- }
38273
- }
38479
+ const plan = getPluginPlan(cfg);
38274
38480
  const baseCtx = { filePath, config: cfg };
38275
38481
  let out = content;
38276
38482
  let changed = true;
38277
38483
  let passes = 0;
38278
38484
  while (changed && passes++ < MAX_FIXER_PASSES) {
38279
38485
  changed = false;
38280
- for (const plugin of pluginDefs) {
38281
- for (const ruleName in plugin.rules) {
38282
- const fullRuleId = `${plugin.name}/${ruleName}`;
38283
- const setting = getRuleSetting(rulesConfig, fullRuleId);
38284
- if (!setting.enabled)
38285
- continue;
38286
- const rule = plugin.rules[ruleName];
38287
- if (typeof rule.fix !== "function")
38288
- continue;
38289
- const ctx = { ...baseCtx, options: setting.options };
38290
- const next = rule.fix(out, ctx);
38291
- if (next !== out) {
38292
- out = next;
38293
- changed = true;
38294
- }
38486
+ for (const planned of plan.fixRules) {
38487
+ if (!shouldRunPlannedRule(planned, filePath, out))
38488
+ continue;
38489
+ const ctx = { ...baseCtx, options: planned.options };
38490
+ const next = planned.rule.fix(out, ctx);
38491
+ if (next !== out) {
38492
+ out = next;
38493
+ changed = true;
38295
38494
  }
38296
38495
  }
38297
38496
  }
@@ -38460,6 +38659,7 @@ function getCommentLines(content) {
38460
38659
  let state = "code";
38461
38660
  let lineNo = 1;
38462
38661
  let lineHasCode = false;
38662
+ let lineSawComment = false;
38463
38663
  let lineStartedInBlockComment = false;
38464
38664
  for (let i = 0;i < content.length; i++) {
38465
38665
  const ch = content[i];
@@ -38469,11 +38669,14 @@ function getCommentLines(content) {
38469
38669
  `) {
38470
38670
  if (lineStartedInBlockComment && state === "block-comment") {
38471
38671
  commentLines.add(lineNo);
38472
- } else if (!lineHasCode && state !== "block-comment") {} else if (!lineHasCode) {
38672
+ } else if (!lineHasCode && lineSawComment && state !== "block-comment") {
38673
+ commentLines.add(lineNo);
38674
+ } else if (!lineHasCode && state === "block-comment") {
38473
38675
  commentLines.add(lineNo);
38474
38676
  }
38475
38677
  lineNo++;
38476
38678
  lineHasCode = false;
38679
+ lineSawComment = false;
38477
38680
  lineStartedInBlockComment = state === "block-comment";
38478
38681
  if (state === "line-comment") {
38479
38682
  state = "code";
@@ -38484,6 +38687,7 @@ function getCommentLines(content) {
38484
38687
  case "code":
38485
38688
  if (ch === "/" && next === "/") {
38486
38689
  state = "line-comment";
38690
+ lineSawComment = true;
38487
38691
  i++;
38488
38692
  } else if (ch === "/" && next === "*") {
38489
38693
  let isRegex = false;
@@ -38525,6 +38729,7 @@ function getCommentLines(content) {
38525
38729
  }
38526
38730
  i--;
38527
38731
  } else {
38732
+ lineSawComment = true;
38528
38733
  state = "block-comment";
38529
38734
  i++;
38530
38735
  }
@@ -38619,6 +38824,8 @@ function getCommentLines(content) {
38619
38824
  }
38620
38825
  if (lineStartedInBlockComment && state === "block-comment") {
38621
38826
  commentLines.add(lineNo);
38827
+ } else if (!lineHasCode && lineSawComment && state !== "block-comment") {
38828
+ commentLines.add(lineNo);
38622
38829
  } else if (!lineHasCode && state === "block-comment") {
38623
38830
  commentLines.add(lineNo);
38624
38831
  }
@@ -38635,6 +38842,10 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38635
38842
  const quotesDisabled = quotesRuleSetting === "off";
38636
38843
  const skipQuotesCheck = quotesDisabled || fileExt === "json" || fileExt === "jsonc" || fileExt === "lock" || isMd || fileExt === "yaml" || fileExt === "yml" || fileExt === "stx" || fileExt === "html" || fileExt === "htm" || fileExt === "vue" || isShell || filePath.endsWith("bun.lock");
38637
38844
  const skipCodeRules = isMd || fileExt === "yaml" || fileExt === "yml" || fileExt === "json" || fileExt === "jsonc" || isShell;
38845
+ const indentRuleSetting = cfg.rules?.indent ?? cfg.pluginRules?.indent ?? cfg.pluginRules?.["style/indent"];
38846
+ const indentDisabled = indentRuleSetting === "off";
38847
+ const isTemplate = fileExt === "stx" || fileExt === "html" || fileExt === "htm" || fileExt === "vue";
38848
+ const shouldCheckIndent = !indentDisabled && !isMd && !isTemplate;
38638
38849
  let quotesReported = false;
38639
38850
  const sevMap = (s) => s === "warn" ? "warning" : s === "error" ? "error" : undefined;
38640
38851
  const wantDebugger = sevMap(cfg.rules.noDebugger);
@@ -38656,33 +38867,34 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38656
38867
  }
38657
38868
  }
38658
38869
  const linesInTemplate = new Set;
38659
- let inTemplate = false;
38660
- let escaped = false;
38661
- let currentLine = 1;
38662
- for (let i = 0;i < content.length; i++) {
38663
- const ch = content[i];
38664
- if (escaped) {
38665
- escaped = false;
38666
- if (ch === `
38870
+ if (content.includes("`")) {
38871
+ let inTemplate = false;
38872
+ let escaped = false;
38873
+ let currentLine = 1;
38874
+ for (let i = 0;i < content.length; i++) {
38875
+ const ch = content[i];
38876
+ if (escaped) {
38877
+ escaped = false;
38878
+ if (ch === `
38667
38879
  `)
38668
- currentLine++;
38669
- continue;
38670
- }
38671
- if (ch === "\\") {
38672
- escaped = true;
38673
- continue;
38674
- }
38675
- if (ch === `
38880
+ currentLine++;
38881
+ continue;
38882
+ }
38883
+ if (ch === "\\") {
38884
+ escaped = true;
38885
+ continue;
38886
+ }
38887
+ if (ch === `
38676
38888
  `) {
38677
- currentLine++;
38678
- continue;
38679
- }
38680
- if (ch === "`") {
38681
- inTemplate = !inTemplate;
38682
- continue;
38683
- }
38684
- if (inTemplate) {
38685
- linesInTemplate.add(currentLine);
38889
+ currentLine++;
38890
+ continue;
38891
+ }
38892
+ if (ch === "`") {
38893
+ inTemplate = !inTemplate;
38894
+ continue;
38895
+ }
38896
+ if (inTemplate)
38897
+ linesInTemplate.add(currentLine);
38686
38898
  }
38687
38899
  }
38688
38900
  for (let i = 0;i < lines.length; i++) {
@@ -38701,12 +38913,11 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38701
38913
  quotesReported = true;
38702
38914
  }
38703
38915
  }
38704
- const indentRuleSetting = cfg.rules?.indent ?? cfg.pluginRules?.indent ?? cfg.pluginRules?.["style/indent"];
38705
- const indentDisabled = indentRuleSetting === "off";
38706
- const isTemplate = fileExt === "stx" || fileExt === "html" || fileExt === "htm" || fileExt === "vue";
38707
- const leadingMatch = line.match(/^[ \t]*/);
38708
- const leading = leadingMatch ? leadingMatch[0] : "";
38709
- if (!indentDisabled && !isMd && !isTemplate && leading.length > 0 && !linesInFencedCodeBlock.has(lineNo) && hasIndentIssue(leading, cfg.format.indent, cfg.format.indentStyle, line)) {
38916
+ let wsEnd = 0;
38917
+ while (wsEnd < line.length && (line.charCodeAt(wsEnd) === 32 || line.charCodeAt(wsEnd) === 9))
38918
+ wsEnd++;
38919
+ const leading = wsEnd > 0 ? line.slice(0, wsEnd) : "";
38920
+ if (shouldCheckIndent && leading.length > 0 && !linesInFencedCodeBlock.has(lineNo) && hasIndentIssue(leading, cfg.format.indent, cfg.format.indentStyle, line)) {
38710
38921
  if (!isSuppressed("indent", lineNo, suppress))
38711
38922
  issues.push({ filePath, line: lineNo, column: 1, ruleId: "indent", message: "Incorrect indentation detected", severity: "warning", help: `Use ${cfg.format.indentStyle === "spaces" ? `${cfg.format.indent} spaces` : "tabs"} for indentation. Configure with format.indent and format.indentStyle in your config` });
38712
38923
  }
@@ -38811,24 +39022,43 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38811
39022
  }
38812
39023
  if (!skipCodeRules && wantNoCondAssign && !linesInTemplate.has(lineNo)) {
38813
39024
  const strippedLine = stripComments2(stripRegexLiterals(line));
38814
- const checkCond = (cond) => /[^=!<>]=(?![=>])/.test(cond.replace(/'[^']*'|"[^"]*"/g, '""'));
38815
- const m1 = strippedLine.match(/\b(?:if|while)\s*\(([^)]*)\)/);
39025
+ const conditionLine = strippedLine.replace(/'[^']*'|"[^"]*"/g, '""');
39026
+ const checkCond = (cond) => /[^=!<>]=(?![=>])/.test(cond);
39027
+ const m1 = conditionLine.match(/\b(?:if|while)\s*\(([^)]*)\)/);
38816
39028
  if (m1) {
38817
39029
  const cond = m1[1];
38818
39030
  if (checkCond(cond)) {
38819
- if (!isSuppressed("no-cond-assign", lineNo, suppress))
38820
- issues.push({ filePath, line: lineNo, column: Math.max(1, line.indexOf("(") + 1), ruleId: "no-cond-assign", message: "Unexpected assignment within a conditional expression", severity: wantNoCondAssign, help: "Use === or == for comparison instead of = (assignment). If assignment was intentional, wrap it in parentheses: if ((x = value))" });
39031
+ if (!isSuppressed("no-cond-assign", lineNo, suppress)) {
39032
+ issues.push({
39033
+ filePath,
39034
+ line: lineNo,
39035
+ column: Math.max(1, line.indexOf("(") + 1),
39036
+ ruleId: "no-cond-assign",
39037
+ message: "Unexpected assignment within a conditional expression",
39038
+ severity: wantNoCondAssign,
39039
+ help: "Use === or == for comparison instead of = (assignment). Wrap intentional assignments in extra parentheses."
39040
+ });
39041
+ }
38821
39042
  }
38822
39043
  }
38823
- const mFor = strippedLine.match(/\bfor\s*\(([^)]*)\)/);
39044
+ const mFor = conditionLine.match(/\bfor\s*\(([^)]*)\)/);
38824
39045
  if (mFor) {
38825
39046
  const inside = mFor[1];
38826
39047
  const parts = inside.split(";");
38827
39048
  if (parts.length >= 2) {
38828
39049
  const cond = parts[1];
38829
39050
  if (checkCond(cond)) {
38830
- if (!isSuppressed("no-cond-assign", lineNo, suppress))
38831
- issues.push({ filePath, line: lineNo, column: Math.max(1, line.indexOf("(") + 1), ruleId: "no-cond-assign", message: "Unexpected assignment within a conditional expression", severity: wantNoCondAssign, help: "Use === or == for comparison instead of = (assignment). If assignment was intentional, wrap it in parentheses: for (let i = 0; (x = arr[i]); i++)" });
39051
+ if (!isSuppressed("no-cond-assign", lineNo, suppress)) {
39052
+ issues.push({
39053
+ filePath,
39054
+ line: lineNo,
39055
+ column: Math.max(1, line.indexOf("(") + 1),
39056
+ ruleId: "no-cond-assign",
39057
+ message: "Unexpected assignment within a conditional expression",
39058
+ severity: wantNoCondAssign,
39059
+ help: "Use === or == for comparison instead of = (assignment). Wrap intentional assignments in extra parentheses."
39060
+ });
39061
+ }
38832
39062
  }
38833
39063
  }
38834
39064
  }
@@ -38840,67 +39070,25 @@ function scanContent(filePath, content, cfg) {
38840
39070
  const suppress = parseDisableDirectives(content);
38841
39071
  const commentLines = getCommentLines(content);
38842
39072
  const issues = scanContentOptimized(filePath, content, cfg, suppress, commentLines);
38843
- if (!cfg._internalSkipPluginRulesInScan) {
38844
- try {
38845
- let pluginDefs = getAllPlugins();
38846
- if (cfg.plugins && cfg.plugins.length > 0) {
38847
- const coreNames = new Set(["pickier", "style", "regexp", "ts"]);
38848
- const userPlugins = cfg.plugins.filter((p) => typeof p !== "string");
38849
- const hasCoreMatch = userPlugins.some((p) => coreNames.has(p.name));
38850
- pluginDefs = hasCoreMatch ? pluginDefs : [];
38851
- for (const p of userPlugins)
38852
- pluginDefs.push(p);
38853
- }
38854
- const rulesConfig = { ...cfg.pluginRules || {} };
38855
- if (cfg.rules?.noUnusedCapturingGroup)
38856
- rulesConfig["regexp/no-unused-capturing-group"] = cfg.rules.noUnusedCapturingGroup;
38857
- for (const key of Object.keys(cfg.pluginRules || {})) {
38858
- if (!key.includes("/")) {
38859
- for (const p of pluginDefs) {
38860
- if (p.rules && Object.prototype.hasOwnProperty.call(p.rules, key))
38861
- rulesConfig[`${p.name}/${key}`] = cfg.pluginRules[key];
38862
- }
38863
- }
38864
- }
38865
- const isRuleEnabled = (ruleId) => {
38866
- const raw = rulesConfig[ruleId];
38867
- const setting = typeof raw === "string" ? raw : undefined;
38868
- return setting === "error" || setting === "warn" || setting === "warning";
38869
- };
38870
- const getRuleSeverity = (ruleId) => {
38871
- const raw = rulesConfig[ruleId];
38872
- const setting = typeof raw === "string" ? raw : undefined;
38873
- if (setting === "error")
38874
- return "error";
38875
- if (setting === "warn" || setting === "warning")
38876
- return "warning";
38877
- return;
38878
- };
38879
- const ctx = { filePath, config: cfg };
38880
- const executedRulesInScan = new Set;
38881
- for (const plugin of pluginDefs) {
38882
- const r = plugin.rules;
38883
- for (const ruleName in r) {
38884
- const fullRuleId = `${plugin.name}/${ruleName}`;
38885
- if (!isRuleEnabled(fullRuleId))
38886
- continue;
38887
- if (executedRulesInScan.has(ruleName))
38888
- continue;
38889
- executedRulesInScan.add(ruleName);
38890
- const rule = r[ruleName];
38891
- if (!rule || typeof rule.check !== "function")
38892
- continue;
38893
- const out = rule.check(content, ctx);
38894
- for (const i of out) {
38895
- if (!isSuppressed(i.ruleId, i.line, suppress)) {
38896
- const sev = getRuleSeverity(fullRuleId);
38897
- issues.push(sev ? { ...i, severity: sev } : i);
38898
- }
38899
- }
38900
- }
39073
+ try {
39074
+ const plan = getPluginPlan(cfg);
39075
+ const ctx = { filePath, config: cfg };
39076
+ for (const planned of plan.checkRules) {
39077
+ if (!shouldRunPlannedRule(planned, filePath, content))
39078
+ continue;
39079
+ if (!planned.rule || typeof planned.rule.check !== "function")
39080
+ continue;
39081
+ const out = planned.rule.check(content, { ...ctx, options: planned.options });
39082
+ for (const i of out) {
39083
+ if (isSuppressed(i.ruleId, i.line, suppress))
39084
+ continue;
39085
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
39086
+ continue;
39087
+ const issueWithHelp = ensureHelpText(i, planned.fullRuleId);
39088
+ issues.push(planned.severity ? { ...issueWithHelp, severity: planned.severity } : issueWithHelp);
38901
39089
  }
38902
- } catch {}
38903
- }
39090
+ }
39091
+ } catch {}
38904
39092
  return issues;
38905
39093
  }
38906
39094
  async function runLint(globs, options) {
@@ -38934,6 +39122,7 @@ async function runLint(globs, options) {
38934
39122
  return !absBase.startsWith(process25.cwd());
38935
39123
  });
38936
39124
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
39125
+ const ignoreMatcher = createIgnoreMatcher(globIgnores);
38937
39126
  if (enableDiagnostics) {
38938
39127
  getLogger2().info(`[pickier:diagnostics] Globbing outside project: ${isGlobbingOutsideProject}, ignore patterns: ${globIgnores.length}`);
38939
39128
  if (isGlobbingOutsideProject)
@@ -38970,7 +39159,7 @@ async function runLint(globs, options) {
38970
39159
  for (const it of items) {
38971
39160
  const full = join11(dir, it);
38972
39161
  const st = statSync6(full);
38973
- if (shouldIgnorePath(full, globIgnores))
39162
+ if (ignoreMatcher(full))
38974
39163
  continue;
38975
39164
  if (st.isDirectory())
38976
39165
  stack.push(full);
@@ -39032,7 +39221,7 @@ async function runLint(globs, options) {
39032
39221
  cntNodeModules++;
39033
39222
  continue;
39034
39223
  }
39035
- if (shouldIgnorePath(f, globIgnores)) {
39224
+ if (ignoreMatcher(f)) {
39036
39225
  cntIgnored++;
39037
39226
  continue;
39038
39227
  }
@@ -39063,7 +39252,6 @@ async function runLint(globs, options) {
39063
39252
  }
39064
39253
  }
39065
39254
  const concurrency = ENV.CONCURRENCY;
39066
- const limit = createLimiter(concurrency);
39067
39255
  if (enableDiagnostics)
39068
39256
  getLogger2().info(`[pickier:diagnostics] Starting to process ${files.length} files with concurrency ${concurrency}...`);
39069
39257
  let processedCount = 0;
@@ -39077,23 +39265,33 @@ async function runLint(globs, options) {
39077
39265
  const src = readFileSync10(file, "utf8");
39078
39266
  if (formatOnly) {
39079
39267
  const fixed = formatCode(src, cfg, file);
39080
- if (fixed !== src && !options.dryRun) {
39081
- writeFileSync11(file, fixed, "utf8");
39268
+ if (fixed !== src) {
39269
+ if (!options.dryRun) {
39270
+ writeFileSync11(file, fixed, "utf8");
39271
+ } else {
39272
+ return [{
39273
+ filePath: file,
39274
+ line: 1,
39275
+ column: 1,
39276
+ ruleId: "format",
39277
+ message: "File is not formatted",
39278
+ severity: "error",
39279
+ help: "Run pickier format with --write to apply formatting."
39280
+ }];
39281
+ }
39082
39282
  }
39083
39283
  return [];
39084
39284
  }
39085
39285
  const suppress = parseDisableDirectives(src);
39086
39286
  const isCodeFileForComments = /\.(?:ts|js|tsx|jsx|mts|mjs|cts|cjs)$/.test(file);
39087
39287
  const commentLines = isCodeFileForComments ? getCommentLines(src) : new Set;
39088
- const cfgAny = cfg;
39089
- cfgAny._internalSkipPluginRulesInScan = true;
39090
39288
  let issues = scanContentOptimized(file, src, cfg, suppress, commentLines);
39091
39289
  try {
39092
39290
  const pluginIssues = await applyPlugins(file, src, cfg);
39093
39291
  for (const i of pluginIssues) {
39094
39292
  if (isSuppressed(i.ruleId, i.line, suppress))
39095
39293
  continue;
39096
- if (commentLines.has(i.line))
39294
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
39097
39295
  continue;
39098
39296
  issues.push({
39099
39297
  filePath: i.filePath,
@@ -39152,7 +39350,7 @@ async function runLint(globs, options) {
39152
39350
  trace2("scan done", relative7(process25.cwd(), file), issues.length);
39153
39351
  return issues;
39154
39352
  };
39155
- const issueArrays = await Promise.all(files.map((file) => limit(() => processFile(file))));
39353
+ const issueArrays = await processWithConcurrency(files, concurrency, processFile);
39156
39354
  const allIssues = issueArrays.flat();
39157
39355
  if (enableDiagnostics)
39158
39356
  getLogger2().info(`[pickier:diagnostics] Processing complete! Found ${allIssues.length} issues total`);
@@ -39177,22 +39375,12 @@ async function runLint(globs, options) {
39177
39375
  const problemsText = total === 1 ? "problem" : "problems";
39178
39376
  const errorsText = errors === 1 ? "error" : "errors";
39179
39377
  const warningsText = warnings === 1 ? "warning" : "warnings";
39180
- const pluginDefs = getAllPlugins();
39181
- const fixableRuleIds = new Set;
39182
- fixableRuleIds.add("no-debugger");
39183
- for (const plugin of pluginDefs) {
39184
- for (const ruleName in plugin.rules) {
39185
- const rule = plugin.rules[ruleName];
39186
- if (rule && typeof rule.fix === "function") {
39187
- fixableRuleIds.add(`${plugin.name}/${ruleName}`);
39188
- }
39189
- }
39190
- }
39378
+ const pluginPlan = getPluginPlan(cfg);
39191
39379
  let fixableErrors = 0;
39192
39380
  let fixableWarnings = 0;
39193
39381
  for (const issue of allIssues) {
39194
39382
  const ruleId = issue.ruleId;
39195
- const isFixable = fixableRuleIds.has(ruleId) || Array.from(fixableRuleIds).some((id) => id.endsWith(`/${ruleId}`));
39383
+ const isFixable = pluginPlan.fixableRuleIds.has(ruleId) || pluginPlan.fixableBareRuleNames.has(ruleId);
39196
39384
  if (isFixable) {
39197
39385
  if (issue.severity === "error")
39198
39386
  fixableErrors++;
@@ -39233,13 +39421,14 @@ async function runLint(globs, options) {
39233
39421
  return 1;
39234
39422
  }
39235
39423
  }
39236
- var _logger2 = null;
39424
+ var _logger2 = null, pluginPlanCache;
39237
39425
  var init_linter = __esm(() => {
39238
39426
  init_src();
39239
39427
  init_format();
39240
39428
  init_formatter();
39241
39429
  init_plugins();
39242
39430
  init_utils3();
39431
+ pluginPlanCache = new WeakMap;
39243
39432
  });
39244
39433
 
39245
39434
  // src/run.ts
@@ -39261,6 +39450,8 @@ async function runUnified(globs, options) {
39261
39450
  const cfg = await loadConfigFromPath(options.config);
39262
39451
  const src = readFileSync11(filePath, "utf8");
39263
39452
  const fmt = formatCode(src, cfg, filePath);
39453
+ if (options.check && fmt !== src)
39454
+ return 1;
39264
39455
  if (options.write && fmt !== src) {
39265
39456
  writeFileSync12(filePath, fmt, "utf8");
39266
39457
  }
@@ -39327,6 +39518,7 @@ export {
39327
39518
  detectQuoteIssues,
39328
39519
  defaultConfig4 as defaultConfig,
39329
39520
  createLimiter,
39521
+ createIgnoreMatcher,
39330
39522
  config5 as config,
39331
39523
  colors,
39332
39524
  colorize,