|
5 | 5 | */ |
6 | 6 |
|
7 | 7 | import type {YargsOptions} from '../third_party/index.js'; |
8 | | -import {yargs, hideBin} from '../third_party/index.js'; |
| 8 | +import {yargs, hideBin, zod as z} from '../third_party/index.js'; |
9 | 9 | import os from 'node:os'; |
10 | 10 | import {readFileSync} from 'node:fs'; |
11 | 11 | import path from 'node:path'; |
@@ -614,24 +614,38 @@ export function parseArguments( |
614 | 614 | console.error(`Unknown arguments: ${unknownArgs.map(arg => `--${arg}`)}`); |
615 | 615 | } |
616 | 616 |
|
617 | | - // Step 5: Validation. Conflicts are only checked against explicit user input |
618 | | - // so that dynamic defaults never conflict. |
619 | | - const activeArgs = new Set<string>(); |
620 | | - for (const [key, val] of Object.entries(explicitConfig)) { |
621 | | - if (val !== undefined && val !== false) { |
622 | | - activeArgs.add(key); |
623 | | - } |
624 | | - } |
625 | | - for (const group of CONFLICTING_ARGS) { |
626 | | - const activeInGroup = group.filter(arg => activeArgs.has(arg)); |
627 | | - if (activeInGroup.length > 1) { |
628 | | - const [arg1, arg2] = activeInGroup; |
629 | | - throw new Error(`Arguments ${arg1} and ${arg2} are mutually exclusive`); |
630 | | - } |
631 | | - } |
| 617 | + // Step 5: Final Schema Validation & Type Safety. Conflicts are only checked |
| 618 | + // against explicit user input so that dynamic defaults never conflict. |
| 619 | + const ConfigSchema = z |
| 620 | + .object({}) |
| 621 | + .passthrough() |
| 622 | + .superRefine((_config, ctx) => { |
| 623 | + const activeArgs = new Set<string>(); |
| 624 | + for (const [key, val] of Object.entries(explicitConfig)) { |
| 625 | + if (val !== undefined && val !== false) { |
| 626 | + activeArgs.add(key); |
| 627 | + } |
| 628 | + } |
| 629 | + |
| 630 | + for (const group of CONFLICTING_ARGS) { |
| 631 | + const activeInGroup = group.filter(arg => activeArgs.has(arg)); |
| 632 | + if (activeInGroup.length > 1) { |
| 633 | + const [arg1, arg2] = activeInGroup; |
| 634 | + ctx.addIssue({ |
| 635 | + code: z.ZodIssueCode.custom, |
| 636 | + message: `Arguments ${arg1} and ${arg2} are mutually exclusive`, |
| 637 | + path: [arg1, arg2], |
| 638 | + }); |
| 639 | + } |
| 640 | + } |
| 641 | + }); |
632 | 642 |
|
633 | | - if (!isParsedArguments(resolvedConfig)) { |
| 643 | + const result = ConfigSchema.safeParse(resolvedConfig); |
| 644 | + if (!result.success) { |
| 645 | + throw new Error(result.error.issues[0].message); |
| 646 | + } |
| 647 | + if (!isParsedArguments(result.data)) { |
634 | 648 | throw new Error('Failed to resolve configuration'); |
635 | 649 | } |
636 | | - return resolvedConfig; |
| 650 | + return result.data; |
637 | 651 | } |
0 commit comments