Skip to content

Commit 57b6add

Browse files
authored
chore: use zod for arg-parser MCP-298 (#2589)
1 parent 41fd911 commit 57b6add

File tree

14 files changed

+1704
-565
lines changed

14 files changed

+1704
-565
lines changed

package-lock.json

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/arg-parser/.depcheckrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ ignores:
1010
- eslint-config-mongodb-js
1111
# needed as a peer dependency of @mongodb-js/devtools-connect
1212
- mongodb
13+
# only used in arg-parser export; should be removed once switched to knip
14+
- yargs-parser
1315
ignore-patterns:
1416
- .eslintrc.js

packages/arg-parser/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
"mongodb-connection-string-url": "^3.0.2",
5252
"yargs-parser": "^20.2.4"
5353
},
54+
"peerDependencies": {
55+
"zod": "^3.25.76"
56+
},
5457
"devDependencies": {
5558
"@mongodb-js/devtools-connect": "^3.9.4",
5659
"@mongodb-js/eslint-config-mongosh": "^1.0.0",
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import z from 'zod/v4';
2+
3+
/**
4+
* Registry for argument options metadata
5+
*/
6+
export const argMetadata = z.registry<ArgumentMetadata>();
7+
8+
/**
9+
* Metadata that can be used to define field's parsing behavior
10+
*/
11+
export type ArgumentMetadata = {
12+
/** If set, sets this field as deprecated and replaces this field with the set field. */
13+
deprecationReplacement?: string;
14+
/** If set, gets replaced with a different field name (without deprecation) */
15+
replacement?: string;
16+
/** Whether this argument is unsupported. Always throws an error if set to true. */
17+
unsupported?: boolean;
18+
/** Aliases for this argument. */
19+
alias?: string[];
20+
};
21+
22+
/**
23+
* Extract metadata for a field using the custom registry
24+
*/
25+
export function getArgumentMetadata(
26+
schema: z.ZodObject,
27+
fieldName: string
28+
): ArgumentMetadata | undefined {
29+
const fieldSchema = schema.shape[fieldName];
30+
if (!fieldSchema) {
31+
return undefined;
32+
}
33+
return argMetadata.get(fieldSchema);
34+
}
35+
36+
/**
37+
* Maps deprecated arguments to their new counterparts, derived from schema metadata.
38+
*/
39+
export function getDeprecatedArgsWithReplacement(
40+
schema: z.ZodObject
41+
): Record<string, keyof z.infer<typeof schema>> {
42+
const deprecated: Record<string, keyof z.infer<typeof schema>> = {};
43+
for (const fieldName of Object.keys(schema.shape)) {
44+
const meta = getArgumentMetadata(schema, fieldName);
45+
if (meta?.deprecationReplacement) {
46+
deprecated[fieldName] = meta.deprecationReplacement;
47+
}
48+
}
49+
return deprecated;
50+
}
51+
52+
/**
53+
* Get list of unsupported arguments, derived from schema metadata.
54+
*/
55+
export function getUnsupportedArgs(schema: z.ZodObject): string[] {
56+
const unsupported: string[] = [];
57+
for (const fieldName of Object.keys(schema.shape)) {
58+
const meta = getArgumentMetadata(schema, fieldName);
59+
if (meta?.unsupported) {
60+
unsupported.push(fieldName);
61+
}
62+
}
63+
return unsupported;
64+
}
65+
66+
export class InvalidArgumentError extends Error {
67+
constructor(message: string) {
68+
super(message);
69+
this.name = 'InvalidArgumentError';
70+
}
71+
}
72+
73+
export class UnknownArgumentError extends Error {
74+
/** The argument that was not parsed. */
75+
readonly argument: string;
76+
constructor(argument: string) {
77+
super(`Unknown argument: ${argument}`);
78+
this.name = 'UnknownArgumentError';
79+
this.argument = argument;
80+
}
81+
}
82+
83+
export class UnsupportedArgumentError extends Error {
84+
/** The argument that was not supported. */
85+
readonly argument: string;
86+
constructor(argument: string) {
87+
super(`Unsupported argument: ${argument}`);
88+
this.name = 'UnsupportedArgumentError';
89+
this.argument = argument;
90+
}
91+
}

0 commit comments

Comments
 (0)