Skip to content

Commit 387925a

Browse files
committed
chore: cleanup browser behavior
1 parent 42d6f1a commit 387925a

File tree

3 files changed

+94
-45
lines changed

3 files changed

+94
-45
lines changed

packages/arg-parser/src/arg-parser.spec.ts

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,10 +1134,45 @@ describe('arg-parser', function () {
11341134
});
11351135

11361136
describe('union type fields', function () {
1137-
for (const { argument, values, onlyFalse, strict } of [
1137+
describe('--browser', function () {
1138+
it('does not coerce to boolean with --browser=true', function () {
1139+
expect(
1140+
parseArgsWithCliOptions({ args: ['--browser=true'] }).parsed.browser
1141+
).to.equal('true');
1142+
});
1143+
1144+
it('coerces to boolean with --browser=false', function () {
1145+
expect(
1146+
parseArgsWithCliOptions({ args: ['--browser=false'] }).parsed.browser
1147+
).to.equal(false);
1148+
});
1149+
1150+
it('coerces to false with --no-browser', function () {
1151+
expect(
1152+
parseArgsWithCliOptions({ args: ['--no-browser'] }).parsed.browser
1153+
).to.equal(false);
1154+
});
1155+
1156+
it('uses string if browser=something', function () {
1157+
expect(
1158+
parseArgsWithCliOptions({ args: ['--browser=something'] }).parsed
1159+
.browser
1160+
).to.equal('something');
1161+
});
1162+
1163+
it('throws if just --browser is provided', function () {
1164+
expect(
1165+
() => parseArgsWithCliOptions({ args: ['--browser'] }).parsed.browser
1166+
).to.throw(
1167+
MongoshUnimplementedError,
1168+
'--browser can only be true or a string'
1169+
);
1170+
});
1171+
});
1172+
1173+
for (const { argument, values } of [
11381174
{ argument: 'json', values: ['relaxed', 'canonical'] },
11391175
{ argument: 'oidcDumpTokens', values: ['redacted', 'include-secrets'] },
1140-
{ argument: 'browser', values: ['test'], onlyFalse: true, strict: false },
11411176
] as const) {
11421177
describe(`with ${argument}`, function () {
11431178
context('with boolean', function () {
@@ -1149,23 +1184,13 @@ describe('arg-parser', function () {
11491184
).to.equal(true);
11501185
});
11511186

1152-
if (!onlyFalse) {
1153-
it(`coerces to true with --${argument}=true`, function () {
1154-
expect(
1155-
parseArgsWithCliOptions({
1156-
args: [`--${argument}=true`],
1157-
}).parsed[argument]
1158-
).to.equal(true);
1159-
});
1160-
} else {
1161-
it(`does not coerce with "--${argument} true"`, function () {
1162-
expect(
1163-
parseArgsWithCliOptions({
1164-
args: [`--${argument}=true`],
1165-
}).parsed[argument]
1166-
).to.be.equal('true');
1167-
});
1168-
}
1187+
it(`coerces to true with --${argument}=true`, function () {
1188+
expect(
1189+
parseArgsWithCliOptions({
1190+
args: [`--${argument}=true`],
1191+
}).parsed[argument]
1192+
).to.equal(true);
1193+
});
11691194

11701195
it(`coerces to false with --${argument}=false`, function () {
11711196
expect(
@@ -1197,22 +1222,16 @@ describe('arg-parser', function () {
11971222
});
11981223
}
11991224

1200-
if (strict) {
1201-
it('throws an error with invalid value', function () {
1202-
try {
1203-
parseArgsWithCliOptions({
1204-
args: [`--${argument}`, 'invalid'],
1205-
});
1206-
} catch (e: any) {
1207-
expect(e).to.be.instanceOf(MongoshUnimplementedError);
1208-
expect(e.message).to.include(
1209-
`--${argument} can only have the values ${values.join(', ')}`
1210-
);
1211-
return;
1212-
}
1213-
expect.fail('Expected error');
1214-
});
1215-
}
1225+
it('throws an error with invalid value', function () {
1226+
expect(() =>
1227+
parseArgsWithCliOptions({
1228+
args: [`--${argument}`, 'invalid'],
1229+
})
1230+
).to.throw(
1231+
MongoshUnimplementedError,
1232+
`--${argument} can only have the values ${values.join(', ')}`
1233+
);
1234+
});
12161235
});
12171236
}
12181237
});
@@ -1246,7 +1265,7 @@ describe('arg-parser', function () {
12461265
});
12471266
});
12481267

1249-
it('generates the expected options for Cli Options', function () {
1268+
it('generates the expected options for CliOptions', function () {
12501269
const options = generateYargsOptionsFromSchema({
12511270
schema: CliOptionsSchema,
12521271
});
@@ -1260,6 +1279,7 @@ describe('arg-parser', function () {
12601279
'awsIamSessionToken',
12611280
'awsSecretAccessKey',
12621281
'awsSessionToken',
1282+
'browser',
12631283
'csfleLibraryPath',
12641284
'cryptSharedLibPath',
12651285
'db',
@@ -1294,6 +1314,7 @@ describe('arg-parser', function () {
12941314
'apiDeprecationErrors',
12951315
'apiStrict',
12961316
'buildInfo',
1317+
'deepInspect',
12971318
'exposeAsyncRewriter',
12981319
'help',
12991320
'ipv6',

packages/arg-parser/src/arg-parser.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ import {
1616
UnsupportedCliArgumentError,
1717
} from './arg-metadata';
1818

19+
function unwrapType(type: unknown): unknown {
20+
if (type instanceof z.ZodOptional) {
21+
return unwrapType(type.unwrap());
22+
}
23+
if (type instanceof z.ZodDefault) {
24+
return unwrapType(type.unwrap());
25+
}
26+
return type;
27+
}
28+
1929
/**
2030
* Generate yargs-parser configuration from schema
2131
*/
@@ -50,11 +60,7 @@ export function generateYargsOptionsFromSchema({
5060
for (const [fieldName, fieldSchema] of Object.entries(schema.shape)) {
5161
const meta = getArgumentMetadata(schema, fieldName);
5262

53-
// Unwrap optional type
54-
let unwrappedType = fieldSchema;
55-
if (fieldSchema instanceof z.ZodOptional) {
56-
unwrappedType = fieldSchema.unwrap();
57-
}
63+
const unwrappedType = unwrapType(fieldSchema);
5864

5965
// Determine type
6066
if (unwrappedType instanceof z.ZodArray) {
@@ -85,6 +91,8 @@ export function generateYargsOptionsFromSchema({
8591
if (hasFalseLiteral) {
8692
// If set to 'false' coerce into false boolean; string in all other cases
8793
options.coerce[fieldName] = coerceIfFalse;
94+
// Setting as string prevents --{field} from being valid.
95+
options.string.push(fieldName);
8896
} else if (hasBoolean) {
8997
// If the field is 'true' or 'false', we coerce the value to a boolean.
9098
options.coerce[fieldName] = coerceIfBoolean;
@@ -107,7 +115,13 @@ export function generateYargsOptionsFromSchema({
107115
);
108116
}
109117
} else {
110-
throw new Error(`Unknown field type: ${unwrappedType.constructor.name}`);
118+
throw new Error(
119+
`Unknown field type: ${
120+
unwrappedType instanceof Object
121+
? unwrappedType.constructor.name
122+
: typeof unwrappedType
123+
}`
124+
);
111125
}
112126

113127
// Add aliases
@@ -253,6 +267,10 @@ export function coerceIfBoolean(value: unknown): unknown {
253267
}
254268

255269
export function coerceIfFalse(value: unknown): unknown {
270+
if (value === undefined || value === '') {
271+
return null;
272+
}
273+
256274
if (typeof value === 'string') {
257275
if (value === 'false') {
258276
return false;

packages/arg-parser/src/cli-options.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export function validateCliOptions(parsed: CliOptions): void {
197197
const jsonValidation = CliOptionsSchema.shape.json.safeParse(parsed.json);
198198
if (!jsonValidation.success) {
199199
throw new MongoshUnimplementedError(
200-
'--json can only have the values relaxed or canonical',
200+
'--json can only have the values relaxed, canonical',
201201
CommonErrors.InvalidArgument
202202
);
203203
}
@@ -206,7 +206,7 @@ export function validateCliOptions(parsed: CliOptions): void {
206206
CliOptionsSchema.shape.oidcDumpTokens.safeParse(parsed.oidcDumpTokens);
207207
if (!oidcDumpTokensValidation.success) {
208208
throw new MongoshUnimplementedError(
209-
'--oidcDumpTokens can only have the values redacted or include-secrets',
209+
'--oidcDumpTokens can only have the values redacted, include-secrets',
210210
CommonErrors.InvalidArgument
211211
);
212212
}
@@ -216,7 +216,17 @@ export function validateCliOptions(parsed: CliOptions): void {
216216
);
217217
if (!jsContextValidation.success) {
218218
throw new MongoshUnimplementedError(
219-
'--jsContext can only have the values repl, plain-vm, or auto',
219+
'--jsContext can only have the values repl, plain-vm, auto',
220+
CommonErrors.InvalidArgument
221+
);
222+
}
223+
224+
const browserValidation = CliOptionsSchema.shape.browser.safeParse(
225+
parsed.browser
226+
);
227+
if (!browserValidation.success) {
228+
throw new MongoshUnimplementedError(
229+
'--browser can only be true or a string',
220230
CommonErrors.InvalidArgument
221231
);
222232
}

0 commit comments

Comments
 (0)