@zgeoff/checks 0.0.0-stage → 0.1.1

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 (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -2
  3. package/dist/cli.js +2285 -0
  4. package/package.json +42 -4
package/dist/cli.js ADDED
@@ -0,0 +1,2285 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // src/cli.ts
5
+ import { resolve as resolve2 } from "path";
6
+
7
+ // src/missing-program-error.ts
8
+ class MissingProgramError extends Error {
9
+ program;
10
+ constructor(check, program) {
11
+ super(`${check}: ${program} is not on the PATH, and the ${check} check needs it. Install ${program}, then run zgeoff-check again.`);
12
+ this.name = "MissingProgramError";
13
+ this.program = program;
14
+ }
15
+ }
16
+
17
+ // src/run-program.ts
18
+ function runProgram(check, context, argv) {
19
+ const [program] = argv;
20
+ if (Bun.which(program, { PATH: context.env["PATH"] ?? "" }) === null) {
21
+ throw new MissingProgramError(check, program);
22
+ }
23
+ const result = Bun.spawnSync([...argv], {
24
+ cwd: context.cwd,
25
+ env: { ...context.env },
26
+ stdin: "ignore",
27
+ stdout: "pipe",
28
+ stderr: "pipe"
29
+ });
30
+ return {
31
+ exitCode: result.exitCode,
32
+ stdout: result.stdout.toString(),
33
+ stderr: result.stderr.toString()
34
+ };
35
+ }
36
+
37
+ // src/checks/parse-shellcheck-output.ts
38
+ function parseShellcheckOutput(result) {
39
+ const problemLine = /^(?<path>.+?):(?<line>\d+):\d+: (?<level>\w+): (?<message>.*)$/u;
40
+ if (result.exitCode > 1) {
41
+ throw new Error(`shell: shellcheck failed: ${result.stderr.trim()}`);
42
+ }
43
+ const findings = result.stdout.split(`
44
+ `).flatMap((line) => {
45
+ const groups = problemLine.exec(line)?.groups;
46
+ if (groups === undefined) {
47
+ return [];
48
+ }
49
+ return [
50
+ {
51
+ path: groups["path"] ?? "",
52
+ line: Number(groups["line"]),
53
+ message: `shellcheck ${groups["level"]}: ${groups["message"]}`
54
+ }
55
+ ];
56
+ });
57
+ if (result.exitCode === 1 && findings.length === 0) {
58
+ throw new Error(`shell: shellcheck failed: ${result.stderr.trim()}`);
59
+ }
60
+ return findings;
61
+ }
62
+
63
+ // src/checks/parse-shfmt-output.ts
64
+ function parseShfmtOutput(result) {
65
+ const parseErrorLine = /^(?<path>.+?):(?<line>\d+):\d+: (?<message>.*)$/u;
66
+ const stderrLines = result.stderr.split(`
67
+ `).filter((line) => line.trim() !== "");
68
+ const failures = stderrLines.filter((line) => !parseErrorLine.test(line));
69
+ if (result.exitCode > 1 || failures.length > 0) {
70
+ throw new Error(`shell: shfmt failed: ${result.stderr.trim()}`);
71
+ }
72
+ const errors = stderrLines.flatMap((line) => {
73
+ const groups = parseErrorLine.exec(line)?.groups;
74
+ if (groups === undefined) {
75
+ return [];
76
+ }
77
+ return [
78
+ {
79
+ path: groups["path"] ?? "",
80
+ line: Number(groups["line"]),
81
+ message: `shfmt cannot parse the file: ${groups["message"]}`
82
+ }
83
+ ];
84
+ });
85
+ const diffs = collectDiffFindings(result.stdout);
86
+ if (result.exitCode !== 0 && errors.length === 0 && diffs.length === 0) {
87
+ throw new Error(`shell: shfmt failed: ${result.stderr.trim()}`);
88
+ }
89
+ return [...errors, ...diffs];
90
+ }
91
+ function collectDiffFindings(diff) {
92
+ const diffTargetLine = /^\+\+\+ (?<path>.+)$/u;
93
+ const hunkHeader = /^@@ -(?<start>\d+)(?:,\d+)? \+\d+(?:,\d+)? @@/u;
94
+ const findings = [];
95
+ let path = "";
96
+ let line = 0;
97
+ let reported = true;
98
+ for (const text of diff.split(`
99
+ `)) {
100
+ const target = diffTargetLine.exec(text)?.groups;
101
+ if (target !== undefined) {
102
+ path = target["path"] ?? "";
103
+ continue;
104
+ }
105
+ const hunk = hunkHeader.exec(text)?.groups;
106
+ if (hunk !== undefined) {
107
+ line = Number(hunk["start"]);
108
+ reported = false;
109
+ continue;
110
+ }
111
+ if (reported || text.startsWith("---")) {
112
+ continue;
113
+ }
114
+ if (text.startsWith("-") || text.startsWith("+")) {
115
+ findings.push({
116
+ path,
117
+ line,
118
+ message: `shfmt would reformat this hunk; run shfmt -w ${path} to fix it`
119
+ });
120
+ reported = true;
121
+ } else if (text.startsWith(" ")) {
122
+ line += 1;
123
+ }
124
+ }
125
+ return findings;
126
+ }
127
+
128
+ // src/checks/shell-check.ts
129
+ var shellCheck = {
130
+ name: "shell",
131
+ glob: "**/*.sh",
132
+ check: checkShellFiles
133
+ };
134
+ var BATCH_SIZE = 200;
135
+ function checkShellFiles(context) {
136
+ const plain = {
137
+ ...context,
138
+ env: Object.fromEntries(Object.entries(context.env).filter(([name]) => name !== "FORCE_COLOR"))
139
+ };
140
+ const findings = [];
141
+ for (let start = 0;start < plain.files.length; start += BATCH_SIZE) {
142
+ const batch = plain.files.slice(start, start + BATCH_SIZE);
143
+ findings.push(...runShellcheck(plain, batch), ...runShfmt(plain, batch));
144
+ }
145
+ return findings;
146
+ }
147
+ function runShellcheck(context, files) {
148
+ const result = runProgram("shell", context, [
149
+ "shellcheck",
150
+ "--format=gcc",
151
+ "--external-sources",
152
+ "--source-path=SCRIPTDIR",
153
+ `--source-path=${context.cwd}`,
154
+ "--",
155
+ ...files
156
+ ]);
157
+ return parseShellcheckOutput(result);
158
+ }
159
+ function runShfmt(context, files) {
160
+ const result = runProgram("shell", context, ["shfmt", "-d", "--", ...files]);
161
+ return parseShfmtOutput(result);
162
+ }
163
+
164
+ // src/all-checks.ts
165
+ var allChecks = [shellCheck];
166
+
167
+ // src/load-config.ts
168
+ import { readFileSync } from "fs";
169
+ import { join } from "path";
170
+
171
+ // ../std/src/is-record.ts
172
+ function isRecord(value) {
173
+ return typeof value === "object" && value !== null && !Array.isArray(value);
174
+ }
175
+ // src/config-error.ts
176
+ class ConfigError extends Error {
177
+ constructor(message) {
178
+ super(message);
179
+ this.name = "ConfigError";
180
+ }
181
+ }
182
+
183
+ // src/load-config.ts
184
+ var CONFIG_FILE = "zgeoff-check.json";
185
+ function loadConfig(cwd, checkNames) {
186
+ let text;
187
+ try {
188
+ text = readFileSync(join(cwd, CONFIG_FILE), "utf8");
189
+ } catch (error) {
190
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
191
+ return { off: new Map };
192
+ }
193
+ throw error;
194
+ }
195
+ let value;
196
+ try {
197
+ value = JSON.parse(text);
198
+ } catch (error) {
199
+ throw new ConfigError(`${CONFIG_FILE}: ${error instanceof Error ? error.message : "not JSON"}`);
200
+ }
201
+ return parseConfig(value, checkNames);
202
+ }
203
+ function parseConfig(value, checkNames) {
204
+ if (!isRecord(value)) {
205
+ throw new ConfigError(`${CONFIG_FILE}: the file must hold an object`);
206
+ }
207
+ const unknownKeys = Object.keys(value).filter((key) => key !== "off");
208
+ if (unknownKeys.length > 0) {
209
+ throw new ConfigError(`${CONFIG_FILE}: unknown key ${unknownKeys.join(", ")}`);
210
+ }
211
+ const entries = value["off"] ?? [];
212
+ if (!Array.isArray(entries)) {
213
+ throw new ConfigError(`${CONFIG_FILE}: off must be a list of { "check", "reason" } entries`);
214
+ }
215
+ const off = new Map;
216
+ for (const [index, entry] of entries.entries()) {
217
+ const at = `${CONFIG_FILE}: off[${index}]`;
218
+ if (!isRecord(entry)) {
219
+ throw new ConfigError(`${at} must be an object with a check and a reason`);
220
+ }
221
+ const check = entry["check"];
222
+ const reason = entry["reason"];
223
+ const extraKeys = Object.keys(entry).filter((key) => key !== "check" && key !== "reason");
224
+ if (extraKeys.length > 0) {
225
+ throw new ConfigError(`${at} has an unknown key ${extraKeys.join(", ")}`);
226
+ }
227
+ if (typeof check !== "string" || !checkNames.includes(check)) {
228
+ throw new ConfigError(`${at} names no known check; the checks are ${checkNames.join(", ")}`);
229
+ }
230
+ if (typeof reason !== "string" || reason.trim() === "") {
231
+ throw new ConfigError(`${at} turns off ${check} with no reason; give one in reason`);
232
+ }
233
+ if (off.has(check)) {
234
+ throw new ConfigError(`${at} turns off ${check} a second time`);
235
+ }
236
+ off.set(check, reason);
237
+ }
238
+ return { off };
239
+ }
240
+
241
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/utils-D-MmF6sM.js
242
+ function kebabnize(str) {
243
+ return str.replace(/[A-Z]/g, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
244
+ }
245
+ function formatChoices(choices) {
246
+ return choices.map((value) => JSON.stringify(value)).join(", ");
247
+ }
248
+
249
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/utils.js
250
+ function isLazyCommand(cmd) {
251
+ return typeof cmd === "function" && "commandName" in cmd;
252
+ }
253
+ async function resolveLazyCommand(cmd, name, needRunResolving = false) {
254
+ let command;
255
+ if (isLazyCommand(cmd)) {
256
+ const baseCommand = {
257
+ name: cmd.commandName,
258
+ description: cmd.description,
259
+ args: cmd.args,
260
+ examples: cmd.examples,
261
+ internal: cmd.internal,
262
+ entry: cmd.entry,
263
+ toKebab: cmd.toKebab,
264
+ rendering: cmd.rendering,
265
+ subCommands: cmd.subCommands
266
+ };
267
+ if ("resource" in cmd && cmd.resource)
268
+ baseCommand.resource = cmd.resource;
269
+ command = Object.assign(create(), baseCommand);
270
+ if (needRunResolving) {
271
+ const loaded = await cmd();
272
+ if (typeof loaded === "function")
273
+ command.run = loaded;
274
+ else if (typeof loaded === "object") {
275
+ if (loaded.run == null)
276
+ throw new TypeError(`'run' is required in command: ${cmd.name || name}`);
277
+ command.run = loaded.run;
278
+ command.name = loaded.name ?? cmd.commandName;
279
+ command.description = loaded.description ?? cmd.description;
280
+ command.args = loaded.args ?? cmd.args;
281
+ command.examples = loaded.examples ?? cmd.examples;
282
+ command.internal = loaded.internal ?? cmd.internal;
283
+ command.entry = loaded.entry ?? cmd.entry;
284
+ command.toKebab = loaded.toKebab ?? cmd.toKebab;
285
+ command.rendering = loaded.rendering ?? cmd.rendering;
286
+ command.subCommands = loaded.subCommands || cmd.subCommands;
287
+ if ("resource" in loaded && loaded.resource)
288
+ command.resource = loaded.resource;
289
+ } else
290
+ throw new TypeError(`Cannot resolve command: ${cmd.name || name}`);
291
+ }
292
+ } else
293
+ command = Object.assign(create(), cmd);
294
+ if (command.name == null && name)
295
+ command.name = name;
296
+ return deepFreeze(command);
297
+ }
298
+ function create(obj = null) {
299
+ return Object.create(obj);
300
+ }
301
+ function log(...args) {
302
+ console.log(...args);
303
+ }
304
+ function getCommandSubCommands(cmd) {
305
+ const subCommands = isLazyCommand(cmd) ? cmd.subCommands : typeof cmd === "object" ? cmd.subCommands : undefined;
306
+ if (!subCommands)
307
+ return;
308
+ if (subCommands instanceof Map)
309
+ return subCommands.size > 0 ? subCommands : undefined;
310
+ if (typeof subCommands === "object") {
311
+ const entries = Object.entries(subCommands);
312
+ if (entries.length === 0)
313
+ return;
314
+ const map = /* @__PURE__ */ new Map;
315
+ for (const [name, cmd] of entries)
316
+ map.set(name, cmd);
317
+ return map;
318
+ }
319
+ }
320
+ function deepFreeze(obj, ignores = []) {
321
+ if (obj === null || typeof obj !== "object")
322
+ return obj;
323
+ for (const key of Object.keys(obj)) {
324
+ const value = obj[key];
325
+ if (ignores.includes(key))
326
+ continue;
327
+ if (typeof value === "object" && value !== null)
328
+ deepFreeze(value, ignores);
329
+ }
330
+ return Object.freeze(obj);
331
+ }
332
+
333
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/context-CSecf6R5.js
334
+ var ANONYMOUS_COMMAND_NAME = "(anonymous)";
335
+ var NOOP = () => {};
336
+ var CLI_OPTIONS_DEFAULT = {
337
+ name: undefined,
338
+ description: undefined,
339
+ version: undefined,
340
+ cwd: undefined,
341
+ usageSilent: false,
342
+ subCommands: undefined,
343
+ leftMargin: 2,
344
+ middleMargin: 10,
345
+ usageOptionType: false,
346
+ usageOptionValue: true,
347
+ strict: false,
348
+ renderHeader: undefined,
349
+ renderUsage: undefined,
350
+ renderValidationErrors: undefined,
351
+ plugins: undefined,
352
+ fallbackToEntry: false
353
+ };
354
+ async function createCommandContext({ args = {}, explicit = {}, values = {}, positionals = [], rest = [], argv = [], tokens = [], command = {}, extensions = {}, cliOptions = {}, callMode = "entry", commandPath = [], omitted = false, validationError }) {
355
+ const _args = Object.entries(args).reduce((acc, [key, value]) => {
356
+ acc[key] = Object.assign(create(), value);
357
+ return acc;
358
+ }, create());
359
+ const env = Object.assign(create(), CLI_OPTIONS_DEFAULT, cliOptions);
360
+ if (command.rendering) {
361
+ const { header, usage, validationErrors } = command.rendering;
362
+ if (header !== undefined)
363
+ env.renderHeader = header;
364
+ if (usage !== undefined)
365
+ env.renderUsage = usage;
366
+ if (validationErrors !== undefined)
367
+ env.renderValidationErrors = validationErrors;
368
+ }
369
+ const core = Object.assign(create(), {
370
+ name: getCommandName(command),
371
+ description: command.description,
372
+ omitted,
373
+ callMode,
374
+ commandPath,
375
+ env,
376
+ args: _args,
377
+ explicit,
378
+ values,
379
+ positionals,
380
+ rest,
381
+ _: argv,
382
+ tokens,
383
+ toKebab: command.toKebab,
384
+ log: cliOptions.usageSilent ? NOOP : log,
385
+ validationError
386
+ });
387
+ if (Object.keys(extensions).length > 0) {
388
+ const ext = create(null);
389
+ Object.defineProperty(core, "extensions", {
390
+ value: ext,
391
+ writable: false,
392
+ enumerable: true,
393
+ configurable: true
394
+ });
395
+ for (const [key, extension] of Object.entries(extensions)) {
396
+ ext[key] = await extension.factory(core, command);
397
+ if (extension.onFactory)
398
+ await extension.onFactory(core, command);
399
+ }
400
+ }
401
+ return deepFreeze(core, ["extensions", "entryCommand"]);
402
+ }
403
+ function getCommandName(cmd) {
404
+ if (isLazyCommand(cmd))
405
+ return cmd.commandName || cmd.name || "(anonymous)";
406
+ else if (typeof cmd === "object")
407
+ return cmd.name || "(anonymous)";
408
+ else
409
+ return ANONYMOUS_COMMAND_NAME;
410
+ }
411
+
412
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/resolver-CAlgxe_R-3pz9PVFu.js
413
+ var HYPHEN_CHAR = "-";
414
+ var HYPHEN_CODE = HYPHEN_CHAR.codePointAt(0);
415
+ var EQUAL_CHAR = "=";
416
+ var EQUAL_CODE = EQUAL_CHAR.codePointAt(0);
417
+ var TERMINATOR = "--";
418
+ var SHORT_OPTION_PREFIX = HYPHEN_CHAR;
419
+ var LONG_OPTION_PREFIX = "--";
420
+ function parseArgs(args, options = {}) {
421
+ const { allowCompatible = false } = options;
422
+ const tokens = [];
423
+ const remainings = [...args];
424
+ let index = -1;
425
+ let groupCount = 0;
426
+ let hasShortGroupValue = false;
427
+ let shortGroupValueInline = true;
428
+ while (remainings.length > 0) {
429
+ const arg = remainings.shift();
430
+ if (arg == undefined)
431
+ break;
432
+ if (groupCount > 0)
433
+ groupCount--;
434
+ else
435
+ index++;
436
+ if (arg === TERMINATOR) {
437
+ tokens.push({
438
+ kind: "option-terminator",
439
+ index
440
+ });
441
+ const mapped = remainings.map((arg) => {
442
+ return {
443
+ kind: "positional",
444
+ index: ++index,
445
+ value: arg
446
+ };
447
+ });
448
+ tokens.push(...mapped);
449
+ break;
450
+ }
451
+ if (isShortOption(arg)) {
452
+ const shortOption = arg.charAt(1);
453
+ let value;
454
+ let inlineValue;
455
+ if (groupCount) {
456
+ tokens.push({
457
+ kind: "option",
458
+ name: shortOption,
459
+ rawName: arg,
460
+ index,
461
+ value,
462
+ inlineValue
463
+ });
464
+ if (groupCount === 1 && hasShortGroupValue) {
465
+ value = remainings.shift();
466
+ inlineValue = shortGroupValueInline;
467
+ hasShortGroupValue = false;
468
+ tokens.push({
469
+ kind: "option",
470
+ index,
471
+ value,
472
+ inlineValue
473
+ });
474
+ }
475
+ } else
476
+ tokens.push({
477
+ kind: "option",
478
+ name: shortOption,
479
+ rawName: arg,
480
+ index,
481
+ value,
482
+ inlineValue
483
+ });
484
+ if (value != null)
485
+ ++index;
486
+ continue;
487
+ }
488
+ if (isShortOptionGroup(arg)) {
489
+ const expanded = [];
490
+ let separated = false;
491
+ let dashed = false;
492
+ let shortValue = "";
493
+ for (let i = 1;i < arg.length; i++) {
494
+ const shortableOption = arg.charAt(i);
495
+ if (separated)
496
+ shortValue += shortableOption;
497
+ else if (!allowCompatible && shortableOption.codePointAt(0) === EQUAL_CODE && expanded.length > 0)
498
+ separated = true;
499
+ else if (!allowCompatible && shortableOption.codePointAt(0) === HYPHEN_CODE) {
500
+ separated = true;
501
+ dashed = true;
502
+ shortValue += shortableOption;
503
+ } else
504
+ expanded.push(`${SHORT_OPTION_PREFIX}${shortableOption}`);
505
+ }
506
+ hasShortGroupValue = separated;
507
+ shortGroupValueInline = !dashed;
508
+ if (separated)
509
+ expanded.push(shortValue);
510
+ remainings.unshift(...expanded);
511
+ groupCount = expanded.length;
512
+ continue;
513
+ }
514
+ if (isLongOption(arg)) {
515
+ const longOption = arg.slice(2);
516
+ tokens.push({
517
+ kind: "option",
518
+ name: longOption,
519
+ rawName: arg,
520
+ index,
521
+ value: undefined,
522
+ inlineValue: undefined
523
+ });
524
+ continue;
525
+ }
526
+ if (isLongOptionAndValue(arg)) {
527
+ const equalIndex = arg.indexOf(EQUAL_CHAR);
528
+ const longOption = arg.slice(2, equalIndex);
529
+ const value = arg.slice(equalIndex + 1);
530
+ tokens.push({
531
+ kind: "option",
532
+ name: longOption,
533
+ rawName: `${LONG_OPTION_PREFIX}${longOption}`,
534
+ index,
535
+ value,
536
+ inlineValue: true
537
+ });
538
+ continue;
539
+ }
540
+ tokens.push({
541
+ kind: "positional",
542
+ index,
543
+ value: arg
544
+ });
545
+ }
546
+ return tokens;
547
+ }
548
+ function isShortOption(arg) {
549
+ return arg.length === 2 && arg.codePointAt(0) === HYPHEN_CODE && arg.codePointAt(1) !== HYPHEN_CODE;
550
+ }
551
+ function isShortOptionGroup(arg) {
552
+ if (arg.length <= 2)
553
+ return false;
554
+ if (arg.codePointAt(0) !== HYPHEN_CODE)
555
+ return false;
556
+ if (arg.codePointAt(1) === HYPHEN_CODE)
557
+ return false;
558
+ return true;
559
+ }
560
+ function isLongOption(arg) {
561
+ return hasLongOptionPrefix(arg) && !arg.includes(EQUAL_CHAR, 3);
562
+ }
563
+ function isLongOptionAndValue(arg) {
564
+ return hasLongOptionPrefix(arg) && arg.includes(EQUAL_CHAR, 3);
565
+ }
566
+ function hasLongOptionPrefix(arg) {
567
+ return arg.startsWith(LONG_OPTION_PREFIX) && arg.length > 2;
568
+ }
569
+ var PURE_PARSE = Symbol.for("args-tokens.pureParse");
570
+ var ArgsValidationErrorKeys = {
571
+ requiredOption: "err:arg:required-option",
572
+ requiredPositional: "err:arg:required-positional",
573
+ invalidType: "err:arg:invalid-type",
574
+ invalidChoice: "err:arg:invalid-choice",
575
+ customParse: "err:arg:custom-parse",
576
+ unknownOption: "err:arg:unknown-option",
577
+ unexpectedValue: "err:arg:unexpected-value",
578
+ missingValue: "err:arg:missing-value",
579
+ conflict: "err:arg:conflict",
580
+ invalidDefault: "err:arg:invalid-default"
581
+ };
582
+ var ARGS_VALIDATION_ERROR_BRAND = Symbol.for("args-tokens.ArgsValidationError");
583
+ var ArgsValidationError = class extends Error {
584
+ code;
585
+ values;
586
+ constructor(message, options = {}) {
587
+ super(message, { cause: options.cause });
588
+ this.name = "ArgsValidationError";
589
+ this.code = options.code;
590
+ this.values = options.values ?? {};
591
+ Object.defineProperty(this, ARGS_VALIDATION_ERROR_BRAND, {
592
+ value: true,
593
+ enumerable: false,
594
+ writable: false,
595
+ configurable: false
596
+ });
597
+ }
598
+ };
599
+ function isArgsValidationError(error) {
600
+ if (error instanceof ArgsValidationError)
601
+ return true;
602
+ if (typeof error !== "object" || error === null)
603
+ return false;
604
+ if (!Object.hasOwn(error, ARGS_VALIDATION_ERROR_BRAND) || error[ARGS_VALIDATION_ERROR_BRAND] !== true)
605
+ return false;
606
+ const values = error.values;
607
+ return typeof values === "object" && values !== null;
608
+ }
609
+ var SKIP_POSITIONAL_DEFAULT = -1;
610
+ var ARG_TYPES = /* @__PURE__ */ new Set([
611
+ "string",
612
+ "boolean",
613
+ "number",
614
+ "enum",
615
+ "positional",
616
+ "custom"
617
+ ]);
618
+ function resolveArgs(args, tokens, { shortGrouping = false, skipPositional = SKIP_POSITIONAL_DEFAULT, toKebab = false } = {}) {
619
+ const skipPositionalIndex = typeof skipPositional === "number" ? Math.max(skipPositional, SKIP_POSITIONAL_DEFAULT) : SKIP_POSITIONAL_DEFAULT;
620
+ const rest = [];
621
+ const optionTokens = [];
622
+ const positionalTokens = [];
623
+ const argEntries = Object.entries(args);
624
+ let currentLongOption;
625
+ let currentShortOption;
626
+ const expandableShortOptions = [];
627
+ function getOptionName(rawArg, schema) {
628
+ return toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
629
+ }
630
+ function checkLongTokenName(option, schema, token) {
631
+ if (token.rawName == undefined || !hasLongOptionPrefix(token.rawName))
632
+ return false;
633
+ return token.name === option || isNegatedToken(token, option, schema);
634
+ }
635
+ function toShortValue() {
636
+ if (expandableShortOptions.length === 0)
637
+ return;
638
+ else {
639
+ let value = "";
640
+ for (let i = 0;i < expandableShortOptions.length; i++)
641
+ value += expandableShortOptions[i].name ?? "";
642
+ expandableShortOptions.length = 0;
643
+ return value;
644
+ }
645
+ }
646
+ function applyLongOptionValue(value) {
647
+ if (currentLongOption) {
648
+ currentLongOption.value = value;
649
+ optionTokens.push({ ...currentLongOption });
650
+ currentLongOption = undefined;
651
+ }
652
+ }
653
+ function applyShortOptionValue(value) {
654
+ if (currentShortOption) {
655
+ currentShortOption.value = value ?? toShortValue();
656
+ optionTokens.push({ ...currentShortOption });
657
+ currentShortOption = undefined;
658
+ }
659
+ }
660
+ const schemas = Object.values(args);
661
+ const booleanLongOptionNames = /* @__PURE__ */ new Set;
662
+ for (let i = 0;i < argEntries.length; i++) {
663
+ const entry = argEntries[i];
664
+ const rawArg = entry[0];
665
+ const schema = entry[1];
666
+ if (typeof schema.parse !== "function") {
667
+ if (schema.type === "custom")
668
+ throw new TypeError(`argument '${getOptionName(rawArg, schema)}' should have a 'parse' function`);
669
+ if (schema.type === "enum" && !Array.isArray(schema.choices))
670
+ throw new TypeError(`argument '${getOptionName(rawArg, schema)}' should have a 'choices' array`);
671
+ if (!ARG_TYPES.has(schema.type))
672
+ throw new Error(`Unsupported argument type '${schema.type}' for option '${getOptionName(rawArg, schema)}'`);
673
+ }
674
+ if (schema.type !== "boolean")
675
+ continue;
676
+ const arg = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
677
+ booleanLongOptionNames.add(arg);
678
+ if (schema.negatable === true)
679
+ booleanLongOptionNames.add(`no-${arg}`);
680
+ }
681
+ let terminated = false;
682
+ for (let i = 0;i < tokens.length; i++) {
683
+ const token = tokens[i];
684
+ if (token.kind === "positional") {
685
+ if (terminated) {
686
+ rest.push(token.value);
687
+ continue;
688
+ }
689
+ if (currentShortOption) {
690
+ if (schemas.find((schema) => schema.short === currentShortOption.name && schema.type === "boolean") || expandableShortOptions.length > 0) {
691
+ positionalTokens.push({ ...token });
692
+ applyShortOptionValue();
693
+ } else
694
+ applyShortOptionValue(token.value);
695
+ } else if (currentLongOption) {
696
+ if (booleanLongOptionNames.has(currentLongOption.name)) {
697
+ positionalTokens.push({ ...token });
698
+ applyLongOptionValue();
699
+ } else
700
+ applyLongOptionValue(token.value);
701
+ } else
702
+ positionalTokens.push({ ...token });
703
+ } else if (token.kind === "option") {
704
+ if (token.rawName) {
705
+ if (token.rawName.startsWith("--")) {
706
+ applyLongOptionValue();
707
+ applyShortOptionValue();
708
+ if (token.inlineValue)
709
+ optionTokens.push({ ...token });
710
+ else
711
+ currentLongOption = { ...token };
712
+ } else if (isShortOption(token.rawName)) {
713
+ if (currentShortOption) {
714
+ if (currentShortOption.index === token.index) {
715
+ if (shortGrouping) {
716
+ currentShortOption.value = token.value;
717
+ optionTokens.push({ ...currentShortOption });
718
+ currentShortOption = { ...token };
719
+ } else
720
+ expandableShortOptions.push({ ...token });
721
+ } else {
722
+ currentShortOption.value = toShortValue();
723
+ optionTokens.push({ ...currentShortOption });
724
+ currentShortOption = { ...token };
725
+ }
726
+ applyLongOptionValue();
727
+ } else {
728
+ currentShortOption = { ...token };
729
+ applyLongOptionValue();
730
+ }
731
+ }
732
+ } else {
733
+ if (currentShortOption && currentShortOption.index == token.index) {
734
+ const letters = toShortValue();
735
+ currentShortOption.value = letters === undefined ? token.value : `${letters}${token.inlineValue ? "=" : ""}${token.value ?? ""}`;
736
+ currentShortOption.inlineValue = token.inlineValue;
737
+ optionTokens.push({ ...currentShortOption });
738
+ currentShortOption = undefined;
739
+ }
740
+ applyLongOptionValue();
741
+ }
742
+ } else {
743
+ if (token.kind === "option-terminator")
744
+ terminated = true;
745
+ applyLongOptionValue();
746
+ applyShortOptionValue();
747
+ }
748
+ }
749
+ applyLongOptionValue();
750
+ applyShortOptionValue();
751
+ const values = Object.create(null);
752
+ const errors = [];
753
+ const explicit = Object.create(null);
754
+ const actualInputNames = /* @__PURE__ */ new Map;
755
+ let requiredPositionalsAfter;
756
+ const positionalItemCount = tokens.filter((token) => token.kind === "positional").length;
757
+ function getPositionalSkipIndex() {
758
+ return Math.min(skipPositionalIndex, positionalItemCount);
759
+ }
760
+ function getRequiredPositionalsAfter(rawArg) {
761
+ requiredPositionalsAfter ??= createRequiredPositionalsAfter(argEntries);
762
+ return requiredPositionalsAfter[rawArg] ?? 0;
763
+ }
764
+ let positionalsCount = 0;
765
+ for (let argIndex = 0;argIndex < argEntries.length; argIndex++) {
766
+ const entry = argEntries[argIndex];
767
+ const rawArg = entry[0];
768
+ const schema = entry[1];
769
+ const arg = getOptionName(rawArg, schema);
770
+ explicit[rawArg] = false;
771
+ if (schema.type === "positional") {
772
+ if (skipPositionalIndex > SKIP_POSITIONAL_DEFAULT)
773
+ while (positionalsCount <= getPositionalSkipIndex())
774
+ positionalsCount++;
775
+ if (schema.multiple) {
776
+ const availablePositionals = Math.max(positionalTokens.length - positionalsCount, 0);
777
+ const positionalsToConsume = availablePositionals > 0 ? Math.max(availablePositionals - getRequiredPositionalsAfter(rawArg), 0) : 0;
778
+ if (positionalsToConsume > 0) {
779
+ const endPositionals = positionalsCount + positionalsToConsume;
780
+ if (typeof schema.parse === "function") {
781
+ const parsed = [];
782
+ for (let i = positionalsCount;i < endPositionals; i++) {
783
+ const p = positionalTokens[i];
784
+ const [parsedValue, error] = parseSchemaValue(p.value, rawArg, arg, schema);
785
+ if (error)
786
+ errors.push(error);
787
+ else
788
+ parsed.push(parsedValue);
789
+ }
790
+ values[rawArg] = parsed;
791
+ } else {
792
+ const valuesArray = [];
793
+ for (let i = positionalsCount;i < endPositionals; i++)
794
+ valuesArray.push(positionalTokens[i].value);
795
+ values[rawArg] = valuesArray;
796
+ }
797
+ positionalsCount = endPositionals;
798
+ explicit[rawArg] = true;
799
+ } else if (schema.required)
800
+ errors.push(createRequireError(rawArg, arg, schema));
801
+ else if (hasDefault(schema))
802
+ values[rawArg] = getDefaultValue(schema);
803
+ } else {
804
+ const positional = positionalTokens[positionalsCount];
805
+ if (shouldRequireMissingSinglePositional(schema)) {
806
+ if (positional != null) {
807
+ resolveSinglePositionalValue(values, errors, rawArg, arg, schema, positional);
808
+ explicit[rawArg] = true;
809
+ positionalsCount++;
810
+ } else
811
+ errors.push(createRequireError(rawArg, arg, schema));
812
+ continue;
813
+ }
814
+ if (positional != null) {
815
+ const requiredPositionals = getRequiredPositionalsAfter(rawArg);
816
+ if (Math.max(positionalTokens.length - positionalsCount, 0) > requiredPositionals) {
817
+ resolveSinglePositionalValue(values, errors, rawArg, arg, schema, positional);
818
+ explicit[rawArg] = true;
819
+ positionalsCount++;
820
+ continue;
821
+ }
822
+ }
823
+ if (hasDefault(schema))
824
+ values[rawArg] = schema.default;
825
+ }
826
+ continue;
827
+ }
828
+ if (schema.required) {
829
+ if (!optionTokens.find((token) => {
830
+ return schema.short && token.name === schema.short && token.rawName != null && isShortOption(token.rawName) || checkLongTokenName(arg, schema, token);
831
+ })) {
832
+ errors.push(createRequireError(rawArg, arg, schema));
833
+ continue;
834
+ }
835
+ }
836
+ let resolved = false;
837
+ for (let i = 0;i < optionTokens.length; i++) {
838
+ const token = optionTokens[i];
839
+ if (checkLongTokenName(arg, schema, token) || schema.short === token.name && token.rawName != null && isShortOption(token.rawName)) {
840
+ explicit[rawArg] = true;
841
+ const rawName = token.rawName;
842
+ const actualInputName = isShortOption(rawName) ? `-${token.name}` : rawName;
843
+ actualInputNames.set(rawArg, actualInputName);
844
+ const missing = schema.type !== "boolean" && token.value === undefined;
845
+ if (!missing) {
846
+ const invalid = validateRequire(token, rawArg, arg, schema);
847
+ if (invalid) {
848
+ errors.push(invalid);
849
+ continue;
850
+ }
851
+ }
852
+ const [parsedValue, error] = missing ? [undefined, createMissingValueError(rawArg, arg, schema, findOptionLikeNextArgument(tokens, optionTokens, i, argEntries, toKebab))] : parse(token, rawArg, arg, schema);
853
+ if (error)
854
+ errors.push(error);
855
+ else {
856
+ resolved = true;
857
+ if (schema.multiple) {
858
+ values[rawArg] ||= [];
859
+ values[rawArg].push(parsedValue);
860
+ } else
861
+ values[rawArg] = parsedValue;
862
+ }
863
+ }
864
+ }
865
+ if (!resolved && schema.default != null) {
866
+ if (hasDefaultOutsideChoices(schema))
867
+ errors.push(createDefaultChoiceError(rawArg, arg, schema));
868
+ else
869
+ values[rawArg] = getDefaultValue(schema);
870
+ }
871
+ }
872
+ const conflictErrors = checkConflicts(args, explicit, toKebab, actualInputNames);
873
+ errors.push(...conflictErrors);
874
+ return {
875
+ values,
876
+ positionals: positionalTokens.map((token) => token.value),
877
+ rest,
878
+ error: errors.length > 0 ? new AggregateError(errors) : undefined,
879
+ explicit
880
+ };
881
+ }
882
+ function isNegatedToken(token, option, schema) {
883
+ return schema.type === "boolean" && schema.negatable === true && token.name === `no-${option}`;
884
+ }
885
+ function parse(token, rawArg, option, schema) {
886
+ if (schema.type === "enum" && schema.choices && !schema.choices.includes(token.value))
887
+ return [undefined, createChoiceError(rawArg, option, schema, token.value)];
888
+ if (typeof schema.parse === "function") {
889
+ if (schema.type === "boolean") {
890
+ const [boolValue, error] = resolveBooleanValue(token, rawArg, option, schema);
891
+ if (error)
892
+ return [undefined, error];
893
+ return parseSchemaValue(String(boolValue), rawArg, option, schema);
894
+ }
895
+ return parseSchemaValue(token.value, rawArg, option, schema);
896
+ }
897
+ switch (schema.type) {
898
+ case "string":
899
+ return typeof token.value === "string" ? [token.value, undefined] : [undefined, createTypeError(rawArg, option, schema, token.value)];
900
+ case "boolean":
901
+ return resolveBooleanValue(token, rawArg, option, schema);
902
+ case "number":
903
+ if (typeof token.value !== "string" || !isNumeric(token.value))
904
+ return [undefined, createTypeError(rawArg, option, schema, token.value)];
905
+ return [+token.value, undefined];
906
+ case "enum":
907
+ return [token.value, undefined];
908
+ case "custom":
909
+ throw new TypeError(`argument '${option}' should have a 'parse' function`);
910
+ default:
911
+ throw new Error(`Unsupported argument type '${schema.type}' for option '${option}'`);
912
+ }
913
+ }
914
+ function resolveBooleanValue(token, rawArg, option, schema) {
915
+ const negated = isNegatedToken(token, option, schema);
916
+ if (!token.inlineValue)
917
+ return [!negated, undefined];
918
+ if (negated)
919
+ return [undefined, createUnexpectedValueError(rawArg, option, schema, token)];
920
+ if (token.value !== "true" && token.value !== "false")
921
+ return [undefined, createTypeError(rawArg, option, schema, token.value)];
922
+ return [token.value === "true", undefined];
923
+ }
924
+ function parseSchemaValue(value, rawArg, option, schema) {
925
+ try {
926
+ return [schema.parse(value), undefined];
927
+ } catch (error) {
928
+ return [undefined, createCustomParseError(error, rawArg, option, schema, value)];
929
+ }
930
+ }
931
+ function createRequireError(rawArg, option, schema) {
932
+ return new ArgResolveError(schema.type === "positional" ? `Positional argument '${option}' is required` : `Optional argument ${createOptionDisplayName(option, schema)} is required`, option, "required", schema, {
933
+ code: schema.type === "positional" ? ArgsValidationErrorKeys.requiredPositional : ArgsValidationErrorKeys.requiredOption,
934
+ values: schema.type === "positional" ? {
935
+ displayName: createArgumentDisplayName(option, schema),
936
+ name: rawArg
937
+ } : {
938
+ displayName: createOptionDisplayName(option, schema),
939
+ name: rawArg
940
+ }
941
+ });
942
+ }
943
+ function resolveSinglePositionalValue(values, errors, rawArg, option, schema, positional) {
944
+ if (typeof schema.parse === "function") {
945
+ const [parsedValue, error] = parseSchemaValue(positional.value, rawArg, option, schema);
946
+ if (error)
947
+ errors.push(error);
948
+ else
949
+ values[rawArg] = parsedValue;
950
+ } else
951
+ values[rawArg] = positional.value;
952
+ }
953
+ function hasDefault(schema) {
954
+ return schema.default != null;
955
+ }
956
+ function getDefaultValue(schema) {
957
+ const value = schema.default;
958
+ return schema.multiple && !Array.isArray(value) ? [value] : value;
959
+ }
960
+ function hasDefaultOutsideChoices(schema) {
961
+ const defaultType = typeof schema.default;
962
+ if (schema.type !== "enum" || !Array.isArray(schema.choices) || defaultType !== "string" && defaultType !== "number" && defaultType !== "boolean" || schema.choices.includes(schema.default))
963
+ return false;
964
+ const { parse } = schema;
965
+ if (typeof parse !== "function")
966
+ return true;
967
+ try {
968
+ return hasPureParseBrand(parse);
969
+ } catch {
970
+ return false;
971
+ }
972
+ }
973
+ function shouldRequireMissingSinglePositional(schema) {
974
+ if (schema.required === true)
975
+ return true;
976
+ if (schema.required === false)
977
+ return false;
978
+ return !hasDefault(schema);
979
+ }
980
+ function getRequiredPositionalInputCount(schema) {
981
+ if (schema.type !== "positional")
982
+ return 0;
983
+ if (schema.multiple)
984
+ return schema.required === true ? 1 : 0;
985
+ return shouldRequireMissingSinglePositional(schema) ? 1 : 0;
986
+ }
987
+ function createRequiredPositionalsAfter(argEntries) {
988
+ const requiredPositionalsAfter = Object.create(null);
989
+ let minimumRequiredPositionals = 0;
990
+ for (let i = argEntries.length - 1;i >= 0; i--) {
991
+ const [rawArg, schema] = argEntries[i];
992
+ if (schema.type !== "positional")
993
+ continue;
994
+ requiredPositionalsAfter[rawArg] = minimumRequiredPositionals;
995
+ minimumRequiredPositionals += getRequiredPositionalInputCount(schema);
996
+ }
997
+ return requiredPositionalsAfter;
998
+ }
999
+ var ArgResolveError = class extends ArgsValidationError {
1000
+ name;
1001
+ schema;
1002
+ type;
1003
+ constructor(message, name, type, schema, options = {}) {
1004
+ super(message, options);
1005
+ this.name = name;
1006
+ this.type = type;
1007
+ this.schema = schema;
1008
+ }
1009
+ };
1010
+ function validateRequire(token, rawArg, option, schema) {
1011
+ if (schema.required && schema.type !== "boolean" && !token.value)
1012
+ return createRequireError(rawArg, option, schema);
1013
+ }
1014
+ function isNumeric(str) {
1015
+ return str.trim() !== "" && !isNaN(str);
1016
+ }
1017
+ function createTypeError(rawArg, option, schema, actual, expected = schema.type) {
1018
+ return new ArgResolveError(`Optional argument ${createOptionDisplayName(option, schema)} should be '${expected}'`, option, "type", schema, {
1019
+ code: ArgsValidationErrorKeys.invalidType,
1020
+ values: {
1021
+ displayName: createOptionDisplayName(option, schema),
1022
+ name: rawArg,
1023
+ expected,
1024
+ ...actual != null ? { actual } : {}
1025
+ }
1026
+ });
1027
+ }
1028
+ function createMissingValueError(rawArg, option, schema, next) {
1029
+ const displayName = createOptionDisplayName(option, schema);
1030
+ const suggestion = next === undefined || !acceptsSuggestedValue(schema, next) ? undefined : `--${option}=${next}`;
1031
+ const hint = suggestion === undefined ? "" : ` (to pass '${next}' as its value, write '${suggestion}')`;
1032
+ const choices = schema.choices ?? [];
1033
+ return new ArgResolveError(`Optional argument ${displayName} requires a value${hint}`, option, "type", schema, {
1034
+ code: ArgsValidationErrorKeys.missingValue,
1035
+ values: {
1036
+ displayName,
1037
+ name: rawArg,
1038
+ expected: schema.type === "custom" ? schema.metavar ?? schema.type : schema.type,
1039
+ ...schema.type === "enum" ? {
1040
+ choices: formatChoices(choices),
1041
+ choiceValues: [...choices]
1042
+ } : {},
1043
+ ...suggestion === undefined ? {} : {
1044
+ next,
1045
+ suggestion
1046
+ }
1047
+ }
1048
+ });
1049
+ }
1050
+ function findOptionLikeNextArgument(tokens, optionTokens, position, argEntries, toKebab) {
1051
+ const token = optionTokens[position];
1052
+ for (let i = position + 1;i < optionTokens.length; i++)
1053
+ if (optionTokens[i].index === token.index)
1054
+ return;
1055
+ const nextArg = tokens.filter((t) => t.index === token.index + 1);
1056
+ if (nextArg.length === 0 || nextArg.some((t) => t.kind !== "option" || t.rawName == null))
1057
+ return;
1058
+ let text;
1059
+ let known;
1060
+ if (nextArg.length === 1 && nextArg[0].rawName.startsWith("--")) {
1061
+ const [option] = nextArg;
1062
+ text = option.inlineValue ? `${option.rawName}=${option.value}` : option.rawName;
1063
+ known = createKnownOptionNames(argEntries, toKebab).long.has(option.name);
1064
+ } else if (nextArg.every((t) => isShortOption(t.rawName) && t.value === undefined)) {
1065
+ text = `-${nextArg.map((t) => t.name).join("")}`;
1066
+ const { short } = createKnownOptionNames(argEntries, toKebab);
1067
+ known = optionTokens.every((t) => t.index !== token.index + 1 || short.has(t.name));
1068
+ } else
1069
+ return;
1070
+ return known ? undefined : text;
1071
+ }
1072
+ function createKnownOptionNames(argEntries, toKebab) {
1073
+ const long = /* @__PURE__ */ new Set;
1074
+ const short = /* @__PURE__ */ new Set;
1075
+ for (const [rawArg, schema] of argEntries) {
1076
+ if (schema.type === "positional")
1077
+ continue;
1078
+ const name = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
1079
+ long.add(name);
1080
+ if (schema.type === "boolean" && schema.negatable === true)
1081
+ long.add(`no-${name}`);
1082
+ if (schema.short)
1083
+ short.add(schema.short);
1084
+ }
1085
+ return {
1086
+ long,
1087
+ short
1088
+ };
1089
+ }
1090
+ function acceptsSuggestedValue(schema, value) {
1091
+ if (schema.type === "number" && !isNumeric(value))
1092
+ return false;
1093
+ if (schema.type === "enum" && schema.choices && !schema.choices.includes(value))
1094
+ return false;
1095
+ const { parse } = schema;
1096
+ if (typeof parse !== "function")
1097
+ return true;
1098
+ try {
1099
+ if (!hasPureParseBrand(parse))
1100
+ return schema.type === "number" || schema.type === "enum" && schema.choices !== undefined;
1101
+ parse(value);
1102
+ return true;
1103
+ } catch {
1104
+ return false;
1105
+ }
1106
+ }
1107
+ function hasPureParseBrand(parse) {
1108
+ return Object.hasOwn(parse, PURE_PARSE) && parse[PURE_PARSE] === true;
1109
+ }
1110
+ function createUnexpectedValueError(rawArg, option, schema, token) {
1111
+ const rawName = token.rawName;
1112
+ const displayName = `'${rawName}'`;
1113
+ return new ArgResolveError(`Optional argument ${displayName} does not take a value`, option, "type", schema, {
1114
+ code: ArgsValidationErrorKeys.unexpectedValue,
1115
+ values: {
1116
+ displayName,
1117
+ name: rawArg,
1118
+ rawName,
1119
+ ...token.value != null ? { actual: token.value } : {}
1120
+ }
1121
+ });
1122
+ }
1123
+ function createChoiceError(rawArg, option, schema, actual) {
1124
+ const choices = schema.choices ?? [];
1125
+ return new ArgResolveError(`Optional argument ${createOptionDisplayName(option, schema)} should be chosen from '${schema.type}' [${formatChoices(choices)}] values`, option, "type", schema, {
1126
+ code: ArgsValidationErrorKeys.invalidChoice,
1127
+ values: {
1128
+ displayName: createOptionDisplayName(option, schema),
1129
+ name: rawArg,
1130
+ expected: schema.type,
1131
+ choices: formatChoices(choices),
1132
+ choiceValues: [...choices],
1133
+ ...actual != null ? { actual } : {}
1134
+ }
1135
+ });
1136
+ }
1137
+ function createDefaultChoiceError(rawArg, option, schema) {
1138
+ const choices = schema.choices ?? [];
1139
+ const displayName = createOptionDisplayName(option, schema);
1140
+ return new ArgResolveError(`Optional argument ${displayName} has the default ${typeof schema.default === "string" ? JSON.stringify(schema.default) : String(schema.default)}, which is not one of '${schema.type}' [${formatChoices(choices)}] values`, option, "type", schema, {
1141
+ code: ArgsValidationErrorKeys.invalidDefault,
1142
+ values: {
1143
+ displayName,
1144
+ name: rawArg,
1145
+ expected: schema.type,
1146
+ choices: formatChoices(choices),
1147
+ choiceValues: [...choices],
1148
+ actual: schema.default
1149
+ }
1150
+ });
1151
+ }
1152
+ function createCustomParseError(error, rawArg, option, schema, value) {
1153
+ const reused = reuseValidationError(error, rawArg, option, schema, value);
1154
+ if (reused)
1155
+ return reused;
1156
+ const reason = getErrorReason(error);
1157
+ return new ArgsValidationError(reason, {
1158
+ code: ArgsValidationErrorKeys.customParse,
1159
+ values: {
1160
+ displayName: createArgumentDisplayName(option, schema),
1161
+ name: rawArg,
1162
+ reason
1163
+ },
1164
+ cause: error
1165
+ });
1166
+ }
1167
+ function reuseValidationError(error, rawArg, option, schema, value) {
1168
+ try {
1169
+ if (isArgsValidationError(error)) {
1170
+ augmentValidationError(error, rawArg, option, schema, value);
1171
+ return error;
1172
+ }
1173
+ } catch {}
1174
+ }
1175
+ function augmentValidationError(error, rawArg, option, schema, value) {
1176
+ const values = error.values;
1177
+ values.name ??= rawArg;
1178
+ values.displayName ??= createArgumentDisplayName(option, schema);
1179
+ if ((error.code === ArgsValidationErrorKeys.invalidType || error.code === ArgsValidationErrorKeys.invalidChoice) && values.actual == null)
1180
+ values.actual = value;
1181
+ }
1182
+ function getErrorReason(error) {
1183
+ return error instanceof Error ? error.message : String(error);
1184
+ }
1185
+ function createArgumentDisplayName(option, schema) {
1186
+ return schema.type === "positional" ? `'${option}'` : createOptionDisplayName(option, schema);
1187
+ }
1188
+ function createOptionDisplayName(option, schema) {
1189
+ return `'--${option}'${schema.short ? ` or '-${schema.short}'` : ""}`;
1190
+ }
1191
+ function createConflictError(rawArg, option, schema, actualName, conflictingArg, conflictingActualName) {
1192
+ const displayName = `'${actualName}'`;
1193
+ const conflictDisplayName = `'${conflictingActualName}'`;
1194
+ return new ArgResolveError(`${schema.type === "positional" ? "Positional" : "Optional"} argument ${displayName} conflicts with ${conflictDisplayName}`, option, "conflict", schema, {
1195
+ code: ArgsValidationErrorKeys.conflict,
1196
+ values: {
1197
+ displayName,
1198
+ name: rawArg,
1199
+ conflictDisplayName,
1200
+ conflictName: conflictingArg
1201
+ }
1202
+ });
1203
+ }
1204
+ function checkConflicts(args, explicit, toKebab, actualInputNames) {
1205
+ for (const rawArg in args) {
1206
+ const schema = args[rawArg];
1207
+ if (!explicit[rawArg])
1208
+ continue;
1209
+ if (!schema.conflicts)
1210
+ continue;
1211
+ const conflicts = Array.isArray(schema.conflicts) ? schema.conflicts : [schema.conflicts];
1212
+ for (let i = 0;i < conflicts.length; i++) {
1213
+ const conflictingArg = conflicts[i];
1214
+ if (!explicit[conflictingArg])
1215
+ continue;
1216
+ const arg = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg;
1217
+ const conflictingArgKebab = toKebab || args[conflictingArg]?.toKebab ? kebabnize(conflictingArg) : conflictingArg;
1218
+ return [createConflictError(rawArg, arg, schema, schema.type === "positional" ? arg : actualInputNames.get(rawArg) || `--${arg}`, conflictingArg, args[conflictingArg]?.type === "positional" ? conflictingArgKebab : actualInputNames.get(conflictingArg) || `--${conflictingArgKebab}`)];
1219
+ }
1220
+ }
1221
+ return [];
1222
+ }
1223
+
1224
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/error-pbHb3QAL.js
1225
+ var CommandNotFoundErrorKeys = { notFound: "err:cmd:not-found" };
1226
+ var CommandResolutionErrorKeys = {
1227
+ ambiguous: "err:cmd:ambiguous",
1228
+ inconsistentOptions: "err:cmd:inconsistent-options",
1229
+ lazySchemaMismatch: "err:cmd:lazy-schema-mismatch"
1230
+ };
1231
+ var COMMAND_NOT_FOUND_ERROR_BRAND = Symbol.for("gunshi.CommandNotFoundError");
1232
+ var COMMAND_RESOLUTION_ERROR_BRAND = Symbol.for("gunshi.CommandResolutionError");
1233
+ var CommandNotFoundError = class extends Error {
1234
+ code;
1235
+ values;
1236
+ commandName;
1237
+ candidates;
1238
+ commandPath;
1239
+ constructor(message, options) {
1240
+ super(message, { cause: options.cause });
1241
+ this.name = "CommandNotFoundError";
1242
+ this.code = options.code;
1243
+ this.values = options.values || {};
1244
+ this.commandName = options.commandName;
1245
+ this.candidates = options.candidates || [];
1246
+ this.commandPath = options.commandPath || [];
1247
+ Object.defineProperty(this, COMMAND_NOT_FOUND_ERROR_BRAND, {
1248
+ value: true,
1249
+ enumerable: false,
1250
+ writable: false,
1251
+ configurable: false
1252
+ });
1253
+ }
1254
+ };
1255
+ var CommandResolutionError = class extends Error {
1256
+ code;
1257
+ values;
1258
+ commandPath;
1259
+ candidatePaths;
1260
+ constructor(message, options = {}) {
1261
+ super(message, { cause: options.cause });
1262
+ this.name = "CommandResolutionError";
1263
+ this.code = options.code;
1264
+ this.values = options.values || {};
1265
+ this.commandPath = options.commandPath || [];
1266
+ this.candidatePaths = options.candidatePaths || [];
1267
+ Object.defineProperty(this, COMMAND_RESOLUTION_ERROR_BRAND, {
1268
+ value: true,
1269
+ enumerable: false,
1270
+ writable: false,
1271
+ configurable: false
1272
+ });
1273
+ }
1274
+ };
1275
+ function isCommandNotFoundError(error) {
1276
+ if (error instanceof CommandNotFoundError)
1277
+ return true;
1278
+ if (!isRecord2(error) || !hasCommandNotFoundErrorShape(error))
1279
+ return false;
1280
+ if (Object.hasOwn(error, COMMAND_NOT_FOUND_ERROR_BRAND) && error[COMMAND_NOT_FOUND_ERROR_BRAND] === true)
1281
+ return true;
1282
+ return error instanceof Error && error.name === "CommandNotFoundError";
1283
+ }
1284
+ function isCommandResolutionError(error) {
1285
+ if (error instanceof CommandResolutionError)
1286
+ return true;
1287
+ if (!isRecord2(error) || !hasCommandResolutionErrorShape(error))
1288
+ return false;
1289
+ return Object.hasOwn(error, COMMAND_RESOLUTION_ERROR_BRAND) && error[COMMAND_RESOLUTION_ERROR_BRAND] === true;
1290
+ }
1291
+ function isArgsValidationError2(error) {
1292
+ if (error instanceof ArgsValidationError)
1293
+ return true;
1294
+ if (!isRecord2(error) || !hasArgsValidationErrorShape(error))
1295
+ return false;
1296
+ if (isArgsValidationError(error))
1297
+ return true;
1298
+ return error instanceof Error && error.name === "ArgsValidationError";
1299
+ }
1300
+ function isRecord2(value) {
1301
+ return typeof value === "object" && value !== null;
1302
+ }
1303
+ function isStringArray(value) {
1304
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
1305
+ }
1306
+ function hasOptionalStringCode(error) {
1307
+ return "code" in error && (error.code === undefined || typeof error.code === "string");
1308
+ }
1309
+ function hasCommandNotFoundErrorShape(error) {
1310
+ return hasOptionalStringCode(error) && isRecord2(error.values) && typeof error.commandName === "string" && isStringArray(error.candidates) && isStringArray(error.commandPath);
1311
+ }
1312
+ function hasCommandResolutionErrorShape(error) {
1313
+ return hasOptionalStringCode(error) && isRecord2(error.values) && isStringArray(error.commandPath) && Array.isArray(error.candidatePaths) && error.candidatePaths.every((path) => isStringArray(path));
1314
+ }
1315
+ function hasArgsValidationErrorShape(error) {
1316
+ return hasOptionalStringCode(error) && isRecord2(error.values);
1317
+ }
1318
+ function hasPriorityValidationError(error) {
1319
+ return error?.errors.some((error) => isCommandNotFoundError(error) || isCommandResolutionError(error) || isArgsValidationError2(error) && error.code === ArgsValidationErrorKeys.unknownOption) ?? false;
1320
+ }
1321
+
1322
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/core-EDPnjwxe.js
1323
+ var EMPTY_RENDERER = () => Promise.resolve("");
1324
+ function createDecorators() {
1325
+ const headerDecorators = [];
1326
+ const usageDecorators = [];
1327
+ const validationDecorators = [];
1328
+ const commandDecorators = [];
1329
+ function buildRenderer(decorators, defaultRenderer) {
1330
+ if (decorators.length === 0)
1331
+ return defaultRenderer;
1332
+ let renderer = defaultRenderer;
1333
+ for (const decorator of decorators) {
1334
+ const previousRenderer = renderer;
1335
+ renderer = (ctx) => decorator(previousRenderer, ctx);
1336
+ }
1337
+ return renderer;
1338
+ }
1339
+ return Object.freeze({
1340
+ addHeaderDecorator(decorator) {
1341
+ headerDecorators.push(decorator);
1342
+ },
1343
+ addUsageDecorator(decorator) {
1344
+ usageDecorators.push(decorator);
1345
+ },
1346
+ addValidationErrorsDecorator(decorator) {
1347
+ validationDecorators.push(decorator);
1348
+ },
1349
+ addCommandDecorator(decorator) {
1350
+ commandDecorators.push(decorator);
1351
+ },
1352
+ get commandDecorators() {
1353
+ return [...commandDecorators];
1354
+ },
1355
+ getHeaderRenderer() {
1356
+ return buildRenderer(headerDecorators, EMPTY_RENDERER);
1357
+ },
1358
+ getUsageRenderer() {
1359
+ return buildRenderer(usageDecorators, EMPTY_RENDERER);
1360
+ },
1361
+ getValidationErrorsRenderer() {
1362
+ if (validationDecorators.length === 0)
1363
+ return EMPTY_RENDERER;
1364
+ let renderer = EMPTY_RENDERER;
1365
+ for (const decorator of validationDecorators) {
1366
+ const previousRenderer = renderer;
1367
+ renderer = (ctx, error) => decorator(previousRenderer, ctx, error);
1368
+ }
1369
+ return renderer;
1370
+ }
1371
+ });
1372
+ }
1373
+ function createPluginContext(decorators, initialSubCommands) {
1374
+ const globalOptions = /* @__PURE__ */ new Map;
1375
+ const subCommands = new Map(initialSubCommands || []);
1376
+ return Object.freeze({
1377
+ get globalOptions() {
1378
+ return new Map(globalOptions);
1379
+ },
1380
+ addGlobalOption(name, schema) {
1381
+ if (!name)
1382
+ throw new Error("Option name must be a non-empty string");
1383
+ if (globalOptions.has(name))
1384
+ throw new Error(`Global option '${name}' is already registered`);
1385
+ const taken = schema.short && findGlobalOptionByShort(globalOptions, schema.short);
1386
+ if (taken) {
1387
+ console.warn(`Short name '-${schema.short}' of the global option '${name}' is already used by '${taken}'. Global option '${name}' is registered without it.`);
1388
+ globalOptions.set(name, {
1389
+ ...schema,
1390
+ short: undefined
1391
+ });
1392
+ return;
1393
+ }
1394
+ globalOptions.set(name, schema);
1395
+ },
1396
+ get subCommands() {
1397
+ return new Map(subCommands);
1398
+ },
1399
+ addCommand(name, command) {
1400
+ if (!name)
1401
+ throw new Error("Command name must be a non-empty string");
1402
+ if (subCommands.has(name))
1403
+ throw new Error(`Command '${name}' is already registered`);
1404
+ subCommands.set(name, command);
1405
+ },
1406
+ hasCommand(name) {
1407
+ return subCommands.has(name);
1408
+ },
1409
+ decorateHeaderRenderer(decorator) {
1410
+ decorators.addHeaderDecorator(decorator);
1411
+ },
1412
+ decorateUsageRenderer(decorator) {
1413
+ decorators.addUsageDecorator(decorator);
1414
+ },
1415
+ decorateValidationErrorsRenderer(decorator) {
1416
+ decorators.addValidationErrorsDecorator(decorator);
1417
+ },
1418
+ decorateCommand(decorator) {
1419
+ decorators.addCommandDecorator(decorator);
1420
+ }
1421
+ });
1422
+ }
1423
+ function findGlobalOptionByShort(globalOptions, short) {
1424
+ for (const [name, schema] of globalOptions)
1425
+ if (schema.short === short)
1426
+ return name;
1427
+ }
1428
+ function resolveDependencies(plugins) {
1429
+ const sorted = [];
1430
+ const visited = /* @__PURE__ */ new Set;
1431
+ const visiting = /* @__PURE__ */ new Set;
1432
+ const pluginMap = /* @__PURE__ */ new Map;
1433
+ for (const plugin of plugins) {
1434
+ if (typeof plugin.id !== "string" || plugin.id.length === 0)
1435
+ throw new Error("Plugin id must be a non-empty string");
1436
+ if (pluginMap.has(plugin.id))
1437
+ console.warn(`Duplicate plugin id detected: \`${plugin.id}\``);
1438
+ pluginMap.set(plugin.id, plugin);
1439
+ }
1440
+ function visit(plugin) {
1441
+ if (typeof plugin.id !== "string" || plugin.id.length === 0)
1442
+ throw new Error("Plugin id must be a non-empty string");
1443
+ if (visited.has(plugin.id))
1444
+ return;
1445
+ if (visiting.has(plugin.id))
1446
+ throw new Error(`Circular dependency detected: \`${[...visiting].join(` -> `) + " -> " + plugin.id}\``);
1447
+ visiting.add(plugin.id);
1448
+ const deps = plugin.dependencies || [];
1449
+ for (const dep of deps) {
1450
+ const depId = typeof dep === "string" ? dep : dep.id;
1451
+ const isOptional = typeof dep === "string" ? false : dep.optional || false;
1452
+ const depPlugin = pluginMap.get(depId);
1453
+ if (!depPlugin && !isOptional)
1454
+ throw new Error(`Missing required dependency: \`${depId}\` on \`${plugin.id}\``);
1455
+ if (depPlugin)
1456
+ visit(depPlugin);
1457
+ }
1458
+ visiting.delete(plugin.id);
1459
+ visited.add(plugin.id);
1460
+ sorted.push(plugin);
1461
+ }
1462
+ for (const plugin of plugins)
1463
+ visit(plugin);
1464
+ return sorted;
1465
+ }
1466
+ function resolveCommandArgs(globalOptions, args) {
1467
+ return Object.assign(create(), resolveGlobalOptions(globalOptions, args), args);
1468
+ }
1469
+ function resolveGlobalOptions(globalOptions, args) {
1470
+ if (!globalOptions)
1471
+ return;
1472
+ const shortNames = /* @__PURE__ */ new Set;
1473
+ for (const schema of Object.values(args || {}))
1474
+ if (schema.type !== "positional" && schema.short)
1475
+ shortNames.add(schema.short);
1476
+ const resolved = create();
1477
+ for (const [name, schema] of globalOptions)
1478
+ resolved[name] = schema.short && shortNames.has(schema.short) ? {
1479
+ ...schema,
1480
+ short: undefined
1481
+ } : schema;
1482
+ return resolved;
1483
+ }
1484
+ async function cliCore(argv, entry, options, plugins, usageOnly = false) {
1485
+ const decorators = createDecorators();
1486
+ if (usageOnly)
1487
+ decorators.addCommandDecorator(usageOnlyDecorator());
1488
+ const entryCommand = createEntryCommand(entry);
1489
+ const initialSubCommands = createInitialSubCommands(options, entryCommand);
1490
+ const pluginContext = createPluginContext(decorators, initialSubCommands);
1491
+ const resolvedPlugins = await applyPlugins(pluginContext, [...plugins, ...options.plugins || []]);
1492
+ const cliOptions = normalizeCliOptions(options, decorators, pluginContext, entryCommand);
1493
+ if (initialSubCommands.size === 0 && cliOptions.subCommands.size > 0 && options.fallbackToEntry === undefined)
1494
+ cliOptions.fallbackToEntry = true;
1495
+ const tokens = parseArgs(argv);
1496
+ const selection = resolveCommandSelection(tokens, entry, cliOptions, pluginContext.globalOptions);
1497
+ const resolved = selection.context;
1498
+ const { commandName: name, command, callMode, commandPath, depth, levelSubCommands } = resolved;
1499
+ let targetCommand = command;
1500
+ let targetCommandName = name;
1501
+ let targetCallMode = callMode;
1502
+ let targetCommandPath = commandPath;
1503
+ let targetDepth = depth;
1504
+ let targetOmitted = resolved.omitted;
1505
+ let targetLevelSubCommands = levelSubCommands;
1506
+ const additionalValidationErrors = selection.error ? [selection.error] : [];
1507
+ if (!targetCommand) {
1508
+ if (!resolved.parentCommand || !resolved.unresolvedCommandName)
1509
+ throw new Error(`Command not found: ${name || ""}`);
1510
+ targetCommand = resolved.parentCommand;
1511
+ targetCommandName = resolved.parentCommandName;
1512
+ targetCommandPath = resolved.parentCommandPath || [];
1513
+ targetDepth = targetCommandPath.length;
1514
+ targetCallMode = targetDepth > 0 ? "subCommand" : "entry";
1515
+ targetOmitted = false;
1516
+ targetLevelSubCommands = resolved.parentSubCommands;
1517
+ additionalValidationErrors.push(createCommandNotFoundError(resolved));
1518
+ }
1519
+ const routingOptions = Object.assign(create(), cliOptions, { subCommands: new Map(cliOptions.subCommands) });
1520
+ if (targetLevelSubCommands)
1521
+ cliOptions.subCommands = targetLevelSubCommands;
1522
+ const resolvedCommand = isLazyCommand(targetCommand) ? await resolveLazyCommand(targetCommand, targetCommandName, true) : targetCommand;
1523
+ if (selection.error == null && isLazyCommand(targetCommand)) {
1524
+ const loaded = resolveCommandTreeFromPositionals(getRoutingPositionals(tokens, pluginContext.globalOptions, resolvedCommand), entry, routingOptions);
1525
+ if (!sameCommandPath(loaded.commandPath, targetCommandPath))
1526
+ additionalValidationErrors.push(createLazySchemaMismatchError(targetCommandPath, loaded.commandPath));
1527
+ }
1528
+ const commandArgs = getCommandArgs(resolvedCommand);
1529
+ const args = resolveCommandArgs(pluginContext.globalOptions, commandArgs);
1530
+ cliOptions.globalOptions = resolveEffectiveGlobalOptions(pluginContext.globalOptions, commandArgs, args);
1531
+ const skipPositional = resolveSkipPositional(tokens, pluginContext.globalOptions, resolvedCommand, targetDepth);
1532
+ const diagnostic = selection.diagnostic === true;
1533
+ const { explicit, values, positionals, rest, error } = diagnostic ? {
1534
+ explicit: create(),
1535
+ values: create(),
1536
+ positionals: [],
1537
+ rest: [],
1538
+ error: undefined
1539
+ } : resolveArgs(args, tokens, {
1540
+ shortGrouping: true,
1541
+ toKebab: resolvedCommand.toKebab,
1542
+ skipPositional
1543
+ });
1544
+ const validationError = mergeValidationErrors(error, [...additionalValidationErrors, ...cliOptions.strict && !diagnostic ? createUnknownOptionErrors(findUnknownOptions(args, tokens, { toKebab: resolvedCommand.toKebab })) : []]);
1545
+ return await executeCommand(resolvedCommand, await createCommandContext({
1546
+ args,
1547
+ explicit,
1548
+ values,
1549
+ positionals,
1550
+ rest,
1551
+ argv,
1552
+ tokens,
1553
+ omitted: targetOmitted,
1554
+ callMode: targetCallMode,
1555
+ commandPath: targetCommandPath,
1556
+ command: resolvedCommand,
1557
+ extensions: getPluginExtensions(resolvedPlugins),
1558
+ validationError,
1559
+ cliOptions
1560
+ }), decorators.commandDecorators);
1561
+ }
1562
+ function usageOnlyDecorator() {
1563
+ return () => async (ctx) => {
1564
+ if (hasPriorityValidationError(ctx.validationError))
1565
+ throw ctx.validationError;
1566
+ const buf = [];
1567
+ if (ctx.env.renderHeader != null) {
1568
+ const header = await ctx.env.renderHeader(ctx);
1569
+ if (header)
1570
+ buf.push(header);
1571
+ }
1572
+ if (ctx.env.renderUsage == null)
1573
+ return;
1574
+ const usage = await ctx.env.renderUsage(ctx);
1575
+ if (!usage)
1576
+ return;
1577
+ buf.push(usage);
1578
+ return buf.join(`
1579
+ `);
1580
+ };
1581
+ }
1582
+ async function applyPlugins(pluginContext, plugins) {
1583
+ const sortedPlugins = resolveDependencies(plugins);
1584
+ for (const plugin of sortedPlugins)
1585
+ try {
1586
+ await plugin(pluginContext);
1587
+ } catch (error) {
1588
+ throw new Error(`Failed to install the plugin \`${plugin.id}\``, { cause: error });
1589
+ }
1590
+ return sortedPlugins;
1591
+ }
1592
+ function resolveEffectiveGlobalOptions(globalOptions, commandArgs, args) {
1593
+ const effective = /* @__PURE__ */ new Map;
1594
+ for (const name of globalOptions.keys())
1595
+ if (!Object.hasOwn(commandArgs, name))
1596
+ effective.set(name, args[name]);
1597
+ return effective;
1598
+ }
1599
+ function getCommandArgs(cmd) {
1600
+ if (isLazyCommand(cmd))
1601
+ return cmd.args || create();
1602
+ else if (typeof cmd === "object")
1603
+ return cmd.args || create();
1604
+ else
1605
+ return create();
1606
+ }
1607
+ var NEGATABLE_OPTION_PREFIX = "no-";
1608
+ function findUnknownOptions(args, tokens, options) {
1609
+ const knownLongOptions = /* @__PURE__ */ new Set;
1610
+ const knownShortOptions = /* @__PURE__ */ new Set;
1611
+ const knownNegatableOptions = /* @__PURE__ */ new Set;
1612
+ const knownLongOptionCandidates = /* @__PURE__ */ new Set;
1613
+ const longOptionCandidates = [];
1614
+ function addLongOptionCandidate(name) {
1615
+ const candidate = `--${name}`;
1616
+ if (knownLongOptionCandidates.has(candidate))
1617
+ return;
1618
+ knownLongOptionCandidates.add(candidate);
1619
+ longOptionCandidates.push(candidate);
1620
+ }
1621
+ for (const [name, schema] of Object.entries(args)) {
1622
+ if (schema.type === "positional")
1623
+ continue;
1624
+ const optionName = resolveOptionName(name, schema, options);
1625
+ knownLongOptions.add(optionName);
1626
+ if (!schema.hidden)
1627
+ addLongOptionCandidate(optionName);
1628
+ if (schema.short)
1629
+ knownShortOptions.add(schema.short);
1630
+ if (schema.type === "boolean" && schema.negatable) {
1631
+ const negatableOptionName = `${NEGATABLE_OPTION_PREFIX}${optionName}`;
1632
+ knownNegatableOptions.add(negatableOptionName);
1633
+ if (!schema.hidden)
1634
+ addLongOptionCandidate(negatableOptionName);
1635
+ }
1636
+ }
1637
+ const unknownOptions = [];
1638
+ for (const token of tokens) {
1639
+ if (token.kind === "option-terminator")
1640
+ break;
1641
+ if (token.kind !== "option" || !token.name || !token.rawName)
1642
+ continue;
1643
+ const isLongOption = token.rawName.startsWith("--");
1644
+ if (isLongOption) {
1645
+ if (knownLongOptions.has(token.name) || knownNegatableOptions.has(token.name))
1646
+ continue;
1647
+ } else if (knownShortOptions.has(token.name))
1648
+ continue;
1649
+ unknownOptions.push({
1650
+ rawName: token.rawName,
1651
+ name: token.name,
1652
+ candidates: isLongOption ? longOptionCandidates : []
1653
+ });
1654
+ }
1655
+ return unknownOptions;
1656
+ }
1657
+ function resolveOptionName(name, schema, options) {
1658
+ return options.toKebab || schema.toKebab ? kebabnize(name) : name;
1659
+ }
1660
+ function createUnknownOptionErrors(unknownOptions) {
1661
+ return unknownOptions.map(({ rawName, name, candidates }) => {
1662
+ return new ArgsValidationError(`Unknown option: ${rawName}`, {
1663
+ code: ArgsValidationErrorKeys.unknownOption,
1664
+ values: {
1665
+ rawName,
1666
+ name,
1667
+ candidates
1668
+ }
1669
+ });
1670
+ });
1671
+ }
1672
+ function mergeValidationErrors(error, additionalErrors) {
1673
+ if (additionalErrors.length === 0)
1674
+ return error;
1675
+ return new AggregateError(error ? [...error.errors, ...additionalErrors] : additionalErrors, error?.message || additionalErrors[0]?.message);
1676
+ }
1677
+ var isObject = (val) => val !== null && typeof val === "object";
1678
+ function createEntryCommand(entryCmd) {
1679
+ if (isLazyCommand(entryCmd))
1680
+ return Object.assign((...args) => entryCmd(...args), entryCmd, { entry: true });
1681
+ else if (typeof entryCmd === "object")
1682
+ return Object.assign(create(), entryCmd, { entry: true });
1683
+ else if (typeof entryCmd === "function")
1684
+ return {
1685
+ run: entryCmd,
1686
+ name: entryCmd.name || "(anonymous)",
1687
+ entry: true
1688
+ };
1689
+ }
1690
+ function createInitialSubCommands(options, entryCommand) {
1691
+ const hasSubCommands = options.subCommands ? options.subCommands instanceof Map ? options.subCommands.size > 0 : isObject(options.subCommands) && Object.keys(options.subCommands).length > 0 : false;
1692
+ const subCommands = new Map(options.subCommands instanceof Map ? options.subCommands : []);
1693
+ if (!(options.subCommands instanceof Map) && isObject(options.subCommands))
1694
+ for (const [name, cmd] of Object.entries(options.subCommands))
1695
+ subCommands.set(name, cmd);
1696
+ if (hasSubCommands && entryCommand)
1697
+ subCommands.set(resolveEntryName(entryCommand), entryCommand);
1698
+ return subCommands;
1699
+ }
1700
+ function normalizeCliOptions(options, decorators, pluginContext, entryCommand) {
1701
+ const subCommands = new Map(pluginContext.subCommands);
1702
+ const resolvedOptions = Object.assign(create(), CLI_OPTIONS_DEFAULT, options, {
1703
+ subCommands,
1704
+ entryCommand
1705
+ });
1706
+ if (resolvedOptions.renderHeader === undefined)
1707
+ resolvedOptions.renderHeader = decorators.getHeaderRenderer();
1708
+ if (resolvedOptions.renderUsage === undefined)
1709
+ resolvedOptions.renderUsage = decorators.getUsageRenderer();
1710
+ if (resolvedOptions.renderValidationErrors === undefined)
1711
+ resolvedOptions.renderValidationErrors = decorators.getValidationErrorsRenderer();
1712
+ return resolvedOptions;
1713
+ }
1714
+ function getPositionalTokens(tokens) {
1715
+ const positionals = [];
1716
+ for (const token of tokens) {
1717
+ if (token.kind === "option-terminator")
1718
+ break;
1719
+ if (token.kind === "positional" && token.value)
1720
+ positionals.push(token.value);
1721
+ }
1722
+ return positionals;
1723
+ }
1724
+ function resolveCommandTree(tokens, entry, options) {
1725
+ return resolveCommandTreeFromPositionals(getPositionalTokens(tokens), entry, options);
1726
+ }
1727
+ function resolveCommandTreeFromPositionals(positionals, entry, options) {
1728
+ function resolveAsEntry() {
1729
+ if (typeof entry === "function") {
1730
+ if (isLazyCommand(entry))
1731
+ return {
1732
+ commandName: resolveEntryName(entry),
1733
+ command: entry,
1734
+ callMode: "entry",
1735
+ commandPath: [],
1736
+ depth: 0,
1737
+ omitted: options.subCommands.size > 0 && !positionals[0],
1738
+ levelSubCommands: options.subCommands.size > 0 ? options.subCommands : undefined
1739
+ };
1740
+ else
1741
+ return {
1742
+ command: {
1743
+ run: entry,
1744
+ entry: true
1745
+ },
1746
+ callMode: "entry",
1747
+ commandPath: [],
1748
+ depth: 0,
1749
+ omitted: options.subCommands.size > 0 && !positionals[0],
1750
+ levelSubCommands: options.subCommands.size > 0 ? options.subCommands : undefined
1751
+ };
1752
+ } else if (typeof entry === "object")
1753
+ return {
1754
+ commandName: resolveEntryName(entry),
1755
+ command: entry,
1756
+ callMode: "entry",
1757
+ commandPath: [],
1758
+ depth: 0,
1759
+ omitted: options.subCommands.size > 0 && !positionals[0],
1760
+ levelSubCommands: options.subCommands.size > 0 ? options.subCommands : undefined
1761
+ };
1762
+ else
1763
+ return {
1764
+ callMode: "unexpected",
1765
+ commandPath: [],
1766
+ depth: 0,
1767
+ omitted: false,
1768
+ levelSubCommands: undefined
1769
+ };
1770
+ }
1771
+ if (positionals.length === 0 || options.subCommands.size === 0)
1772
+ return resolveAsEntry();
1773
+ let currentSubCommands = options.subCommands;
1774
+ let resolvedCommand;
1775
+ let resolvedName;
1776
+ const commandPath = [];
1777
+ let depth = 0;
1778
+ for (let i = 0;i < positionals.length; i++) {
1779
+ const token = positionals[i];
1780
+ const cmd = currentSubCommands.get(token);
1781
+ if (cmd == null) {
1782
+ if (depth === 0) {
1783
+ if (options.fallbackToEntry)
1784
+ return resolveAsEntry();
1785
+ const parent = resolveAsEntry();
1786
+ return {
1787
+ commandName: token,
1788
+ callMode: "unexpected",
1789
+ commandPath: [],
1790
+ depth: 0,
1791
+ omitted: false,
1792
+ levelSubCommands: undefined,
1793
+ unresolvedCommandName: token,
1794
+ parentCommand: parent.command,
1795
+ parentCommandName: parent.commandName,
1796
+ parentCommandPath: [],
1797
+ parentSubCommands: options.subCommands
1798
+ };
1799
+ }
1800
+ return {
1801
+ commandName: token,
1802
+ callMode: "unexpected",
1803
+ commandPath: [...commandPath],
1804
+ depth,
1805
+ omitted: false,
1806
+ levelSubCommands: undefined,
1807
+ unresolvedCommandName: token,
1808
+ parentCommand: resolvedCommand,
1809
+ parentCommandName: resolvedName,
1810
+ parentCommandPath: [...commandPath],
1811
+ parentSubCommands: currentSubCommands
1812
+ };
1813
+ }
1814
+ let resolved = cmd;
1815
+ if (typeof cmd === "function" && cmd.commandName == null)
1816
+ resolved = Object.assign((...args) => cmd(...args), cmd, { commandName: token });
1817
+ else if (typeof cmd === "object" && cmd.name == null)
1818
+ resolved = Object.assign(create(), cmd, { name: token });
1819
+ resolvedCommand = resolved;
1820
+ resolvedName = token;
1821
+ commandPath.push(token);
1822
+ depth++;
1823
+ const nestedSubCommands = getCommandSubCommands(cmd);
1824
+ if (nestedSubCommands && nestedSubCommands.size > 0)
1825
+ currentSubCommands = nestedSubCommands;
1826
+ else
1827
+ break;
1828
+ }
1829
+ if (!resolvedCommand)
1830
+ return resolveAsEntry();
1831
+ const resolvedSubCommands = getCommandSubCommands(resolvedCommand);
1832
+ const omitted = resolvedSubCommands != null && resolvedSubCommands.size > 0;
1833
+ let levelSubCommands;
1834
+ if (omitted && resolvedSubCommands) {
1835
+ levelSubCommands = new Map(resolvedSubCommands);
1836
+ let entryCopy;
1837
+ if (typeof resolvedCommand === "function")
1838
+ entryCopy = Object.assign((...args) => resolvedCommand(...args), resolvedCommand, { entry: true });
1839
+ else
1840
+ entryCopy = Object.assign(create(), resolvedCommand, { entry: true });
1841
+ levelSubCommands.set(resolvedName || resolveEntryName(entryCopy), entryCopy);
1842
+ }
1843
+ return {
1844
+ commandName: resolvedName,
1845
+ command: resolvedCommand,
1846
+ callMode: depth > 0 ? "subCommand" : "entry",
1847
+ commandPath,
1848
+ depth,
1849
+ omitted,
1850
+ levelSubCommands
1851
+ };
1852
+ }
1853
+ function resolveCommandSelection(tokens, entry, options, globalOptions) {
1854
+ const rawPositionals = getPositionalTokens(tokens);
1855
+ const legacy = resolveCommandTree(tokens, entry, options);
1856
+ if (!tokens.some((token) => token.kind === "option"))
1857
+ return { context: legacy };
1858
+ const candidates = collectRoutingCandidates(rawPositionals, options.subCommands);
1859
+ const evaluations = candidates.map((candidate) => evaluateRoutingCandidate(candidate));
1860
+ const validExplicit = evaluations.filter((evaluation) => evaluation.result.command != null && evaluation.result.unresolvedCommandName == null && sameCommandPath(evaluation.result.commandPath, evaluation.path) && evaluation.path.length > 0);
1861
+ if (legacy.command != null && legacy.unresolvedCommandName == null && legacy.commandPath.length > 0) {
1862
+ const legacyMatch = validExplicit.find((evaluation) => sameCommandPath(evaluation.path, legacy.commandPath));
1863
+ if (legacyMatch)
1864
+ return { context: legacyMatch.result };
1865
+ }
1866
+ if (validExplicit.length === 1)
1867
+ return { context: validExplicit[0].result };
1868
+ if (validExplicit.length > 1)
1869
+ return createCommandResolutionResult(options, entry, CommandResolutionErrorKeys.ambiguous, validExplicit.map((evaluation) => evaluation.path));
1870
+ const entryEvaluation = evaluateRoutingCandidate({
1871
+ path: [],
1872
+ command: getEntryRoutingCommand(entry, options)
1873
+ });
1874
+ if (entryEvaluation.result.command != null && entryEvaluation.result.unresolvedCommandName == null && entryEvaluation.result.commandPath.length === 0)
1875
+ return { context: entryEvaluation.result };
1876
+ const failures = evaluations.filter((evaluation) => {
1877
+ const { result } = evaluation;
1878
+ if (!result.unresolvedCommandName)
1879
+ return false;
1880
+ const parentPath = result.parentCommandPath || [];
1881
+ return isPathPrefix(evaluation.path, parentPath);
1882
+ }).map((evaluation) => evaluation.result);
1883
+ if (entryEvaluation.result.unresolvedCommandName)
1884
+ failures.push(entryEvaluation.result);
1885
+ const deepestFailures = selectDeepestFailures(failures);
1886
+ if (deepestFailures.length === 1)
1887
+ return { context: deepestFailures[0] };
1888
+ if (deepestFailures.length > 1) {
1889
+ const paths = deepestFailures.map((result) => result.parentCommandPath || []);
1890
+ return createCommandResolutionResult(options, entry, CommandResolutionErrorKeys.ambiguous, paths);
1891
+ }
1892
+ return createCommandResolutionResult(options, entry, CommandResolutionErrorKeys.inconsistentOptions, candidates.map((candidate) => candidate.path));
1893
+ function evaluateRoutingCandidate(candidate) {
1894
+ const positionals = getRoutingPositionals(tokens, globalOptions, candidate.command);
1895
+ return {
1896
+ ...candidate,
1897
+ positionals,
1898
+ result: resolveCommandTreeFromPositionals(positionals, entry, options)
1899
+ };
1900
+ }
1901
+ }
1902
+ function collectRoutingCandidates(rawPositionals, root) {
1903
+ const candidates = [];
1904
+ const seen = /* @__PURE__ */ new Set;
1905
+ function collect(commands, offset, parentPath) {
1906
+ for (let index = offset;index < rawPositionals.length; index++) {
1907
+ const name = rawPositionals[index];
1908
+ const command = commands.get(name);
1909
+ if (command == null)
1910
+ continue;
1911
+ const path = [...parentPath, name];
1912
+ const key = JSON.stringify(path);
1913
+ const normalized = normalizeCommandReference(command, name);
1914
+ if (!seen.has(key)) {
1915
+ seen.add(key);
1916
+ candidates.push({
1917
+ path,
1918
+ command: normalized
1919
+ });
1920
+ }
1921
+ const nested = getCommandSubCommands(normalized);
1922
+ if (nested && nested.size > 0)
1923
+ collect(nested, index + 1, path);
1924
+ }
1925
+ }
1926
+ collect(root, 0, []);
1927
+ return candidates;
1928
+ }
1929
+ function normalizeCommandReference(command, name) {
1930
+ if (typeof command === "function" && command.commandName == null)
1931
+ return Object.assign((...args) => command(...args), command, { commandName: name });
1932
+ if (typeof command === "object" && command.name == null)
1933
+ return Object.assign(create(), command, { name });
1934
+ return command;
1935
+ }
1936
+ function getEntryRoutingCommand(entry, options) {
1937
+ if (options.entryCommand)
1938
+ return options.entryCommand;
1939
+ if (typeof entry === "function" && !isLazyCommand(entry))
1940
+ return {
1941
+ run: entry,
1942
+ entry: true
1943
+ };
1944
+ return entry;
1945
+ }
1946
+ function getRoutingPositionals(tokens, globalOptions, command) {
1947
+ return readPositionals(tokens, globalOptions, command).filter((value) => value !== "");
1948
+ }
1949
+ function readPositionals(tokens, globalOptions, command) {
1950
+ const effective = resolveCommandArgs(globalOptions, getCommandArgs(command));
1951
+ const routingArgs = create();
1952
+ for (const [name, schema] of Object.entries(effective)) {
1953
+ if (schema.type === "positional")
1954
+ continue;
1955
+ routingArgs[name] = {
1956
+ type: schema.type === "boolean" ? "boolean" : "string",
1957
+ short: schema.short,
1958
+ negatable: schema.negatable,
1959
+ toKebab: schema.toKebab
1960
+ };
1961
+ }
1962
+ return resolveArgs(routingArgs, tokens, {
1963
+ shortGrouping: true,
1964
+ toKebab: command.toKebab
1965
+ }).positionals;
1966
+ }
1967
+ function resolveSkipPositional(tokens, globalOptions, command, depth) {
1968
+ if (depth === 0)
1969
+ return -1;
1970
+ if (!tokens.some((token) => token.kind === "positional" && token.value === ""))
1971
+ return depth - 1;
1972
+ let names = 0;
1973
+ for (const [index, value] of readPositionals(tokens, globalOptions, command).entries()) {
1974
+ if (value === "")
1975
+ continue;
1976
+ names++;
1977
+ if (names === depth)
1978
+ return index;
1979
+ }
1980
+ return depth - 1;
1981
+ }
1982
+ function sameCommandPath(left, right) {
1983
+ return left.length === right.length && left.every((name, index) => name === right[index]);
1984
+ }
1985
+ function isPathPrefix(prefix, path) {
1986
+ return prefix.length <= path.length && prefix.every((name, index) => name === path[index]);
1987
+ }
1988
+ function selectDeepestFailures(failures) {
1989
+ const unique = /* @__PURE__ */ new Map;
1990
+ for (const failure of failures) {
1991
+ const path = failure.parentCommandPath || [];
1992
+ const key = JSON.stringify(path);
1993
+ unique.set(key, failure);
1994
+ }
1995
+ const deepest = Math.max(-1, ...[...unique.values()].map((failure) => (failure.parentCommandPath || []).length));
1996
+ return [...unique.values()].filter((failure) => (failure.parentCommandPath || []).length === deepest);
1997
+ }
1998
+ function createCommandResolutionResult(options, entry, code, candidatePaths) {
1999
+ const normalizedPaths = candidatePaths.map((path) => [...path]);
2000
+ const commandPath = commonCommandPath(normalizedPaths);
2001
+ const parent = resolveCommandTreeFromPositionals(commandPath, entry, options);
2002
+ const command = createDiagnosticCommand(parent.command, commandPath.at(-1));
2003
+ const context = {
2004
+ ...parent,
2005
+ command,
2006
+ commandPath,
2007
+ depth: commandPath.length,
2008
+ commandName: parent.commandName || commandPath.at(-1),
2009
+ callMode: commandPath.length > 0 ? "subCommand" : "entry",
2010
+ omitted: false
2011
+ };
2012
+ const formattedPaths = normalizedPaths.map((path) => path.join(" ")).join(", ");
2013
+ const formattedPath = commandPath.join(" ");
2014
+ const values = {
2015
+ commandPath: formattedPath,
2016
+ candidatePaths: formattedPaths,
2017
+ candidates: formattedPaths
2018
+ };
2019
+ const message = createCommandResolutionMessage(code, formattedPath, formattedPaths);
2020
+ return {
2021
+ context,
2022
+ error: new CommandResolutionError(message, {
2023
+ code,
2024
+ values,
2025
+ commandPath,
2026
+ candidatePaths: normalizedPaths
2027
+ }),
2028
+ diagnostic: true
2029
+ };
2030
+ }
2031
+ function commonCommandPath(paths) {
2032
+ if (paths.length === 0)
2033
+ return [];
2034
+ const common = [...paths[0]];
2035
+ for (const path of paths.slice(1)) {
2036
+ let length = 0;
2037
+ while (length < common.length && length < path.length && common[length] === path[length])
2038
+ length++;
2039
+ common.length = length;
2040
+ }
2041
+ return common;
2042
+ }
2043
+ function createDiagnosticCommand(command, name) {
2044
+ if (typeof command === "function")
2045
+ return Object.assign(create(), command, {
2046
+ name: command.commandName || name,
2047
+ run: undefined
2048
+ });
2049
+ return Object.assign(create(), command || {}, {
2050
+ name: command?.name || name,
2051
+ run: undefined
2052
+ });
2053
+ }
2054
+ function createCommandResolutionMessage(code, commandPath, candidatePaths) {
2055
+ switch (code) {
2056
+ case CommandResolutionErrorKeys.ambiguous:
2057
+ return `Ambiguous command resolution. Move options after the command name: ${candidatePaths}`;
2058
+ case CommandResolutionErrorKeys.lazySchemaMismatch:
2059
+ return `Lazy command schema mismatch at ${commandPath}. Declare leading options in the lazy definition or move options after the command name.`;
2060
+ default:
2061
+ return "The options do not identify a consistent command. Move options after the command name.";
2062
+ }
2063
+ }
2064
+ function createLazySchemaMismatchError(commandPath, loadedPath) {
2065
+ const expected = [...commandPath];
2066
+ const actual = [...loadedPath];
2067
+ return new CommandResolutionError(`Lazy command schema mismatch at ${expected.join(" ")}. Declare leading options in the lazy definition or move options after the command name.`, {
2068
+ code: CommandResolutionErrorKeys.lazySchemaMismatch,
2069
+ values: {
2070
+ commandPath: expected.join(" "),
2071
+ loadedCommandPath: actual.join(" ")
2072
+ },
2073
+ commandPath: expected,
2074
+ candidatePaths: [expected, actual]
2075
+ });
2076
+ }
2077
+ function createCommandNotFoundError(resolved) {
2078
+ const commandName = resolved.unresolvedCommandName || resolved.commandName || "";
2079
+ return new CommandNotFoundError(`Command not found: ${commandName}`, {
2080
+ code: CommandNotFoundErrorKeys.notFound,
2081
+ values: { commandName },
2082
+ commandName,
2083
+ candidates: [...resolved.parentSubCommands?.keys() || []],
2084
+ commandPath: resolved.parentCommandPath || []
2085
+ });
2086
+ }
2087
+ function resolveEntryName(entry) {
2088
+ return isLazyCommand(entry) ? entry.commandName || "(anonymous)" : entry.name || "(anonymous)";
2089
+ }
2090
+ function getPluginExtensions(plugins) {
2091
+ const extensions = create();
2092
+ for (const plugin of plugins)
2093
+ if (plugin.extension) {
2094
+ const key = plugin.id;
2095
+ if (extensions[key])
2096
+ console.warn(`Plugin "${key}" is already installed. Ignore it for command context extending.`);
2097
+ else
2098
+ extensions[key] = plugin.extension;
2099
+ }
2100
+ return extensions;
2101
+ }
2102
+ async function executeCommand(cmd, ctx, decorators) {
2103
+ const commandRunner = cmd.run || NOOP;
2104
+ const baseRunner = (ctx) => {
2105
+ if (hasPriorityValidationError(ctx.validationError))
2106
+ throw ctx.validationError;
2107
+ return commandRunner(ctx);
2108
+ };
2109
+ const decoratedRunner = decorators.reduceRight((runner, decorator) => decorator(runner), baseRunner);
2110
+ try {
2111
+ if (ctx.env.onBeforeCommand)
2112
+ await ctx.env.onBeforeCommand(ctx);
2113
+ const result = await decoratedRunner(ctx);
2114
+ if (ctx.env.onAfterCommand)
2115
+ await ctx.env.onAfterCommand(ctx, result);
2116
+ return typeof result === "string" ? result : undefined;
2117
+ } catch (error) {
2118
+ if (ctx.env.onErrorCommand)
2119
+ try {
2120
+ await ctx.env.onErrorCommand(ctx, error);
2121
+ } catch (hookError) {
2122
+ console.error("Error in onErrorCommand hook:", hookError);
2123
+ }
2124
+ throw error;
2125
+ }
2126
+ }
2127
+
2128
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/bone.js
2129
+ async function cli(args, entry, options = {}) {
2130
+ return cliCore(args, entry, options, []);
2131
+ }
2132
+
2133
+ // ../../node_modules/.bun/gunshi@1.0.0-rc.1/node_modules/gunshi/lib/definition.js
2134
+ function define(definition) {
2135
+ return definition;
2136
+ }
2137
+
2138
+ // src/parse-cli-args.ts
2139
+ async function parseCLIArgs(argv) {
2140
+ let parsed = null;
2141
+ const command = define({
2142
+ name: "zgeoff-check",
2143
+ args: {
2144
+ help: { type: "boolean", short: "h", default: false }
2145
+ },
2146
+ run: (ctx) => {
2147
+ if (ctx.validationError !== undefined) {
2148
+ throw ctx.validationError;
2149
+ }
2150
+ parsed = { help: ctx.values.help, files: [...ctx.positionals, ...ctx.rest] };
2151
+ }
2152
+ });
2153
+ try {
2154
+ await cli([...argv], command, { strict: true });
2155
+ } catch (error) {
2156
+ return formatParseError(error);
2157
+ }
2158
+ if (parsed === null) {
2159
+ return "the command line could not be parsed";
2160
+ }
2161
+ const args = parsed;
2162
+ if (args.help && args.files.length > 0) {
2163
+ return "--help takes no files";
2164
+ }
2165
+ return args;
2166
+ }
2167
+ function formatParseError(error) {
2168
+ if (error instanceof AggregateError) {
2169
+ return error.errors.map((reason) => formatParseError(reason)).join(`
2170
+ `);
2171
+ }
2172
+ return error instanceof Error ? error.message : String(error);
2173
+ }
2174
+
2175
+ // src/run-checks.ts
2176
+ import { statSync } from "fs";
2177
+ import { isAbsolute, relative, resolve } from "path";
2178
+ async function runChecks(options) {
2179
+ const files = (options.files ?? runGitLsFiles(options)).map((file) => toRepoPath(options.cwd, file)).filter((file) => checkPathExists(options.cwd, file));
2180
+ const findings = [];
2181
+ for (const check of options.checks) {
2182
+ if (options.config.off.has(check.name)) {
2183
+ continue;
2184
+ }
2185
+ const glob = new Bun.Glob(check.glob);
2186
+ const matched = files.filter((file) => glob.match(file));
2187
+ if (matched.length === 0) {
2188
+ continue;
2189
+ }
2190
+ const checkFindings = await check.check({ cwd: options.cwd, files: matched, env: options.env });
2191
+ findings.push(...checkFindings.toSorted((a, b) => a.path.localeCompare(b.path) || a.line - b.line).map((finding) => ({
2192
+ check: check.name,
2193
+ path: finding.path,
2194
+ line: finding.line,
2195
+ message: finding.message
2196
+ })));
2197
+ }
2198
+ return findings;
2199
+ }
2200
+ function runGitLsFiles(options) {
2201
+ const result = Bun.spawnSync(["git", "ls-files", "-z"], {
2202
+ cwd: options.cwd,
2203
+ env: { ...options.env },
2204
+ stdin: "ignore",
2205
+ stdout: "pipe",
2206
+ stderr: "pipe"
2207
+ });
2208
+ if (result.exitCode !== 0) {
2209
+ throw new Error(`git ls-files failed: ${result.stderr.toString().trim()}`);
2210
+ }
2211
+ return result.stdout.toString().split("\x00").filter((file) => file !== "");
2212
+ }
2213
+ function checkPathExists(cwd, file) {
2214
+ try {
2215
+ statSync(resolve(cwd, file));
2216
+ } catch (error) {
2217
+ if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
2218
+ return false;
2219
+ }
2220
+ throw error;
2221
+ }
2222
+ return true;
2223
+ }
2224
+ function toRepoPath(cwd, file) {
2225
+ const path = relative(cwd, resolve(cwd, file));
2226
+ return isAbsolute(path) ? file : path;
2227
+ }
2228
+
2229
+ // src/run-git-show-toplevel.ts
2230
+ function runGitShowToplevel(cwd, env) {
2231
+ if (Bun.which("git", { PATH: env["PATH"] ?? "" }) === null) {
2232
+ return cwd;
2233
+ }
2234
+ const result = Bun.spawnSync(["git", "rev-parse", "--show-toplevel"], {
2235
+ cwd,
2236
+ env: { ...env },
2237
+ stdin: "ignore",
2238
+ stdout: "pipe",
2239
+ stderr: "pipe"
2240
+ });
2241
+ return result.exitCode === 0 ? result.stdout.toString().trim() : cwd;
2242
+ }
2243
+
2244
+ // src/cli.ts
2245
+ var USAGE = `usage: zgeoff-check [--] [file ...]
2246
+
2247
+ Runs every check over the files that git tracks, or over the files given.
2248
+ Each finding prints as path:line: <check>: <message>, with the path from the repo root.
2249
+ Exits 0 with no finding, 1 with any finding, and 2 when the run could not finish.
2250
+ Checks: ${allChecks.map((check) => check.name).join(", ")}`;
2251
+ var parsed = await parseCLIArgs(process.argv.slice(2));
2252
+ if (typeof parsed === "string") {
2253
+ process.stderr.write(`zgeoff-check: ${parsed}
2254
+ ${USAGE}
2255
+ `);
2256
+ process.exit(2);
2257
+ }
2258
+ if (parsed.help) {
2259
+ process.stdout.write(`${USAGE}
2260
+ `);
2261
+ process.exit(0);
2262
+ }
2263
+ var files = parsed.files;
2264
+ try {
2265
+ const root = runGitShowToplevel(process.cwd(), process.env);
2266
+ const config = loadConfig(root, allChecks.map((check) => check.name));
2267
+ const findings = await runChecks({
2268
+ cwd: root,
2269
+ checks: allChecks,
2270
+ config,
2271
+ env: process.env,
2272
+ ...files.length === 0 ? {} : { files: files.map((file) => resolve2(file)) }
2273
+ });
2274
+ for (const finding of findings) {
2275
+ process.stdout.write(`${finding.path}:${finding.line}: ${finding.check}: ${finding.message}
2276
+ `);
2277
+ }
2278
+ const exitCode = findings.length === 0 ? 0 : 1;
2279
+ process.exit(exitCode);
2280
+ } catch (error) {
2281
+ const message = error instanceof Error ? error.message : String(error);
2282
+ process.stderr.write(`zgeoff-check: ${message}
2283
+ `);
2284
+ process.exit(2);
2285
+ }