@kgdiff/cli 0.0.0-stage → 0.1.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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -2
  3. package/dist/apply-command.d.ts +34 -0
  4. package/dist/apply-command.d.ts.map +1 -0
  5. package/dist/apply-command.js +135 -0
  6. package/dist/apply-command.js.map +1 -0
  7. package/dist/args.d.ts +96 -0
  8. package/dist/args.d.ts.map +1 -0
  9. package/dist/args.js +463 -0
  10. package/dist/args.js.map +1 -0
  11. package/dist/bin.d.ts +3 -0
  12. package/dist/bin.d.ts.map +1 -0
  13. package/dist/bin.js +17 -0
  14. package/dist/bin.js.map +1 -0
  15. package/dist/diff-command.d.ts +29 -0
  16. package/dist/diff-command.d.ts.map +1 -0
  17. package/dist/diff-command.js +236 -0
  18. package/dist/diff-command.js.map +1 -0
  19. package/dist/errors.d.ts +48 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +92 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/help.d.ts +11 -0
  24. package/dist/help.d.ts.map +1 -0
  25. package/dist/help.js +247 -0
  26. package/dist/help.js.map +1 -0
  27. package/dist/html.d.ts +53 -0
  28. package/dist/html.d.ts.map +1 -0
  29. package/dist/html.js +107 -0
  30. package/dist/html.js.map +1 -0
  31. package/dist/index.d.ts +25 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +24 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/inputs.d.ts +54 -0
  36. package/dist/inputs.d.ts.map +1 -0
  37. package/dist/inputs.js +204 -0
  38. package/dist/inputs.js.map +1 -0
  39. package/dist/io.d.ts +64 -0
  40. package/dist/io.d.ts.map +1 -0
  41. package/dist/io.js +2 -0
  42. package/dist/io.js.map +1 -0
  43. package/dist/locale.d.ts +58 -0
  44. package/dist/locale.d.ts.map +1 -0
  45. package/dist/locale.js +121 -0
  46. package/dist/locale.js.map +1 -0
  47. package/dist/main.d.ts +10 -0
  48. package/dist/main.d.ts.map +1 -0
  49. package/dist/main.js +51 -0
  50. package/dist/main.js.map +1 -0
  51. package/dist/markdown.d.ts +30 -0
  52. package/dist/markdown.d.ts.map +1 -0
  53. package/dist/markdown.js +93 -0
  54. package/dist/markdown.js.map +1 -0
  55. package/dist/model.d.ts +63 -0
  56. package/dist/model.d.ts.map +1 -0
  57. package/dist/model.js +151 -0
  58. package/dist/model.js.map +1 -0
  59. package/dist/node-io.d.ts +12 -0
  60. package/dist/node-io.d.ts.map +1 -0
  61. package/dist/node-io.js +135 -0
  62. package/dist/node-io.js.map +1 -0
  63. package/dist/output.d.ts +27 -0
  64. package/dist/output.d.ts.map +1 -0
  65. package/dist/output.js +50 -0
  66. package/dist/output.js.map +1 -0
  67. package/dist/overwrite.d.ts +14 -0
  68. package/dist/overwrite.d.ts.map +1 -0
  69. package/dist/overwrite.js +55 -0
  70. package/dist/overwrite.js.map +1 -0
  71. package/dist/report.d.ts +52 -0
  72. package/dist/report.d.ts.map +1 -0
  73. package/dist/report.js +64 -0
  74. package/dist/report.js.map +1 -0
  75. package/dist/style.d.ts +46 -0
  76. package/dist/style.d.ts.map +1 -0
  77. package/dist/style.js +140 -0
  78. package/dist/style.js.map +1 -0
  79. package/dist/summary.d.ts +40 -0
  80. package/dist/summary.d.ts.map +1 -0
  81. package/dist/summary.js +352 -0
  82. package/dist/summary.js.map +1 -0
  83. package/dist/version.d.ts +6 -0
  84. package/dist/version.d.ts.map +1 -0
  85. package/dist/version.js +19 -0
  86. package/dist/version.js.map +1 -0
  87. package/dist/width.d.ts +45 -0
  88. package/dist/width.d.ts.map +1 -0
  89. package/dist/width.js +232 -0
  90. package/dist/width.js.map +1 -0
  91. package/package.json +56 -3
  92. package/src/apply-command.ts +201 -0
  93. package/src/args.ts +605 -0
  94. package/src/bin.ts +22 -0
  95. package/src/diff-command.ts +299 -0
  96. package/src/errors.ts +131 -0
  97. package/src/help.ts +286 -0
  98. package/src/html.ts +145 -0
  99. package/src/index.ts +71 -0
  100. package/src/inputs.ts +264 -0
  101. package/src/io.ts +68 -0
  102. package/src/locale.ts +177 -0
  103. package/src/main.ts +56 -0
  104. package/src/markdown.ts +119 -0
  105. package/src/model.ts +181 -0
  106. package/src/node-io.ts +146 -0
  107. package/src/output.ts +81 -0
  108. package/src/overwrite.ts +75 -0
  109. package/src/report.ts +101 -0
  110. package/src/style.ts +164 -0
  111. package/src/summary.ts +440 -0
  112. package/src/version.ts +21 -0
  113. package/src/width.ts +222 -0
