pickier 0.1.32 → 0.1.34

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
@@ -296,6 +296,87 @@ function normalizeSpacingLine(line) {
296
296
  }
297
297
  return strings.length > 0 ? unmaskStrings(t, strings) : t;
298
298
  }
299
+ function inTemplateText(stack) {
300
+ const top = stack[stack.length - 1];
301
+ return top !== undefined && top.t === "tmpl";
302
+ }
303
+ function skipQuoted(line, i, quote) {
304
+ i++;
305
+ while (i < line.length) {
306
+ const c = line[i];
307
+ if (c === "\\") {
308
+ i += 2;
309
+ continue;
310
+ }
311
+ if (c === quote)
312
+ return i + 1;
313
+ i++;
314
+ }
315
+ return i;
316
+ }
317
+ function advanceTemplateState(line, stack) {
318
+ for (const ctx of stack) {
319
+ if (ctx.t === "tmpl")
320
+ ctx.start = -1;
321
+ }
322
+ let i = 0;
323
+ while (i < line.length) {
324
+ const top = stack[stack.length - 1];
325
+ const ch = line[i];
326
+ if (top === undefined || top.t === "interp") {
327
+ if (ch === "`") {
328
+ stack.push({ t: "tmpl", start: i });
329
+ i++;
330
+ continue;
331
+ }
332
+ if (ch === "'" || ch === '"') {
333
+ i = skipQuoted(line, i, ch);
334
+ continue;
335
+ }
336
+ if (ch === "/" && line[i + 1] === "/")
337
+ break;
338
+ if (top !== undefined) {
339
+ if (ch === "{") {
340
+ top.braces++;
341
+ i++;
342
+ continue;
343
+ }
344
+ if (ch === "}") {
345
+ if (top.braces === 0)
346
+ stack.pop();
347
+ else
348
+ top.braces--;
349
+ i++;
350
+ continue;
351
+ }
352
+ }
353
+ i++;
354
+ } else {
355
+ if (ch === "\\") {
356
+ i += 2;
357
+ continue;
358
+ }
359
+ if (ch === "`") {
360
+ stack.pop();
361
+ i++;
362
+ continue;
363
+ }
364
+ if (ch === "$" && line[i + 1] === "{") {
365
+ stack.push({ t: "interp", braces: 0 });
366
+ i += 2;
367
+ continue;
368
+ }
369
+ i++;
370
+ }
371
+ }
372
+ if (inTemplateText(stack)) {
373
+ for (const ctx of stack) {
374
+ if (ctx.t === "tmpl" && ctx.start >= 0)
375
+ return ctx.start;
376
+ }
377
+ }
378
+ return -1;
379
+ }
299
380
  function processCodeLinesFused(content, cfg) {
300
381
  const lines = content.split(`
301
382
  `);
@@ -304,8 +385,29 @@ function processCodeLinesFused(content, cfg) {
304
385
  const preferred = cfg.format.quotes;
305
386
  const doSemiRemoval = cfg.format.semi === true;
306
387
  let indentLevel = 0;
388
+ const tmplStack = [];
307
389
  for (let idx = 0;idx < len; idx++) {
308
390
  let line = lines[idx];
391
+ const protectedLine = inTemplateText(tmplStack);
392
+ let splitIdx = -1;
393
+ if (tmplStack.length > 0 || line.indexOf("`") !== -1)
394
+ splitIdx = advanceTemplateState(line, tmplStack);
395
+ if (protectedLine) {
396
+ result[idx] = line;
397
+ continue;
398
+ }
399
+ let tmplTail = "";
400
+ let prefixEndedWithSpace = false;
401
+ if (splitIdx >= 0) {
402
+ tmplTail = line.slice(splitIdx);
403
+ const prefix = line.slice(0, splitIdx);
404
+ if (prefix.length === 0) {
405
+ result[idx] = tmplTail;
406
+ continue;
407
+ }
408
+ prefixEndedWithSpace = RE_TRAILING_WS.test(prefix);
409
+ line = prefix;
410
+ }
309
411
  if (line.length === 0) {
310
412
  result[idx] = "";
311
413
  continue;
@@ -330,6 +432,11 @@ function processCodeLinesFused(content, cfg) {
330
432
  }
331
433
  }
332
434
  }
435
+ if (splitIdx >= 0) {
436
+ if (prefixEndedWithSpace && !RE_TRAILING_WS.test(line))
437
+ line += " ";
438
+ line += tmplTail;
439
+ }
333
440
  result[idx] = line;
334
441
  }
335
442
  return result.join(`
@@ -338,7 +445,16 @@ function processCodeLinesFused(content, cfg) {
338
445
  function collapseBlankLines(lines, maxConsecutive) {
339
446
  const out = [];
340
447
  let blank = 0;
448
+ const stack = [];
341
449
  for (const l of lines) {
450
+ const protectedLine = inTemplateText(stack);
451
+ if (stack.length > 0 || l.indexOf("`") !== -1)
452
+ advanceTemplateState(l, stack);
453
+ if (protectedLine) {
454
+ out.push(l);
455
+ blank = 0;
456
+ continue;
457
+ }
342
458
  if (l === "") {
343
459
  blank++;
344
460
  if (blank <= maxConsecutive)
@@ -362,7 +478,17 @@ function formatCode(src, cfg, filePath) {
362
478
  lines = [];
363
479
  let blank = 0;
364
480
  const maxConsecutive = Math.max(0, cfg.format.maxConsecutiveBlankLines);
481
+ const stack = [];
365
482
  for (const l of rawLines) {
483
+ const protectedLine = inTemplateText(stack);
484
+ let endsInTemplate = false;
485
+ if (stack.length > 0 || l.indexOf("`") !== -1)
486
+ endsInTemplate = advanceTemplateState(l, stack) >= 0;
487
+ if (protectedLine || endsInTemplate) {
488
+ lines.push(l);
489
+ blank = 0;
490
+ continue;
491
+ }
366
492
  const last = l[l.length - 1];
367
493
  const trimmed = last === " " || last === "\t" ? l.replace(RE_TRAILING_WS, "") : l;
368
494
  if (trimmed === "") {
@@ -488,6 +614,45 @@ function hasIndentIssue(leading, indentSize, indentStyle = "spaces", lineContent
488
614
  }
489
615
  return spaces % indentSize !== 0;
490
616
  }
617
+ function skipTemplate(input, start) {
618
+ let i = start + 1;
619
+ while (i < input.length) {
620
+ const c = input[i];
621
+ if (c === "\\") {
622
+ i += 2;
623
+ continue;
624
+ }
625
+ if (c === "`")
626
+ return i + 1;
627
+ if (c === "$" && input[i + 1] === "{") {
628
+ i += 2;
629
+ let depth = 1;
630
+ while (i < input.length && depth > 0) {
631
+ const d = input[i];
632
+ if (d === "\\") {
633
+ i += 2;
634
+ continue;
635
+ }
636
+ if (d === "`") {
637
+ i = skipTemplate(input, i);
638
+ continue;
639
+ }
640
+ if (d === "'" || d === '"') {
641
+ i = skipQuoted(input, i, d);
642
+ continue;
643
+ }
644
+ if (d === "{")
645
+ depth++;
646
+ else if (d === "}")
647
+ depth--;
648
+ i++;
649
+ }
650
+ continue;
651
+ }
652
+ i++;
653
+ }
654
+ return i;
655
+ }
491
656
  function maskStrings(input) {
492
657
  if (!input.includes("'") && !input.includes('"') && !input.includes("`"))
493
658
  return { text: input, strings: [] };
@@ -501,18 +666,22 @@ function maskStrings(input) {
501
666
  if (i > segStart)
502
667
  parts.push(input.slice(segStart, i));
503
668
  const start = i;
504
- const close = ch;
505
- i++;
506
- while (i < input.length) {
507
- if (input[i] === "\\") {
508
- i += 2;
509
- continue;
510
- }
511
- if (input[i] === close) {
669
+ if (ch === "`") {
670
+ i = skipTemplate(input, i);
671
+ } else {
672
+ const close = ch;
673
+ i++;
674
+ while (i < input.length) {
675
+ if (input[i] === "\\") {
676
+ i += 2;
677
+ continue;
678
+ }
679
+ if (input[i] === close) {
680
+ i++;
681
+ break;
682
+ }
512
683
  i++;
513
- break;
514
684
  }
515
- i++;
516
685
  }
517
686
  strings.push(input.slice(start, i));
518
687
  parts.push(`@@S${strings.length - 1}@@`);
@@ -40045,11 +40214,9 @@ class Command {
40045
40214
  isMatched(name) {
40046
40215
  if (this.aliasNames.includes(name))
40047
40216
  return true;
40048
- if (this.name === name)
40049
- return true;
40050
- if (this.namespace && `${this.namespace}:${this.name}` === name)
40051
- return true;
40052
- return false;
40217
+ if (this.namespace)
40218
+ return `${this.namespace}:${this.name}` === name;
40219
+ return this.name === name;
40053
40220
  }
40054
40221
  get isDefaultCommand() {
40055
40222
  return this.name === "" || this.aliasNames.includes("!");
@@ -40057,6 +40224,9 @@ class Command {
40057
40224
  get isGlobalCommand() {
40058
40225
  return this instanceof GlobalCommand;
40059
40226
  }
40227
+ get displayName() {
40228
+ return this.namespace ? `${this.namespace}:${this.name}` : this.name;
40229
+ }
40060
40230
  hasOption(name) {
40061
40231
  name = name.split(".")[0];
40062
40232
  return !!this.options.find((option) => {
@@ -40122,7 +40292,7 @@ class Command {
40122
40292
  });
40123
40293
  sections.push({
40124
40294
  title: `For more info, run any command with the \`--help\` flag`,
40125
- body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join(`
40295
+ body: commands.map((command) => ` $ ${name}${command.displayName === "" ? "" : ` ${command.displayName}`} --help`).join(`
40126
40296
  `)
40127
40297
  });
40128
40298
  }
@@ -42594,8 +42764,8 @@ Received ${signal}, cleaning up...`);
42594
42764
  if (this.enableDidYouMean) {
42595
42765
  const allCommandNames = [];
42596
42766
  for (const command of this.commands) {
42597
- if (command.name) {
42598
- allCommandNames.push(command.name);
42767
+ if (command.displayName) {
42768
+ allCommandNames.push(command.displayName);
42599
42769
  }
42600
42770
  if (command.aliasNames) {
42601
42771
  allCommandNames.push(...command.aliasNames);
@@ -43100,7 +43270,7 @@ Run \`${this.name ?? "cli"} --help\` for usage.`;
43100
43270
  this.value = [];
43101
43271
  }
43102
43272
  if (item.group === true) {
43103
- const group = item.value;
43273
+ const group = String(item.value);
43104
43274
  const groupedItems = this.getGroupItems(group);
43105
43275
  if (this.isGroupSelected(group)) {
43106
43276
  this.value = this.value.filter((v) => groupedItems.findIndex((i) => i.value === v) === -1);
@@ -43520,7 +43690,7 @@ var require_package = __commonJS((exports, module) => {
43520
43690
  module.exports = {
43521
43691
  name: "pickier",
43522
43692
  type: "module",
43523
- version: "0.1.32",
43693
+ version: "0.1.34",
43524
43694
  description: "Format, lint and more in a fraction of seconds.",
43525
43695
  author: "Chris Breuer <chris@stacksjs.org>",
43526
43696
  license: "MIT",
package/dist/format.d.ts CHANGED
@@ -3,4 +3,16 @@ export declare function formatCode(src: string, cfg: PickierConfig, filePath: st
3
3
  export declare function detectQuoteIssues(line: string, preferred: 'single' | 'double'): number[];
4
4
  export declare function hasIndentIssue(leading: string, indentSize: number, indentStyle?: 'spaces' | 'tabs', lineContent?: string): boolean;
5
5
  export declare function formatImports(source: string): string;
6
+ // ── Multi-line template-literal tracking ──────────────────────────────────
7
+ // The line-based formatter must never touch the *contents* of a template
8
+ // literal (re-indenting, re-spacing `${` → `$ {`, re-quoting, or trimming would
9
+ // corrupt the string and break interpolation). These helpers track, line by
10
+ // line, whether we are inside a template literal's text so such lines can be
11
+ // emitted verbatim. The scan degrades safely: on exotic input it can only ever
12
+ // under-format (skip a line), never corrupt one.
13
+ // `start` records the index of the backtick that opened the template, but only
14
+ // while scanning the line on which it opened (carried-over contexts from earlier
15
+ // lines are reset to -1 on entry). It lets callers split an opening line into a
16
+ // formattable code prefix and a verbatim template tail.
17
+ declare type TmplCtx = { t: 'tmpl', start: number } | { t: 'interp', braces: number }
6
18
  declare type ImportKind = 'value' | 'type' | 'side-effect';
package/dist/src/index.js CHANGED
@@ -9130,6 +9130,87 @@ function normalizeSpacingLine(line) {
9130
9130
  }
9131
9131
  return strings.length > 0 ? unmaskStrings(t, strings) : t;
9132
9132
  }
9133
+ function inTemplateText(stack) {
9134
+ const top = stack[stack.length - 1];
9135
+ return top !== undefined && top.t === "tmpl";
9136
+ }
9137
+ function skipQuoted(line, i, quote) {
9138
+ i++;
9139
+ while (i < line.length) {
9140
+ const c = line[i];
9141
+ if (c === "\\") {
9142
+ i += 2;
9143
+ continue;
9144
+ }
9145
+ if (c === quote)
9146
+ return i + 1;
9147
+ i++;
9148
+ }
9149
+ return i;
9150
+ }
9151
+ function advanceTemplateState(line, stack) {
9152
+ for (const ctx of stack) {
9153
+ if (ctx.t === "tmpl")
9154
+ ctx.start = -1;
9155
+ }
9156
+ let i = 0;
9157
+ while (i < line.length) {
9158
+ const top = stack[stack.length - 1];
9159
+ const ch = line[i];
9160
+ if (top === undefined || top.t === "interp") {
9161
+ if (ch === "`") {
9162
+ stack.push({ t: "tmpl", start: i });
9163
+ i++;
9164
+ continue;
9165
+ }
9166
+ if (ch === "'" || ch === '"') {
9167
+ i = skipQuoted(line, i, ch);
9168
+ continue;
9169
+ }
9170
+ if (ch === "/" && line[i + 1] === "/")
9171
+ break;
9172
+ if (top !== undefined) {
9173
+ if (ch === "{") {
9174
+ top.braces++;
9175
+ i++;
9176
+ continue;
9177
+ }
9178
+ if (ch === "}") {
9179
+ if (top.braces === 0)
9180
+ stack.pop();
9181
+ else
9182
+ top.braces--;
9183
+ i++;
9184
+ continue;
9185
+ }
9186
+ }
9187
+ i++;
9188
+ } else {
9189
+ if (ch === "\\") {
9190
+ i += 2;
9191
+ continue;
9192
+ }
9193
+ if (ch === "`") {
9194
+ stack.pop();
9195
+ i++;
9196
+ continue;
9197
+ }
9198
+ if (ch === "$" && line[i + 1] === "{") {
9199
+ stack.push({ t: "interp", braces: 0 });
9200
+ i += 2;
9201
+ continue;
9202
+ }
9203
+ i++;
9204
+ }
9205
+ }
9206
+ if (inTemplateText(stack)) {
9207
+ for (const ctx of stack) {
9208
+ if (ctx.t === "tmpl" && ctx.start >= 0)
9209
+ return ctx.start;
9210
+ }
9211
+ }
9212
+ return -1;
9213
+ }
9133
9214
  function processCodeLinesFused(content, cfg) {
9134
9215
  const lines = content.split(`
9135
9216
  `);
@@ -9138,8 +9219,29 @@ function processCodeLinesFused(content, cfg) {
9138
9219
  const preferred = cfg.format.quotes;
9139
9220
  const doSemiRemoval = cfg.format.semi === true;
9140
9221
  let indentLevel = 0;
9222
+ const tmplStack = [];
9141
9223
  for (let idx = 0;idx < len; idx++) {
9142
9224
  let line = lines[idx];
9225
+ const protectedLine = inTemplateText(tmplStack);
9226
+ let splitIdx = -1;
9227
+ if (tmplStack.length > 0 || line.indexOf("`") !== -1)
9228
+ splitIdx = advanceTemplateState(line, tmplStack);
9229
+ if (protectedLine) {
9230
+ result[idx] = line;
9231
+ continue;
9232
+ }
9233
+ let tmplTail = "";
9234
+ let prefixEndedWithSpace = false;
9235
+ if (splitIdx >= 0) {
9236
+ tmplTail = line.slice(splitIdx);
9237
+ const prefix = line.slice(0, splitIdx);
9238
+ if (prefix.length === 0) {
9239
+ result[idx] = tmplTail;
9240
+ continue;
9241
+ }
9242
+ prefixEndedWithSpace = RE_TRAILING_WS.test(prefix);
9243
+ line = prefix;
9244
+ }
9143
9245
  if (line.length === 0) {
9144
9246
  result[idx] = "";
9145
9247
  continue;
@@ -9164,6 +9266,11 @@ function processCodeLinesFused(content, cfg) {
9164
9266
  }
9165
9267
  }
9166
9268
  }
9269
+ if (splitIdx >= 0) {
9270
+ if (prefixEndedWithSpace && !RE_TRAILING_WS.test(line))
9271
+ line += " ";
9272
+ line += tmplTail;
9273
+ }
9167
9274
  result[idx] = line;
9168
9275
  }
9169
9276
  return result.join(`
@@ -9172,7 +9279,16 @@ function processCodeLinesFused(content, cfg) {
9172
9279
  function collapseBlankLines(lines, maxConsecutive) {
9173
9280
  const out = [];
9174
9281
  let blank = 0;
9282
+ const stack = [];
9175
9283
  for (const l of lines) {
9284
+ const protectedLine = inTemplateText(stack);
9285
+ if (stack.length > 0 || l.indexOf("`") !== -1)
9286
+ advanceTemplateState(l, stack);
9287
+ if (protectedLine) {
9288
+ out.push(l);
9289
+ blank = 0;
9290
+ continue;
9291
+ }
9176
9292
  if (l === "") {
9177
9293
  blank++;
9178
9294
  if (blank <= maxConsecutive)
@@ -9196,7 +9312,17 @@ function formatCode(src, cfg, filePath) {
9196
9312
  lines = [];
9197
9313
  let blank = 0;
9198
9314
  const maxConsecutive = Math.max(0, cfg.format.maxConsecutiveBlankLines);
9315
+ const stack = [];
9199
9316
  for (const l of rawLines) {
9317
+ const protectedLine = inTemplateText(stack);
9318
+ let endsInTemplate = false;
9319
+ if (stack.length > 0 || l.indexOf("`") !== -1)
9320
+ endsInTemplate = advanceTemplateState(l, stack) >= 0;
9321
+ if (protectedLine || endsInTemplate) {
9322
+ lines.push(l);
9323
+ blank = 0;
9324
+ continue;
9325
+ }
9200
9326
  const last = l[l.length - 1];
9201
9327
  const trimmed = last === " " || last === "\t" ? l.replace(RE_TRAILING_WS, "") : l;
9202
9328
  if (trimmed === "") {
@@ -9322,6 +9448,45 @@ function hasIndentIssue(leading, indentSize, indentStyle = "spaces", lineContent
9322
9448
  }
9323
9449
  return spaces % indentSize !== 0;
9324
9450
  }
9451
+ function skipTemplate(input, start) {
9452
+ let i = start + 1;
9453
+ while (i < input.length) {
9454
+ const c = input[i];
9455
+ if (c === "\\") {
9456
+ i += 2;
9457
+ continue;
9458
+ }
9459
+ if (c === "`")
9460
+ return i + 1;
9461
+ if (c === "$" && input[i + 1] === "{") {
9462
+ i += 2;
9463
+ let depth = 1;
9464
+ while (i < input.length && depth > 0) {
9465
+ const d = input[i];
9466
+ if (d === "\\") {
9467
+ i += 2;
9468
+ continue;
9469
+ }
9470
+ if (d === "`") {
9471
+ i = skipTemplate(input, i);
9472
+ continue;
9473
+ }
9474
+ if (d === "'" || d === '"') {
9475
+ i = skipQuoted(input, i, d);
9476
+ continue;
9477
+ }
9478
+ if (d === "{")
9479
+ depth++;
9480
+ else if (d === "}")
9481
+ depth--;
9482
+ i++;
9483
+ }
9484
+ continue;
9485
+ }
9486
+ i++;
9487
+ }
9488
+ return i;
9489
+ }
9325
9490
  function maskStrings(input) {
9326
9491
  if (!input.includes("'") && !input.includes('"') && !input.includes("`"))
9327
9492
  return { text: input, strings: [] };
@@ -9335,18 +9500,22 @@ function maskStrings(input) {
9335
9500
  if (i > segStart)
9336
9501
  parts.push(input.slice(segStart, i));
9337
9502
  const start = i;
9338
- const close = ch;
9339
- i++;
9340
- while (i < input.length) {
9341
- if (input[i] === "\\") {
9342
- i += 2;
9343
- continue;
9344
- }
9345
- if (input[i] === close) {
9503
+ if (ch === "`") {
9504
+ i = skipTemplate(input, i);
9505
+ } else {
9506
+ const close = ch;
9507
+ i++;
9508
+ while (i < input.length) {
9509
+ if (input[i] === "\\") {
9510
+ i += 2;
9511
+ continue;
9512
+ }
9513
+ if (input[i] === close) {
9514
+ i++;
9515
+ break;
9516
+ }
9346
9517
  i++;
9347
- break;
9348
9518
  }
9349
- i++;
9350
9519
  }
9351
9520
  strings.push(input.slice(start, i));
9352
9521
  parts.push(`@@S${strings.length - 1}@@`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pickier",
3
3
  "type": "module",
4
- "version": "0.1.32",
4
+ "version": "0.1.34",
5
5
  "description": "Format, lint and more in a fraction of seconds.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",