pickier 0.1.28 → 0.1.30

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 +554 -436
  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 +527 -423
  262. package/dist/utils.d.ts +12 -3
  263. package/package.json +3 -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;
@@ -20885,6 +20886,50 @@ var init_no_unused_vars = __esm(() => {
20885
20886
  }
20886
20887
  return null;
20887
20888
  };
20889
+ const collectArrowExpressionBody = (startLine, arrowCol) => {
20890
+ const state = {
20891
+ parenDepth: 0,
20892
+ braceDepth: 0,
20893
+ bracketDepth: 0,
20894
+ inTemplate: false
20895
+ };
20896
+ const updateState = (text2) => {
20897
+ for (let k = 0;k < text2.length; k++) {
20898
+ const ch = text2[k];
20899
+ if (ch === "`")
20900
+ state.inTemplate = !state.inTemplate;
20901
+ else if (ch === "(")
20902
+ state.parenDepth++;
20903
+ else if (ch === ")")
20904
+ state.parenDepth--;
20905
+ else if (ch === "{")
20906
+ state.braceDepth++;
20907
+ else if (ch === "}")
20908
+ state.braceDepth--;
20909
+ else if (ch === "[")
20910
+ state.bracketDepth++;
20911
+ else if (ch === "]")
20912
+ state.bracketDepth--;
20913
+ }
20914
+ };
20915
+ const isOpen = () => state.parenDepth > 0 || state.braceDepth > 0 || state.bracketDepth > 0 || state.inTemplate;
20916
+ const endsWithContinuation = (text2) => /(?:\?|:|\.|,|&&|\|\||\?\?|\+|-|\*|\/|%|\*\*)$/.test(text2.trimEnd());
20917
+ const startsWithContinuation = (text2) => /^(?:\?|:|\.|,|&&|\|\||\?\?|\+|-|\*|\/|%|\*\*)/.test(text2.trimStart());
20918
+ let bodyText = lines[startLine].slice(arrowCol + 2);
20919
+ updateState(bodyText);
20920
+ let nextLine = startLine + 1;
20921
+ while (nextLine < lines.length) {
20922
+ const previousLine = nextLine === startLine + 1 ? bodyText : lines[nextLine - 1];
20923
+ const shouldContinue = !bodyText.trim() || isOpen() || endsWithContinuation(previousLine) || startsWithContinuation(lines[nextLine]);
20924
+ if (!shouldContinue)
20925
+ break;
20926
+ bodyText += `
20927
+ ${lines[nextLine]}`;
20928
+ updateState(lines[nextLine]);
20929
+ nextLine++;
20930
+ }
20931
+ return bodyText;
20932
+ };
20888
20933
  const mainTmplStack = [];
20889
20934
  let mainInSingle = false;
20890
20935
  let mainInDouble = false;
@@ -21248,73 +21293,7 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
21248
21293
  }
21249
21294
  }
21250
21295
  } else {
21251
- bodyText = line.slice(arrowIdx + 2);
21252
- let parenDepth = 0;
21253
- let braceDepth = 0;
21254
- let bracketDepth = 0;
21255
- let inTemplate = false;
21256
- for (let k = arrowIdx + 2;k < line.length; k++) {
21257
- const ch = line[k];
21258
- if (ch === "`")
21259
- inTemplate = !inTemplate;
21260
- else if (ch === "(")
21261
- parenDepth++;
21262
- else if (ch === ")")
21263
- parenDepth--;
21264
- else if (ch === "{")
21265
- braceDepth++;
21266
- else if (ch === "}")
21267
- braceDepth--;
21268
- else if (ch === "[")
21269
- bracketDepth++;
21270
- else if (ch === "]")
21271
- bracketDepth--;
21272
- }
21273
- let nextLine = i + 1;
21274
- if ((!bodyText.trim() || inTemplate) && nextLine < lines.length) {
21275
- bodyText += `
21276
- ${lines[nextLine]}`;
21277
- for (let k = 0;k < lines[nextLine].length; k++) {
21278
- const ch = lines[nextLine][k];
21279
- if (ch === "`")
21280
- inTemplate = !inTemplate;
21281
- else if (ch === "(")
21282
- parenDepth++;
21283
- else if (ch === ")")
21284
- parenDepth--;
21285
- else if (ch === "{")
21286
- braceDepth++;
21287
- else if (ch === "}")
21288
- braceDepth--;
21289
- else if (ch === "[")
21290
- bracketDepth++;
21291
- else if (ch === "]")
21292
- bracketDepth--;
21293
- }
21294
- nextLine++;
21295
- }
21296
- while (nextLine < lines.length && (parenDepth > 0 || braceDepth > 0 || bracketDepth > 0 || inTemplate)) {
21297
- bodyText += `
21298
- ${lines[nextLine]}`;
21299
- for (let k = 0;k < lines[nextLine].length; k++) {
21300
- const ch = lines[nextLine][k];
21301
- if (ch === "`")
21302
- inTemplate = !inTemplate;
21303
- else if (ch === "(")
21304
- parenDepth++;
21305
- else if (ch === ")")
21306
- parenDepth--;
21307
- else if (ch === "{")
21308
- braceDepth++;
21309
- else if (ch === "}")
21310
- braceDepth--;
21311
- else if (ch === "[")
21312
- bracketDepth++;
21313
- else if (ch === "]")
21314
- bracketDepth--;
21315
- }
21316
- nextLine++;
21317
- }
21296
+ bodyText = collectArrowExpressionBody(i, arrowIdx);
21318
21297
  }
21319
21298
  for (const name of params) {
21320
21299
  if (!name || argIgnoreRe.test(name) || name === "undefined")
@@ -21371,73 +21350,7 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
21371
21350
  }
21372
21351
  }
21373
21352
  } else {
21374
- bodyText = line.slice(arrowIdx2 + 2);
21375
- let parenDepth = 0;
21376
- let braceDepth = 0;
21377
- let bracketDepth = 0;
21378
- let inTemplate = false;
21379
- for (let k = arrowIdx2 + 2;k < line.length; k++) {
21380
- const ch = line[k];
21381
- if (ch === "`")
21382
- inTemplate = !inTemplate;
21383
- else if (ch === "(")
21384
- parenDepth++;
21385
- else if (ch === ")")
21386
- parenDepth--;
21387
- else if (ch === "{")
21388
- braceDepth++;
21389
- else if (ch === "}")
21390
- braceDepth--;
21391
- else if (ch === "[")
21392
- bracketDepth++;
21393
- else if (ch === "]")
21394
- bracketDepth--;
21395
- }
21396
- let nextLine = i + 1;
21397
- if ((!bodyText.trim() || inTemplate) && nextLine < lines.length) {
21398
- bodyText += `
21399
- ${lines[nextLine]}`;
21400
- for (let k = 0;k < lines[nextLine].length; k++) {
21401
- const ch = lines[nextLine][k];
21402
- if (ch === "`")
21403
- inTemplate = !inTemplate;
21404
- else if (ch === "(")
21405
- parenDepth++;
21406
- else if (ch === ")")
21407
- parenDepth--;
21408
- else if (ch === "{")
21409
- braceDepth++;
21410
- else if (ch === "}")
21411
- braceDepth--;
21412
- else if (ch === "[")
21413
- bracketDepth++;
21414
- else if (ch === "]")
21415
- bracketDepth--;
21416
- }
21417
- nextLine++;
21418
- }
21419
- while (nextLine < lines.length && (parenDepth > 0 || braceDepth > 0 || bracketDepth > 0 || inTemplate)) {
21420
- bodyText += `
21421
- ${lines[nextLine]}`;
21422
- for (let k = 0;k < lines[nextLine].length; k++) {
21423
- const ch = lines[nextLine][k];
21424
- if (ch === "`")
21425
- inTemplate = !inTemplate;
21426
- else if (ch === "(")
21427
- parenDepth++;
21428
- else if (ch === ")")
21429
- parenDepth--;
21430
- else if (ch === "{")
21431
- braceDepth++;
21432
- else if (ch === "}")
21433
- braceDepth--;
21434
- else if (ch === "[")
21435
- bracketDepth++;
21436
- else if (ch === "]")
21437
- bracketDepth--;
21438
- }
21439
- nextLine++;
21440
- }
21353
+ bodyText = collectArrowExpressionBody(i, arrowIdx2);
21441
21354
  }
