pickier 0.1.36 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/cli.js CHANGED
@@ -47,6 +47,287 @@ var __export = (target, all) => {
47
47
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
48
48
  var __require = import.meta.require;
49
49
 
50
+ // src/rules/shell/_shared.ts
51
+ function maskShellStrings(line) {
52
+ const n = line.length;
53
+ const out = Array.from({ length: n }, (_, i2) => line[i2]);
54
+ let i = 0;
55
+ while (i < n) {
56
+ const ch = line[i];
57
+ if (ch === "#" && (i === 0 || /\s/.test(line[i - 1]))) {
58
+ while (i < n) {
59
+ out[i] = " ";
60
+ i++;
61
+ }
62
+ break;
63
+ }
64
+ if (ch === "$" && line[i + 1] === "'") {
65
+ i += 2;
66
+ while (i < n) {
67
+ if (line[i] === "\\" && i + 1 < n) {
68
+ out[i] = " ";
69
+ out[i + 1] = " ";
70
+ i += 2;
71
+ continue;
72
+ }
73
+ if (line[i] === "'") {
74
+ i++;
75
+ break;
76
+ }
77
+ out[i] = " ";
78
+ i++;
79
+ }
80
+ continue;
81
+ }
82
+ if (ch === "$" && line[i + 1] === '"') {
83
+ i++;
84
+ i = maskDoubleQuoted(line, i, out);
85
+ continue;
86
+ }
87
+ if (ch === "$" && line[i + 1] === "{") {
88
+ i += 2;
89
+ let depth = 1;
90
+ while (i < n && depth > 0) {
91
+ const c = line[i];
92
+ if (c === "\\" && i + 1 < n) {
93
+ out[i] = " ";
94
+ out[i + 1] = " ";
95
+ i += 2;
96
+ continue;
97
+ }
98
+ if (c === "'") {
99
+ i++;
100
+ while (i < n && line[i] !== "'") {
101
+ out[i] = " ";
102
+ i++;
103
+ }
104
+ if (i < n)
105
+ i++;
106
+ continue;
107
+ }
108
+ if (c === '"') {
109
+ i = maskDoubleQuoted(line, i, out);
110
+ continue;
111
+ }
112
+ if (c === "{") {
113
+ depth++;
114
+ i++;
115
+ continue;
116
+ }
117
+ if (c === "}") {
118
+ depth--;
119
+ i++;
120
+ continue;
121
+ }
122
+ out[i] = " ";
123
+ i++;
124
+ }
125
+ continue;
126
+ }
127
+ if (ch === "$" && line[i + 1] === "(" && line[i + 2] === "(") {
128
+ i += 3;
129
+ let depth = 2;
130
+ while (i < n && depth > 0) {
131
+ const c = line[i];
132
+ if (c === "(") {
133
+ depth++;
134
+ i++;
135
+ continue;
136
+ }
137
+ if (c === ")") {
138
+ depth--;
139
+ i++;
140
+ continue;
141
+ }
142
+ out[i] = " ";
143
+ i++;
144
+ }
145
+ continue;
146
+ }
147
+ if (ch === "$" && line[i + 1] === "(") {
148
+ i += 2;
149
+ let depth = 1;
150
+ while (i < n && depth > 0) {
151
+ const c = line[i];
152
+ if (c === "\\" && i + 1 < n) {
153
+ out[i] = " ";
154
+ out[i + 1] = " ";
155
+ i += 2;
156
+ continue;
157
+ }
158
+ if (c === "'") {
159
+ i++;
160
+ while (i < n && line[i] !== "'") {
161
+ out[i] = " ";
162
+ i++;
163
+ }
164
+ if (i < n)
165
+ i++;
166
+ continue;
167
+ }
168
+ if (c === '"') {
169
+ i = maskDoubleQuoted(line, i, out);
170
+ continue;
171
+ }
172
+ if (c === "(") {
173
+ depth++;
174
+ i++;
175
+ continue;
176
+ }
177
+ if (c === ")") {
178
+ depth--;
179
+ i++;
180
+ continue;
181
+ }
182
+ out[i] = " ";
183
+ i++;
184
+ }
185
+ continue;
186
+ }
187
+ if (ch === "'") {
188
+ i++;
189
+ while (i < n && line[i] !== "'") {
190
+ out[i] = " ";
191
+ i++;
192
+ }
193
+ if (i < n)
194
+ i++;
195
+ continue;
196
+ }
197
+ if (ch === '"') {
198
+ i = maskDoubleQuoted(line, i, out);
199
+ continue;
200
+ }
201
+ if (ch === "`") {
202
+ i++;
203
+ while (i < n && line[i] !== "`") {
204
+ if (line[i] === "\\" && i + 1 < n) {
205
+ out[i] = " ";
206
+ out[i + 1] = " ";
207
+ i += 2;
208
+ continue;
209
+ }
210
+ out[i] = " ";
211
+ i++;
212
+ }
213
+ if (i < n)
214
+ i++;
215
+ continue;
216
+ }
217
+ i++;
218
+ }
219
+ return out.join("");
220
+ }
221
+ function maskDoubleQuoted(line, start, out) {
222
+ const n = line.length;
223
+ let i = start + 1;
224
+ while (i < n) {
225
+ const c = line[i];
226
+ if (c === "\\" && i + 1 < n) {
227
+ out[i] = " ";
228
+ out[i + 1] = " ";
229
+ i += 2;
230
+ continue;
231
+ }
232
+ if (c === '"')
233
+ return i + 1;
234
+ if (c === "$" && line[i + 1] === "(" && line[i + 2] === "(") {
235
+ i += 3;
236
+ let depth = 2;
237
+ while (i < n && depth > 0) {
238
+ const x = line[i];
239
+ if (x === "(") {
240
+ depth++;
241
+ i++;
242
+ continue;
243
+ }
244
+ if (x === ")") {
245
+ depth--;
246
+ i++;
247
+ continue;
248
+ }
249
+ out[i] = " ";
250
+ i++;
251
+ }
252
+ continue;
253
+ }
254
+ if (c === "$" && line[i + 1] === "(") {
255
+ i += 2;
256
+ let depth = 1;
257
+ while (i < n && depth > 0) {
258
+ const x = line[i];
259
+ if (x === "\\" && i + 1 < n) {
260
+ out[i] = " ";
261
+ out[i + 1] = " ";
262
+ i += 2;
263
+ continue;
264
+ }
265
+ if (x === "'") {
266
+ i++;
267
+ while (i < n && line[i] !== "'") {
268
+ out[i] = " ";
269
+ i++;
270
+ }
271
+ if (i < n)
272
+ i++;
273
+ continue;
274
+ }
275
+ if (x === '"') {
276
+ i = maskDoubleQuoted(line, i, out);
277
+ continue;
278
+ }
279
+ if (x === "(") {
280
+ depth++;
281
+ i++;
282
+ continue;
283
+ }
284
+ if (x === ")") {
285
+ depth--;
286
+ i++;
287
+ continue;
288
+ }
289
+ out[i] = " ";
290
+ i++;
291
+ }
292
+ continue;
293
+ }
294
+ if (c === "$" && line[i + 1] === "{") {
295
+ i += 2;
296
+ let depth = 1;
297
+ while (i < n && depth > 0) {
298
+ const x = line[i];
299
+ if (x === "{") {
300
+ depth++;
301
+ i++;
302
+ continue;
303
+ }
304
+ if (x === "}") {
305
+ depth--;
306
+ i++;
307
+ continue;
308
+ }
309
+ out[i] = " ";
310
+ i++;
311
+ }
312
+ continue;
313
+ }
314
+ out[i] = " ";
315
+ i++;
316
+ }
317
+ return i;
318
+ }
319
+ function heredocDelimiter(line) {
320
+ const masked = maskShellStrings(line);
321
+ const m = masked.match(/<<-?/);
322
+ if (!m || m.index === undefined)
323
+ return null;
324
+ const after = line.slice(m.index + m[0].length);
325
+ const delim = after.match(/^\s*(['"]?)(\w+)\1/);
326
+ if (!delim)
327
+ return null;
328
+ return delim[2];
329
+ }
330
+
50
331
  // src/format.ts
51
332
  function isHangingControlLine(code) {
52
333
  const m = RE_CONTROL_OPEN.exec(code);
@@ -124,10 +405,10 @@ function processShellLinesFused(content, cfg) {
124
405
  }
125
406
  continue;
126
407
  }
127
- const heredocMatch = line.match(/<<-?\s*['"]?(\w+)['"]?/);
128
- if (heredocMatch) {
408
+ const delim = heredocDelimiter(line);
409
+ if (delim) {
129
410
  inHeredoc = true;
130
- heredocDelim = heredocMatch[1];
411
+ heredocDelim = delim;
131
412
  }
132
413
  let wsEnd = 0;
133
414
  while (wsEnd < line.length && (line.charCodeAt(wsEnd) === 32 || line.charCodeAt(wsEnd) === 9))
@@ -197,16 +478,25 @@ function makeIndent(visualLevels, cfg) {
197
478
  }
198
479
  function convertDoubleToSingle(str) {
199
480
  const inner = str.slice(1, -1);
200
- let result = inner.replace(/\\"/g, '"');
201
- result = result.replace(/'/g, '"');
481
+ const result = inner.replace(/\\"/g, '"');
202
482
  return `'${result}'`;
203
483
  }
204
484
  function convertSingleToDouble(str) {
205
485
  const inner = str.slice(1, -1);
206
- let result = inner.replace(/\\'/g, "'");
207
- result = result.replace(/"/g, "'");
486
+ const result = inner.replace(/\\'/g, "'");
208
487
  return `"${result}"`;
209
488
  }
489
+ function hasUnescapedChar(content, ch) {
490
+ for (let i = 0;i < content.length; i++) {
491
+ if (content[i] === "\\") {
492
+ i++;
493
+ continue;
494
+ }
495
+ if (content[i] === ch)
496
+ return true;
497
+ }
498
+ return false;
499
+ }
210
500
  function fixQuotes(content, preferred, filePath) {
211
501
  if (!isCodeFileExt(filePath))
212
502
  return content;
@@ -281,11 +571,12 @@ function fixQuotesLine(line, preferred) {
281
571
  }
282
572
  const closeChar = inString === 1 ? "'" : '"';
283
573
  if (ch === closeChar) {
284
- const needConvert = inString === 2 && wantSingle || inString === 1 && !wantSingle;
574
+ const stringContent = line.slice(stringStart + 1, i);
575
+ const targetQuote = wantSingle ? "'" : '"';
576
+ const needConvert = (inString === 2 && wantSingle || inString === 1 && !wantSingle) && !hasUnescapedChar(stringContent, targetQuote);
285
577
  if (needConvert) {
286
578
  if (stringStart > segStart)
287
579
  parts.push(line.slice(segStart, stringStart));
288
- const stringContent = line.slice(stringStart + 1, i);
289
580
  if (inString === 2)
290
581
  parts.push(convertDoubleToSingle(`"${stringContent}"`));
291
582
  else
@@ -661,6 +952,20 @@ function formatCode(src, cfg, filePath) {
661
952
  return `${joined}
662
953
  `;
663
954
  }
955
+ function quoteConvertible(line, openIdx, quote, target) {
956
+ for (let j = openIdx + 1;j < line.length; j++) {
957
+ const c = line[j];
958
+ if (c === "\\") {
959
+ j++;
960
+ continue;
961
+ }
962
+ if (c === quote)
963
+ return true;
964
+ if (c === target)
965
+ return false;
966
+ }
967
+ return true;
968
+ }
664
969
  function detectQuoteIssues(line, preferred) {
665
970
  if (/^\s*\/\/\/\s*<reference/.test(line)) {
666
971
  return [];
@@ -679,21 +984,18 @@ function detectQuoteIssues(line, preferred) {
679
984
  continue;
680
985
  }
681
986
  if (!inString) {
987
+ if (ch === "/" && line[i + 1] === "/") {
988
+ break;
989
+ }
682
990
  if (ch === "'") {
683
- if (preferred === "double") {
684
- const beforeSlash = line.lastIndexOf("//", i);
685
- if (beforeSlash === -1 || beforeSlash > i) {
686
- indices.push(i);
687
- }
991
+ if (preferred === "double" && quoteConvertible(line, i, "'", '"')) {
992
+ indices.push(i);
688
993
  }
689
994
  inString = "single";
690
995
  continue;
691
996
  } else if (ch === '"') {
692
- if (preferred === "single") {
693
- const beforeSlash = line.lastIndexOf("//", i);
694
- if (beforeSlash === -1 || beforeSlash > i) {
695
- indices.push(i);
696
- }
997
+ if (preferred === "single" && quoteConvertible(line, i, '"', "'")) {
998
+ indices.push(i);
697
999
  }
698
1000
  inString = "double";
699
1001
  continue;
@@ -783,16 +1085,20 @@ function isRegexStart(input, slashIdx) {
783
1085
  function scanRegexEnd(input, start) {
784
1086
  let i = start + 1;
785
1087
  let inClass = false;
1088
+ let classStart = -1;
786
1089
  while (i < input.length) {
787
1090
  const c = input[i];
788
1091
  if (c === "\\") {
789
1092
  i += 2;
790
1093
  continue;
791
1094
  }
792
- if (c === "[") {
1095
+ if (c === "[" && !inClass) {
793
1096
  inClass = true;
794
- } else if (c === "]") {
795
- inClass = false;
1097
+ classStart = i;
1098
+ } else if (c === "]" && inClass) {
1099
+ const bodyStart = input[classStart + 1] === "^" ? classStart + 2 : classStart + 1;
1100
+ if (i !== bodyStart)
1101
+ inClass = false;
796
1102
  } else if (c === "/" && !inClass) {
797
1103
  i++;
798
1104
  while (i < input.length && /[a-z]/i.test(input[i]))
@@ -10589,7 +10895,7 @@ function createIgnoreMatcher(ignoreGlobs, cwd = process19.cwd()) {
10589
10895
  return (absPath) => {
10590
10896
  const normalizedAbs = toPosixPath(absPath);
10591
10897
  const normalizedCwd = toPosixPath(cwd).replace(/\/$/, "");
10592
- const isOutsideProject = !normalizedAbs.startsWith(normalizedCwd);
10898
+ const isOutsideProject = normalizedAbs !== normalizedCwd && !normalizedAbs.startsWith(`${normalizedCwd}/`);
10593
10899
  const rel = isOutsideProject ? normalizedAbs : normalizedAbs.slice(normalizedCwd.length);
10594
10900
  for (const pattern of compiled) {
10595
10901
  if (isOutsideProject && !universalRaw.has(pattern.raw))
@@ -19230,7 +19536,7 @@ var init_no_empty = __esm(() => {
19230
19536
  const beforeBlock = line.substring(0, line.lastIndexOf("{")).trim();
19231
19537
  const isStatementBlock = /(?:if|else|for|while|do|try|catch|finally|function|\})\s*$/.test(beforeBlock);
19232
19538
  const isObjectLiteral = /[=:]$/.test(beforeBlock) || /return\s*$/.test(beforeBlock);
19233
- if (isStatementBlock && !isObjectLiteral && j === i + 1) {
19539
+ if (isStatementBlock && !isObjectLiteral) {
19234
19540
  issues.push({
19235
19541
  filePath: ctx.filePath,
19236
19542
  line: i + 1,
@@ -22658,7 +22964,9 @@ var init_prefer_const = __esm(() => {
22658
22964
  for (const { name, fixable } of decls) {
22659
22965
  if (!fixable)
22660
22966
  continue;
22661
- issues.push({ filePath: ctx.filePath, line: i + 1, column: Math.max(1, line.indexOf(name) + 1), ruleId: "prefer-const", message: `'${name}' is never reassigned. Use 'const' instead`, severity: "error", help: `Change 'let ${name}' to 'const ${name}' since the variable is never reassigned. This makes your code more predictable and prevents accidental mutations` });
22967
+ const wordIdx = line.search(new RegExp(`\\b${name.replace(/\$/g, "\\$")}\\b`));
22968
+ const nameIdx = wordIdx !== -1 ? wordIdx : line.indexOf(name);
22969
+ issues.push({ filePath: ctx.filePath, line: i + 1, column: Math.max(1, nameIdx + 1), ruleId: "prefer-const", message: `'${name}' is never reassigned. Use 'const' instead`, severity: "error", help: `Change 'let ${name}' to 'const ${name}' since the variable is never reassigned. This makes your code more predictable and prevents accidental mutations` });
22662
22970
  }
22663
22971
  }
22664
22972
  return issues;
@@ -24159,6 +24467,33 @@ var init_code_block_style = __esm(() => {
24159
24467
  });
24160
24468
 
24161
24469
  // src/rules/markdown/code-fence-style.ts
24470
+ function fenceBoundaryLines(lines) {
24471
+ const out = new Set;
24472
+ let fenceChar = null;
24473
+ let fenceLen = 0;
24474
+ for (let i = 0;i < lines.length; i++) {
24475
+ const trimmed = lines[i].trim();
24476
+ if (fenceChar === null) {
24477
+ const open = trimmed.match(/^(`{3,}|~{3,})(.*)$/);
24478
+ if (open) {
24479
+ const ch = open[1][0];
24480
+ if (ch === "`" && open[2].includes("`"))
24481
+ continue;
24482
+ fenceChar = ch;
24483
+ fenceLen = open[1].length;
24484
+ out.add(i);
24485
+ }
24486
+ } else {
24487
+ const close = trimmed.match(/^(`{3,}|~{3,})\s*$/);
24488
+ if (close && close[1][0] === fenceChar && close[1].length >= fenceLen) {
24489
+ out.add(i);
24490
+ fenceChar = null;
24491
+ fenceLen = 0;
24492
+ }
24493
+ }
24494
+ }
24495
+ return out;
24496
+ }
24162
24497
  var codeFenceStyleRule;
24163
24498
  var init_code_fence_style = __esm(() => {
24164
24499
  codeFenceStyleRule = {
@@ -24168,60 +24503,37 @@ var init_code_fence_style = __esm(() => {
24168
24503
  check: (text, ctx) => {
24169
24504
  const issues = [];
24170
24505
  const lines = text.split(/\r?\n/);
24506
+ const boundaries = fenceBoundaryLines(lines);
24171
24507
  const options = ctx.options || {};
24172
24508
  const style = options.style || "consistent";
24173
24509
  let detectedStyle = null;
24174
- for (let i = 0;i < lines.length; i++) {
24510
+ for (const i of boundaries) {
24175
24511
  const line = lines[i];
24176
- const isBacktick = /^`{3,}/.test(line);
24177
- const isTilde = /^~{3,}/.test(line);
24178
- if (isBacktick) {
24179
- if (style === "tilde") {
24512
+ const isBacktick = /^`{3,}/.test(line.trim());
24513
+ const fenceStyle = isBacktick ? "backtick" : "tilde";
24514
+ if (style === "backtick" || style === "tilde") {
24515
+ if (fenceStyle !== style) {
24180
24516
  issues.push({
24181
24517
  filePath: ctx.filePath,
24182
24518
  line: i + 1,
24183
24519
  column: 1,
24184
24520
  ruleId: "markdown/code-fence-style",
24185
- message: "Expected tilde (~~~) code fence",
24521
+ message: style === "tilde" ? "Expected tilde (~~~) code fence" : "Expected backtick (```) code fence",
24186
24522
  severity: "error"
24187
24523
  });
24188
- } else if (style === "consistent") {
24189
- if (detectedStyle === null) {
24190
- detectedStyle = "backtick";
24191
- } else if (detectedStyle === "tilde") {
24192
- issues.push({
24193
- filePath: ctx.filePath,
24194
- line: i + 1,
24195
- column: 1,
24196
- ruleId: "markdown/code-fence-style",
24197
- message: "Code fence style should be consistent throughout document",
24198
- severity: "error"
24199
- });
24200
- }
24201
24524
  }
24202
- } else if (isTilde) {
24203
- if (style === "backtick") {
24525
+ } else if (style === "consistent") {
24526
+ if (detectedStyle === null) {
24527
+ detectedStyle = fenceStyle;
24528
+ } else if (detectedStyle !== fenceStyle) {
24204
24529
  issues.push({
24205
24530
  filePath: ctx.filePath,
24206
24531
  line: i + 1,
24207
24532
  column: 1,
24208
24533
  ruleId: "markdown/code-fence-style",
24209
- message: "Expected backtick (```) code fence",
24534
+ message: "Code fence style should be consistent throughout document",
24210
24535
  severity: "error"
24211
24536
  });
24212
- } else if (style === "consistent") {
24213
- if (detectedStyle === null) {
24214
- detectedStyle = "tilde";
24215
- } else if (detectedStyle === "backtick") {
24216
- issues.push({
24217
- filePath: ctx.filePath,
24218
- line: i + 1,
24219
- column: 1,
24220
- ruleId: "markdown/code-fence-style",
24221
- message: "Code fence style should be consistent throughout document",
24222
- severity: "error"
24223
- });
24224
- }
24225
24537
  }
24226
24538
  }
24227
24539
  }
@@ -24231,32 +24543,22 @@ var init_code_fence_style = __esm(() => {
24231
24543
  const options = ctx.options || {};
24232
24544
  const style = options.style || "consistent";
24233
24545
  const lines = text.split(/\r?\n/);
24546
+ const boundaries = fenceBoundaryLines(lines);
24234
24547
  let targetStyle = "backtick";
24235
- if (style === "backtick") {
24236
- targetStyle = "backtick";
24237
- } else if (style === "tilde") {
24238
- targetStyle = "tilde";
24239
- } else if (style === "consistent") {
24240
- for (const line of lines) {
24241
- if (/^`{3,}/.test(line)) {
24242
- targetStyle = "backtick";
24243
- break;
24244
- } else if (/^~{3,}/.test(line)) {
24245
- targetStyle = "tilde";
24246
- break;
24247
- }
24548
+ if (style === "backtick" || style === "tilde") {
24549
+ targetStyle = style;
24550
+ } else {
24551
+ for (const i of boundaries) {
24552
+ targetStyle = /^`{3,}/.test(lines[i].trim()) ? "backtick" : "tilde";
24553
+ break;
24248
24554
  }
24249
24555
  }
24250
- const fixedLines = lines.map((line) => {
24251
- if (targetStyle === "backtick") {
24252
- return line.replace(/^(~{3,})(.*)$/, (_match, _tildes, rest) => {
24253
- return `\`\`\`${rest}`;
24254
- });
24255
- } else {
24256
- return line.replace(/^(`{3,})(.*)$/, (_match, _backticks, rest) => {
24257
- return `~~~${rest}`;
24258
- });
24259
- }
24556
+ const targetChar = targetStyle === "backtick" ? "`" : "~";
24557
+ const sourceRun = targetStyle === "backtick" ? /^(\s*)(~{3,})(.*)$/ : /^(\s*)(`{3,})(.*)$/;
24558
+ const fixedLines = lines.map((line, i) => {
24559
+ if (!boundaries.has(i))
24560
+ return line;
24561
+ return line.replace(sourceRun, (_m, ws, run, rest) => `${ws}${targetChar.repeat(run.length)}${rest}`);
24260
24562
  });
24261
24563
  return fixedLines.join(`
24262
24564
  `);
@@ -24374,16 +24676,12 @@ var init_emphasis_style = __esm(() => {
24374
24676
  const options = ctx.options || {};
24375
24677
  const style = options.style || "consistent";
24376
24678
  let detectedStyle = null;
24377
- let inFence = false;
24679
+ const inCode = getCodeBlockLines(lines);
24378
24680
  for (let i = 0;i < lines.length; i++) {
24379
24681
  const line = lines[i];
24380
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
24381
- inFence = !inFence;
24382
- continue;
24383
- }
24384
- if (inFence)
24682
+ if (inCode.has(i))
24385
24683
  continue;
24386
- const stripped = line.replace(/``[^`]+``/g, " ").replace(/`[^`]+`/g, " ");
24684
+ const stripped = maskInlineCode(line);
24387
24685
  const asteriskMatches = stripped.matchAll(/(?<!\*)\*(?!\*)([^*]+)\*(?!\*)/g);
24388
24686
  for (const match of asteriskMatches) {
24389
24687
  if (style === "underscore") {
@@ -25359,15 +25657,11 @@ var init_no_bare_urls = __esm(() => {
25359
25657
  check: (text, ctx) => {
25360
25658
  const issues = [];
25361
25659
  const lines = text.split(/\r?\n/);
25362
- let inFence = false;
25660
+ const codeLines = getCodeBlockLines(lines);
25363
25661
  let inHtmlComment = false;
25364
25662
  for (let i = 0;i < lines.length; i++) {
25365
25663
  const line = lines[i];
25366
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
25367
- inFence = !inFence;
25368
- continue;
25369
- }
25370
- if (inFence)
25664
+ if (codeLines.has(i))
25371
25665
  continue;
25372
25666
  if (line.includes("<!--"))
25373
25667
  inHtmlComment = true;
@@ -25397,14 +25691,10 @@ var init_no_bare_urls = __esm(() => {
25397
25691
  },
25398
25692
  fix: (text) => {
25399
25693
  const lines = text.split(/\r?\n/);
25400
- let inFence = false;
25694
+ const codeLines = getCodeBlockLines(lines);
25401
25695
  let inHtmlComment = false;
25402
- const fixedLines = lines.map((line) => {
25403
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
25404
- inFence = !inFence;
25405
- return line;
25406
- }
25407
- if (inFence)
25696
+ const fixedLines = lines.map((line, i) => {
25697
+ if (codeLines.has(i))
25408
25698
  return line;
25409
25699
  if (line.includes("<!--"))
25410
25700
  inHtmlComment = true;
@@ -25726,7 +26016,19 @@ var init_no_hard_tabs = __esm(() => {
25726
26016
  return issues;
25727
26017
  },
25728
26018
  fix: (text) => {
25729
- return text.replace(/\t/g, " ");
26019
+ const lines = text.split(/\r?\n/);
26020
+ let inFence = false;
26021
+ const fixed = lines.map((line) => {
26022
+ if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
26023
+ inFence = !inFence;
26024
+ return line;
26025
+ }
26026
+ if (inFence)
26027
+ return line;
26028
+ return line.replace(/\t/g, " ");
26029
+ });
26030
+ return fixed.join(`
26031
+ `);
25730
26032
  }
25731
26033
  };
25732
26034
  });
@@ -25789,7 +26091,10 @@ var init_no_missing_space_atx = __esm(() => {
25789
26091
  check: (text, ctx) => {
25790
26092
  const issues = [];
25791
26093
  const lines = text.split(/\r?\n/);
26094
+ const codeLines = getCodeBlockLines(lines);
25792
26095
  for (let i = 0;i < lines.length; i++) {
26096
+ if (codeLines.has(i))
26097
+ continue;
25793
26098
  const line = lines[i];
25794
26099
  const match = line.match(/^(#{1,6})([^\s#])/);
25795
26100
  if (match) {
@@ -25807,7 +26112,10 @@ var init_no_missing_space_atx = __esm(() => {
25807
26112
  },
25808
26113
  fix: (text) => {
25809
26114
  const lines = text.split(/\r?\n/);
25810
- const fixedLines = lines.map((line) => {
26115
+ const codeLines = getCodeBlockLines(lines);
26116
+ const fixedLines = lines.map((line, i) => {
26117
+ if (codeLines.has(i))
26118
+ return line;
25811
26119
  return line.replace(/^(#{1,6})([^\s#])/, "$1 $2");
25812
26120
  });
25813
26121
  return fixedLines.join(`
@@ -25826,7 +26134,10 @@ var init_no_missing_space_closed_atx = __esm(() => {
25826
26134
  check: (text, ctx) => {
25827
26135
  const issues = [];
25828
26136
  const lines = text.split(/\r?\n/);
26137
+ const codeLines = getCodeBlockLines(lines);
25829
26138
  for (let i = 0;i < lines.length; i++) {
26139
+ if (codeLines.has(i))
26140
+ continue;
25830
26141
  const line = lines[i];
25831
26142
  const match = line.match(/^(#{1,6})\s+(.+?)(#{1,6})\s*$/);
25832
26143
  if (match) {
@@ -25928,7 +26239,10 @@ var init_no_multiple_space_atx = __esm(() => {
25928
26239
  check: (text, ctx) => {
25929
26240
  const issues = [];
25930
26241
  const lines = text.split(/\r?\n/);
26242
+ const codeLines = getCodeBlockLines(lines);
25931
26243
  for (let i = 0;i < lines.length; i++) {
26244
+ if (codeLines.has(i))
26245
+ continue;
25932
26246
  const line = lines[i];
25933
26247
  const match = line.match(/^(#{1,6})\s{2,}/);
25934
26248
  if (match) {
@@ -25946,7 +26260,10 @@ var init_no_multiple_space_atx = __esm(() => {
25946
26260
  },
25947
26261
  fix: (text) => {
25948
26262
  const lines = text.split(/\r?\n/);
25949
- const fixedLines = lines.map((line) => {
26263
+ const codeLines = getCodeBlockLines(lines);
26264
+ const fixedLines = lines.map((line, i) => {
26265
+ if (codeLines.has(i))
26266
+ return line;
25950
26267
  return line.replace(/^(#{1,6})\s{2,}/, "$1 ");
25951
26268
  });
25952
26269
  return fixedLines.join(`
@@ -25965,7 +26282,10 @@ var init_no_multiple_space_blockquote = __esm(() => {
25965
26282
  check: (text, ctx) => {
25966
26283
  const issues = [];
25967
26284
  const lines = text.split(/\r?\n/);
26285
+ const codeLines = getCodeBlockLines(lines);
25968
26286
  for (let i = 0;i < lines.length; i++) {
26287
+ if (codeLines.has(i))
26288
+ continue;
25969
26289
  const line = lines[i];
25970
26290
  const match = line.match(/^(\s*)(>+)\s{2,}/);
25971
26291
  if (match) {
@@ -25984,7 +26304,10 @@ var init_no_multiple_space_blockquote = __esm(() => {
25984
26304
  },
25985
26305
  fix: (text) => {
25986
26306
  const lines = text.split(/\r?\n/);
25987
- const fixedLines = lines.map((line) => {
26307
+ const codeLines = getCodeBlockLines(lines);
26308
+ const fixedLines = lines.map((line, i) => {
26309
+ if (codeLines.has(i))
26310
+ return line;
25988
26311
  return line.replace(/^(\s*>+)\s{2,}/, "$1 ");
25989
26312
  });
25990
26313
  return fixedLines.join(`
@@ -26003,7 +26326,10 @@ var init_no_multiple_space_closed_atx = __esm(() => {
26003
26326
  check: (text, ctx) => {
26004
26327
  const issues = [];
26005
26328
  const lines = text.split(/\r?\n/);
26329
+ const codeLines = getCodeBlockLines(lines);
26006
26330
  for (let i = 0;i < lines.length; i++) {
26331
+ if (codeLines.has(i))
26332
+ continue;
26007
26333
  const line = lines[i];
26008
26334
  const openMatch = line.match(/^(#{1,6})\s{2,}(?:\S.*?|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF])#{1,6}\s*$/);
26009
26335
  if (openMatch) {
@@ -26077,14 +26403,10 @@ var init_no_space_in_code = __esm(() => {
26077
26403
  check: (text, ctx) => {
26078
26404
  const issues = [];
26079
26405
  const lines = text.split(/\r?\n/);
26080
- let inFence = false;
26406
+ const codeLines = getCodeBlockLines(lines);
26081
26407
  for (let i = 0;i < lines.length; i++) {
26082
26408
  const line = lines[i];
26083
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
26084
- inFence = !inFence;
26085
- continue;
26086
- }
26087
- if (inFence)
26409
+ if (codeLines.has(i))
26088
26410
  continue;
26089
26411
  const codeSpanPattern = /(`+)([\s\S]*?)\1/g;
26090
26412
  for (const match of line.matchAll(codeSpanPattern)) {
@@ -26105,15 +26427,11 @@ var init_no_space_in_code = __esm(() => {
26105
26427
  },
26106
26428
  fix: (text) => {
26107
26429
  const lines = text.split(/\r?\n/);
26108
- let inFence = false;
26430
+ const codeLines = getCodeBlockLines(lines);
26109
26431
  const result = [];
26110
- for (const line of lines) {
26111
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
26112
- inFence = !inFence;
26113
- result.push(line);
26114
- continue;
26115
- }
26116
- if (inFence) {
26432
+ for (let i = 0;i < lines.length; i++) {
26433
+ const line = lines[i];
26434
+ if (codeLines.has(i)) {
26117
26435
  result.push(line);
26118
26436
  continue;
26119
26437
  }
@@ -26145,14 +26463,10 @@ var init_no_space_in_emphasis = __esm(() => {
26145
26463
  check: (text, ctx) => {
26146
26464
  const issues = [];
26147
26465
  const lines = text.split(/\r?\n/);
26148
- let inFence = false;
26466
+ const codeLines = getCodeBlockLines(lines);
26149
26467
  for (let i = 0;i < lines.length; i++) {
26150
26468
  const line = lines[i];
26151
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
26152
- inFence = !inFence;
26153
- continue;
26154
- }
26155
- if (inFence)
26469
+ if (codeLines.has(i))
26156
26470
  continue;
26157
26471
  const stripped = line.replace(/`[^`]+`/g, (m) => "\x01".repeat(m.length));
26158
26472
  for (const pattern of EMPHASIS_SPACE_PATTERNS) {
@@ -26172,15 +26486,11 @@ var init_no_space_in_emphasis = __esm(() => {
26172
26486
  },
26173
26487
  fix: (text) => {
26174
26488
  const lines = text.split(/\r?\n/);
26175
- let inFence = false;
26489
+ const codeLines = getCodeBlockLines(lines);
26176
26490
  const result = [];
26177
- for (const line of lines) {
26178
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
26179
- inFence = !inFence;
26180
- result.push(line);
26181
- continue;
26182
- }
26183
- if (inFence) {
26491
+ for (let i = 0;i < lines.length; i++) {
26492
+ const line = lines[i];
26493
+ if (codeLines.has(i)) {
26184
26494
  result.push(line);
26185
26495
  continue;
26186
26496
  }
@@ -26295,7 +26605,14 @@ var init_no_trailing_punctuation = __esm(() => {
26295
26605
  const punctuation = options.punctuation || ".,;:!?";
26296
26606
  const punctRegex = new RegExp(`[${punctuation.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}]+$`);
26297
26607
  const lines = text.split(/\r?\n/);
26608
+ let inFence = false;
26298
26609
  const fixedLines = lines.map((line, i) => {
26610
+ if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
26611
+ inFence = !inFence;
26612
+ return line;
26613
+ }
26614
+ if (inFence)
26615
+ return line;
26299
26616
  const atxMatch = line.match(/^(#{1,6}\s+)(.+?)(\s*#+\s*)?$/);
26300
26617
  if (atxMatch) {
26301
26618
  const prefix = atxMatch[1];
@@ -27136,17 +27453,13 @@ var init_ul_style = __esm(() => {
27136
27453
  check: (text, ctx) => {
27137
27454
  const issues = [];
27138
27455
  const lines = text.split(/\r?\n/);
27456
+ const codeLines = getCodeBlockLines(lines);
27139
27457
  const options = ctx.options || {};
27140
27458
  const style = options.style || "consistent";
27141
27459
  let detectedStyle = null;
27142
- let inFence = false;
27143
27460
  for (let i = 0;i < lines.length; i++) {
27144
27461
  const line = lines[i];
27145
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
27146
- inFence = !inFence;
27147
- continue;
27148
- }
27149
- if (inFence)
27462
+ if (codeLines.has(i))
27150
27463
  continue;
27151
27464
  const match = line.match(/^(\s*)([*\-+])\s+/);
27152
27465
  if (match) {
@@ -27200,6 +27513,7 @@ var init_ul_style = __esm(() => {
27200
27513
  const options = ctx.options || {};
27201
27514
  const style = options.style || "consistent";
27202
27515
  const lines = text.split(/\r?\n/);
27516
+ const codeLines = getCodeBlockLines(lines);
27203
27517
  let targetMarker = "*";
27204
27518
  if (style === "asterisk") {
27205
27519
  targetMarker = "*";
@@ -27208,21 +27522,18 @@ var init_ul_style = __esm(() => {
27208
27522
  } else if (style === "plus") {
27209
27523
  targetMarker = "+";
27210
27524
  } else if (style === "consistent") {
27211
- for (const line of lines) {
27212
- const match = line.match(/^(\s*)([*\-+])\s+/);
27525
+ for (let i = 0;i < lines.length; i++) {
27526
+ if (codeLines.has(i))
27527
+ continue;
27528
+ const match = lines[i].match(/^(\s*)([*\-+])\s+/);
27213
27529
  if (match) {
27214
27530
  targetMarker = match[2];
27215
27531
  break;
27216
27532
  }
27217
27533
  }
27218
27534
  }
27219
- let inFence = false;
27220
- const fixedLines = lines.map((line) => {
27221
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
27222
- inFence = !inFence;
27223
- return line;
27224
- }
27225
- if (inFence)
27535
+ const fixedLines = lines.map((line, i) => {
27536
+ if (codeLines.has(i))
27226
27537
  return line;
27227
27538
  return line.replace(/^(\s*)([*\-+])(\s+)/, `$1${targetMarker}$3`);
27228
27539
  });
@@ -27426,36 +27737,26 @@ var init_prefer_global_buffer = __esm(() => {
27426
27737
  check(content, context) {
27427
27738
  const issues = [];
27428
27739
  const lines = content.split(/\r?\n/);
27429
- const hasBufferImport = content.match(/(?:import|require)\s*\(?.*?['"]buffer['"]/);
27430
- if (!hasBufferImport) {
27431
- for (let i = 0;i < lines.length; i++) {
27432
- const line = lines[i];
27433
- const trimmed = line.trim();
27434
- if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*"))
27435
- continue;
27436
- const bufferUsagePattern = /\bBuffer\./;
27437
- if (bufferUsagePattern.test(line)) {
27438
- const match = line.match(bufferUsagePattern);
27439
- if (match) {
27440
- const beforeMatch = line.slice(0, match.index);
27441
- const singleQuotes = (beforeMatch.match(/'/g) || []).length;
27442
- const doubleQuotes = (beforeMatch.match(/"/g) || []).length;
27443
- const backticks = (beforeMatch.match(/`/g) || []).length;
27444
- if (singleQuotes % 2 === 1 || doubleQuotes % 2 === 1 || backticks % 2 === 1)
27445
- continue;
27446
- const column = (match.index || 0) + 1;
27447
- issues.push({
27448
- filePath: context.filePath,
27449
- line: i + 1,
27450
- column,
27451
- ruleId: "node/prefer-global/buffer",
27452
- message: `Unexpected use of the global variable 'Buffer'. Use 'require("buffer").Buffer' instead`,
27453
- severity: "error",
27454
- help: 'Import Buffer explicitly: const { Buffer } = require("buffer")'
27455
- });
27456
- }
27457
- }
27458
- }
27740
+ const importRe = /(?:import\b[^;\n]*\bfrom\s*|require\s*\(\s*)['"](?:node:)?buffer['"]/;
27741
+ for (let i = 0;i < lines.length; i++) {
27742
+ const line = lines[i];
27743
+ const trimmed = line.trim();
27744
+ if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*"))
27745
+ continue;
27746
+ const match = line.match(importRe);
27747
+ if (!match || match.index === undefined)
27748
+ continue;
27749
+ if (!/\bBuffer\b/.test(line))
27750
+ continue;
27751
+ issues.push({
27752
+ filePath: context.filePath,
27753
+ line: i + 1,
27754
+ column: match.index + 1,
27755
+ ruleId: "node/prefer-global/buffer",
27756
+ message: "Unexpected import of 'Buffer'. Use the global 'Buffer' instead",
27757
+ severity: "error",
27758
+ help: "`Buffer` is a global in Node.js \u2014 remove the import and use it directly."
27759
+ });
27459
27760
  }
27460
27761
  return issues;
27461
27762
  }
@@ -27473,36 +27774,24 @@ var init_prefer_global_process = __esm(() => {
27473
27774
  check(content, context) {
27474
27775
  const issues = [];
27475
27776
  const lines = content.split(/\r?\n/);
27476
- const hasProcessImport = content.match(/(?:import|require)\s*\(?.*?['"](?:node:)?process['"]/);
27477
- if (!hasProcessImport) {
27478
- for (let i = 0;i < lines.length; i++) {
27479
- const line = lines[i];
27480
- const trimmed = line.trim();
27481
- if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*"))
27482
- continue;
27483
- const processUsagePattern = /\bprocess\./;
27484
- if (processUsagePattern.test(line)) {
27485
- const match = line.match(processUsagePattern);
27486
- if (match) {
27487
- const beforeMatch = line.slice(0, match.index);
27488
- const singleQuotes = (beforeMatch.match(/'/g) || []).length;
27489
- const doubleQuotes = (beforeMatch.match(/"/g) || []).length;
27490
- const backticks = (beforeMatch.match(/`/g) || []).length;
27491
- if (singleQuotes % 2 === 1 || doubleQuotes % 2 === 1 || backticks % 2 === 1)
27492
- continue;
27493
- const column = (match.index || 0) + 1;
27494
- issues.push({
27495
- filePath: context.filePath,
27496
- line: i + 1,
27497
- column,
27498
- ruleId: "node/prefer-global/process",
27499
- message: `Unexpected use of the global variable 'process'. Use 'require("process")' instead`,
27500
- severity: "error",
27501
- help: 'Import process explicitly: const process = require("process")'
27502
- });
27503
- }
27504
- }
27505
- }
27777
+ const importRe = /(?:import\b[^;\n]*\bfrom\s*|require\s*\(\s*)['"](?:node:)?process['"]/;
27778
+ for (let i = 0;i < lines.length; i++) {
27779
+ const line = lines[i];
27780
+ const trimmed = line.trim();
27781
+ if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*"))
27782
+ continue;
27783
+ const match = line.match(importRe);
27784
+ if (!match || match.index === undefined)
27785
+ continue;
27786
+ issues.push({
27787
+ filePath: context.filePath,
27788
+ line: i + 1,
27789
+ column: match.index + 1,
27790
+ ruleId: "node/prefer-global/process",
27791
+ message: "Unexpected import of 'process'. Use the global 'process' instead",
27792
+ severity: "error",
27793
+ help: "`process` is a global in Node.js \u2014 remove the import and use it directly."
27794
+ });
27506
27795
  }
27507
27796
  return issues;
27508
27797
  }
@@ -27662,7 +27951,7 @@ function startsWithShebang(code) {
27662
27951
  return /^#!\s*\//.test(code);
27663
27952
  }
27664
27953
  function stripComments(code) {
27665
- return code.replace(/\/\*(.|[\r\n])*?\*\//gm, "").replace(/\/\/.*/g, "");
27954
+ return code.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*/g, "");
27666
27955
  }
27667
27956
  function crawlExportsOrImports(value, basePath, isImports, visitor) {
27668
27957
  _crawl(value, basePath, isImports, visitor);
@@ -28143,11 +28432,15 @@ var init_local_dependency = __esm(() => {
28143
28432
  if (!pkg)
28144
28433
  return [];
28145
28434
  const issues = [];
28146
- if (pkg.dependencies && typeof pkg.dependencies === "object") {
28147
- for (const depName of Object.keys(pkg.dependencies)) {
28148
- const depVersion = pkg.dependencies[depName];
28435
+ const fields = ["dependencies", "optionalDependencies", "peerDependencies"];
28436
+ for (const field of fields) {
28437
+ const deps = pkg[field];
28438
+ if (!deps || typeof deps !== "object")
28439
+ continue;
28440
+ for (const depName of Object.keys(deps)) {
28441
+ const depVersion = deps[depName];
28149
28442
  if (typeof depVersion === "string" && (depVersion.startsWith("file:") || depVersion.startsWith("link:"))) {
28150
- issues.push(createIssue(context.filePath, content, ["dependencies", depName], "publint/local-dependency", `The "${depName}" dependency references "${depVersion}" that will likely not work when installed by end-users.`, "error", "Local file references (file: or link:) are not portable and will fail for consumers of the package."));
28443
+ issues.push(createIssue(context.filePath, content, [field, depName], "publint/local-dependency", `The "${depName}" dependency references "${depVersion}" that will likely not work when installed by end-users.`, "error", "Local file references (file: or link:) are not portable and will fail for consumers of the package."));
28151
28444
  }
28152
28445
  }
28153
28446
  }
@@ -29836,7 +30129,7 @@ function parseRegexLiteral(content, idx) {
29836
30129
  return null;
29837
30130
  const pattern = content.slice(idx + 1, closedAt);
29838
30131
  let flagEnd = closedAt + 1;
29839
- while (flagEnd < content.length && /[gimsuy]/.test(content[flagEnd]))
30132
+ while (flagEnd < content.length && /[gimsuvy]/.test(content[flagEnd]))
29840
30133
  flagEnd++;
29841
30134
  if (/\\[1-9]/.test(pattern))
29842
30135
  return null;
@@ -29954,7 +30247,7 @@ function skipRegexLiteral(content, idx) {
29954
30247
  inClass = false;
29955
30248
  } else if (c === "/" && !inClass) {
29956
30249
  i++;
29957
- while (i < content.length && /[gimsuy]/.test(content[i]))
30250
+ while (i < content.length && /[gimsuvy]/.test(content[i]))
29958
30251
  i++;
29959
30252
  return i;
29960
30253
  } else if (c === `
@@ -30651,16 +30944,12 @@ var init_quote_variables = __esm(() => {
30651
30944
  inHeredoc = false;
30652
30945
  continue;
30653
30946
  }
30654
- const heredocMatch = line.match(/<<-?\s*(['"])(\w+)\1/);
30655
- if (heredocMatch) {
30656
- inHeredoc = true;
30657
- heredocDelim = heredocMatch[2];
30658
- continue;
30659
- }
30660
- const heredocMatch2 = line.match(/<<-?\s*(\w+)/);
30661
- if (heredocMatch2 && !heredocMatch) {
30947
+ const delim = heredocDelimiter(line);
30948
+ if (delim) {
30662
30949
  inHeredoc = true;
30663
- heredocDelim = heredocMatch2[1];
30950
+ heredocDelim = delim;
30951
+ if (new RegExp(`<<-?\\s*['"]${delim}['"]`).test(line))
30952
+ continue;
30664
30953
  }
30665
30954
  const trimmed = line.replace(/^\s+/, "");
30666
30955
  if (trimmed.startsWith("#"))
@@ -30988,283 +31277,6 @@ var init_indent = __esm(() => {
30988
31277
  };
30989
31278
  });
30990
31279
 
30991
- // src/rules/shell/_shared.ts
30992
- function maskShellStrings(line) {
30993
- const n = line.length;
30994
- const out = Array.from({ length: n }, (_, i2) => line[i2]);
30995
- let i = 0;
30996
- while (i < n) {
30997
- const ch = line[i];
30998
- if (ch === "#" && (i === 0 || /\s/.test(line[i - 1]))) {
30999
- while (i < n) {
31000
- out[i] = " ";
31001
- i++;
31002
- }
31003
- break;
31004
- }
31005
- if (ch === "$" && line[i + 1] === "'") {
31006
- i += 2;
31007
- while (i < n) {
31008
- if (line[i] === "\\" && i + 1 < n) {
31009
- out[i] = " ";
31010
- out[i + 1] = " ";
31011
- i += 2;
31012
- continue;
31013
- }
31014
- if (line[i] === "'") {
31015
- i++;
31016
- break;
31017
- }
31018
- out[i] = " ";
31019
- i++;
31020
- }
31021
- continue;
31022
- }
31023
- if (ch === "$" && line[i + 1] === '"') {
31024
- i++;
31025
- i = maskDoubleQuoted(line, i, out);
31026
- continue;
31027
- }
31028
- if (ch === "$" && line[i + 1] === "{") {
31029
- i += 2;
31030
- let depth = 1;
31031
- while (i < n && depth > 0) {
31032
- const c = line[i];
31033
- if (c === "\\" && i + 1 < n) {
31034
- out[i] = " ";
31035
- out[i + 1] = " ";
31036
- i += 2;
31037
- continue;
31038
- }
31039
- if (c === "'") {
31040
- i++;
31041
- while (i < n && line[i] !== "'") {
31042
- out[i] = " ";
31043
- i++;
31044
- }
31045
- if (i < n)
31046
- i++;
31047
- continue;
31048
- }
31049
- if (c === '"') {
31050
- i = maskDoubleQuoted(line, i, out);
31051
- continue;
31052
- }
31053
- if (c === "{") {
31054
- depth++;
31055
- i++;
31056
- continue;
31057
- }
31058
- if (c === "}") {
31059
- depth--;
31060
- i++;
31061
- continue;
31062
- }
31063
- out[i] = " ";
31064
- i++;
31065
- }
31066
- continue;
31067
- }
31068
- if (ch === "$" && line[i + 1] === "(" && line[i + 2] === "(") {
31069
- i += 3;
31070
- let depth = 2;
31071
- while (i < n && depth > 0) {
31072
- const c = line[i];
31073
- if (c === "(") {
31074
- depth++;
31075
- i++;
31076
- continue;
31077
- }
31078
- if (c === ")") {
31079
- depth--;
31080
- i++;
31081
- continue;
31082
- }
31083
- out[i] = " ";
31084
- i++;
31085
- }
31086
- continue;
31087
- }
31088
- if (ch === "$" && line[i + 1] === "(") {
31089
- i += 2;
31090
- let depth = 1;
31091
- while (i < n && depth > 0) {
31092
- const c = line[i];
31093
- if (c === "\\" && i + 1 < n) {
31094
- out[i] = " ";
31095
- out[i + 1] = " ";
31096
- i += 2;
31097
- continue;
31098
- }
31099
- if (c === "'") {
31100
- i++;
31101
- while (i < n && line[i] !== "'") {
31102
- out[i] = " ";
31103
- i++;
31104
- }
31105
- if (i < n)
31106
- i++;
31107
- continue;
31108
- }
31109
- if (c === '"') {
31110
- i = maskDoubleQuoted(line, i, out);
31111
- continue;
31112
- }
31113
- if (c === "(") {
31114
- depth++;
31115
- i++;
31116
- continue;
31117
- }
31118
- if (c === ")") {
31119
- depth--;
31120
- i++;
31121
- continue;
31122
- }
31123
- out[i] = " ";
31124
- i++;
31125
- }
31126
- continue;
31127
- }
31128
- if (ch === "'") {
31129
- i++;
31130
- while (i < n && line[i] !== "'") {
31131
- out[i] = " ";
31132
- i++;
31133
- }
31134
- if (i < n)
31135
- i++;
31136
- continue;
31137
- }
31138
- if (ch === '"') {
31139
- i = maskDoubleQuoted(line, i, out);
31140
- continue;
31141
- }
31142
- if (ch === "`") {
31143
- i++;
31144
- while (i < n && line[i] !== "`") {
31145
- if (line[i] === "\\" && i + 1 < n) {
31146
- out[i] = " ";
31147
- out[i + 1] = " ";
31148
- i += 2;
31149
- continue;
31150
- }
31151
- out[i] = " ";
31152
- i++;
31153
- }
31154
- if (i < n)
31155
- i++;
31156
- continue;
31157
- }
31158
- i++;
31159
- }
31160
- return out.join("");
31161
- }
31162
- function maskDoubleQuoted(line, start, out) {
31163
- const n = line.length;
31164
- let i = start + 1;
31165
- while (i < n) {
31166
- const c = line[i];
31167
- if (c === "\\" && i + 1 < n) {
31168
- out[i] = " ";
31169
- out[i + 1] = " ";
31170
- i += 2;
31171
- continue;
31172
- }
31173
- if (c === '"')
31174
- return i + 1;
31175
- if (c === "$" && line[i + 1] === "(" && line[i + 2] === "(") {
31176
- i += 3;
31177
- let depth = 2;
31178
- while (i < n && depth > 0) {
31179
- const x = line[i];
31180
- if (x === "(") {
31181
- depth++;
31182
- i++;
31183
- continue;
31184
- }
31185
- if (x === ")") {
31186
- depth--;
31187
- i++;
31188
- continue;
31189
- }
31190
- out[i] = " ";
31191
- i++;
31192
- }
31193
- continue;
31194
- }
31195
- if (c === "$" && line[i + 1] === "(") {
31196
- i += 2;
31197
- let depth = 1;
31198
- while (i < n && depth > 0) {
31199
- const x = line[i];
31200
- if (x === "\\" && i + 1 < n) {
31201
- out[i] = " ";
31202
- out[i + 1] = " ";
31203
- i += 2;
31204
- continue;
31205
- }
31206
- if (x === "'") {
31207
- i++;
31208
- while (i < n && line[i] !== "'") {
31209
- out[i] = " ";
31210
- i++;
31211
- }
31212
- if (i < n)
31213
- i++;
31214
- continue;
31215
- }
31216
- if (x === '"') {
31217
- i = maskDoubleQuoted(line, i, out);
31218
- continue;
31219
- }
31220
- if (x === "(") {
31221
- depth++;
31222
- i++;
31223
- continue;
31224
- }
31225
- if (x === ")") {
31226
- depth--;
31227
- i++;
31228
- continue;
31229
- }
31230
- out[i] = " ";
31231
- i++;
31232
- }
31233
- continue;
31234
- }
31235
- if (c === "$" && line[i + 1] === "{") {
31236
- i += 2;
31237
- let depth = 1;
31238
- while (i < n && depth > 0) {
31239
- const x = line[i];
31240
- if (x === "{") {
31241
- depth++;
31242
- i++;
31243
- continue;
31244
- }
31245
- if (x === "}") {
31246
- depth--;
31247
- i++;
31248
- continue;
31249
- }
31250
- out[i] = " ";
31251
- i++;
31252
- }
31253
- continue;
31254
- }
31255
- out[i] = " ";
31256
- i++;
31257
- }
31258
- return i;
31259
- }
31260
- function heredocDelimiter(line) {
31261
- const masked = maskShellStrings(line);
31262
- const m = masked.match(/<<-?\s*['"]?(\w+)['"]?/);
31263
- if (!m)
31264
- return null;
31265
- return m[1];
31266
- }
31267
-
31268
31280
  // src/rules/shell/keyword-spacing.ts
31269
31281
  var keywordSpacingRule;
31270
31282
  var init_keyword_spacing = __esm(() => {
@@ -31424,10 +31436,10 @@ var init_no_trailing_whitespace = __esm(() => {
31424
31436
  inHeredoc = false;
31425
31437
  continue;
31426
31438
  }
31427
- const heredocMatch = line.match(/<<-?\s*['"]?(\w+)['"]?/);
31428
- if (heredocMatch) {
31439
+ const delim = heredocDelimiter(line);
31440
+ if (delim) {
31429
31441
  inHeredoc = true;
31430
- heredocDelim = heredocMatch[1];
31442
+ heredocDelim = delim;
31431
31443
  }
31432
31444
  if (/[ \t]+$/.test(line)) {
31433
31445
  const trailingMatch = line.match(/[ \t]+$/);
@@ -31444,7 +31456,24 @@ var init_no_trailing_whitespace = __esm(() => {
31444
31456
  return issues;
31445
31457
  },
31446
31458
  fix(content) {
31447
- return content.replace(/[ \t]+$/gm, "");
31459
+ const lines = content.split(/\r?\n/);
31460
+ let inHeredoc = false;
31461
+ let heredocDelim = "";
31462
+ const fixed = lines.map((line) => {
31463
+ if (inHeredoc) {
31464
+ if (line.trim() === heredocDelim)
31465
+ inHeredoc = false;
31466
+ return line;
31467
+ }
31468
+ const delim = heredocDelimiter(line);
31469
+ if (delim) {
31470
+ inHeredoc = true;
31471
+ heredocDelim = delim;
31472
+ }
31473
+ return line.replace(/[ \t]+$/, "");
31474
+ });
31475
+ return fixed.join(`
31476
+ `);
31448
31477
  }
31449
31478
  };
31450
31479
  });
@@ -31842,21 +31871,26 @@ var init_heredoc_indent = __esm(() => {
31842
31871
  const trimmed = line.replace(/^\s+/, "");
31843
31872
  if (trimmed.startsWith("#"))
31844
31873
  continue;
31845
- const heredocMatch = line.match(/^(\s+).*<<\s*(['"]?)(\w+)\2\s*$/);
31846
- if (heredocMatch && !line.includes("<<-")) {
31847
- const indent = heredocMatch[1];
31848
- const delim = heredocMatch[3];
31849
- if (indent.length > 0) {
31850
- issues.push({
31851
- filePath: ctx.filePath,
31852
- line: i + 1,
31853
- column: line.indexOf("<<") + 1,
31854
- ruleId: "shell/heredoc-indent",
31855
- message: `Use <<- instead of << for indented heredoc (delimiter '${delim}' must be at column 0 otherwise)`,
31856
- severity: "warning",
31857
- help: "Use <<- to strip leading tabs from heredoc content, allowing proper indentation"
31858
- });
31859
- }
31874
+ const indent = line.match(/^\s+/);
31875
+ if (!indent)
31876
+ continue;
31877
+ const masked = maskShellStrings(line);
31878
+ const op = masked.match(/(?<!<)<<(?![<-])/);
31879
+ if (!op || op.index === undefined)
31880
+ continue;
31881
+ const after = line.slice(op.index + 2);
31882
+ const delimMatch = after.match(/^\s*(['"]?)(\w+)\1\s*$/);
31883
+ if (delimMatch) {
31884
+ const delim = delimMatch[2];
31885
+ issues.push({
31886
+ filePath: ctx.filePath,
31887
+ line: i + 1,
31888
+ column: op.index + 1,
31889
+ ruleId: "shell/heredoc-indent",
31890
+ message: `Use <<- instead of << for indented heredoc (delimiter '${delim}' must be at column 0 otherwise)`,
31891
+ severity: "warning",
31892
+ help: "Use <<- to strip leading tabs from heredoc content, allowing proper indentation"
31893
+ });
31860
31894
  }
31861
31895
  }
31862
31896
  return issues;
@@ -31884,17 +31918,18 @@ var init_no_broken_redirect = __esm(() => {
31884
31918
  inHeredoc = false;
31885
31919
  continue;
31886
31920
  }
31887
- const heredocMatch = line.match(/<<-?\s*['"]?(\w+)['"]?/);
31888
- if (heredocMatch) {
31921
+ const delim = heredocDelimiter(line);
31922
+ if (delim) {
31889
31923
  inHeredoc = true;
31890
- heredocDelim = heredocMatch[1];
31924
+ heredocDelim = delim;
31891
31925
  }
31892
31926
  const trimmed = line.replace(/^\s+/, "");
31893
31927
  if (trimmed.startsWith("#"))
31894
31928
  continue;
31895
- const brokenPattern = line.match(/2>&1\s+>(?!&)\s*\S/);
31929
+ const masked = maskShellStrings(line);
31930
+ const brokenPattern = masked.match(/2>&1\s+>(?!&)\s*\S/);
31896
31931
  if (brokenPattern) {
31897
- const col = line.indexOf("2>&1");
31932
+ const col = masked.indexOf("2>&1");
31898
31933
  issues.push({
31899
31934
  filePath: ctx.filePath,
31900
31935
  line: i + 1,
@@ -32192,8 +32227,6 @@ function createSpellRule(ruleId, filterFn) {
32192
32227
  for (const { word, offset: wordOffset } of words) {
32193
32228
  if (word.length < minLen)
32194
32229
  continue;
32195
- if (word.length <= 2)
32196
- continue;
32197
32230
  if (word === word.toUpperCase() && word.length <= 5)
32198
32231
  continue;
32199
32232
  if (userWords.has(word.toLowerCase()))
@@ -32450,9 +32483,36 @@ var init_arrow_spacing = __esm(() => {
32450
32483
  return issues;
32451
32484
  },
32452
32485
  fix(content) {
32453
- let result = content.replace(/(\S)=>/g, "$1 =>");
32454
- result = result.replace(/=>(\S)/g, "=> $1");
32455
- return result;
32486
+ const lines = content.split(`
32487
+ `);
32488
+ for (let li = 0;li < lines.length; li++) {
32489
+ const line = lines[li];
32490
+ const trimmed = line.trim();
32491
+ if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*"))
32492
+ continue;
32493
+ let out = "";
32494
+ let last = 0;
32495
+ ARROW_RE.lastIndex = 0;
32496
+ let m;
32497
+ while ((m = ARROW_RE.exec(line)) !== null) {
32498
+ const idx = m.index;
32499
+ if (isInStringOrComment3(line, idx))
32500
+ continue;
32501
+ const before = line[idx - 1];
32502
+ const after = line[idx + 2];
32503
+ const needBefore = idx > 0 && before !== " " && before !== "\t";
32504
+ const needAfter = after !== undefined && after !== " " && after !== "\t";
32505
+ if (!needBefore && !needAfter)
32506
+ continue;
32507
+ out += line.slice(last, idx);
32508
+ out += `${needBefore ? " " : ""}=>${needAfter ? " " : ""}`;
32509
+ last = idx + 2;
32510
+ }
32511
+ if (last > 0)
32512
+ lines[li] = out + line.slice(last);
32513
+ }
32514
+ return lines.join(`
32515
+ `);
32456
32516
  }
32457
32517
  };
32458
32518
  });
@@ -33709,11 +33769,14 @@ var init_dot_location = __esm(() => {
33709
33769
  check(content, context) {
33710
33770
  const issues = [];
33711
33771
  const lines = content.split(/\r?\n/);
33772
+ const inTemplate = computeLineStartsInTemplate(content);
33712
33773
  for (let i = 0;i < lines.length; i++) {
33713
33774
  const line = lines[i];
33714
33775
  const trimmed = line.trim();
33715
33776
  if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("/*"))
33716
33777
  continue;
33778
+ if (inTemplate[i + 1])
33779
+ continue;
33717
33780
  if (trimmed.endsWith(".") && i + 1 < lines.length) {
33718
33781
  const nextTrimmed = lines[i + 1].trim();
33719
33782
  if (nextTrimmed && /^[a-zA-Z_$]/.test(nextTrimmed)) {
@@ -33733,10 +33796,11 @@ var init_dot_location = __esm(() => {
33733
33796
  fix(content) {
33734
33797
  const lines = content.split(/\r?\n/);
33735
33798
  const result = [];
33799
+ const inTemplate = computeLineStartsInTemplate(content);
33736
33800
  for (let i = 0;i < lines.length; i++) {
33737
33801
  const line = lines[i];
33738
33802
  const trimmed = line.trim();
33739
- if (trimmed.endsWith(".") && i + 1 < lines.length) {
33803
+ if (trimmed.endsWith(".") && !inTemplate[i + 1] && i + 1 < lines.length) {
33740
33804
  const nextLine = lines[i + 1];
33741
33805
  const nextTrimmed = nextLine.trim();
33742
33806
  if (nextTrimmed && /^[a-zA-Z_$]/.test(nextTrimmed)) {
@@ -37466,32 +37530,60 @@ var init_prefer_nullish_coalescing = __esm(() => {
37466
37530
  const lines = text.split(/\r?\n/);
37467
37531
  let inBlockComment = false;
37468
37532
  for (let i = 0;i < lines.length; i++) {
37469
- let line = lines[i];
37470
- const originalLine = line;
37533
+ const originalLine = lines[i];
37534
+ const chars = originalLine.split("");
37535
+ const n = chars.length;
37536
+ let k = 0;
37471
37537
  if (inBlockComment) {
37472
- const endIdx = line.indexOf("*/");
37473
- if (endIdx >= 0) {
37474
- line = line.slice(endIdx + 2);
37475
- inBlockComment = false;
37476
- } else {
37538
+ const endIdx = originalLine.indexOf("*/");
37539
+ if (endIdx < 0)
37477
37540
  continue;
37478
- }
37541
+ for (let p = 0;p <= endIdx + 1; p++)
37542
+ chars[p] = " ";
37543
+ inBlockComment = false;
37544
+ k = endIdx + 2;
37479
37545
  }
37480
- const blockStart = line.indexOf("/*");
37481
- const lineComment = line.indexOf("//");
37482
- if (blockStart >= 0 && (lineComment === -1 || blockStart < lineComment)) {
37483
- const endIdx = line.indexOf("*/", blockStart + 2);
37484
- if (endIdx >= 0) {
37485
- line = line.slice(0, blockStart) + line.slice(endIdx + 2);
37486
- } else {
37487
- inBlockComment = true;
37488
- line = line.slice(0, blockStart);
37546
+ let inStr = null;
37547
+ for (;k < n; k++) {
37548
+ const ch = chars[k];
37549
+ if (inStr) {
37550
+ if (ch === "\\") {
37551
+ chars[k] = " ";
37552
+ if (k + 1 < n) {
37553
+ chars[k + 1] = " ";
37554
+ k++;
37555
+ }
37556
+ continue;
37557
+ }
37558
+ if (ch === inStr) {
37559
+ inStr = null;
37560
+ continue;
37561
+ }
37562
+ chars[k] = " ";
37563
+ continue;
37489
37564
  }
37565
+ if (ch === "/" && chars[k + 1] === "/") {
37566
+ for (let p = k;p < n; p++)
37567
+ chars[p] = " ";
37568
+ break;
37569
+ }
37570
+ if (ch === "/" && chars[k + 1] === "*") {
37571
+ const endIdx = originalLine.indexOf("*/", k + 2);
37572
+ if (endIdx < 0) {
37573
+ for (let p = k;p < n; p++)
37574
+ chars[p] = " ";
37575
+ inBlockComment = true;
37576
+ break;
37577
+ }
37578
+ for (let p = k;p <= endIdx + 1; p++)
37579
+ chars[p] = " ";
37580
+ k = endIdx + 1;
37581
+ continue;
37582
+ }
37583
+ if (ch === '"' || ch === "'" || ch === "`")
37584
+ inStr = ch;
37490
37585
  }
37491
- if (lineComment >= 0) {
37492
- line = line.slice(0, lineComment);
37493
- }
37494
- const cleanedLine = line.replace(/(['"`])(?:(?!\1)[^\\]|\\.)*?\1/g, '""');
37586
+ const cleanedLine = chars.join("");
37495
37587
  const orPattern = /\|\|/g;
37496
37588
  let match;
37497
37589
  while ((match = orPattern.exec(cleanedLine)) !== null) {
@@ -37586,11 +37678,10 @@ var init_prefer_nullish_coalescing = __esm(() => {
37586
37678
  const looksLikeDefaultValue = /^["'`\d]/.test(rightOperand) || /^\{/.test(rightOperand) || /^[\w$]+\(/.test(rightOperand) || /^[\w$.[\]]+$/.test(rightOperand);
37587
37679
  const looksLikeNullableValue = /^[\w$]+$/.test(leftOperand) || /^[\w$.?[\]()]+$/.test(leftOperand);
37588
37680
  if (looksLikeDefaultValue && looksLikeNullableValue) {
37589
- const actualIdx = originalLine.indexOf("||", Math.max(0, idx - 5));
37590
37681
  issues.push({
37591
37682
  filePath: ctx.filePath,
37592
37683
  line: i + 1,
37593
- column: actualIdx >= 0 ? actualIdx + 1 : idx + 1,
37684
+ column: idx + 1,
37594
37685
  ruleId: "ts/prefer-nullish-coalescing",
37595
37686
  message: "Prefer nullish coalescing operator (??) over logical OR (||)",
37596
37687
  severity: "error",
@@ -38287,35 +38378,30 @@ async function runFormat(globs, options) {
38287
38378
  return extSet.has(ext);
38288
38379
  });
38289
38380
  trace("filtered files", files.length);
38290
- let changed = 0;
38291
38381
  let checked = 0;
38382
+ const unformatted = [];
38292
38383
  for (const file of files) {
38293
38384
  trace("format start", relative6(process23.cwd(), file));
38294
38385
  const src = readFileSync9(file, "utf8");
38295
38386
  const fmt = formatCode(src, cfg, file);
38296
- if (options.check) {
38297
- if (fmt !== src) {
38298
- getLogger().debug(`${relative6(process23.cwd(), file)} needs formatting`);
38299
- changed++;
38300
- }
38301
- checked++;
38302
- } else if (options.write) {
38303
- if (fmt !== src) {
38387
+ const differs = fmt !== src;
38388
+ if (options.write) {
38389
+ if (differs)
38304
38390
  writeFileSync10(file, fmt, "utf8");
38305
- changed++;
38306
- }
38307
- checked++;
38308
- } else {
38309
- if (fmt !== src) {
38310
- getLogger().debug(`${relative6(process23.cwd(), file)} needs formatting`);
38311
- changed++;
38312
- }
38313
- checked++;
38314
38391
  }
38392
+ if (differs)
38393
+ unformatted.push(relative6(process23.cwd(), file));
38394
+ checked++;
38315
38395
  }
38316
- const isVerbose = options.verbose !== undefined ? options.verbose : cfg.verbose;
38317
- if (isVerbose) {
38318
- getLogger().debug(colors.gray(`Checked ${checked} files, ${changed} changed.`));
38396
+ const changed = unformatted.length;
38397
+ if (changed > 0) {
38398
+ for (const file of unformatted)
38399
+ console.log(colors.gray(` ${file}`));
38400
+ console.log(options.write ? colors.gray(`Formatted ${changed} of ${checked} file(s).`) : colors.yellow(`${changed} of ${checked} file(s) need formatting. Run with --write to fix.`));
38401
+ } else {
38402
+ const isVerbose = options.verbose !== undefined ? options.verbose : cfg.verbose;
38403
+ if (isVerbose)
38404
+ console.log(colors.gray(`Checked ${checked} files, all formatted.`));
38319
38405
  }
38320
38406
  return options.check && changed > 0 ? 1 : 0;
38321
38407
  }
@@ -38338,7 +38424,7 @@ __export(exports_linter, {
38338
38424
  applyPlugins: () => applyPlugins
38339
38425
  });
38340
38426
  import { readdirSync as readdirSync9, readFileSync as readFileSync10, statSync as statSync6, writeFileSync as writeFileSync11 } from "fs";
38341
- import { isAbsolute as isAbsolute8, join as join11, relative as relative7, resolve as resolve23 } from "path";
38427
+ import { isAbsolute as isAbsolute8, join as join11, relative as relative7, resolve as resolve23, sep } from "path";
38342
38428
  import process25 from "process";
38343
38429
  function getLogger2() {
38344
38430
  if (!_logger2)
@@ -38395,7 +38481,8 @@ async function runLintProgrammatic(globs, options, signal) {
38395
38481
  const isGlobbingOutsideProject = patterns.some((p) => {
38396
38482
  const base = p.replace(/\/?\*\*\/*\*\*$/, "");
38397
38483
  const absBase = isAbsolute8(base) ? base : resolve23(process25.cwd(), base);
38398
- return !absBase.startsWith(process25.cwd());
38484
+ const cwd = process25.cwd();
38485
+ return absBase !== cwd && !absBase.startsWith(cwd + sep);
38399
38486
  });
38400
38487
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
38401
38488
  const ignoreMatcher = createIgnoreMatcher(globIgnores);
@@ -39426,7 +39513,10 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
39426
39513
  }
39427
39514
  } else {
39428
39515
  if (inString === "double" && ch === '"' || inString === "single" && ch === "'" || inString === "template" && ch === "`") {
39429
- if (k === 0 || line[k - 1] !== "\\")
39516
+ let backslashes = 0;
39517
+ for (let p = k - 1;p >= 0 && line[p] === "\\"; p--)
39518
+ backslashes++;
39519
+ if (backslashes % 2 === 0)
39430
39520
  inString = null;
39431
39521
  }
39432
39522
  }
@@ -39503,6 +39593,12 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
39503
39593
  const strippedLine = stripComments2(stripRegexLiterals(line));
39504
39594
  const conditionLine = strippedLine.replace(/'[^']*'|"[^"]*"/g, '""');
39505
39595
  const checkCond = (cond) => /[^=!<>]=(?![=>])/.test(cond);
39596
+ const condParenColumn = (keyword) => {
39597
+ const km = line.match(keyword);
39598
+ if (km && km.index !== undefined)
39599
+ return km.index + km[0].length;
39600
+ return Math.max(1, line.indexOf("(") + 1);
39601
+ };
39506
39602
  const m1 = conditionLine.match(/\b(?:if|while)\s*\(([^)]*)\)/);
39507
39603
  if (m1) {
39508
39604
  const cond = m1[1];
@@ -39511,7 +39607,7 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
39511
39607
  issues.push({
39512
39608
  filePath,
39513
39609
  line: lineNo,
39514
- column: Math.max(1, line.indexOf("(") + 1),
39610
+ column: condParenColumn(/\b(?:if|while)\s*\(/),
39515
39611
  ruleId: "no-cond-assign",
39516
39612
  message: "Unexpected assignment within a conditional expression",
39517
39613
  severity: wantNoCondAssign,
@@ -39531,7 +39627,7 @@ function scanContentOptimized(filePath, content, cfg, suppress, commentLines) {
39531
39627
  issues.push({
39532
39628
  filePath,
39533
39629
  line: lineNo,
39534
- column: Math.max(1, line.indexOf("(") + 1),
39630
+ column: condParenColumn(/\bfor\s*\(/),
39535
39631
  ruleId: "no-cond-assign",
39536
39632
  message: "Unexpected assignment within a conditional expression",
39537
39633
  severity: wantNoCondAssign,
@@ -39598,7 +39694,8 @@ async function runLint(globs, options) {
39598
39694
  const isGlobbingOutsideProject = patterns.some((p) => {
39599
39695
  const base = p.replace(/\/?\*\*\/*\*\*$/, "");
39600
39696
  const absBase = isAbsolute8(base) ? base : resolve23(process25.cwd(), base);
39601
- return !absBase.startsWith(process25.cwd());
39697
+ const cwd = process25.cwd();
39698
+ return absBase !== cwd && !absBase.startsWith(cwd + sep);
39602
39699
  });
39603
39700
  const globIgnores = isGlobbingOutsideProject ? [...UNIVERSAL_IGNORES] : cfg.ignores;
39604
39701
  const ignoreMatcher = createIgnoreMatcher(globIgnores);
@@ -44066,7 +44163,7 @@ var require_package = __commonJS((exports, module) => {
44066
44163
  module.exports = {
44067
44164
  name: "pickier",
44068
44165
  type: "module",
44069
- version: "0.1.36",
44166
+ version: "0.1.38",
44070
44167
  description: "Format, lint and more in a fraction of seconds.",
44071
44168
  author: "Chris Breuer <chris@stacksjs.org>",
44072
44169
  license: "MIT",