|
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'; |
@@ -623,24 +623,38 @@ export function parseArguments( |
623 | 623 | console.error(`Unknown arguments: ${unknownArgs.map(arg => `--${arg}`)}`); |
624 | 624 | } |
625 | 625 |
|
626 | | - // Step 5: Validation. Conflicts are only checked against explicit user input |
627 | | - // so that dynamic defaults never conflict. |
628 | | - const activeArgs = new Set<string>(); |
629 | | - for (const [key, val] of Object.entries(explicitConfig)) { |
630 | | - if (val !== undefined && val !== false) { |
631 | | - activeArgs.add(key); |
632 | | - } |
633 | | - } |
634 | | - for (const group of CONFLICTING_ARGS) { |
635 | | - const activeInGroup = group.filter(arg => activeArgs.has(arg)); |
636 | | - if (activeInGroup.length > 1) { |
637 | | - const [arg1, arg2] = activeInGroup; |
638 | | - throw new Error(`Arguments ${arg1} and ${arg2} are mutually exclusive`); |
639 | | - } |
640 | | - } |
| 626 | + // Step 5: Final Schema Validation & Type Safety. Conflicts are only checked |
| 627 | + // against explicit user input so that dynamic defaults never conflict. |
| 628 | + const ConfigSchema = z |
| 629 | + .object({}) |
| 630 | + .passthrough() |
| 631 | + .superRefine((_config, ctx) => { |
| 632 | + const activeArgs = new Set<string>(); |
| 633 | + for (const [key, val] of Object.entries(explicitConfig)) { |
| 634 | + if (val !== undefined && val !== false) { |
| 635 | + activeArgs.add(key); |
| 636 | + } |
| 637 | + } |
| 638 | + |
| 639 | + for (const group of CONFLICTING_ARGS) { |
| 640 | + const activeInGroup = group.filter(arg => activeArgs.has(arg)); |
| 641 | + if (activeInGroup.length > 1) { |
| 642 | + const [arg1, arg2] = activeInGroup; |
| 643 | + ctx.addIssue({ |
| 644 | + code: z.ZodIssueCode.custom, |
| 645 | + message: `Arguments ${arg1} and ${arg2} are mutually exclusive`, |
| 646 | + path: [arg1, arg2], |
| 647 | + }); |
| 648 | + } |
| 649 | + } |
| 650 | + }); |
641 | 651 |
|
642 | | - if (!isParsedArguments(resolvedConfig)) { |
| 652 | + const result = ConfigSchema.safeParse(resolvedConfig); |
| 653 | + if (!result.success) { |
| 654 | + throw new Error(result.error.issues[0].message); |
| 655 | + } |
| 656 | + if (!isParsedArguments(result.data)) { |
643 | 657 | throw new Error('Failed to resolve configuration'); |
644 | 658 | } |
645 | | - return resolvedConfig; |
| 659 | + return result.data; |
646 | 660 | } |
0 commit comments