21442
21355
  const useRe = new RegExp(`\\b${name}\\b`, "g");
21443
21356
  if (!useRe.test(bodyText)) {
@@ -21756,6 +21669,90 @@ function findTopLevelEquals(s) {
21756
21669
  }
21757
21670
  return -1;
21758
21671
  }
21672
+ function destructuringReassignsName(text, name) {
21673
+ const re = new RegExp(`\\b${name}\\b`);
21674
+ let i = 0;
21675
+ let inStr = null;
21676
+ let escaped = false;
21677
+ while (i < text.length) {
21678
+ const c = text[i];
21679
+ if (escaped) {
21680
+ escaped = false;
21681
+ i++;
21682
+ continue;
21683
+ }
21684
+ if (c === "\\" && inStr) {
21685
+ escaped = true;
21686
+ i++;
21687
+ continue;
21688
+ }
21689
+ if (inStr) {
21690
+ if (inStr === "single" && c === "'" || inStr === "double" && c === '"' || inStr === "template" && c === "`")
21691
+ inStr = null;
21692
+ i++;
21693
+ continue;
21694
+ }
21695
+ if (c === "'") {
21696
+ inStr = "single";
21697
+ i++;
21698
+ continue;
21699
+ }
21700
+ if (c === '"') {
21701
+ inStr = "double";
21702
+ i++;
21703
+ continue;
21704
+ }
21705
+ if (c === "`") {
21706
+ inStr = "template";
21707
+ i++;
21708
+ continue;
21709
+ }
21710
+ if (c === "[" || c === "{") {
21711
+ const open = c;
21712
+ const close = c === "[" ? "]" : "}";
21713
+ let depth = 1;
21714
+ let j = i + 1;
21715
+ while (j < text.length && depth > 0) {
21716
+ const cj = text[j];
21717
+ if (cj === "\\") {
21718
+ j += 2;
21719
+ continue;
21720
+ }
21721
+ if (cj === open)
21722
+ depth++;
21723
+ else if (cj === close)
21724
+ depth--;
21725
+ if (depth === 0)
21726
+ break;
21727
+ j++;
21728
+ }
21729
+ if (depth === 0 && j < text.length) {
21730
+ let k = j + 1;
21731
+ while (k < text.length && (text[k] === " " || text[k] === "\t" || text[k] === "\r" || text[k] === `
21732
+ `))
21733
+ k++;
21734
+ if (text[k] === "=" && text[k + 1] !== "=" && text[k + 1] !== ">") {
21735
+ const inside = text.slice(i + 1, j);
21736
+ if (re.test(inside)) {
21737
+ const keyOnly = new RegExp(`\\b${name}\\b\\s*:`);
21738
+ const valueAfterColon = new RegExp(`:\\s*\\b${name}\\b`);
21739
+ if (open === "{") {
21740
+ const isKeyOnly = keyOnly.test(inside) && !valueAfterColon.test(inside) && !new RegExp(`(?:^|[\\s,{])\\s*${name}\\s*(?:,|\\s*=|\\s*})`).test(inside);
21741
+ if (!isKeyOnly)
21742
+ return true;
21743
+ } else {
21744
+ return true;
21745
+ }
21746
+ }
21747
+ }
21748
+ }
21749
+ i = j + 1;
21750
+ continue;
21751
+ }
21752
+ i++;
21753
+ }
21754
+ return false;
21755
+ }
21759
21756
  function analyzeLetDecl(line, text) {
21760
21757
  const declRe = new RegExp("^\\s*(?:let|var)\\s+(.+?)" + ";" + "?\\s*$");
21761
21758
  const decl = line.match(declRe);
@@ -21793,7 +21790,8 @@ function analyzeLetDecl(line, text) {
21793
21790
  const assignPattern = `\\b${name}\\s*(?:${assignOps.map((op) => op.replace(/[|\\^$*+?.(){}[\]]/g, (r) => `\\${r}`)).join("|")})`;
21794
21791
  const directAssign = new RegExp(assignPattern).test(rest);
21795
21792
  const incDecChanged = new RegExp(`(?:^|[^$w])(?:\\+\\+|--)\\s*${name}\\b|\\b${name}\\s*(?:\\+\\+|--)`).test(rest);
21796
- result.push({ name, fixable: !directAssign && !incDecChanged });
21793
+ const destructReassigned = destructuringReassignsName(rest, name);
21794
+ result.push({ name, fixable: !directAssign && !incDecChanged && !destructReassigned });
21797
21795
  }
21798
21796
  return result;
21799
21797
  }
