@zgeoff/format-codemod 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/parse-cli-args.d.ts +1 -1
- package/dist/cli.js +116 -107
- package/package.json +5 -4
|
@@ -8,4 +8,4 @@ export interface CLIArgs {
|
|
|
8
8
|
readonly ignore: readonly string[];
|
|
9
9
|
readonly inputs: readonly string[];
|
|
10
10
|
}
|
|
11
|
-
export declare function parseCLIArgs(argv: readonly string[]): CLIArgs | string
|
|
11
|
+
export declare function parseCLIArgs(argv: readonly string[]): Promise<CLIArgs | string>;
|
package/dist/cli.js
CHANGED
|
@@ -62,35 +62,43 @@ function loadFormatIgnore(dir) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// src/cli/parse-cli-args.ts
|
|
65
|
-
import {
|
|
66
|
-
|
|
65
|
+
import { cli } from "gunshi/bone";
|
|
66
|
+
import { define } from "gunshi/definition";
|
|
67
|
+
var CLI_ARGS = {
|
|
68
|
+
check: { type: "boolean", default: false },
|
|
69
|
+
dry: { type: "boolean", default: false },
|
|
70
|
+
bench: { type: "boolean", default: false },
|
|
71
|
+
quiet: { type: "boolean", default: false },
|
|
72
|
+
version: { type: "boolean", default: false },
|
|
73
|
+
help: { type: "boolean", default: false },
|
|
74
|
+
ignore: { type: "string", multiple: true }
|
|
75
|
+
};
|
|
76
|
+
async function parseCLIArgs(argv) {
|
|
77
|
+
let parsed = null;
|
|
78
|
+
const command = define({
|
|
79
|
+
name: "format-codemod",
|
|
80
|
+
args: CLI_ARGS,
|
|
81
|
+
run: (ctx) => {
|
|
82
|
+
if (ctx.validationError !== undefined) {
|
|
83
|
+
throw ctx.validationError;
|
|
84
|
+
}
|
|
85
|
+
parsed = {
|
|
86
|
+
mode: pickMode(ctx.values.check, ctx.values.dry),
|
|
87
|
+
quiet: ctx.values.quiet,
|
|
88
|
+
bench: ctx.values.bench,
|
|
89
|
+
help: ctx.values.help,
|
|
90
|
+
version: ctx.values.version,
|
|
91
|
+
ignore: ctx.values.ignore ?? [],
|
|
92
|
+
inputs: [...ctx.positionals, ...ctx.rest]
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
67
96
|
try {
|
|
68
|
-
|
|
69
|
-
args: [...argv],
|
|
70
|
-
options: {
|
|
71
|
-
check: { type: "boolean", default: false },
|
|
72
|
-
dry: { type: "boolean", default: false },
|
|
73
|
-
bench: { type: "boolean", default: false },
|
|
74
|
-
quiet: { type: "boolean", default: false },
|
|
75
|
-
version: { type: "boolean", default: false },
|
|
76
|
-
help: { type: "boolean", default: false },
|
|
77
|
-
ignore: { type: "string", multiple: true, default: [] }
|
|
78
|
-
},
|
|
79
|
-
allowPositionals: true,
|
|
80
|
-
strict: true
|
|
81
|
-
});
|
|
82
|
-
return {
|
|
83
|
-
mode: pickMode(parsed.values.check, parsed.values.dry),
|
|
84
|
-
quiet: parsed.values.quiet,
|
|
85
|
-
bench: parsed.values.bench,
|
|
86
|
-
help: parsed.values.help,
|
|
87
|
-
version: parsed.values.version,
|
|
88
|
-
ignore: parsed.values.ignore,
|
|
89
|
-
inputs: parsed.positionals
|
|
90
|
-
};
|
|
97
|
+
await cli([...argv], command, { strict: true });
|
|
91
98
|
} catch (error) {
|
|
92
|
-
return
|
|
99
|
+
return formatParseError(error);
|
|
93
100
|
}
|
|
101
|
+
return parsed ?? "the command line could not be parsed";
|
|
94
102
|
}
|
|
95
103
|
function pickMode(check, dry) {
|
|
96
104
|
if (check) {
|
|
@@ -98,6 +106,13 @@ function pickMode(check, dry) {
|
|
|
98
106
|
}
|
|
99
107
|
return dry ? "dry" : "write";
|
|
100
108
|
}
|
|
109
|
+
function formatParseError(error) {
|
|
110
|
+
if (error instanceof AggregateError) {
|
|
111
|
+
return error.errors.map((reason) => formatParseError(reason)).join(`
|
|
112
|
+
`);
|
|
113
|
+
}
|
|
114
|
+
return error instanceof Error ? error.message : String(error);
|
|
115
|
+
}
|
|
101
116
|
|
|
102
117
|
// src/cli/print-help.ts
|
|
103
118
|
function printHelp() {
|
|
@@ -531,8 +546,8 @@ import fs4 from "node:fs";
|
|
|
531
546
|
|
|
532
547
|
// src/cli/build-unified-diff.ts
|
|
533
548
|
function buildUnifiedDiff(before, after, label) {
|
|
534
|
-
const
|
|
535
|
-
const hunks = buildHunks(
|
|
549
|
+
const operations = buildDiffOps({ before: splitLines(before), after: splitLines(after) });
|
|
550
|
+
const hunks = buildHunks(operations);
|
|
536
551
|
if (hunks.length === 0) {
|
|
537
552
|
return "";
|
|
538
553
|
}
|
|
@@ -548,88 +563,82 @@ function splitLines(s) {
|
|
|
548
563
|
}
|
|
549
564
|
return lines;
|
|
550
565
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
trace = [];
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
buildOps() {
|
|
562
|
-
this.updateTrace();
|
|
563
|
-
return this.backtrack();
|
|
564
|
-
}
|
|
565
|
-
updateTrace() {
|
|
566
|
-
for (let d = 0;d <= this.a.length + this.b.length; d++) {
|
|
567
|
-
this.trace.push(new Map(this.v));
|
|
568
|
-
if (this.stepRound(d)) {
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
stepRound(d) {
|
|
574
|
-
for (let k = -d;k <= d; k += 2) {
|
|
575
|
-
const x = this.slideDiagonal(this.pickX(k, d), k);
|
|
576
|
-
this.v.set(k, x);
|
|
577
|
-
if (x >= this.a.length && x - k >= this.b.length) {
|
|
578
|
-
return true;
|
|
579
|
-
}
|
|
566
|
+
function buildDiffOps(lines) {
|
|
567
|
+
return backtrack(lines, buildTrace(lines));
|
|
568
|
+
}
|
|
569
|
+
function buildTrace(lines) {
|
|
570
|
+
const furthestX = new Map([[1, 0]]);
|
|
571
|
+
const trace = [];
|
|
572
|
+
for (let depth = 0;depth <= lines.before.length + lines.after.length; depth++) {
|
|
573
|
+
trace.push(new Map(furthestX));
|
|
574
|
+
if (stepRound(lines, furthestX, depth)) {
|
|
575
|
+
break;
|
|
580
576
|
}
|
|
581
|
-
return false;
|
|
582
|
-
}
|
|
583
|
-
pickX(k, d) {
|
|
584
|
-
const moveDown = k === -d || k !== d && (this.v.get(k - 1) ?? 0) < (this.v.get(k + 1) ?? 0);
|
|
585
|
-
return moveDown ? this.v.get(k + 1) ?? 0 : (this.v.get(k - 1) ?? 0) + 1;
|
|
586
577
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const ops = [];
|
|
596
|
-
let pos = { x: this.a.length, y: this.b.length };
|
|
597
|
-
for (let d = this.trace.length - 1;d >= 0; d--) {
|
|
598
|
-
const round = this.unwindRound(pos, d);
|
|
599
|
-
ops.push(...round.ops);
|
|
600
|
-
pos = round.pos;
|
|
601
|
-
}
|
|
602
|
-
return ops.toReversed();
|
|
603
|
-
}
|
|
604
|
-
unwindRound(pos, d) {
|
|
605
|
-
const previous = this.findPrevious(pos, d);
|
|
606
|
-
const prev = previous.prev;
|
|
607
|
-
const ops = this.buildEqualOps(pos, prev);
|
|
608
|
-
if (d > 0) {
|
|
609
|
-
const changeOp = previous.moveDown ? { kind: "+", text: this.b[prev.y] ?? "" } : { kind: "-", text: this.a[prev.x] ?? "" };
|
|
610
|
-
ops.push(changeOp);
|
|
611
|
-
}
|
|
612
|
-
return { ops, pos: prev };
|
|
613
|
-
}
|
|
614
|
-
findPrevious(pos, d) {
|
|
615
|
-
const v = this.trace[d] ?? new Map;
|
|
616
|
-
const k = pos.x - pos.y;
|
|
617
|
-
const moveDown = k === -d || k !== d && (v.get(k - 1) ?? 0) < (v.get(k + 1) ?? 0);
|
|
618
|
-
const prevK = moveDown ? k + 1 : k - 1;
|
|
619
|
-
const prevX = v.get(prevK) ?? 0;
|
|
620
|
-
return { prev: { x: prevX, y: prevX - prevK }, moveDown };
|
|
621
|
-
}
|
|
622
|
-
buildEqualOps(pos, prev) {
|
|
623
|
-
const ops = [];
|
|
624
|
-
let x = pos.x;
|
|
625
|
-
let y = pos.y;
|
|
626
|
-
while (x > prev.x && y > prev.y) {
|
|
627
|
-
ops.push({ kind: " ", text: this.a[x - 1] ?? "" });
|
|
628
|
-
x--;
|
|
629
|
-
y--;
|
|
578
|
+
return trace;
|
|
579
|
+
}
|
|
580
|
+
function stepRound(lines, furthestX, depth) {
|
|
581
|
+
for (let diagonal = -depth;diagonal <= depth; diagonal += 2) {
|
|
582
|
+
const x = slideDiagonal(lines, pickX(furthestX, diagonal, depth), diagonal);
|
|
583
|
+
furthestX.set(diagonal, x);
|
|
584
|
+
if (x >= lines.before.length && x - diagonal >= lines.after.length) {
|
|
585
|
+
return true;
|
|
630
586
|
}
|
|
631
|
-
return ops;
|
|
632
587
|
}
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
function pickX(furthestX, diagonal, depth) {
|
|
591
|
+
const below = furthestX.get(diagonal - 1) ?? 0;
|
|
592
|
+
const above = furthestX.get(diagonal + 1) ?? 0;
|
|
593
|
+
const moveDown = diagonal === -depth || diagonal !== depth && below < above;
|
|
594
|
+
return moveDown ? above : below + 1;
|
|
595
|
+
}
|
|
596
|
+
function slideDiagonal(lines, x, diagonal) {
|
|
597
|
+
let endX = x;
|
|
598
|
+
while (endX < lines.before.length && endX - diagonal < lines.after.length && lines.before[endX] === lines.after[endX - diagonal]) {
|
|
599
|
+
endX++;
|
|
600
|
+
}
|
|
601
|
+
return endX;
|
|
602
|
+
}
|
|
603
|
+
function backtrack(lines, trace) {
|
|
604
|
+
const operations = [];
|
|
605
|
+
let position = { x: lines.before.length, y: lines.after.length };
|
|
606
|
+
for (let depth = trace.length - 1;depth >= 0; depth--) {
|
|
607
|
+
const round = unwindRound(lines, trace, position, depth);
|
|
608
|
+
operations.push(...round.operations);
|
|
609
|
+
position = round.position;
|
|
610
|
+
}
|
|
611
|
+
return operations.toReversed();
|
|
612
|
+
}
|
|
613
|
+
function unwindRound(lines, trace, position, depth) {
|
|
614
|
+
const step = findPreviousStep(trace, position, depth);
|
|
615
|
+
const operations = buildEqualOps(lines, position, step.position);
|
|
616
|
+
if (depth > 0) {
|
|
617
|
+
const changeOp = step.moveDown ? { kind: "+", text: lines.after[step.position.y] ?? "" } : { kind: "-", text: lines.before[step.position.x] ?? "" };
|
|
618
|
+
operations.push(changeOp);
|
|
619
|
+
}
|
|
620
|
+
return { operations, position: step.position };
|
|
621
|
+
}
|
|
622
|
+
function findPreviousStep(trace, position, depth) {
|
|
623
|
+
const furthestX = trace[depth] ?? new Map;
|
|
624
|
+
const diagonal = position.x - position.y;
|
|
625
|
+
const below = furthestX.get(diagonal - 1) ?? 0;
|
|
626
|
+
const above = furthestX.get(diagonal + 1) ?? 0;
|
|
627
|
+
const moveDown = diagonal === -depth || diagonal !== depth && below < above;
|
|
628
|
+
const previousDiagonal = moveDown ? diagonal + 1 : diagonal - 1;
|
|
629
|
+
const previousX = furthestX.get(previousDiagonal) ?? 0;
|
|
630
|
+
return { position: { x: previousX, y: previousX - previousDiagonal }, moveDown };
|
|
631
|
+
}
|
|
632
|
+
function buildEqualOps(lines, position, previous) {
|
|
633
|
+
const operations = [];
|
|
634
|
+
let x = position.x;
|
|
635
|
+
let y = position.y;
|
|
636
|
+
while (x > previous.x && y > previous.y) {
|
|
637
|
+
operations.push({ kind: " ", text: lines.before[x - 1] ?? "" });
|
|
638
|
+
x--;
|
|
639
|
+
y--;
|
|
640
|
+
}
|
|
641
|
+
return operations;
|
|
633
642
|
}
|
|
634
643
|
function buildHunks(ops) {
|
|
635
644
|
return buildWindows(ops).map((w) => buildHunk(ops, w));
|
|
@@ -729,7 +738,7 @@ function tryCheckFile(file, mode) {
|
|
|
729
738
|
}
|
|
730
739
|
|
|
731
740
|
// src/cli.ts
|
|
732
|
-
var parsedArgs = parseCLIArgs(process.argv.slice(2));
|
|
741
|
+
var parsedArgs = await parseCLIArgs(process.argv.slice(2));
|
|
733
742
|
if (typeof parsedArgs === "string") {
|
|
734
743
|
console.error(parsedArgs);
|
|
735
744
|
process.exit(2);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zgeoff/format-codemod",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Enforce blank-line padding conventions in TypeScript via a fast text-splice codemod",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
"typecheck": "tsc"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"
|
|
33
|
+
"gunshi": "1.0.0-rc.1",
|
|
34
|
+
"oxc-parser": "0.153.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
|
-
"@types/bun": "1.
|
|
37
|
-
"typescript": "7.0.
|
|
37
|
+
"@types/bun": "1.4.2",
|
|
38
|
+
"typescript": "7.0.2"
|
|
38
39
|
},
|
|
39
40
|
"engines": {
|
|
40
41
|
"bun": ">=1.3",
|