package/dist/inputs.js ADDED
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Reading inputs: files or stdin, gzip-compressed or not, UTF-8 / UTF-16 text, parsed with
3
+ * `@kgdiff/formats`. Failures become `CliError`s that name the file and suggest a fix.
4
+ */
5
+ import { basename, resolve } from 'node:path';
6
+ import { parseGraph } from '@kgdiff/formats';
7
+ import { FORMATS, STDIO } from './args.js';
8
+ import { CliError, isKgdiffError, systemErrorCode, systemReason } from './errors.js';
9
+ import { sanitize } from './width.js';
10
+ export const FORMAT_NAMES = {
11
+ json: 'JSON',
12
+ jsonld: 'JSON-LD',
13
+ turtle: 'Turtle',
14
+ ntriples: 'N-Triples',
15
+ nquads: 'N-Quads',
16
+ trig: 'TriG',
17
+ rdfxml: 'RDF/XML',
18
+ obo: 'OBO',
19
+ };
20
+ const READ_HINTS = {
21
+ ENOENT: 'Check the path. Use - to read from stdin.',
22
+ EISDIR: 'Pass a file, not a directory.',
23
+ EACCES: 'Check the file permissions.',
24
+ };
25
+ /** Resolve a user-supplied path against the IO's working directory. */
26
+ export function resolvePath(io, path) {
27
+ return resolve(io.cwd, path);
28
+ }
29
+ /** Default input size limit (bytes, after decompression): 1 GiB. */
30
+ export const DEFAULT_MAX_INPUT = 1024 ** 3;
31
+ const SIZE_UNITS = { '': 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3 };
32
+ /**
33
+ * Input size limit: `KGDIFF_MAX_INPUT` (bytes, or with a binary `K` / `M` / `G` suffix, e.g.
34
+ * `4G`), else `DEFAULT_MAX_INPUT`. Applies to files, stdin and decompressed gzip data.
35
+ *
36
+ * @throws CliError `usage` for an unreadable value.
37
+ */
38
+ export function maxInputBytes(env) {
39
+ const raw = env.KGDIFF_MAX_INPUT?.trim();
40
+ if (!raw)
41
+ return DEFAULT_MAX_INPUT;
42
+ const match = /^(\d+(?:\.\d+)?)\s*([kmg]?)i?b?$/i.exec(raw);
43
+ const value = match ? Number(match[1]) * (SIZE_UNITS[(match[2] ?? '').toLowerCase()] ?? 1) : NaN;
44
+ if (!Number.isFinite(value) || value < 1) {
45
+ throw new CliError('usage', `Invalid KGDIFF_MAX_INPUT "${sanitize(raw)}".`, 'Use a byte count such as 2147483648, or 512M / 2G.');
46
+ }
47
+ return Math.floor(value);
48
+ }
49
+ function formatBytes(bytes) {
50
+ for (const [unit, size] of [
51
+ ['GiB', 1024 ** 3],
52
+ ['MiB', 1024 ** 2],
53
+ ['KiB', 1024],
54
+ ]) {
55
+ if (bytes >= size)
56
+ return `${Number((bytes / size).toFixed(1))} ${unit}`;
57
+ }
58
+ return `${bytes} B`;
59
+ }
60
+ function tooLarge(where, limit, cause) {
61
+ return new CliError('input', `${where} is too large: the input limit is ${formatBytes(limit)}.`, 'If the input is genuine, raise the limit with KGDIFF_MAX_INPUT (e.g. KGDIFF_MAX_INPUT=4G).', cause === undefined ? undefined : { cause });
62
+ }
63
+ function isTooLarge(error) {
64
+ const code = error?.code;
65
+ return (error instanceof RangeError ||
66
+ code === 'ERR_BUFFER_TOO_LARGE' ||
67
+ code === 'ERR_FS_FILE_TOO_LARGE' ||
68
+ code === 'ERR_STRING_TOO_LONG');
69
+ }
70
+ /**
71
+ * Decode input bytes: gunzip when gzip-compressed (output capped at `limit`, so a gzip bomb is
72
+ * an error, not an out-of-memory crash), UTF-16 by BOM, else strict UTF-8.
73
+ */
74
+ export async function decodeText(bytes, where, limit) {
75
+ let data = bytes;
76
+ if (data[0] === 0x1f && data[1] === 0x8b) {
77
+ const { gunzipSync } = await import('node:zlib');
78
+ try {
79
+ data = gunzipSync(data, { maxOutputLength: limit });
80
+ }
81
+ catch (error) {
82
+ if (isTooLarge(error))
83
+ throw tooLarge(`${where} (decompressed)`, limit, error);
84
+ throw new CliError('input', `Cannot decompress ${where}: ${systemReason(error)}.`, undefined, {
85
+ cause: error,
86
+ });
87
+ }
88
+ }
89
+ const encoding = data[0] === 0xff && data[1] === 0xfe
90
+ ? 'utf-16le'
91
+ : data[0] === 0xfe && data[1] === 0xff
92
+ ? 'utf-16be'
93
+ : 'utf-8';
94
+ try {
95
+ return new TextDecoder(encoding, { fatal: true }).decode(data);
96
+ }
97
+ catch (error) {
98
+ if (isTooLarge(error))
99
+ throw tooLarge(where, limit, error);
100
+ throw new CliError('input', `${where} is not valid ${encoding.toUpperCase()} text.`, `kgdiff reads text formats (${Object.values(FORMAT_NAMES).join(', ')}). Convert binary formats first.`, { cause: error });
101
+ }
102
+ }
103
+ /**
104
+ * Read a file (or stdin for `-`) as text. `role` names the argument in messages. Inputs above
105
+ * the size limit, and empty inputs unless `allowEmpty`, are errors.
106
+ */
107
+ export async function readInput(io, path, role, options = {}) {
108
+ const limit = maxInputBytes(io.env);
109
+ let raw;
110
+ if (path === STDIO) {
111
+ if (io.stdinIsTTY) {
112
+ io.stderr.write(`Reading ${role} from stdin… (end with Ctrl-D)\n`);
113
+ }
114
+ let bytes;
115
+ try {
116
+ bytes = await io.readStdin(limit);
117
+ }
118
+ catch (error) {
119
+ if (isTooLarge(error))
120
+ throw tooLarge(`${role} (stdin)`, limit, error);
121
+ throw error;
122
+ }
123
+ raw = { display: 'stdin', where: `${role} (stdin)`, bytes };
124
+ }
125
+ else {
126
+ const display = sanitize(path);
127
+ const where = `${role} "${display}"`;
128
+ const absolute = resolvePath(io, path);
129
+ let bytes;
130
+ try {
131
+ const size = (await io.fs.stat(absolute))?.size;
132
+ if (size !== undefined && size > limit)
133
+ throw tooLarge(where, limit);
134
+ bytes = await io.fs.readFile(absolute);
135
+ }
136
+ catch (error) {
137
+ if (error instanceof CliError)
138
+ throw error;
139
+ if (isTooLarge(error))
140
+ throw tooLarge(where, limit, error);
141
+ const code = systemErrorCode(error);
142
+ throw new CliError('input', `Cannot read ${where}: ${systemReason(error)}.`, (code && READ_HINTS[code]) || undefined, { cause: error });
143
+ }
144
+ raw = { display, where, filename: basename(path).replace(/\.gz$/i, ''), bytes };
145
+ }
146
+ const text = await decodeText(raw.bytes, raw.where, limit);
147
+ const empty = text.trim() === '';
148
+ if (empty && !options.allowEmpty) {
149
+ throw new CliError('input', `${raw.where} is empty.`, options.emptyHint ??
150
+ (path === STDIO
151
+ ? 'Did the command before the pipe fail? Pass --allow-empty if an empty graph is intended.'
152
+ : 'Pass --allow-empty to compare with an empty graph (e.g. before a first release).'));
153
+ }
154
+ return {
155
+ display: raw.display,
156
+ ...(raw.filename !== undefined ? { filename: raw.filename } : {}),
157
+ text,
158
+ empty,
159
+ };
160
+ }
161
+ /**
162
+ * Read two inputs concurrently; when both fail, the first one's error is reported (so the
163
+ * message does not depend on which read finished first).
164
+ */
165
+ export async function readPair(first, second) {
166
+ const [a, b] = await Promise.allSettled([first, second]);
167
+ if (a.status === 'rejected')
168
+ throw a.reason;
169
+ if (b.status === 'rejected')
170
+ throw b.reason;
171
+ return [a.value, b.value];
172
+ }
173
+ /** Parse a graph, turning parser errors into messages that name the input. */
174
+ export function parseInput(input, options) {
175
+ const parseOptions = {
176
+ format: options.format,
177
+ ...(input.filename !== undefined ? { filename: input.filename } : {}),
178
+ ...(options.languages ? { rdf: { languages: options.languages } } : {}),
179
+ };
180
+ if (input.empty) {
181
+ // --allow-empty: an empty graph, without asking a parser to guess the format of nothing.
182
+ return parseGraph('{"nodes":[],"edges":[]}', { ...parseOptions, format: 'json' });
183
+ }
184
+ try {
185
+ return parseGraph(input.text, parseOptions);
186
+ }
187
+ catch (error) {
188
+ if (!isKgdiffError(error))
189
+ throw error;
190
+ const where = input.display === 'stdin' ? 'stdin' : `"${input.display}"`;
191
+ const undetected = /could not detect the format/i.test(error.message);
192
+ const message = undetected
193
+ ? `Cannot tell the format of ${where}.`
194
+ : `${where}: ${error.message.replace(/\.$/, '')}.`;
195
+ const formats = FORMATS.filter((format) => format !== 'auto').join(', ');
196
+ const hint = undetected
197
+ ? `Pass ${options.formatFlag} <fmt> (${formats}) or use a known file extension.`
198
+ : options.format === 'auto'
199
+ ? `If the format was detected wrongly, pass ${options.formatFlag} <fmt> (${formats}).`
200
+ : undefined;
201
+ throw new CliError('input', message, hint, { cause: error });
202
+ }
203
+ }
204
+ //# sourceMappingURL=inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.js","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"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"}
package/dist/io.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Everything the CLI needs from the outside world, injected so that `main` runs in-process in
3
+ * tests (fake streams, in-memory files, fixed clock) and for real in `bin.ts` (`nodeIO`).
4
+ */
5
+ import type { Env } from './style.js';
6
+ /** The standalone viewer bundles an HTML report can inline. */
7
+ export type ViewerBundle = 'main' | 'compute';
8
+ /** A writable text stream (stdout / stderr). */
9
+ export interface OutputStream {
10
+ write(chunk: string): void;
11
+ }
12
+ /** What overwrite checks need to know about an existing file. */
13
+ export interface FileStat {
14
+ /** Device and inode: equal for the same file under any name (case variant, link). */
15
+ readonly dev: number;
16
+ readonly ino: number;
17
+ readonly size: number;
18
+ }
19
+ export interface CliFileSystem {
20
+ /** Read a whole file. Rejects with a Node-style error (`code`: ENOENT, EISDIR, EACCES…). */
21
+ readFile(path: string): Promise<Uint8Array>;
22
+ /**
23
+ * Create or replace a file atomically: write a temporary file in the same directory, then
24
+ * rename it over `path` (readers never see a half-written file; a symlink at `path` is
25
+ * replaced, not written through).
26
+ */
27
+ writeFile(path: string, data: string | Uint8Array): Promise<void>;
28
+ /** Stat following symlinks; `undefined` when nothing exists at `path`. */
29
+ stat(path: string): Promise<FileStat | undefined>;
30
+ /** Canonical absolute path (symlinks resolved). Rejects when `path` does not exist. */
31
+ realpath(path: string): Promise<string>;
32
+ }
33
+ export interface CliIO {
34
+ readonly stdout: OutputStream;
35
+ readonly stderr: OutputStream;
36
+ /** Read all of stdin; rejects with a `RangeError` beyond `maxBytes`. */
37
+ readStdin(maxBytes: number): Promise<Uint8Array>;
38
+ readonly fs: CliFileSystem;
39
+ readonly env: Env;
40
+ /** Directory relative paths are resolved against. */
41
+ readonly cwd: string;
42
+ /** Whether stdout is a terminal. */
43
+ readonly isTTY: boolean;
44
+ /** Whether stderr is a terminal (colors of errors and notices). */
45
+ readonly stderrIsTTY: boolean;
46
+ /** Whether stdin is a terminal (nothing piped in). */
47
+ readonly stdinIsTTY: boolean;
48
+ /** Terminal width of stdout, when known. */
49
+ readonly columns: number | undefined;
50
+ /** Clock for `generatedAt` in HTML reports. */
51
+ now(): Date;
52
+ /** Create a fresh private directory (`mkdtemp`) for reports opened with `--open` and no `-o`. */
53
+ makeTempDir(): Promise<string>;
54
+ /** Open a file with the platform's default application (the browser, for HTML). */
55
+ openFile(path: string): Promise<void>;
56
+ /**
57
+ * Source of a standalone viewer bundle: `main` (`@kgdiff/viewer/standalone`, the
58
+ * `<kgdiff-viewer>` element) or `compute` (`@kgdiff/viewer/standalone/compute`, the optional
59
+ * diff / layout add-on). Rejects with a `CliError` (`viewer-missing`) when it is not built or
60
+ * not installed.
61
+ */
62
+ loadViewerBundle(part: ViewerBundle): Promise<string>;
63
+ }
64
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,CAAC;AAE9C,gDAAgD;AAChD,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,qFAAqF;IACrF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,0EAA0E;IAC1E,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;IAClD,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,wEAAwE;IACxE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,qDAAqD;IACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,+CAA+C;IAC/C,GAAG,IAAI,IAAI,CAAC;IACZ,iGAAiG;IACjG,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD"}
package/dist/io.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=io.js.map
package/dist/io.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Locale selection and the CLI's own strings (summary, stat, Markdown). Hunk titles come from
3
+ * `@kgdiff/core`'s `formatHunk`; errors and notices on stderr stay in English so they can be
4
+ * searched for.
5
+ */
6
+ import type { Locale, ReplayPhase } from '@kgdiff/core';
7
+ import type { ChangeFamily } from './model.js';
8
+ import type { Env } from './style.js';
9
+ export declare const LOCALES: readonly Locale[];
10
+ /**
11
+ * Map a locale tag or POSIX locale (`zh_CN.UTF-8`, `zh-Hant`, `en_US`, `C`) to a supported
12
+ * locale: any Chinese tag → `zh-CN`, any English or POSIX tag → `en`, anything else `undefined`.
13
+ */
14
+ export declare function matchLocale(tag: string): Locale | undefined;
15
+ /**
16
+ * The locale to use: `--locale` when given, else the first non-empty of `LC_ALL`, `LC_MESSAGES`,
17
+ * `LANG` (POSIX precedence), mapped with `matchLocale`; `en` when nothing matches.
18
+ */
19
+ export declare function resolveLocale(flag: Locale | undefined, env: Env): Locale;
20
+ /** Thousands separators without `Intl`, so output never depends on the runtime's ICU data. */
21
+ export declare function formatInt(n: number): string;
22
+ export interface Messages {
23
+ /** Group headings, by replay phase. */
24
+ readonly phase: Readonly<Record<ReplayPhase, string>>;
25
+ /** Counter labels (`+3 added`), by replay phase. */
26
+ readonly counter: Readonly<Record<ReplayPhase, string>>;
27
+ readonly family: Readonly<Record<ChangeFamily, string>>;
28
+ /** `179 → 184 nodes · 351 → 353 edges`; one number when a count did not change. */
29
+ readonly totals: (nodes: Count, edges: Count) => string;
30
+ readonly changes: (changes: number, hunks: number) => string;
31
+ readonly more: (n: number) => string;
32
+ readonly moreHint: string;
33
+ readonly identical: string;
34
+ readonly identicalDetail: (nodes: number, edges: number) => string;
35
+ readonly table: {
36
+ readonly nodes: string;
37
+ readonly edges: string;
38
+ readonly added: string;
39
+ readonly removed: string;
40
+ readonly modified: string;
41
+ readonly unchanged: string;
42
+ readonly total: string;
43
+ };
44
+ readonly byType: string;
45
+ readonly untyped: string;
46
+ readonly moreTypes: (n: number) => string;
47
+ readonly markdown: {
48
+ readonly legend: string;
49
+ readonly more: (n: number) => string;
50
+ readonly generatedBy: (generator: string) => string;
51
+ };
52
+ }
53
+ /** A count before and after the change. */
54
+ export type Count = readonly [before: number, after: number];
55
+ /** `179 → 184`, or `74` when unchanged. */
56
+ export declare function formatCount([before, after]: Count): string;
57
+ export declare function messages(locale: Locale): Messages;
58
+ //# sourceMappingURL=locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../src/locale.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC,eAAO,MAAM,OAAO,EAAE,SAAS,MAAM,EAAoB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAS3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,CAOxE;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,MAAM,WAAW,QAAQ;IACvB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC;IACxD,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7D,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnE,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;QACrC,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;KACrD,CAAC;CACH;AAED,2CAA2C;AAC3C,MAAM,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAK7D,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAE1D;AAyFD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAEjD"}
package/dist/locale.js ADDED
@@ -0,0 +1,121 @@
1
+ export const LOCALES = ['en', 'zh-CN'];
2
+ /**
3
+ * Map a locale tag or POSIX locale (`zh_CN.UTF-8`, `zh-Hant`, `en_US`, `C`) to a supported
4
+ * locale: any Chinese tag → `zh-CN`, any English or POSIX tag → `en`, anything else `undefined`.
5
+ */
6
+ export function matchLocale(tag) {
7
+ const t = tag
8
+ .trim()
9
+ .toLowerCase()
10
+ .replace(/[.@].*$/, '')
11
+ .replace(/_/g, '-');
12
+ if (t === 'zh' || t.startsWith('zh-') || t === 'cn')
13
+ return 'zh-CN';
14
+ if (t === 'en' || t.startsWith('en-') || t === 'c' || t === 'posix')
15
+ return 'en';
16
+ return undefined;
17
+ }
18
+ /**
19
+ * The locale to use: `--locale` when given, else the first non-empty of `LC_ALL`, `LC_MESSAGES`,
20
+ * `LANG` (POSIX precedence), mapped with `matchLocale`; `en` when nothing matches.
21
+ */
22
+ export function resolveLocale(flag, env) {
23
+ if (flag)
24
+ return flag;
25
+ for (const name of ['LC_ALL', 'LC_MESSAGES', 'LANG']) {
26
+ const value = env[name];
27
+ if (value)
28
+ return matchLocale(value) ?? 'en';
29
+ }
30
+ return 'en';
31
+ }
32
+ /** Thousands separators without `Intl`, so output never depends on the runtime's ICU data. */
33
+ export function formatInt(n) {
34
+ return String(Math.trunc(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
35
+ }
36
+ const plural = (n, one, many) => `${formatInt(n)} ${n === 1 ? one : many}`;
37
+ /** `179 → 184`, or `74` when unchanged. */
38
+ export function formatCount([before, after]) {
39
+ return before === after ? formatInt(after) : `${formatInt(before)} → ${formatInt(after)}`;
40
+ }
41
+ const en = {
42
+ phase: {
43
+ restructure: 'Restructured',
44
+ modify: 'Modified',
45
+ add: 'Added',
46
+ remove: 'Removed',
47
+ },
48
+ counter: { add: 'added', remove: 'removed', modify: 'modified', restructure: 'restructured' },
49
+ family: {
50
+ added: 'added',
51
+ removed: 'removed',
52
+ content: 'content',
53
+ structure: 'structure',
54
+ identity: 'identity',
55
+ },
56
+ // The noun agrees with the number next to it (the after count): `1 node`, `2 → 1 node`.
57
+ totals: (nodes, edges) => `${formatCount(nodes)} ${nodes[1] === 1 ? 'node' : 'nodes'} · ` +
58
+ `${formatCount(edges)} ${edges[1] === 1 ? 'edge' : 'edges'}`,
59
+ changes: (changes, hunks) => `${plural(changes, 'change', 'changes')} in ${plural(hunks, 'hunk', 'hunks')}`,
60
+ more: (n) => `… and ${formatInt(n)} more`,
61
+ moreHint: '--limit 0 lists all',
62
+ identical: 'No differences',
63
+ identicalDetail: (nodes, edges) => `Both versions have ${plural(nodes, 'node', 'nodes')} and ${plural(edges, 'edge', 'edges')}.`,
64
+ table: {
65
+ nodes: 'nodes',
66
+ edges: 'edges',
67
+ added: 'added',
68
+ removed: 'removed',
69
+ modified: 'modified',
70
+ unchanged: 'unchanged',
71
+ total: 'before → after',
72
+ },
73
+ byType: 'By type',
74
+ untyped: '(untyped)',
75
+ moreTypes: (n) => `… and ${plural(n, 'more type', 'more types')}`,
76
+ markdown: {
77
+ legend: '🟩 added · 🟥 removed · 🟨 content (renames, attributes, types, synonyms) · ' +
78
+ '🟦 structure (moves, relations) · 🟪 identity (merges, splits)',
79
+ more: (n) => `…and ${plural(n, 'more hunk', 'more hunks')}. Open the HTML report for the full list.`,
80
+ generatedBy: (generator) => `Generated by ${generator}`,
81
+ },
82
+ };
83
+ const zh = {
84
+ phase: { restructure: '结构调整', modify: '修改', add: '新增', remove: '删除' },
85
+ counter: { add: '新增', remove: '删除', modify: '修改', restructure: '结构调整' },
86
+ family: {
87
+ added: '新增',
88
+ removed: '删除',
89
+ content: '内容',
90
+ structure: '结构',
91
+ identity: '身份',
92
+ },
93
+ totals: (nodes, edges) => `节点 ${formatCount(nodes)} · 关系 ${formatCount(edges)}`,
94
+ changes: (changes, hunks) => `${formatInt(hunks)} 组共 ${formatInt(changes)} 处变化`,
95
+ more: (n) => `… 另有 ${formatInt(n)} 组`,
96
+ moreHint: '--limit 0 显示全部',
97
+ identical: '没有差异',
98
+ identicalDetail: (nodes, edges) => `两个版本均有 ${formatInt(nodes)} 个节点、${formatInt(edges)} 条关系。`,
99
+ table: {
100
+ nodes: '节点',
101
+ edges: '关系',
102
+ added: '新增',
103
+ removed: '删除',
104
+ modified: '修改',
105
+ unchanged: '未变',
106
+ total: '变更前 → 变更后',
107
+ },
108
+ byType: '按类型',
109
+ untyped: '(无类型)',
110
+ moreTypes: (n) => `… 另有 ${formatInt(n)} 个类型`,
111
+ markdown: {
112
+ legend: '🟩 新增 · 🟥 删除 · 🟨 内容(改名、属性、类型、别名) · 🟦 结构(移动、关系) · 🟪 身份(合并、拆分、换 ID)',
113
+ more: (n) => `……另有 ${formatInt(n)} 组变更未列出,完整列表请查看 HTML 报告。`,
114
+ generatedBy: (generator) => `由 ${generator} 生成`,
115
+ },
116
+ };
117
+ const MESSAGES = { en, 'zh-CN': zh };
118
+ export function messages(locale) {
119
+ return MESSAGES[locale];
120
+ }
121
+ //# sourceMappingURL=locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.js","sourceRoot":"","sources":["../src/locale.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,OAAO,GAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,CAAC,GAAG,GAAG;SACV,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IACpE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IACjF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAwB,EAAE,GAAQ;IAC9D,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,CAAU,EAAE,CAAC;QAC9D,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,KAAK;YAAE,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;AACrE,CAAC;AAqCD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,IAAY,EAAU,EAAE,CAC9D,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5C,2CAA2C;AAC3C,MAAM,UAAU,WAAW,CAAC,CAAC,MAAM,EAAE,KAAK,CAAQ;IAChD,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AAC5F,CAAC;AAED,MAAM,EAAE,GAAa;IACnB,KAAK,EAAE;QACL,WAAW,EAAE,cAAc;QAC3B,MAAM,EAAE,UAAU;QAClB,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,SAAS;KAClB;IACD,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE;IAC7F,MAAM,EAAE;QACN,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE,WAAW;QACtB,QAAQ,EAAE,UAAU;KACrB;IACD,wFAAwF;IACxF,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACvB,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK;QAC/D,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;IAC9D,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAC1B,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,OAAO,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAChF,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,OAAO;IACzC,QAAQ,EAAE,qBAAqB;IAC/B,SAAS,EAAE,gBAAgB;IAC3B,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAChC,sBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG;IAC/F,KAAK,EAAE;QACL,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,UAAU;QACpB,SAAS,EAAE,WAAW;QACtB,KAAK,EAAE,gBAAgB;KACxB;IACD,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,WAAW;IACpB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE;IACjE,QAAQ,EAAE;QACR,MAAM,EACJ,8EAA8E;YAC9E,gEAAgE;QAClE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CACV,QAAQ,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,2CAA2C;QACzF,WAAW,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,SAAS,EAAE;KACxD;CACF,CAAC;AAEF,MAAM,EAAE,GAAa;IACnB,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IACrE,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE;IACvE,MAAM,EAAE;QACN,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,IAAI;KACf;IACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,SAAS,WAAW,CAAC,KAAK,CAAC,EAAE;IAC/E,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM;IAC/E,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,SAAS,CAAC,CAAC,CAAC,IAAI;IACrC,QAAQ,EAAE,gBAAgB;IAC1B,SAAS,EAAE,MAAM;IACjB,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAChC,UAAU,SAAS,CAAC,KAAK,CAAC,QAAQ,SAAS,CAAC,KAAK,CAAC,OAAO;IAC3D,KAAK,EAAE;QACL,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,WAAW;KACnB;IACD,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,SAAS,CAAC,CAAC,CAAC,MAAM;IAC5C,QAAQ,EAAE;QACR,MAAM,EACJ,uEAAuE;QACzE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,SAAS,CAAC,CAAC,CAAC,0BAA0B;QAC3D,WAAW,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,SAAS,KAAK;KAChD;CACF,CAAC;AAEF,MAAM,QAAQ,GAAuC,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAEzE,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { CliIO } from './io.js';
2
+ /**
3
+ * Run the CLI with `argv` (without `node` and the script path).
4
+ *
5
+ * Exit codes: 0 success (and no differences with `--exit-code`), 1 differences with
6
+ * `--exit-code`, 2 usage or input error (message on stderr; stack trace only with
7
+ * `DEBUG=kgdiff`). Never throws.
8
+ */
9
+ export declare function main(argv: readonly string[], io: CliIO): Promise<number>;
10
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAIrC;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC9E"}
package/dist/main.js ADDED
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Entry point logic: parse the command line, dispatch, map every failure to a friendly message
3
+ * on stderr and an exit code. Commands are loaded on demand so `--help` and `--version` never
4
+ * load the diff engine.
5
+ */
6
+ import { parseCommandLine, peekColorMode } from './args.js';
7
+ import { debugEnabled, formatError } from './errors.js';
8
+ import { renderHelp } from './help.js';
9
+ import { createPainter, isLightBackground, resolveColorLevel } from './style.js';
10
+ import { cliVersion } from './version.js';
11
+ /**
12
+ * Run the CLI with `argv` (without `node` and the script path).
13
+ *
14
+ * Exit codes: 0 success (and no differences with `--exit-code`), 1 differences with
15
+ * `--exit-code`, 2 usage or input error (message on stderr; stack trace only with
16
+ * `DEBUG=kgdiff`). Never throws.
17
+ */
18
+ export async function main(argv, io) {
19
+ const light = isLightBackground(io.env);
20
+ try {
21
+ const command = parseCommandLine(argv);
22
+ switch (command.kind) {
23
+ case 'help': {
24
+ const paint = createPainter(resolveColorLevel(command.color, io.env, io.isTTY), light);
25
+ io.stdout.write(renderHelp(command.topic, cliVersion(), paint, io.isTTY && io.columns ? io.columns : 80));
26
+ return 0;
27
+ }
28
+ case 'version':
29
+ io.stdout.write(`kgdiff ${cliVersion()}\n`);
30
+ return 0;
31
+ case 'diff': {
32
+ const { runDiff } = await import('./diff-command.js');
33
+ return await runDiff(command.options, io);
34
+ }
35
+ case 'apply': {
36
+ const { runApply } = await import('./apply-command.js');
37
+ return await runApply(command.options, io);
38
+ }
39
+ default: {
40
+ const exhaustive = command;
41
+ throw new Error(`Unknown command ${JSON.stringify(exhaustive)}`);
42
+ }
43
+ }
44
+ }
45
+ catch (error) {
46
+ const paint = createPainter(resolveColorLevel(peekColorMode(argv), io.env, io.stderrIsTTY), light);
47
+ io.stderr.write(formatError(error, paint, debugEnabled(io.env.DEBUG)));
48
+ return 2;
49
+ }
50
+ }
51
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAuB,EAAE,EAAS;IAC3D,MAAM,KAAK,GAAG,iBAAiB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACvC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,MAAM,EAAE,CAAC;gBACZ,MAAM,KAAK,GAAG,aAAa,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;gBACvF,EAAE,CAAC,MAAM,CAAC,KAAK,CACb,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CACzF,CAAC;gBACF,OAAO,CAAC,CAAC;YACX,CAAC;YACD,KAAK,SAAS;gBACZ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,UAAU,EAAE,IAAI,CAAC,CAAC;gBAC5C,OAAO,CAAC,CAAC;YACX,KAAK,MAAM,EAAE,CAAC;gBACZ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;gBACtD,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC5C,CAAC;YACD,KAAK,OAAO,EAAE,CAAC;gBACb,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;gBACxD,OAAO,MAAM,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7C,CAAC;YACD,SAAS,CAAC;gBACR,MAAM,UAAU,GAAU,OAAO,CAAC;gBAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,aAAa,CACzB,iBAAiB,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,EAC9D,KAAK,CACN,CAAC;QACF,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
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 { type DiffResult, type Locale } from '@kgdiff/core';
7
+ /** Hunks listed before "…and N more". */
8
+ export declare const MARKDOWN_HUNK_LIMIT = 100;
9
+ /**
10
+ * Escape untrusted text for inline GFM.
11
+ *
12
+ * 1. Invisible and bidirectional controls become a visible `⟨U+202E⟩`; C0 controls and line
13
+ * breaks become spaces; C1 controls are dropped.
14
+ * 2. GitHub's post-Markdown filters are defused first (they act on the rendered text, so
15
+ * escaping alone does not stop them): a zero-width space breaks `:shortcode:` emoji,
16
+ * `@mentions`, `#123` / `org/repo#123` / `GH-123` references, bare `scheme://` URLs and
17
+ * `www.` autolinks.
18
+ * 3. Markdown punctuation (backslash, backtick, `*`, `_`, brackets, `|`, `~`, `#`, `$` for math)
19
+ * is backslash-escaped; `<`, `>` and `&` become entities, so no raw HTML gets through.
20
+ */
21
+ export declare function escapeMarkdown(text: string): string;
22
+ export interface MarkdownOptions {
23
+ readonly locale: Locale;
24
+ readonly title: string;
25
+ /** e.g. `kgdiff 0.1.0`. */
26
+ readonly generator: string;
27
+ }
28
+ /** Render the Markdown summary. Deterministic: no timestamps. */
29
+ export declare function renderMarkdown(diff: DiffResult, options: MarkdownOptions): string;
30
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,UAAU,EAAc,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAMxE,yCAAyC;AACzC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAevC;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBnD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAoDjF"}