@@ -21822,8 +21820,20 @@ var init_prefer_const = __esm(() => {
21822
21820
  },
21823
21821
  fix: (text) => {
21824
21822
  const lines = text.split(/\r?\n/);
21823
+ const disabledLines = new Set;
21824
+ const disableNextRe = /(?:eslint|pickier)-disable-next-line\b([^*\n]*)/;
21825
+ for (let i = 0;i < lines.length; i++) {
21826
+ const m = lines[i].match(disableNextRe);
21827
+ if (!m)
21828
+ continue;
21829
+ const ruleList = m[1].trim();
21830
+ if (ruleList === "" || /\bprefer-const\b/.test(ruleList))
21831
+ disabledLines.add(i + 2);
21832
+ }
21825
21833
  let changed = false;
21826
21834
  for (let i = 0;i < lines.length; i++) {
21835
+ if (disabledLines.has(i + 1))
21836
+ continue;
21827
21837
  const line = lines[i];
21828
21838
  if (!/^\s*let\b/.test(line))
21829
21839
  continue;
@@ -28473,14 +28483,27 @@ function getVariantPriority(cls) {
28473
28483
  }
28474
28484
  return priority;
28475
28485
  }
28486
+ function getClassSortKey(cls) {
28487
+ const cached = sortKeyCache.get(cls);
28488
+ if (cached)
28489
+ return cached;
28490
+ const key = {
28491
+ group: getGroupIndex(cls),
28492
+ variant: getVariantPriority(cls)
28493
+ };
28494
+ sortKeyCache.set(cls, key);
28495
+ return key;
28496
+ }
28476
28497
  function sortClasses(classes) {
28477
28498
  return [...classes].sort((a, b) => {
28478
- const ga = getGroupIndex(a);
28479
- const gb = getGroupIndex(b);
28499
+ const aKey = getClassSortKey(a);
28500
+ const bKey = getClassSortKey(b);
28501
+ const ga = aKey.group;
28502
+ const gb = bKey.group;
28480
28503
  if (ga !== gb)
28481
28504
  return ga - gb;
28482
- const va = getVariantPriority(a);
28483
- const vb = getVariantPriority(b);
28505
+ const va = aKey.variant;
28506
+ const vb = bKey.variant;
28484
28507
  if (va !== vb)
28485
28508
  return va - vb;
28486
28509
  return a.localeCompare(b);
@@ -28499,6 +28522,8 @@ function looksLikeJsExpression(value) {
28499
28522
  }
28500
28523
  function extractClassValues(content) {
28501
28524
  const matches = [];
28525
+ if (!content.includes("class") && !content.includes("clsx") && !content.includes("cn(") && !content.includes("tw(") && !content.includes("cva(") && !content.includes("tv("))
28526
+ return matches;
28502
28527
  for (const re of [ATTR_RE, ATTR_TMPL_RE, UTIL_FN_RE]) {
28503
28528
  re.lastIndex = 0;
28504
28529
  let m;
@@ -28545,7 +28570,7 @@ function isSorted(classes) {
28545
28570
  const sorted = sortClasses(classes);
28546
28571
  return classes.every((c, i) => c === sorted[i]);
28547
28572
  }
28548
- var GROUP_ORDER, VARIANT_RE, ATTR_RE, ATTR_TMPL_RE, UTIL_FN_RE, sortTailwindClassesRule;
28573
+ var GROUP_ORDER, VARIANT_RE, sortKeyCache, ATTR_RE, ATTR_TMPL_RE, UTIL_FN_RE, sortTailwindClassesRule;
28549
28574
  var init_tailwind_classes = __esm(() => {
28550
28575
  GROUP_ORDER = [
28551
28576
  [/^(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 +28594,7 @@ var init_tailwind_classes = __esm(() => {
28569
28594
  [/^(sr-only|not-sr-only)$/, 15]
28570
28595
  ];
28571
28596
  VARIANT_RE = /^([a-z0-9][-a-z0-9]{0,50}:)+(?!\[)/;
28597
+ sortKeyCache = new Map;
28572
28598
  ATTR_RE = /\b(?:class|className|:class)\s*=\s*(?:"([^"]*?)"|'([^']*?)')/g;
28573
28599
  ATTR_TMPL_RE = /\b(?:class|className|:class)\s*=\s*\{`([^`]*?)`\}/g;
28574
28600
  UTIL_FN_RE = /\b(?:clsx|cn|tw|cva|tv)\s*\(\s*(?:"([^"]*?)"|'([^']*?)')/g;
@@ -37167,15 +37193,7 @@ function globToRegex(pattern) {
37167
37193
  }
37168
37194
  return new RegExp(`^${src}$`);
37169
37195
  }
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) {
37196
+ function* walkDirWithMatcher(dir, ignoreMatcher, dot) {
37179
37197
  let entries;
37180
37198
  try {
37181
37199
  entries = readdirSync8(dir);
@@ -37186,8 +37204,7 @@ function* walkDir(dir, ignore, dot, cwd) {
37186
37204
  if (!dot && name.startsWith("."))
37187
37205
  continue;
37188
37206
  const full = join10(dir, name);
37189
- const rel = full.startsWith(`${cwd}/`) ? full.slice(cwd.length + 1) : full;
37190
- if (ignore.length && matchesAnyPattern(rel, ignore))
37207
+ if (ignoreMatcher(full))
37191
37208
  continue;
37192
37209
  let st;
37193
37210
  try {
@@ -37196,17 +37213,21 @@ function* walkDir(dir, ignore, dot, cwd) {
37196
37213
  continue;
37197
37214
  }
37198
37215
  if (st.isDirectory()) {
37199
- yield* walkDir(full, ignore, dot, cwd);
37216
+ yield* walkDirWithMatcher(full, ignoreMatcher, dot);
37200
37217
  } else {
37201
37218
  yield full;
37202
37219
  }
37203
37220
  }
37204
37221
  }
37222
+ function* walkDir(dir, ignore, dot, cwd) {
37223
+ yield* walkDirWithMatcher(dir, createIgnoreMatcher(ignore, cwd), dot);
37224
+ }
37205
37225
  async function glob(patterns, opts = {}) {
37206
37226
  const cwd = opts.cwd ?? process21.cwd();
37207
37227
  const ignore = opts.ignore ?? [];
37208
37228
  const dot = opts.dot ?? false;
37209
37229
  const absolute = opts.absolute ?? true;
37230
+ const ignoreMatcher = createIgnoreMatcher(ignore, cwd);
37210
37231
  if (typeof globalThis.Bun?.Glob !== "undefined") {
37211
37232
  const BunGlob = globalThis.Bun.Glob;
37212
37233
  const results2 = [];
@@ -37215,7 +37236,7 @@ async function glob(patterns, opts = {}) {
37215
37236
  for await (const file of g.scan({ cwd, dot, onlyFiles: opts.onlyFiles ?? true, followSymlinks: false })) {
37216
37237
  const full = isAbsolute6(file) ? file : join10(cwd, file);
37217
37238
  const rel = full.startsWith(`${cwd}/`) ? full.slice(cwd.length + 1) : full;
37218
- if (ignore.length && matchesAnyPattern(rel, ignore))
37239
+ if (ignoreMatcher(full))
37219
37240
  continue;
37220
37241
  results2.push(absolute ? full : rel);
37221
37242
  }
@@ -37230,7 +37251,7 @@ async function glob(patterns, opts = {}) {
37230
37251
  const st = statSync5(full);
37231
37252
  if (!st.isDirectory()) {
37232
37253
  const rel = full.startsWith(`${cwd}/`) ? full.slice(cwd.length + 1) : full;
37233
- if (!ignore.length || !matchesAnyPattern(rel, ignore))
37254
+ if (!ignoreMatcher(full))
37234
37255
  results.push(absolute ? full : rel);
37235
37256
  } else {
37236
37257
  for (const f of walkDir(full, ignore, dot, cwd))
@@ -37405,36 +37426,60 @@ function isCodeFile(file, allowedExts) {
37405
37426
  function toPosixPath(p) {
37406
37427
  return p.replace(/\\/g, "/").replace(/\/+/g, "/");
37407
37428
  }
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) {
37429
+ function compileIgnoreGlobs(ignoreGlobs) {
37430
+ const compiled = [];
37431
+ for (const g of ignoreGlobs) {
37414
37432
  const gg = toPosixPath(g.trim());
37433
+ if (!gg)
37434
+ continue;
37415
37435
  const filePattern = gg.match(/\*\*\/\*\.(.+)$/);
37416
37436
  if (filePattern) {
37417
- const extension = filePattern[1];
37418
- if (rel.endsWith(`.${extension}`))
37419
- return true;
37437
+ compiled.push({ raw: gg, kind: "extension", value: filePattern[1] });
37420
37438
  continue;
37421
37439
  }
37422
37440
  const m = gg.match(/\*\*\/(.+?)\/\*\*$/);
37423
37441
  if (m) {
37424
- const name = m[1];
37425
- if (rel.includes(`/${name}/`) || rel.endsWith(`/${name}`))
37426
- return true;
37442
+ compiled.push({ raw: gg, kind: "segment", value: m[1] });
37427
37443
  continue;
37428
37444
  }
37429
37445
  const m2 = gg.match(/\*\*\/(.+)$/);
37430
37446
  if (m2) {
37431
- const name = m2[1].replace(/\/$/, "");
37432
- if (rel.includes(`/${name}/`) || rel.endsWith(`/${name}`))
37433
- return true;
37434
- continue;
37447
+ compiled.push({ raw: gg, kind: "suffix", value: m2[1].replace(/\/$/, "") });
37448
+ }
37449
+ }
37450
+ return compiled;
37451
+ }
37452
+ function createIgnoreMatcher(ignoreGlobs, cwd = process21.cwd()) {
37453
+ if (ignoreGlobs.length === 0)
37454
+ return () => false;
37455
+ const compiled = compileIgnoreGlobs(ignoreGlobs);
37456
+ if (compiled.length === 0)
37457
+ return () => false;
37458
+ const universalRaw = new Set(UNIVERSAL_IGNORES);
37459
+ return (absPath) => {
37460
+ const normalizedAbs = toPosixPath(absPath);
37461
+ const normalizedCwd = toPosixPath(cwd).replace(/\/$/, "");
37462
+ const isOutsideProject = !normalizedAbs.startsWith(normalizedCwd);
37463
+ const rel = isOutsideProject ? normalizedAbs : normalizedAbs.slice(normalizedCwd.length);
37464
+ for (const pattern of compiled) {
37465
+ if (isOutsideProject && !universalRaw.has(pattern.raw))
37466
+ continue;
37467
+ if (pattern.kind === "extension") {
37468
+ if (rel.endsWith(`.${pattern.value}`))
37469
+ return true;
37470
+ continue;
37471
+ }
37472
+ if (pattern.kind === "segment" || pattern.kind === "suffix") {
37473
+ const name = pattern.value;
37474
+ if (rel.includes(`/${name}/`) || rel.endsWith(`/${name}`))
37475
+ return true;
37476
+ }
37435
37477
  }
37436
- }
37437
- return false;
37478
+ return false;
37479
+ };
37480
+ }
37481
+ function shouldIgnorePath(absPath, ignoreGlobs) {
37482
+ return createIgnoreMatcher(ignoreGlobs)(absPath);
37438
37483
  }
37439
37484
  var MAX_FIXER_PASSES = 5, ENV, UNIVERSAL_IGNORES, colors, _cachedDefaultConfig = null;
37440
37485
  var init_utils3 = __esm(() => {
@@ -37646,6 +37691,7 @@ async function runFormat(globs, options) {
37646
37691
  return !absBase.startsWith(process23.cwd());
37647
37692
  });
37648
37693
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
37694
+ const ignoreMatcher = createIgnoreMatcher(globIgnores);
37649
37695
  let entries = [];
37650
37696
  const simpleDirPattern = patterns.length === 1 && /\*\*\/\*$/.test(patterns[0]);
37651
37697
  if (simpleDirPattern) {
@@ -37660,7 +37706,7 @@ async function runFormat(globs, options) {
37660
37706
  for (const it of items) {
37661
37707
  const full = join8(dir, it);
37662
37708
  const st = statSync4(full);
37663
- if (shouldIgnorePath(full, globIgnores))
37709
+ if (ignoreMatcher(full))
37664
37710
  continue;
37665
37711
  if (st.isDirectory())
37666
37712
  stack.push(full);
@@ -37686,7 +37732,7 @@ async function runFormat(globs, options) {
37686
37732
  }
37687
37733
  trace("globbed entries", entries.length);
37688
37734
  const files = entries.filter((f) => {
37689
- if (shouldIgnorePath(f, globIgnores))
37735
+ if (ignoreMatcher(f))
37690
37736
  return false;
37691
37737
  const idx = f.lastIndexOf(".");
37692
37738
  if (idx < 0)
@@ -37758,24 +37804,21 @@ function trace2(...args) {
37758
37804
  getLogger2().error("[pickier:trace]", args);
37759
37805
  }
37760
37806
  async function lintText(text, cfg, filePath = "untitled", signal) {
37761
- if (signal?.aborted) {
37807
+ if (signal?.aborted)
37762
37808
  throw new Error("AbortError");
37763
- }
37764
- const cfg2 = cfg;
37765
- cfg2._internalSkipPluginRulesInScan = true;
37766
- const issues = scanContent(filePath, text, cfg);
37809
+ const suppress = parseDisableDirectives(text);
37810
+ const commentLines = getCommentLines(text);
37811
+ const issues = scanContentOptimized(filePath, text, cfg, suppress, commentLines);
37767
37812
  if (signal?.aborted)
37768
37813
  throw new Error("AbortError");
37769
37814
  try {
37770
37815
  const pluginIssues = await applyPlugins(filePath, text, cfg);
37771
- const suppress = parseDisableDirectives(text);
37772
- const commentLines = getCommentLines(text);
37773
37816
  for (const i of pluginIssues) {
37774
37817
  if (signal?.aborted)
37775
37818
  throw new Error("AbortError");
37776
37819
  if (isSuppressed(i.ruleId, i.line, suppress))
37777
37820
  continue;
37778
- if (commentLines.has(i.line))
37821
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
37779
37822
  continue;
37780
37823
  issues.push({
37781
37824
  filePath: i.filePath,
@@ -37809,6 +37852,7 @@ async function runLintProgrammatic(globs, options, signal) {
37809
37852
  return !absBase.startsWith(process25.cwd());
37810
37853
  });
37811
37854
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
37855
+ const ignoreMatcher = createIgnoreMatcher(globIgnores);
37812
37856
  let entries = [];
37813
37857
  const nonGlobSingle = patterns.length === 1 && !/[*?[\]{}()!]/.test(patterns[0]);
37814
37858
  if (nonGlobSingle) {
@@ -37834,7 +37878,7 @@ async function runLintProgrammatic(globs, options, signal) {
37834
37878
  for (const it of items) {
37835
37879
  const full = join11(dir, it);
37836
37880
  const st = statSync6(full);
37837
- if (shouldIgnorePath(full, globIgnores))
37881
+ if (ignoreMatcher(full))
37838
37882
  continue;
37839
37883
  if (st.isDirectory())
37840
37884
  stack.push(full);
@@ -37873,7 +37917,7 @@ async function runLintProgrammatic(globs, options, signal) {
37873
37917
  cntNodeModules++;
37874
37918
  continue;
37875
37919
  }
37876
- if (shouldIgnorePath(f, globIgnores)) {
37920
+ if (ignoreMatcher(f)) {
37877
37921
  cntIgnored++;
37878
37922
  continue;
37879
37923
  }
@@ -37886,15 +37930,12 @@ async function runLintProgrammatic(globs, options, signal) {
37886
37930
  }
37887
37931
  trace2("filter:programmatic", { total: cntTotal, included: cntIncluded, node_modules: cntNodeModules, ignored: cntIgnored, wrongExt: cntWrongExt });
37888
37932
  const concurrency = ENV.CONCURRENCY;
37889
- const limit = createLimiter(concurrency);
37890
37933
  const processFile = async (file) => {
37891
37934
  if (signal?.aborted)
37892
37935
  throw new Error("AbortError");
37893
37936
  const src = readFileSync10(file, "utf8");
37894
37937
  const suppress = parseDisableDirectives(src);
37895
37938
  const commentLines = getCommentLines(src);
37896
- const cfgAny = cfg;
37897
- cfgAny._internalSkipPluginRulesInScan = true;
37898
37939
  let issues = scanContentOptimized(file, src, cfg, suppress, commentLines);
37899
37940
  try {
37900
37941
  const pluginIssues = await applyPlugins(file, src, cfg);
@@ -37903,7 +37944,7 @@ async function runLintProgrammatic(globs, options, signal) {
37903
37944
  throw new Error("AbortError");
37904
37945
  if (isSuppressed(i.ruleId, i.line, suppress))
37905
37946
  continue;
37906
- if (commentLines.has(i.line))
37947
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
37907
37948
  continue;
37908
37949
  issues.push({
37909
37950
  filePath: i.filePath,
@@ -37953,7 +37994,7 @@ async function runLintProgrammatic(globs, options, signal) {
37953
37994
  }
37954
37995
  return issues;
37955
37996
  };
37956
- const issueArrays = await Promise.all(files.map((file) => limit(() => processFile(file))));
37997
+ const issueArrays = await processWithConcurrency(files, concurrency, processFile);
37957
37998
  const allIssues = issueArrays.flat();
37958
37999
  const errors = allIssues.filter((i) => i.severity === "error").length;
37959
38000
  const warnings = allIssues.filter((i) => i.severity === "warning").length;
@@ -37975,10 +38016,10 @@ function parseDisableDirectives(content) {
37975
38016
  for (let i = 0;i < lines.length; i++) {
37976
38017
  const t = lines[i].trim();
37977
38018
  const lineNo = i + 1;
37978
- const nextLineMatch = t.match(/^\/\/\s*(?:eslint|pickier)-disable-next-line\s+(\S.*)$/);
38019
+ const nextLineMatch = t.match(/^\/\/\s*(?:eslint|pickier)-disable-next-line(?:\s+(\S.*))?$/);
37979
38020
  if (nextLineMatch) {
37980
- const ruleText = nextLineMatch[1].replace(/\s+--\s.*$/, "");
37981
- const list = ruleText.split(",").map((s) => s.trim()).filter(Boolean);
38021
+ const ruleText = nextLineMatch[1]?.replace(/\s+--\s.*$/, "");
38022
+ const list = ruleText ? ruleText.split(",").map((s) => s.trim()).filter(Boolean) : ["*"];
37982
38023
  if (list.length > 0) {
37983
38024
  const target = lineNo + 1;
37984
38025
  const set = nextLine.get(target) || new Set;
@@ -38069,23 +38110,6 @@ function parseDisableDirectives(content) {
38069
38110
  const sortedEnableLines = Array.from(rangeEnable.keys()).sort((a, b) => a - b);
38070
38111
  return { nextLine, fileLevel, rangeDisable, rangeEnable, sortedDisableLines, sortedEnableLines };
38071
38112
  }
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
38113
  function isSuppressed(ruleId, line, directives) {
38090
38114
  if (directives instanceof Map) {
38091
38115
  const set = directives.get(line);
@@ -38100,14 +38124,28 @@ function isSuppressed(ruleId, line, directives) {
38100
38124
  const nextLineSet = directives.nextLine.get(line);
38101
38125
  if (nextLineSet && matchesRule(ruleId, nextLineSet))
38102
38126
  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;
38127
+ let disabled = false;
38128
+ let disableIndex = 0;
38129
+ let enableIndex = 0;
38130
+ while (true) {
38131
+ const nextDisable = disableIndex < directives.sortedDisableLines.length ? directives.sortedDisableLines[disableIndex] : Number.POSITIVE_INFINITY;
38132
+ const nextEnable = enableIndex < directives.sortedEnableLines.length ? directives.sortedEnableLines[enableIndex] : Number.POSITIVE_INFINITY;
38133
+ const nextDirectiveLine = Math.min(nextDisable, nextEnable);
38134
+ if (nextDirectiveLine >= line)
38135
+ break;
38136
+ if (nextDisable === nextDirectiveLine) {
38137
+ const disabledRules = directives.rangeDisable.get(nextDisable);
38138
+ if (matchesRule(ruleId, disabledRules))
38139
+ disabled = true;
38140
+ disableIndex++;
38141
+ continue;
38142
+ }
38143
+ const enabledRules = directives.rangeEnable.get(nextEnable);
38144
+ if (enabledRules.has("*") || matchesRule(ruleId, enabledRules))
38145
+ disabled = false;
38146
+ enableIndex++;
38109
38147
  }
38110
- return false;
38148
+ return disabled;
38111
38149
  }
38112
38150
  function matchesRule(ruleId, ruleSet) {
38113
38151
  if (ruleSet.size === 0)
@@ -38127,6 +38165,9 @@ function matchesRule(ruleId, ruleSet) {
38127
38165
  }
38128
38166
  return false;
38129
38167
  }
38168
+ function shouldSkipCommentOnlyPluginIssue(ruleId) {
38169
+ return ruleId !== "spaced-comment" && !ruleId.endsWith("/spaced-comment");
38170
+ }
38130
38171
  function ensureHelpText(issue, ruleId) {
38131
38172
  if (issue.help) {
38132
38173
  return issue;
@@ -38163,8 +38204,22 @@ async function withTimeout2(p, ms, label) {
38163
38204
  throw e;
38164
38205
  }
38165
38206
  }
38166
- async function applyPlugins(filePath, content, cfg) {
38167
- const issues = [];
38207
+ async function processWithConcurrency(items, concurrency, worker) {
38208
+ const results = new Array(items.length);
38209
+ if (items.length === 0)
38210
+ return results;
38211
+ let nextIndex = 0;
38212
+ const workerCount = Math.max(1, Math.min(Math.max(1, concurrency), items.length));
38213
+ async function runWorker() {
38214
+ while (nextIndex < items.length) {
38215
+ const index = nextIndex++;
38216
+ results[index] = await worker(items[index], index);
38217
+ }
38218
+ }
38219
+ await Promise.all(Array.from({ length: workerCount }, runWorker));
38220
+ return results;
38221
+ }
38222
+ function getPluginDefinitions(cfg) {
38168
38223
  let pluginDefs = getAllPlugins();
38169
38224
  if (cfg.plugins && cfg.plugins.length > 0) {
38170
38225
  const coreNames = new Set(["pickier", "style", "regexp", "ts"]);
@@ -38174,6 +38229,9 @@ async function applyPlugins(filePath, content, cfg) {
38174
38229
  for (const p of userPlugins)
38175
38230
  pluginDefs.push(p);
38176
38231
  }
38232
+ return pluginDefs;
38233
+ }
38234
+ function getRulesConfig(cfg, pluginDefs) {
38177
38235
  const rulesConfig = { ...cfg.pluginRules || {} };
38178
38236
  if (cfg.rules?.noUnusedCapturingGroup)
38179
38237
  rulesConfig["regexp/no-unused-capturing-group"] = cfg.rules.noUnusedCapturingGroup;
@@ -38183,115 +38241,168 @@ async function applyPlugins(filePath, content, cfg) {
38183
38241
  "antfu/no-top-level-await": "ts/no-top-level-await"
38184
38242
  };
38185
38243
  for (const [alias, target] of Object.entries(ruleAliases)) {
38186
- if (rulesConfig[alias]) {
38244
+ if (rulesConfig[alias])
38187
38245
  rulesConfig[target] = rulesConfig[alias];
38188
- }
38189
38246
  }
38190
38247
  for (const key of Object.keys(cfg.pluginRules || {})) {
38191
38248
  if (!key.includes("/")) {
38192
38249
  for (const p of pluginDefs) {
38193
- if (p.rules && Object.prototype.hasOwnProperty.call(p.rules, key)) {
38250
+ if (p.rules && Object.prototype.hasOwnProperty.call(p.rules, key))
38194
38251
  rulesConfig[`${p.name}/${key}`] = cfg.pluginRules[key];
38195
- }
38196
38252
  }
38197
38253
  }
38198
38254
  }
38199
- const baseCtx = { filePath, config: cfg };
38255
+ return rulesConfig;
38256
+ }
38257
+ function getPluginPlan(cfg) {
38258
+ const cached = pluginPlanCache.get(cfg);
38259
+ if (cached)
38260
+ return cached;
38261
+ const pluginDefs = getPluginDefinitions(cfg);
38262
+ const rulesConfig = getRulesConfig(cfg, pluginDefs);
38263
+ const checkRules = [];
38264
+ const fixRules = [];
38265
+ const fixableRuleIds = new Set(["no-debugger"]);
38266
+ const fixableBareRuleNames = new Set(["no-debugger"]);
38200
38267
  const executedRules = new Set;
38201
38268
  for (const plugin of pluginDefs) {
38202
- const r = plugin.rules;
38203
- for (const ruleName in r) {
38269
+ for (const ruleName in plugin.rules) {
38204
38270
  const fullRuleId = `${plugin.name}/${ruleName}`;
38205
38271
  const setting = getRuleSetting(rulesConfig, fullRuleId);
38206
38272
  if (!setting.enabled)
38207
38273
  continue;
38208
- if (executedRules.has(ruleName)) {
38274
+ if (executedRules.has(ruleName))
38209
38275
  continue;
38210
- }
38211
38276
  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;
38277
+ const rule = plugin.rules[ruleName];
38278
+ const planned = {
38279
+ pluginName: plugin.name,
38280
+ ruleName,
38281
+ fullRuleId,
38282
+ rule,
38283
+ severity: setting.severity,
38284
+ options: setting.options
38285
+ };
38286
+ if (typeof rule?.check === "function")
38287
+ checkRules.push(planned);
38288
+ else if (setting.severity === "error") {
38289
+ checkRules.push(planned);
38290
+ }
38291
+ if (typeof rule?.fix === "function") {
38292
+ fixRules.push(planned);
38293
+ fixableRuleIds.add(fullRuleId);
38294
+ fixableBareRuleNames.add(ruleName);
38295
+ }
38296
+ }
38297
+ }
38298
+ const plan = { checkRules, fixRules, fixableRuleIds, fixableBareRuleNames };
38299
+ pluginPlanCache.set(cfg, plan);
38300
+ return plan;
38301
+ }
38302
+ function isShellPath(filePath, content) {
38303
+ return /\.(?:sh|bash|zsh|ksh|dash)$/.test(filePath) || /^#!\s*(?:\/usr\/bin\/env\s+)?(?:ba|z|k|da)?sh\b/.test(content);
38304
+ }
38305
+ function isLockfilePath(filePath) {
38306
+ return /(?:^|[/\\])(?:bun\.lock|bun\.lockb|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|npm-shrinkwrap\.json)$/.test(filePath);
38307
+ }
38308
+ function shouldRunPlannedRule(rule, filePath, content) {
38309
+ switch (rule.pluginName) {
38310
+ case "markdown":
38311
+ return filePath.endsWith(".md");
38312
+ case "shell":
38313
+ return isShellPath(filePath, content);
38314
+ case "publint":
38315
+ return /(?:^|[/\\])package\.json$/.test(filePath);
38316
+ case "lockfile":
38317
+ return isLockfilePath(filePath);
38318
+ case "node":
38319
+ case "ts":
38320
+ case "general":
38321
+ case "quality":
38322
+ case "eslint":
38323
+ case "regexp":
38324
+ case "unused-imports":
38325
+ case "perfectionist":
38326
+ return /\.(?:ts|js|tsx|jsx|mts|mjs|cts|cjs)$/.test(filePath);
38327
+ default:
38328
+ return true;
38329
+ }
38330
+ }
38331
+ async function applyPlugins(filePath, content, cfg) {
38332
+ const issues = [];
38333
+ const plan = getPluginPlan(cfg);
38334
+ const baseCtx = { filePath, config: cfg };
38335
+ for (const planned of plan.checkRules) {
38336
+ if (!shouldRunPlannedRule(planned, filePath, content))
38337
+ continue;
38338
+ const { fullRuleId, rule, severity: overrideSeverity } = planned;
38339
+ if (!rule || typeof rule.check !== "function") {
38340
+ if (overrideSeverity === "error") {
38341
+ issues.push({
38342
+ filePath,
38343
+ line: 1,
38344
+ column: 1,
38345
+ ruleId: `${fullRuleId}-internal`,
38346
+ message: "Rule missing implementation (check function is undefined)",
38347
+ severity: "error"
38348
+ });
38226
38349
  }
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) {
38350
+ continue;
38351
+ }
38352
+ try {
38353
+ trace2("rule:start", fullRuleId);
38354
+ const ruleTimeoutMs = ENV.RULE_TIMEOUT_MS;
38355
+ const ctx = { ...baseCtx, options: planned.options };
38356
+ const started = performance.now();
38357
+ const out = await withTimeout2(Promise.resolve().then(() => rule.check(content, ctx)), ruleTimeoutMs, `rule:${fullRuleId}`);
38358
+ const elapsed = performance.now() - started;
38359
+ if (elapsed > ruleTimeoutMs) {
38241
38360
  issues.push({
38242
38361
  filePath,
38243
38362
  line: 1,
38244
38363
  column: 1,
38245
38364
  ruleId: `${fullRuleId}-internal`,
38246
- message: `Rule threw: ${e?.message || e}`,
38365
+ message: `Rule exceeded timeout budget: ${Math.round(elapsed)}ms > ${ruleTimeoutMs}ms`,
38247
38366
  severity: "error"
38248
38367
  });
38249
38368
  }
38369
+ trace2("rule:end", fullRuleId, Array.isArray(out) ? out.length : 0);
38370
+ for (const i of out) {
38371
+ const issueWithHelp = ensureHelpText(i, fullRuleId);
38372
+ if (overrideSeverity)
38373
+ issues.push({ ...issueWithHelp, severity: overrideSeverity });
38374
+ else
38375
+ issues.push(issueWithHelp);
38376
+ }
38377
+ } catch (e) {
38378
+ issues.push({
38379
+ filePath,
38380
+ line: 1,
38381
+ column: 1,
38382
+ ruleId: `${fullRuleId}-internal`,
38383
+ message: `Rule threw: ${e?.message || e}`,
38384
+ severity: "error"
38385
+ });
38250
38386
  }
38251
38387
  }
38252
38388
  return issues;
38253
38389
  }
38254
38390
  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
- }
38391
+ const plan = getPluginPlan(cfg);
38274
38392
  const baseCtx = { filePath, config: cfg };
38275
38393
  let out = content;
38276
38394
  let changed = true;
38277
38395
  let passes = 0;
38278
38396
  while (changed && passes++ < MAX_FIXER_PASSES) {
38279
38397
  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
- }
38398
+ for (const planned of plan.fixRules) {
38399
+ if (!shouldRunPlannedRule(planned, filePath, out))
38400
+ continue;
38401
+ const ctx = { ...baseCtx, options: planned.options };
38402
+ const next = planned.rule.fix(out, ctx);
38403
+ if (next !== out) {
38404
+ out = next;
38405
+ changed = true;
38295
38406
  }
38296
38407
  }
38297
38408
  }
@@ -38460,6 +38571,7 @@ function getCommentLines(content) {
38460
38571
  let state = "code";
38461
38572
  let lineNo = 1;
38462
38573
  let lineHasCode = false;
38574
+ let lineSawComment = false;
38463
38575
  let lineStartedInBlockComment = false;
38464
38576
  for (let i = 0;i < content.length; i++) {
38465
38577
  const ch = content[i];
@@ -38469,11 +38581,14 @@ function getCommentLines(content) {
38469
38581
  `) {
38470
38582
  if (lineStartedInBlockComment && state === "block-comment") {
38471
38583
  commentLines.add(lineNo);
38472
- } else if (!lineHasCode && state !== "block-comment") {} else if (!lineHasCode) {
38584
+ } else if (!lineHasCode && lineSawComment && state !== "block-comment") {
38585
+ commentLines.add(lineNo);
38586
+ } else if (!lineHasCode && state === "block-comment") {
38473
38587
  commentLines.add(lineNo);
38474
38588
  }
38475
38589
  lineNo++;
38476
38590
  lineHasCode = false;
38591
+ lineSawComment = false;
38477
38592
  lineStartedInBlockComment = state === "block-comment";
38478
38593
  if (state === "line-comment") {
38479
38594
  state = "code";
@@ -38484,6 +38599,7 @@ function getCommentLines(content) {
38484
38599
  case "code":
38485
38600
  if (ch === "/" && next === "/") {
38486
38601
  state = "line-comment";
38602
+ lineSawComment = true;
38487
38603
  i++;
38488
38604
  } else if (ch === "/" && next === "*") {
38489
38605
  let isRegex = false;
@@ -38525,6 +38641,7 @@ function getCommentLines(content) {
38525
38641
  }
38526
38642
  i--;
38527
38643
  } else {
38644
+ lineSawComment = true;
38528
38645
  state = "block-comment";
38529
38646
  i++;
38530
38647
  }
@@ -38619,6 +38736,8 @@ function getCommentLines(content) {
38619
38736
  }
38620
38737
  if (lineStartedInBlockComment && state === "block-comment") {
38621
38738
  commentLines.add(lineNo);
38739
+ } else if (!lineHasCode && lineSawComment && state !== "block-comment") {
38740
+ commentLines.add(lineNo);
38622
38741
  } else if (!lineHasCode && state === "block-comment") {
38623
38742
  commentLines.add(lineNo);
38624
38743
  }
@@ -38635,6 +38754,10 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38635
38754
  const quotesDisabled = quotesRuleSetting === "off";
38636
38755
  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
38756
  const skipCodeRules = isMd || fileExt === "yaml" || fileExt === "yml" || fileExt === "json" || fileExt === "jsonc" || isShell;
38757
+ const indentRuleSetting = cfg.rules?.indent ?? cfg.pluginRules?.indent ?? cfg.pluginRules?.["style/indent"];
38758
+ const indentDisabled = indentRuleSetting === "off";
38759
+ const isTemplate = fileExt === "stx" || fileExt === "html" || fileExt === "htm" || fileExt === "vue";
38760
+ const shouldCheckIndent = !indentDisabled && !isMd && !isTemplate;
38638
38761
  let quotesReported = false;
38639
38762
  const sevMap = (s) => s === "warn" ? "warning" : s === "error" ? "error" : undefined;
38640
38763
  const wantDebugger = sevMap(cfg.rules.noDebugger);
@@ -38656,33 +38779,34 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38656
38779
  }
38657
38780
  }
38658
38781
  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 === `
38782
+ if (content.includes("`")) {
38783
+ let inTemplate = false;
38784
+ let escaped = false;
38785
+ let currentLine = 1;
38786
+ for (let i = 0;i < content.length; i++) {
38787
+ const ch = content[i];
38788
+ if (escaped) {
38789
+ escaped = false;
38790
+ if (ch === `
38667
38791
  `)
38668
- currentLine++;
38669
- continue;
38670
- }
38671
- if (ch === "\\") {
38672
- escaped = true;
38673
- continue;
38674
- }
38675
- if (ch === `
38792
+ currentLine++;
38793
+ continue;
38794
+ }
38795
+ if (ch === "\\") {
38796
+ escaped = true;
38797
+ continue;
38798
+ }
38799
+ if (ch === `
38676
38800
  `) {
38677
- currentLine++;
38678
- continue;
38679
- }
38680
- if (ch === "`") {
38681
- inTemplate = !inTemplate;
38682
- continue;
38683
- }
38684
- if (inTemplate) {
38685
- linesInTemplate.add(currentLine);
38801
+ currentLine++;
38802
+ continue;
38803
+ }
38804
+ if (ch === "`") {
38805
+ inTemplate = !inTemplate;
38806
+ continue;
38807
+ }
38808
+ if (inTemplate)
38809
+ linesInTemplate.add(currentLine);
38686
38810
  }
38687
38811
  }
38688
38812
  for (let i = 0;i < lines.length; i++) {
@@ -38701,12 +38825,11 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38701
38825
  quotesReported = true;
38702
38826
  }
38703
38827
  }
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)) {
38828
+ let wsEnd = 0;
38829
+ while (wsEnd < line.length && (line.charCodeAt(wsEnd) === 32 || line.charCodeAt(wsEnd) === 9))
38830
+ wsEnd++;
38831
+ const leading = wsEnd > 0 ? line.slice(0, wsEnd) : "";
38832
+ if (shouldCheckIndent && leading.length > 0 && !linesInFencedCodeBlock.has(lineNo) && hasIndentIssue(leading, cfg.format.indent, cfg.format.indentStyle, line)) {
38710
38833
  if (!isSuppressed("indent", lineNo, suppress))
38711
38834
  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
38835
  }
@@ -38811,24 +38934,43 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
38811
38934
  }
38812
38935
  if (!skipCodeRules && wantNoCondAssign && !linesInTemplate.has(lineNo)) {
38813
38936
  const strippedLine = stripComments2(stripRegexLiterals(line));
38814
- const checkCond = (cond) => /[^=!<>]=(?![=>])/.test(cond.replace(/'[^']*'|"[^"]*"/g, '""'));
38815
- const m1 = strippedLine.match(/\b(?:if|while)\s*\(([^)]*)\)/);
38937
+ const conditionLine = strippedLine.replace(/'[^']*'|"[^"]*"/g, '""');
38938
+ const checkCond = (cond) => /[^=!<>]=(?![=>])/.test(cond);
38939
+ const m1 = conditionLine.match(/\b(?:if|while)\s*\(([^)]*)\)/);
38816
38940
  if (m1) {
38817
38941
  const cond = m1[1];
38818
38942
  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))" });
38943
+ if (!isSuppressed("no-cond-assign", lineNo, suppress)) {
38944
+ issues.push({
38945
+ filePath,
38946
+ line: lineNo,
38947
+ column: Math.max(1, line.indexOf("(") + 1),
38948
+ ruleId: "no-cond-assign",
38949
+ message: "Unexpected assignment within a conditional expression",
38950
+ severity: wantNoCondAssign,
38951
+ help: "Use === or == for comparison instead of = (assignment). Wrap intentional assignments in extra parentheses."
38952
+ });
38953
+ }
38821
38954
  }
38822
38955
  }
38823
- const mFor = strippedLine.match(/\bfor\s*\(([^)]*)\)/);
38956
+ const mFor = conditionLine.match(/\bfor\s*\(([^)]*)\)/);
38824
38957
  if (mFor) {
38825
38958
  const inside = mFor[1];
38826
38959
  const parts = inside.split(";");
38827
38960
  if (parts.length >= 2) {
38828
38961
  const cond = parts[1];
38829
38962
  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++)" });
38963
+ if (!isSuppressed("no-cond-assign", lineNo, suppress)) {
38964
+ issues.push({
38965
+ filePath,
38966
+ line: lineNo,
38967
+ column: Math.max(1, line.indexOf("(") + 1),
38968
+ ruleId: "no-cond-assign",
38969
+ message: "Unexpected assignment within a conditional expression",
38970
+ severity: wantNoCondAssign,
38971
+ help: "Use === or == for comparison instead of = (assignment). Wrap intentional assignments in extra parentheses."
38972
+ });
38973
+ }
38832
38974
  }
38833
38975
  }
38834
38976
  }
@@ -38840,67 +38982,25 @@ function scanContent(filePath, content, cfg) {
38840
38982
  const suppress = parseDisableDirectives(content);
38841
38983
  const commentLines = getCommentLines(content);
38842
38984
  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
- }
38985
+ try {
38986
+ const plan = getPluginPlan(cfg);
38987
+ const ctx = { filePath, config: cfg };
38988
+ for (const planned of plan.checkRules) {
38989
+ if (!shouldRunPlannedRule(planned, filePath, content))
38990
+ continue;
38991
+ if (!planned.rule || typeof planned.rule.check !== "function")
38992
+ continue;
38993
+ const out = planned.rule.check(content, { ...ctx, options: planned.options });
38994
+ for (const i of out) {
38995
+ if (isSuppressed(i.ruleId, i.line, suppress))
38996
+ continue;
38997
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
38998
+ continue;
38999
+ const issueWithHelp = ensureHelpText(i, planned.fullRuleId);
39000
+ issues.push(planned.severity ? { ...issueWithHelp, severity: planned.severity } : issueWithHelp);
38901
39001
  }
38902
- } catch {}
38903
- }
39002
+ }
39003
+ } catch {}
38904
39004
  return issues;
