@kgdiff/cli 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +211 -2
- package/dist/apply-command.d.ts +34 -0
- package/dist/apply-command.d.ts.map +1 -0
- package/dist/apply-command.js +137 -0
- package/dist/apply-command.js.map +1 -0
- package/dist/args.d.ts +96 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +463 -0
- package/dist/args.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +17 -0
- package/dist/bin.js.map +1 -0
- package/dist/diff-command.d.ts +29 -0
- package/dist/diff-command.d.ts.map +1 -0
- package/dist/diff-command.js +236 -0
- package/dist/diff-command.js.map +1 -0
- package/dist/errors.d.ts +48 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +92 -0
- package/dist/errors.js.map +1 -0
- package/dist/help.d.ts +11 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +247 -0
- package/dist/help.js.map +1 -0
- package/dist/html.d.ts +53 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +107 -0
- package/dist/html.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs.d.ts +54 -0
- package/dist/inputs.d.ts.map +1 -0
- package/dist/inputs.js +209 -0
- package/dist/inputs.js.map +1 -0
- package/dist/io.d.ts +64 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +2 -0
- package/dist/io.js.map +1 -0
- package/dist/locale.d.ts +58 -0
- package/dist/locale.d.ts.map +1 -0
- package/dist/locale.js +121 -0
- package/dist/locale.js.map +1 -0
- package/dist/main.d.ts +10 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +51 -0
- package/dist/main.js.map +1 -0
- package/dist/markdown.d.ts +30 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +93 -0
- package/dist/markdown.js.map +1 -0
- package/dist/model.d.ts +63 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +151 -0
- package/dist/model.js.map +1 -0
- package/dist/node-io.d.ts +12 -0
- package/dist/node-io.d.ts.map +1 -0
- package/dist/node-io.js +135 -0
- package/dist/node-io.js.map +1 -0
- package/dist/output.d.ts +27 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +50 -0
- package/dist/output.js.map +1 -0
- package/dist/overwrite.d.ts +14 -0
- package/dist/overwrite.d.ts.map +1 -0
- package/dist/overwrite.js +55 -0
- package/dist/overwrite.js.map +1 -0
- package/dist/report.d.ts +52 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +64 -0
- package/dist/report.js.map +1 -0
- package/dist/style.d.ts +46 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/style.js +140 -0
- package/dist/style.js.map +1 -0
- package/dist/summary.d.ts +40 -0
- package/dist/summary.d.ts.map +1 -0
- package/dist/summary.js +352 -0
- package/dist/summary.js.map +1 -0
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/dist/width.d.ts +45 -0
- package/dist/width.d.ts.map +1 -0
- package/dist/width.js +232 -0
- package/dist/width.js.map +1 -0
- package/package.json +56 -3
- package/src/apply-command.ts +203 -0
- package/src/args.ts +605 -0
- package/src/bin.ts +22 -0
- package/src/diff-command.ts +299 -0
- package/src/errors.ts +131 -0
- package/src/help.ts +286 -0
- package/src/html.ts +145 -0
- package/src/index.ts +71 -0
- package/src/inputs.ts +269 -0
- package/src/io.ts +68 -0
- package/src/locale.ts +177 -0
- package/src/main.ts +56 -0
- package/src/markdown.ts +119 -0
- package/src/model.ts +181 -0
- package/src/node-io.ts +146 -0
- package/src/output.ts +81 -0
- package/src/overwrite.ts +75 -0
- package/src/report.ts +101 -0
- package/src/style.ts +164 -0
- package/src/summary.ts +440 -0
- package/src/version.ts +21 -0
- package/src/width.ts +222 -0
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub-flavoured Markdown summary for PR comments and `$GITHUB_STEP_SUMMARY`
|
|
3
|
+
* (docs/cli.md §Markdown summary): title, diffstat table, family legend and the hunk list
|
|
4
|
+
* grouped by phase in `<details>` blocks. No HTML beyond `<details>` / `<summary>`.
|
|
5
|
+
*/
|
|
6
|
+
import { formatHunk } from '@kgdiff/core';
|
|
7
|
+
import { formatInt, messages } from './locale.js';
|
|
8
|
+
import { groupByPhase, hunkFamily, hunkGlyph, overview } from './model.js';
|
|
9
|
+
import { totalsText } from './summary.js';
|
|
10
|
+
import { revealInvisible } from './width.js';
|
|
11
|
+
/** Hunks listed before "…and N more". */
|
|
12
|
+
export const MARKDOWN_HUNK_LIMIT = 100;
|
|
13
|
+
/** Groups start expanded when the whole list is at most this long. */
|
|
14
|
+
const OPEN_THRESHOLD = 30;
|
|
15
|
+
const FAMILY_SQUARE = {
|
|
16
|
+
added: '🟩',
|
|
17
|
+
removed: '🟥',
|
|
18
|
+
content: '🟨',
|
|
19
|
+
structure: '🟦',
|
|
20
|
+
identity: '🟪',
|
|
21
|
+
};
|
|
22
|
+
/** Zero-width space: invisible, but enough to stop GitHub's autolinkers and filters. */
|
|
23
|
+
const ZWSP = '\u200B';
|
|
24
|
+
/**
|
|
25
|
+
* Escape untrusted text for inline GFM.
|
|
26
|
+
*
|
|
27
|
+
* 1. Invisible and bidirectional controls become a visible `⟨U+202E⟩`; C0 controls and line
|
|
28
|
+
* breaks become spaces; C1 controls are dropped.
|
|
29
|
+
* 2. GitHub's post-Markdown filters are defused first (they act on the rendered text, so
|
|
30
|
+
* escaping alone does not stop them): a zero-width space breaks `:shortcode:` emoji,
|
|
31
|
+
* `@mentions`, `#123` / `org/repo#123` / `GH-123` references, bare `scheme://` URLs and
|
|
32
|
+
* `www.` autolinks.
|
|
33
|
+
* 3. Markdown punctuation (backslash, backtick, `*`, `_`, brackets, `|`, `~`, `#`, `$` for math)
|
|
34
|
+
* is backslash-escaped; `<`, `>` and `&` become entities, so no raw HTML gets through.
|
|
35
|
+
*/
|
|
36
|
+
export function escapeMarkdown(text) {
|
|
37
|
+
return (revealInvisible(text)
|
|
38
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: control characters are replaced on purpose.
|
|
39
|
+
.replace(/[\u0000-\u001f\u2028\u2029]+/g, ' ')
|
|
40
|
+
.replace(/[\u007f-\u009f]/g, '')
|
|
41
|
+
.replace(/:([a-z0-9_+-]+):/gi, `:${ZWSP}$1:`)
|
|
42
|
+
.replace(/\b(GH)-(?=\d)/gi, `$1${ZWSP}-`)
|
|
43
|
+
.replace(/([@#])(?=[\p{L}\p{N}_])/gu, `$1${ZWSP}`)
|
|
44
|
+
.replace(/:\/\//g, `://${ZWSP}`)
|
|
45
|
+
.replace(/\b(www)\./gi, `$1${ZWSP}.`)
|
|
46
|
+
.replace(/[\\`*_[\]|~#$]/g, '\\$&')
|
|
47
|
+
.replace(/&/g, '&')
|
|
48
|
+
.replace(/</g, '<')
|
|
49
|
+
.replace(/>/g, '>')
|
|
50
|
+
.trim());
|
|
51
|
+
}
|
|
52
|
+
/** Render the Markdown summary. Deterministic: no timestamps. */
|
|
53
|
+
export function renderMarkdown(diff, options) {
|
|
54
|
+
const m = messages(options.locale);
|
|
55
|
+
const ov = overview(diff);
|
|
56
|
+
const out = [`## kgdiff · ${escapeMarkdown(options.title)}`, ''];
|
|
57
|
+
const totals = escapeMarkdown(totalsText(diff, m));
|
|
58
|
+
if (ov.hunks === 0) {
|
|
59
|
+
const detail = m.identicalDetail(diff.stats.after.nodes, diff.stats.after.edges);
|
|
60
|
+
out.push(`✅ **${m.identical}.** ${escapeMarkdown(detail)}`, '');
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
out.push(`**${escapeMarkdown(m.changes(ov.changes, ov.hunks))}** · ${totals}`, '');
|
|
64
|
+
// Table cells are sentence-cased (a no-op for Chinese).
|
|
65
|
+
const t = Object.fromEntries(Object.entries(m.table).map(([k, v]) => [k, v.charAt(0).toUpperCase() + v.slice(1)]));
|
|
66
|
+
const { nodes, edges, before, after } = diff.stats;
|
|
67
|
+
const pair = (b, a) => `${formatInt(b)} → ${formatInt(a)}`;
|
|
68
|
+
out.push(`| | ${t.added} | ${t.removed} | ${t.modified} | ${t.unchanged} | ${t.total} |`, '| :-- | --: | --: | --: | --: | --: |', `| **${t.nodes}** | ${formatInt(nodes.added)} | ${formatInt(nodes.removed)} | ${formatInt(nodes.modified)} | ${formatInt(nodes.unchanged)} | ${pair(before.nodes, after.nodes)} |`, `| **${t.edges}** | ${formatInt(edges.added)} | ${formatInt(edges.removed)} | ${formatInt(edges.modified)} | ${formatInt(edges.unchanged)} | ${pair(before.edges, after.edges)} |`, '', m.markdown.legend, '');
|
|
69
|
+
let budget = MARKDOWN_HUNK_LIMIT;
|
|
70
|
+
const open = ov.hunks <= OPEN_THRESHOLD ? ' open' : '';
|
|
71
|
+
for (const group of groupByPhase(diff.hunks)) {
|
|
72
|
+
if (budget <= 0)
|
|
73
|
+
break;
|
|
74
|
+
const listed = group.hunks.slice(0, budget);
|
|
75
|
+
budget -= listed.length;
|
|
76
|
+
out.push(`<details${open}>`, `<summary>${m.phase[group.phase]} (${formatInt(group.hunks.length)})</summary>`, '');
|
|
77
|
+
for (const hunk of listed) {
|
|
78
|
+
const { title, subtitle } = formatHunk(hunk, diff, options.locale);
|
|
79
|
+
const family = hunkFamily(hunk);
|
|
80
|
+
const glyph = hunkGlyph(hunk) === '~' ? '\\~' : hunkGlyph(hunk);
|
|
81
|
+
const note = subtitle ? ` — *${escapeMarkdown(subtitle)}*` : '';
|
|
82
|
+
out.push(`- ${FAMILY_SQUARE[family]} ${glyph} ${escapeMarkdown(title)}${note}`);
|
|
83
|
+
}
|
|
84
|
+
out.push('', '</details>', '');
|
|
85
|
+
}
|
|
86
|
+
if (ov.hunks > MARKDOWN_HUNK_LIMIT) {
|
|
87
|
+
out.push(`*${escapeMarkdown(m.markdown.more(ov.hunks - MARKDOWN_HUNK_LIMIT))}*`, '');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
out.push(`*${escapeMarkdown(m.markdown.generatedBy(options.generator))}*`);
|
|
91
|
+
return `${out.join('\n')}\n`;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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"}
|
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation model shared by every text output: hunk families, glyphs, name-status letters,
|
|
3
|
+
* phase grouping and the per-phase counts behind the counters and the diffstat bar.
|
|
4
|
+
*/
|
|
5
|
+
import type { DiffResult, Hunk, HunkKind, ReplayPhase } from '@kgdiff/core';
|
|
6
|
+
/** The five meaning families of docs/visual-language.md (mirrors `@kgdiff/scene`). */
|
|
7
|
+
export type ChangeFamily = 'added' | 'removed' | 'content' | 'structure' | 'identity';
|
|
8
|
+
/**
|
|
9
|
+
* Family of each hunk kind. Identical to `hunkFamily` in `@kgdiff/scene` (a test enforces it);
|
|
10
|
+
* duplicated so text outputs do not load the scene and layout modules.
|
|
11
|
+
*/
|
|
12
|
+
export declare const KIND_FAMILY: Readonly<Record<HunkKind, ChangeFamily>>;
|
|
13
|
+
/**
|
|
14
|
+
* Family a hunk is shown with: its kind's family, except that a `modify` hunk made only of
|
|
15
|
+
* hierarchy moves (phase `restructure`) is `structure`, as its node is drawn
|
|
16
|
+
* (docs/visual-language.md: move → structure).
|
|
17
|
+
*/
|
|
18
|
+
export declare function hunkFamily(hunk: Hunk): ChangeFamily;
|
|
19
|
+
/** One-character glyph of a hunk: `+ − ~ ⇄ ⊕ ⑂`. */
|
|
20
|
+
export declare function hunkGlyph(hunk: Hunk): string;
|
|
21
|
+
export type NameStatus = 'A' | 'D' | 'M' | 'R' | 'V' | 'G' | 'S' | 'E';
|
|
22
|
+
/**
|
|
23
|
+
* `--name-status` letter: `A` added, `D` removed, `M` modified, `R` renamed, `V` moved,
|
|
24
|
+
* `G` merged, `S` split, `E` relations. A modify hunk is `R` when its node was renamed, else `V`
|
|
25
|
+
* when it moved in the hierarchy, else `M`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function nameStatus(hunk: Hunk, diff: DiffResult): NameStatus;
|
|
28
|
+
/**
|
|
29
|
+
* Order of the phase groups in hunk lists: the replay order ("clean up, restructure, refine,
|
|
30
|
+
* grow"), shared with the viewer's change list and the Markdown summary.
|
|
31
|
+
*/
|
|
32
|
+
export declare const LIST_PHASES: readonly ReplayPhase[];
|
|
33
|
+
/** Order of the counters and the diffstat bar segments. */
|
|
34
|
+
export declare const COUNTER_PHASES: readonly ReplayPhase[];
|
|
35
|
+
/** Counter glyph and family of each phase. */
|
|
36
|
+
export declare const PHASE_GLYPH: Readonly<Record<ReplayPhase, string>>;
|
|
37
|
+
export declare const PHASE_FAMILY: Readonly<Record<ReplayPhase, ChangeFamily>>;
|
|
38
|
+
export interface PhaseCount {
|
|
39
|
+
/** Hunks in the phase. */
|
|
40
|
+
readonly hunks: number;
|
|
41
|
+
/** Changed elements (nodes + edges) owned by those hunks. */
|
|
42
|
+
readonly changes: number;
|
|
43
|
+
}
|
|
44
|
+
export interface Overview {
|
|
45
|
+
readonly phases: Readonly<Record<ReplayPhase, PhaseCount>>;
|
|
46
|
+
/** Changed elements (every changed node and edge belongs to exactly one hunk). */
|
|
47
|
+
readonly changes: number;
|
|
48
|
+
readonly hunks: number;
|
|
49
|
+
}
|
|
50
|
+
/** Per-phase hunk and change counts. O(hunks). */
|
|
51
|
+
export declare function overview(diff: DiffResult): Overview;
|
|
52
|
+
/** Hunks in list order: grouped by `LIST_PHASES`, each group in review order. */
|
|
53
|
+
export declare function groupByPhase(hunks: readonly Hunk[]): {
|
|
54
|
+
phase: ReplayPhase;
|
|
55
|
+
hunks: Hunk[];
|
|
56
|
+
}[];
|
|
57
|
+
/**
|
|
58
|
+
* Split `total` cells among `weights` proportionally (largest remainder); every positive weight
|
|
59
|
+
* gets at least one cell when `total` allows. Deterministic; ties go to the earlier entry.
|
|
60
|
+
*/
|
|
61
|
+
export declare function apportion(weights: readonly number[], total: number): number[];
|
|
62
|
+
export declare function assertNever(value: never): never;
|
|
63
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE5E,sFAAsF;AACtF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAEtF;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAOhE,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAGnD;AAED,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAiB5C;AAED,MAAM,MAAM,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEvE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,CAqBnE;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,WAAW,EAA+C,CAAC;AAE9F,2DAA2D;AAC3D,eAAO,MAAM,cAAc,EAAE,SAAS,WAAW,EAA+C,CAAC;AAEjG,8CAA8C;AAC9C,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAK7D,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAKpE,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC;IAC3D,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,kDAAkD;AAClD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,CAenD;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,EAAE,CAK5F;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B7E;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C"}
|
package/dist/model.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family of each hunk kind. Identical to `hunkFamily` in `@kgdiff/scene` (a test enforces it);
|
|
3
|
+
* duplicated so text outputs do not load the scene and layout modules.
|
|
4
|
+
*/
|
|
5
|
+
export const KIND_FAMILY = {
|
|
6
|
+
add: 'added',
|
|
7
|
+
remove: 'removed',
|
|
8
|
+
merge: 'identity',
|
|
9
|
+
split: 'identity',
|
|
10
|
+
relations: 'structure',
|
|
11
|
+
modify: 'content',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Family a hunk is shown with: its kind's family, except that a `modify` hunk made only of
|
|
15
|
+
* hierarchy moves (phase `restructure`) is `structure`, as its node is drawn
|
|
16
|
+
* (docs/visual-language.md: move → structure).
|
|
17
|
+
*/
|
|
18
|
+
export function hunkFamily(hunk) {
|
|
19
|
+
if (hunk.kind === 'modify' && hunk.phase === 'restructure')
|
|
20
|
+
return 'structure';
|
|
21
|
+
return KIND_FAMILY[hunk.kind];
|
|
22
|
+
}
|
|
23
|
+
/** One-character glyph of a hunk: `+ − ~ ⇄ ⊕ ⑂`. */
|
|
24
|
+
export function hunkGlyph(hunk) {
|
|
25
|
+
switch (hunk.kind) {
|
|
26
|
+
case 'add':
|
|
27
|
+
return '+';
|
|
28
|
+
case 'remove':
|
|
29
|
+
return '−';
|
|
30
|
+
case 'merge':
|
|
31
|
+
return '⊕';
|
|
32
|
+
case 'split':
|
|
33
|
+
return '⑂';
|
|
34
|
+
case 'relations':
|
|
35
|
+
return '⇄';
|
|
36
|
+
case 'modify':
|
|
37
|
+
return hunk.phase === 'restructure' ? '⇄' : '~';
|
|
38
|
+
default:
|
|
39
|
+
return assertNever(hunk.kind);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `--name-status` letter: `A` added, `D` removed, `M` modified, `R` renamed, `V` moved,
|
|
44
|
+
* `G` merged, `S` split, `E` relations. A modify hunk is `R` when its node was renamed, else `V`
|
|
45
|
+
* when it moved in the hierarchy, else `M`.
|
|
46
|
+
*/
|
|
47
|
+
export function nameStatus(hunk, diff) {
|
|
48
|
+
switch (hunk.kind) {
|
|
49
|
+
case 'add':
|
|
50
|
+
return 'A';
|
|
51
|
+
case 'remove':
|
|
52
|
+
return 'D';
|
|
53
|
+
case 'merge':
|
|
54
|
+
return 'G';
|
|
55
|
+
case 'split':
|
|
56
|
+
return 'S';
|
|
57
|
+
case 'relations':
|
|
58
|
+
return 'E';
|
|
59
|
+
case 'modify': {
|
|
60
|
+
const facets = diff.index.node(hunk.anchor)?.facets ?? [];
|
|
61
|
+
if (facets.some((f) => f.kind === 'rename'))
|
|
62
|
+
return 'R';
|
|
63
|
+
if (facets.some((f) => f.kind === 'move'))
|
|
64
|
+
return 'V';
|
|
65
|
+
return 'M';
|
|
66
|
+
}
|
|
67
|
+
default:
|
|
68
|
+
return assertNever(hunk.kind);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Order of the phase groups in hunk lists: the replay order ("clean up, restructure, refine,
|
|
73
|
+
* grow"), shared with the viewer's change list and the Markdown summary.
|
|
74
|
+
*/
|
|
75
|
+
export const LIST_PHASES = ['remove', 'restructure', 'modify', 'add'];
|
|
76
|
+
/** Order of the counters and the diffstat bar segments. */
|
|
77
|
+
export const COUNTER_PHASES = ['add', 'remove', 'modify', 'restructure'];
|
|
78
|
+
/** Counter glyph and family of each phase. */
|
|
79
|
+
export const PHASE_GLYPH = {
|
|
80
|
+
add: '+',
|
|
81
|
+
remove: '−',
|
|
82
|
+
modify: '~',
|
|
83
|
+
restructure: '⇄',
|
|
84
|
+
};
|
|
85
|
+
export const PHASE_FAMILY = {
|
|
86
|
+
add: 'added',
|
|
87
|
+
remove: 'removed',
|
|
88
|
+
modify: 'content',
|
|
89
|
+
restructure: 'structure',
|
|
90
|
+
};
|
|
91
|
+
/** Per-phase hunk and change counts. O(hunks). */
|
|
92
|
+
export function overview(diff) {
|
|
93
|
+
const phases = {
|
|
94
|
+
add: { hunks: 0, changes: 0 },
|
|
95
|
+
remove: { hunks: 0, changes: 0 },
|
|
96
|
+
modify: { hunks: 0, changes: 0 },
|
|
97
|
+
restructure: { hunks: 0, changes: 0 },
|
|
98
|
+
};
|
|
99
|
+
let changes = 0;
|
|
100
|
+
for (const h of diff.hunks) {
|
|
101
|
+
const n = h.nodes.length + h.edges.length;
|
|
102
|
+
phases[h.phase].hunks++;
|
|
103
|
+
phases[h.phase].changes += n;
|
|
104
|
+
changes += n;
|
|
105
|
+
}
|
|
106
|
+
return { phases, changes, hunks: diff.hunks.length };
|
|
107
|
+
}
|
|
108
|
+
/** Hunks in list order: grouped by `LIST_PHASES`, each group in review order. */
|
|
109
|
+
export function groupByPhase(hunks) {
|
|
110
|
+
return LIST_PHASES.map((phase) => ({
|
|
111
|
+
phase,
|
|
112
|
+
hunks: hunks.filter((h) => h.phase === phase).sort((a, b) => a.order - b.order),
|
|
113
|
+
})).filter((g) => g.hunks.length > 0);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Split `total` cells among `weights` proportionally (largest remainder); every positive weight
|
|
117
|
+
* gets at least one cell when `total` allows. Deterministic; ties go to the earlier entry.
|
|
118
|
+
*/
|
|
119
|
+
export function apportion(weights, total) {
|
|
120
|
+
const sum = weights.reduce((a, b) => a + b, 0);
|
|
121
|
+
if (sum <= 0 || total <= 0)
|
|
122
|
+
return weights.map(() => 0);
|
|
123
|
+
const exact = weights.map((w) => (w / sum) * total);
|
|
124
|
+
const cells = exact.map((x, i) => (weights[i] > 0 ? Math.max(1, Math.floor(x)) : 0));
|
|
125
|
+
let used = cells.reduce((a, b) => a + b, 0);
|
|
126
|
+
const byRemainder = exact
|
|
127
|
+
.map((x, i) => ({ i, r: x - Math.floor(x) }))
|
|
128
|
+
.sort((a, b) => b.r - a.r || a.i - b.i);
|
|
129
|
+
for (let k = 0; used < total && k < byRemainder.length * 2; k++) {
|
|
130
|
+
const { i } = byRemainder[k % byRemainder.length];
|
|
131
|
+
if (weights[i] > 0) {
|
|
132
|
+
cells[i] = cells[i] + 1;
|
|
133
|
+
used++;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Minimum cells may overshoot a tiny total: take back from the largest segments.
|
|
137
|
+
while (used > total) {
|
|
138
|
+
let largest = 0;
|
|
139
|
+
for (let i = 1; i < cells.length; i++) {
|
|
140
|
+
if (cells[i] > cells[largest])
|
|
141
|
+
largest = i;
|
|
142
|
+
}
|
|
143
|
+
cells[largest] = cells[largest] - 1;
|
|
144
|
+
used--;
|
|
145
|
+
}
|
|
146
|
+
return cells;
|
|
147
|
+
}
|
|
148
|
+
export function assertNever(value) {
|
|
149
|
+
throw new Error(`Unexpected value: ${String(value)}`);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CliFileSystem, CliIO } from './io.js';
|
|
2
|
+
/** The real file system (exported for tests that exercise links and case variants). */
|
|
3
|
+
export declare function nodeFileSystem(): CliFileSystem;
|
|
4
|
+
/** Command that opens a file with the default application on this platform. */
|
|
5
|
+
export declare function openCommand(platform: NodeJS.Platform, path: string): {
|
|
6
|
+
command: string;
|
|
7
|
+
args: string[];
|
|
8
|
+
verbatim: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** `CliIO` bound to the current process. */
|
|
11
|
+
export declare function nodeIO(): CliIO;
|
|
12
|
+
//# sourceMappingURL=node-io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-io.d.ts","sourceRoot":"","sources":["../src/node-io.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAgB,MAAM,SAAS,CAAC;AAmClE,uFAAuF;AACvF,wBAAgB,cAAc,IAAI,aAAa,CAiB9C;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,IAAI,EAAE,MAAM,GACX;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAQxD;AAiDD,4CAA4C;AAC5C,wBAAgB,MAAM,IAAI,KAAK,CAiB9B"}
|
package/dist/node-io.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The real `CliIO`: process streams, the file system, the platform opener and the viewer
|
|
3
|
+
* bundles resolved from `@kgdiff/viewer/standalone` and `@kgdiff/viewer/standalone/compute`.
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
import { randomBytes } from 'node:crypto';
|
|
7
|
+
import { chmod, mkdtemp, readFile, realpath, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import { basename, dirname, join } from 'node:path';
|
|
11
|
+
import { CliError, systemErrorCode } from './errors.js';
|
|
12
|
+
async function readStdin(maxBytes) {
|
|
13
|
+
const chunks = [];
|
|
14
|
+
let size = 0;
|
|
15
|
+
for await (const chunk of process.stdin) {
|
|
16
|
+
const buffer = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
17
|
+
size += buffer.byteLength;
|
|
18
|
+
if (size > maxBytes) {
|
|
19
|
+
process.stdin.destroy();
|
|
20
|
+
throw new RangeError(`stdin is larger than ${maxBytes} bytes`);
|
|
21
|
+
}
|
|
22
|
+
chunks.push(buffer);
|
|
23
|
+
}
|
|
24
|
+
return Buffer.concat(chunks);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Atomic replace: write `.<name>.<random>.tmp` next to `path` (exclusive create), copy the
|
|
28
|
+
* permissions of an existing file, then rename over `path`. The temporary file is removed on
|
|
29
|
+
* failure.
|
|
30
|
+
*/
|
|
31
|
+
async function writeFileAtomic(path, data) {
|
|
32
|
+
const temp = join(dirname(path), `.${basename(path)}.${randomBytes(6).toString('hex')}.tmp`);
|
|
33
|
+
try {
|
|
34
|
+
await writeFile(temp, data, { flag: 'wx', mode: 0o666 });
|
|
35
|
+
const existing = await stat(path).catch(() => undefined);
|
|
36
|
+
if (existing)
|
|
37
|
+
await chmod(temp, existing.mode & 0o7777);
|
|
38
|
+
await rename(temp, path);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
await rm(temp, { force: true }).catch(() => undefined);
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** The real file system (exported for tests that exercise links and case variants). */
|
|
46
|
+
export function nodeFileSystem() {
|
|
47
|
+
return {
|
|
48
|
+
readFile: (path) => readFile(path),
|
|
49
|
+
writeFile: writeFileAtomic,
|
|
50
|
+
stat: async (path) => {
|
|
51
|
+
try {
|
|
52
|
+
const s = await stat(path);
|
|
53
|
+
return { dev: s.dev, ino: s.ino, size: s.size };
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (systemErrorCode(error) === 'ENOENT' || systemErrorCode(error) === 'ENOTDIR') {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
realpath: (path) => realpath(path),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** Command that opens a file with the default application on this platform. */
|
|
66
|
+
export function openCommand(platform, path) {
|
|
67
|
+
if (platform === 'darwin')
|
|
68
|
+
return { command: 'open', args: [path], verbatim: false };
|
|
69
|
+
if (platform === 'win32') {
|
|
70
|
+
// `start` takes its first quoted argument as a window title, hence the empty "". With /s,
|
|
71
|
+
// cmd strips the outer quotes and runs the rest verbatim.
|
|
72
|
+
return { command: 'cmd', args: ['/d', '/s', '/c', `"start "" "${path}""`], verbatim: true };
|
|
73
|
+
}
|
|
74
|
+
return { command: 'xdg-open', args: [path], verbatim: false };
|
|
75
|
+
}
|
|
76
|
+
function openFile(path) {
|
|
77
|
+
const { command, args, verbatim } = openCommand(process.platform, path);
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
const child = spawn(command, args, {
|
|
80
|
+
stdio: 'ignore',
|
|
81
|
+
detached: true,
|
|
82
|
+
windowsHide: true,
|
|
83
|
+
windowsVerbatimArguments: verbatim,
|
|
84
|
+
});
|
|
85
|
+
child.once('error', reject);
|
|
86
|
+
child.once('spawn', () => {
|
|
87
|
+
child.unref();
|
|
88
|
+
resolve();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const VIEWER_SPECIFIERS = {
|
|
93
|
+
main: '@kgdiff/viewer/standalone',
|
|
94
|
+
compute: '@kgdiff/viewer/standalone/compute',
|
|
95
|
+
};
|
|
96
|
+
async function loadViewerBundle(part) {
|
|
97
|
+
const specifier = VIEWER_SPECIFIERS[part];
|
|
98
|
+
const what = part === 'main' ? 'standalone viewer bundle' : 'viewer compute add-on';
|
|
99
|
+
const hint = 'Build it with `pnpm --filter @kgdiff/viewer build` (development) or reinstall kgdiff.';
|
|
100
|
+
let path;
|
|
101
|
+
try {
|
|
102
|
+
path = createRequire(import.meta.url).resolve(specifier);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
throw new CliError('viewer-missing', `The HTML report needs the ${what} (${specifier}), which was not found.`, hint, { cause: error });
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
return await readFile(path, 'utf8');
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
throw new CliError('viewer-missing', `Cannot read the ${what} at ${path}.`, hint, {
|
|
112
|
+
cause: error,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** `CliIO` bound to the current process. */
|
|
117
|
+
export function nodeIO() {
|
|
118
|
+
return {
|
|
119
|
+
stdout: process.stdout,
|
|
120
|
+
stderr: process.stderr,
|
|
121
|
+
readStdin,
|
|
122
|
+
fs: nodeFileSystem(),
|
|
123
|
+
env: process.env,
|
|
124
|
+
cwd: process.cwd(),
|
|
125
|
+
isTTY: process.stdout.isTTY === true,
|
|
126
|
+
stderrIsTTY: process.stderr.isTTY === true,
|
|
127
|
+
stdinIsTTY: process.stdin.isTTY === true,
|
|
128
|
+
columns: process.stdout.isTTY ? process.stdout.columns : undefined,
|
|
129
|
+
now: () => new Date(),
|
|
130
|
+
makeTempDir: () => mkdtemp(join(tmpdir(), 'kgdiff-')),
|
|
131
|
+
openFile,
|
|
132
|
+
loadViewerBundle,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=node-io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-io.js","sourceRoot":"","sources":["../src/node-io.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared output plumbing of the commands: painters for stdout / stderr, the resolved locale,
|
|
3
|
+
* `--quiet`, and writing output files with a short notice on stderr.
|
|
4
|
+
*/
|
|
5
|
+
import type { Locale } from '@kgdiff/core';
|
|
6
|
+
import type { CommonOptions } from './args.js';
|
|
7
|
+
import type { CliIO } from './io.js';
|
|
8
|
+
import { type Painter } from './style.js';
|
|
9
|
+
export interface OutputContext {
|
|
10
|
+
readonly io: CliIO;
|
|
11
|
+
readonly locale: Locale;
|
|
12
|
+
/** Painter for stdout. */
|
|
13
|
+
readonly paint: Painter;
|
|
14
|
+
/** Painter for stderr. */
|
|
15
|
+
readonly errPaint: Painter;
|
|
16
|
+
readonly quiet: boolean;
|
|
17
|
+
/** Write to stdout unless `--quiet`. */
|
|
18
|
+
stdout(text: string): void;
|
|
19
|
+
/** Write a notice or warning to stderr unless `--quiet`. */
|
|
20
|
+
notice(text: string): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function outputContext(io: CliIO, options: CommonOptions): OutputContext;
|
|
23
|
+
/** `1.2 MB`, `512 kB`, `90 B` (decimal units, like most file managers). */
|
|
24
|
+
export declare function formatSize(bytes: number): string;
|
|
25
|
+
/** Write an output file and report it on stderr (`✓ Wrote report.html (1.2 MB)`). */
|
|
26
|
+
export declare function writeOutputFile(ctx: OutputContext, path: string, content: string, label: string): Promise<void>;
|
|
27
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAoC,KAAK,OAAO,EAAqB,MAAM,YAAY,CAAC;AAG/F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,wCAAwC;IACxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,4DAA4D;IAC5D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,GAAG,aAAa,CAe9E;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAQD,qFAAqF;AACrF,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CliError, systemErrorCode, systemReason } from './errors.js';
|
|
2
|
+
import { resolvePath } from './inputs.js';
|
|
3
|
+
import { resolveLocale } from './locale.js';
|
|
4
|
+
import { createPainter, isLightBackground, resolveColorLevel } from './style.js';
|
|
5
|
+
import { sanitize } from './width.js';
|
|
6
|
+
export function outputContext(io, options) {
|
|
7
|
+
const light = isLightBackground(io.env);
|
|
8
|
+
return {
|
|
9
|
+
io,
|
|
10
|
+
locale: resolveLocale(options.locale, io.env),
|
|
11
|
+
paint: createPainter(resolveColorLevel(options.color, io.env, io.isTTY), light),
|
|
12
|
+
errPaint: createPainter(resolveColorLevel(options.color, io.env, io.stderrIsTTY), light),
|
|
13
|
+
quiet: options.quiet,
|
|
14
|
+
stdout: (text) => {
|
|
15
|
+
if (!options.quiet && text)
|
|
16
|
+
io.stdout.write(text);
|
|
17
|
+
},
|
|
18
|
+
notice: (text) => {
|
|
19
|
+
if (!options.quiet)
|
|
20
|
+
io.stderr.write(text);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** `1.2 MB`, `512 kB`, `90 B` (decimal units, like most file managers). */
|
|
25
|
+
export function formatSize(bytes) {
|
|
26
|
+
if (bytes < 1000)
|
|
27
|
+
return `${bytes} B`;
|
|
28
|
+
if (bytes < 1_000_000)
|
|
29
|
+
return `${(bytes / 1000).toFixed(bytes < 10_000 ? 1 : 0)} kB`;
|
|
30
|
+
return `${(bytes / 1_000_000).toFixed(1)} MB`;
|
|
31
|
+
}
|
|
32
|
+
const WRITE_HINTS = {
|
|
33
|
+
ENOENT: 'Create the directory first.',
|
|
34
|
+
EISDIR: 'Pass a file name, not a directory.',
|
|
35
|
+
EACCES: 'Check the permissions of the directory.',
|
|
36
|
+
};
|
|
37
|
+
/** Write an output file and report it on stderr (`✓ Wrote report.html (1.2 MB)`). */
|
|
38
|
+
export async function writeOutputFile(ctx, path, content, label) {
|
|
39
|
+
const data = new TextEncoder().encode(content);
|
|
40
|
+
try {
|
|
41
|
+
await ctx.io.fs.writeFile(resolvePath(ctx.io, path), data);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const code = systemErrorCode(error);
|
|
45
|
+
throw new CliError('output', `Cannot write ${label} to "${sanitize(path)}": ${systemReason(error)}.`, (code && WRITE_HINTS[code]) || undefined, { cause: error });
|
|
46
|
+
}
|
|
47
|
+
const p = ctx.errPaint;
|
|
48
|
+
ctx.notice(`${p.tone('added', '✓')} Wrote ${label} ${p.bold(sanitize(path))} ${p.dim(`(${formatSize(data.byteLength)})`)}\n`);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CliIO } from './io.js';
|
|
2
|
+
export interface PathRole {
|
|
3
|
+
/** How the path was given, for messages (`<before>`, `--json`, `-o`). */
|
|
4
|
+
readonly role: string;
|
|
5
|
+
/** Path as given; `-` (stdin / stdout) and `undefined` are ignored. */
|
|
6
|
+
readonly path: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
/** Identity of the file at `path`: `inode:dev:ino` when it exists, else a canonical path. */
|
|
9
|
+
export declare function fileIdentity(io: CliIO, path: string): Promise<string>;
|
|
10
|
+
/**
|
|
11
|
+
* @throws CliError `usage` when an output is one of the inputs or two outputs are one file.
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkNoOverwrite(io: CliIO, inputs: readonly PathRole[], outputs: readonly PathRole[]): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=overwrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overwrite.d.ts","sourceRoot":"","sources":["../src/overwrite.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGrC,MAAM,WAAW,QAAQ;IACvB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,6FAA6F;AAC7F,wBAAsB,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa3E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,KAAK,EACT,MAAM,EAAE,SAAS,QAAQ,EAAE,EAC3B,OAAO,EAAE,SAAS,QAAQ,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
|