38905
39005
  }
38906
39006
  async function runLint(globs, options) {
@@ -38934,6 +39034,7 @@ async function runLint(globs, options) {
38934
39034
  return !absBase.startsWith(process25.cwd());
38935
39035
  });
38936
39036
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
39037
+ const ignoreMatcher = createIgnoreMatcher(globIgnores);
38937
39038
  if (enableDiagnostics) {
38938
39039
  getLogger2().info(`[pickier:diagnostics] Globbing outside project: ${isGlobbingOutsideProject}, ignore patterns: ${globIgnores.length}`);
38939
39040
  if (isGlobbingOutsideProject)
@@ -38970,7 +39071,7 @@ async function runLint(globs, options) {
38970
39071
  for (const it of items) {
38971
39072
  const full = join11(dir, it);
38972
39073
  const st = statSync6(full);
38973
- if (shouldIgnorePath(full, globIgnores))
39074
+ if (ignoreMatcher(full))
38974
39075
  continue;
38975
39076
  if (st.isDirectory())
38976
39077
  stack.push(full);
@@ -39032,7 +39133,7 @@ async function runLint(globs, options) {
39032
39133
  cntNodeModules++;
39033
39134
  continue;
39034
39135
  }
39035
- if (shouldIgnorePath(f, globIgnores)) {
39136
+ if (ignoreMatcher(f)) {
39036
39137
  cntIgnored++;
39037
39138
  continue;
39038
39139
  }
@@ -39063,7 +39164,6 @@ async function runLint(globs, options) {
39063
39164
  }
39064
39165
  }
39065
39166
  const concurrency = ENV.CONCURRENCY;
39066
- const limit = createLimiter(concurrency);
39067
39167
  if (enableDiagnostics)
39068
39168
  getLogger2().info(`[pickier:diagnostics] Starting to process ${files.length} files with concurrency ${concurrency}...`);
39069
39169
  let processedCount = 0;
@@ -39077,23 +39177,33 @@ async function runLint(globs, options) {
39077
39177
  const src = readFileSync10(file, "utf8");
39078
39178
  if (formatOnly) {
39079
39179
  const fixed = formatCode(src, cfg, file);
39080
- if (fixed !== src && !options.dryRun) {
39081
- writeFileSync11(file, fixed, "utf8");
39180
+ if (fixed !== src) {
39181
+ if (!options.dryRun) {
39182
+ writeFileSync11(file, fixed, "utf8");
39183
+ } else {
39184
+ return [{
39185
+ filePath: file,
39186
+ line: 1,
39187
+ column: 1,
39188
+ ruleId: "format",
39189
+ message: "File is not formatted",
39190
+ severity: "error",
39191
+ help: "Run pickier format with --write to apply formatting."
39192
+ }];
39193
+ }
39082
39194
  }
39083
39195
  return [];
39084
39196
  }
39085
39197
  const suppress = parseDisableDirectives(src);
39086
39198
  const isCodeFileForComments = /\.(?:ts|js|tsx|jsx|mts|mjs|cts|cjs)$/.test(file);
39087
39199
  const commentLines = isCodeFileForComments ? getCommentLines(src) : new Set;
39088
- const cfgAny = cfg;
39089
- cfgAny._internalSkipPluginRulesInScan = true;
39090
39200
  let issues = scanContentOptimized(file, src, cfg, suppress, commentLines);
39091
39201
  try {
39092
39202
  const pluginIssues = await applyPlugins(file, src, cfg);
39093
39203
  for (const i of pluginIssues) {
39094
39204
  if (isSuppressed(i.ruleId, i.line, suppress))
39095
39205
  continue;
39096
- if (commentLines.has(i.line))
39206
+ if (commentLines.has(i.line) && shouldSkipCommentOnlyPluginIssue(i.ruleId))
39097
39207
  continue;
39098
39208
  issues.push({
39099
39209
  filePath: i.filePath,
@@ -39152,7 +39262,7 @@ async function runLint(globs, options) {
39152
39262
  trace2("scan done", relative7(process25.cwd(), file), issues.length);
39153
39263
  return issues;
39154
39264
  };
39155
- const issueArrays = await Promise.all(files.map((file) => limit(() => processFile(file))));
39265
+ const issueArrays = await processWithConcurrency(files, concurrency, processFile);
39156
39266
  const allIssues = issueArrays.flat();
39157
39267
  if (enableDiagnostics)
39158
39268
  getLogger2().info(`[pickier:diagnostics] Processing complete! Found ${allIssues.length} issues total`);
@@ -39177,22 +39287,12 @@ async function runLint(globs, options) {
39177
39287
  const problemsText = total === 1 ? "problem" : "problems";
39178
39288
  const errorsText = errors === 1 ? "error" : "errors";
39179
39289
  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
- }
39290
+ const pluginPlan = getPluginPlan(cfg);
39191
39291
  let fixableErrors = 0;
39192
39292
  let fixableWarnings = 0;
39193
39293
  for (const issue of allIssues) {
39194
39294
  const ruleId = issue.ruleId;
39195
- const isFixable = fixableRuleIds.has(ruleId) || Array.from(fixableRuleIds).some((id) => id.endsWith(`/${ruleId}`));
39295
+ const isFixable = pluginPlan.fixableRuleIds.has(ruleId) || pluginPlan.fixableBareRuleNames.has(ruleId);
39196
39296
  if (isFixable) {
39197
39297
  if (issue.severity === "error")
39198
39298
  fixableErrors++;
@@ -39233,13 +39333,14 @@ async function runLint(globs, options) {
39233
39333
  return 1;
39234
39334
  }
39235
39335
  }
39236
- var _logger2 = null;
39336
+ var _logger2 = null, pluginPlanCache;
39237
39337
  var init_linter = __esm(() => {
39238
39338
  init_src();
39239
39339
  init_format();
39240
39340
  init_formatter();
39241
39341
  init_plugins();
39242
39342
  init_utils3();
39343
+ pluginPlanCache = new WeakMap;
39243
39344
  });
39244
39345
 
39245
39346
  // src/run.ts
@@ -39261,6 +39362,8 @@ async function runUnified(globs, options) {
39261
39362
  const cfg = await loadConfigFromPath(options.config);
39262
39363
  const src = readFileSync11(filePath, "utf8");
39263
39364
  const fmt = formatCode(src, cfg, filePath);
39365
+ if (options.check && fmt !== src)
39366
+ return 1;
39264
39367
  if (options.write && fmt !== src) {
39265
39368
  writeFileSync12(filePath, fmt, "utf8");
39266
39369
  }
@@ -39327,6 +39430,7 @@ export {
39327
39430
  detectQuoteIssues,
39328
39431
  defaultConfig4 as defaultConfig,
39329
39432
  createLimiter,
39433
+ createIgnoreMatcher,
39330
39434
  config5 as config,
39331
39435
  colors,
39332
39436
  colorize,