@optique/zod 1.0.0-dev.1424 → 1.0.0-dev.1436
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.
- package/dist/index.cjs +190 -31
- package/dist/index.d.ts +1 -1
- package/dist/index.js +189 -30
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
//#endregion
|
|
24
24
|
const __optique_core_message = __toESM(require("@optique/core/message"));
|
|
25
25
|
const __optique_core_nonempty = __toESM(require("@optique/core/nonempty"));
|
|
26
|
+
const zod = __toESM(require("zod"));
|
|
26
27
|
|
|
27
28
|
//#region src/index.ts
|
|
28
29
|
/**
|
|
@@ -39,6 +40,114 @@ function isZodAsyncError(error) {
|
|
|
39
40
|
if (error.message === "Async refinement encountered during synchronous parse operation. Use .parseAsync instead." || error.message === "Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead." || error.message === "Synchronous parse encountered promise.") return true;
|
|
40
41
|
return false;
|
|
41
42
|
}
|
|
43
|
+
const BOOL_TRUE_LITERALS = [
|
|
44
|
+
"true",
|
|
45
|
+
"1",
|
|
46
|
+
"yes",
|
|
47
|
+
"on"
|
|
48
|
+
];
|
|
49
|
+
const BOOL_FALSE_LITERALS = [
|
|
50
|
+
"false",
|
|
51
|
+
"0",
|
|
52
|
+
"no",
|
|
53
|
+
"off"
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Analyzes whether the given Zod schema represents a boolean type,
|
|
57
|
+
* unwrapping all known Zod wrappers. Also determines whether it is
|
|
58
|
+
* safe to expose `choices` and `suggest()` — wrappers that can narrow
|
|
59
|
+
* the accepted domain (effects, catch) suppress choice exposure.
|
|
60
|
+
*/
|
|
61
|
+
function analyzeBooleanSchema(schema) {
|
|
62
|
+
const result = analyzeBooleanInner(schema, true, /* @__PURE__ */ new WeakSet());
|
|
63
|
+
if (!result.isBoolean) return {
|
|
64
|
+
isBoolean: false,
|
|
65
|
+
exposeChoices: false,
|
|
66
|
+
isCoerced: false
|
|
67
|
+
};
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
function analyzeBooleanInner(schema, canExposeChoices, visited) {
|
|
71
|
+
if (visited.has(schema)) return {
|
|
72
|
+
isBoolean: false,
|
|
73
|
+
exposeChoices: false,
|
|
74
|
+
isCoerced: false
|
|
75
|
+
};
|
|
76
|
+
visited.add(schema);
|
|
77
|
+
const def = schema._def;
|
|
78
|
+
if (!def) return {
|
|
79
|
+
isBoolean: false,
|
|
80
|
+
exposeChoices: false,
|
|
81
|
+
isCoerced: false
|
|
82
|
+
};
|
|
83
|
+
const typeName = def.typeName ?? def.type;
|
|
84
|
+
if (typeName === "ZodBoolean" || typeName === "boolean") {
|
|
85
|
+
const hasCustomChecks = Array.isArray(def.checks) && def.checks.some((c) => c.kind === "custom" || c.type === "custom" || c._zod?.def?.check === "custom");
|
|
86
|
+
return {
|
|
87
|
+
isBoolean: true,
|
|
88
|
+
exposeChoices: canExposeChoices && !hasCustomChecks,
|
|
89
|
+
isCoerced: def.coerce === true
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (typeName === "ZodOptional" || typeName === "optional" || typeName === "ZodNullable" || typeName === "nullable" || typeName === "ZodDefault" || typeName === "default" || typeName === "ZodReadonly" || typeName === "readonly" || typeName === "prefault" || typeName === "nonoptional") {
|
|
93
|
+
const innerType = def.innerType;
|
|
94
|
+
if (innerType != null) return analyzeBooleanInner(innerType, canExposeChoices, visited);
|
|
95
|
+
}
|
|
96
|
+
if (typeName === "ZodLazy" || typeName === "lazy") {
|
|
97
|
+
if (typeof def.getter === "function") return analyzeBooleanInner(def.getter(), canExposeChoices, visited);
|
|
98
|
+
}
|
|
99
|
+
if (typeName === "ZodEffects" || typeName === "effects") {
|
|
100
|
+
if (def.effect?.type === "preprocess") return {
|
|
101
|
+
isBoolean: false,
|
|
102
|
+
exposeChoices: false,
|
|
103
|
+
isCoerced: false
|
|
104
|
+
};
|
|
105
|
+
const innerSchema = def.schema;
|
|
106
|
+
if (innerSchema != null) return analyzeBooleanInner(innerSchema, false, visited);
|
|
107
|
+
}
|
|
108
|
+
if (typeName === "ZodCatch" || typeName === "catch") {
|
|
109
|
+
const innerType = def.innerType;
|
|
110
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
111
|
+
}
|
|
112
|
+
if (typeName === "ZodBranded" || typeName === "branded") {
|
|
113
|
+
const innerType = def.innerType ?? (typeof def.type === "object" && def.type != null ? def.type : void 0);
|
|
114
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
115
|
+
}
|
|
116
|
+
if (typeName === "pipe" || typeName === "ZodPipeline") {
|
|
117
|
+
const inSchema = def.in;
|
|
118
|
+
if (inSchema != null) return analyzeBooleanInner(inSchema, false, visited);
|
|
119
|
+
const innerType = def.innerType;
|
|
120
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
121
|
+
}
|
|
122
|
+
if (typeName === "pipeline") {
|
|
123
|
+
const innerType = def.innerType;
|
|
124
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
isBoolean: false,
|
|
128
|
+
exposeChoices: false,
|
|
129
|
+
isCoerced: false
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Pre-converts a CLI string input to an actual boolean value using
|
|
134
|
+
* CLI-friendly literals (true/false, 1/0, yes/no, on/off).
|
|
135
|
+
*/
|
|
136
|
+
function preConvertBoolean(input) {
|
|
137
|
+
const normalized = input.trim().toLowerCase();
|
|
138
|
+
if (BOOL_TRUE_LITERALS.includes(normalized)) return {
|
|
139
|
+
success: true,
|
|
140
|
+
value: true
|
|
141
|
+
};
|
|
142
|
+
if (BOOL_FALSE_LITERALS.includes(normalized)) return {
|
|
143
|
+
success: true,
|
|
144
|
+
value: false
|
|
145
|
+
};
|
|
146
|
+
return {
|
|
147
|
+
success: false,
|
|
148
|
+
error: __optique_core_message.message`Invalid Boolean value: ${input}. Expected one of ${(0, __optique_core_message.valueSet)([...BOOL_TRUE_LITERALS, ...BOOL_FALSE_LITERALS], { locale: "en-US" })}.`
|
|
149
|
+
};
|
|
150
|
+
}
|
|
42
151
|
/**
|
|
43
152
|
* Infers an appropriate metavar string from a Zod schema.
|
|
44
153
|
*
|
|
@@ -249,14 +358,86 @@ function inferChoices(schema) {
|
|
|
249
358
|
* operations that cannot be executed synchronously.
|
|
250
359
|
* @since 0.7.0
|
|
251
360
|
*/
|
|
252
|
-
function zod(schema, options = {}) {
|
|
361
|
+
function zod$1(schema, options = {}) {
|
|
253
362
|
const choices = inferChoices(schema);
|
|
254
|
-
const
|
|
363
|
+
const boolInfo = analyzeBooleanSchema(schema);
|
|
364
|
+
const metavar = options.metavar ?? (boolInfo.isBoolean ? "BOOLEAN" : inferMetavar(schema));
|
|
255
365
|
(0, __optique_core_nonempty.ensureNonEmptyString)(metavar);
|
|
366
|
+
function doSafeParse(input, rawInput) {
|
|
367
|
+
let result;
|
|
368
|
+
try {
|
|
369
|
+
result = schema.safeParse(input);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (error instanceof Error && isZodAsyncError(error)) throw new TypeError("Async Zod schemas (e.g., async refinements) are not supported by zod(). Use synchronous schemas instead.");
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
if (result.success) return {
|
|
375
|
+
success: true,
|
|
376
|
+
value: result.data
|
|
377
|
+
};
|
|
378
|
+
if (options.errors?.zodError) return {
|
|
379
|
+
success: false,
|
|
380
|
+
error: typeof options.errors.zodError === "function" ? options.errors.zodError(result.error, rawInput) : options.errors.zodError
|
|
381
|
+
};
|
|
382
|
+
const zodModule = schema;
|
|
383
|
+
if (typeof zodModule.constructor?.prettifyError === "function") try {
|
|
384
|
+
const pretty = zodModule.constructor.prettifyError(result.error);
|
|
385
|
+
return {
|
|
386
|
+
success: false,
|
|
387
|
+
error: __optique_core_message.message`${pretty}`
|
|
388
|
+
};
|
|
389
|
+
} catch {}
|
|
390
|
+
const firstError = result.error.issues[0];
|
|
391
|
+
return {
|
|
392
|
+
success: false,
|
|
393
|
+
error: __optique_core_message.message`${firstError?.message ?? "Validation failed"}`
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Handles a failed boolean literal pre-conversion.
|
|
398
|
+
*
|
|
399
|
+
* - *Non-coerced* (`z.boolean()`): falls through to `doSafeParse`
|
|
400
|
+
* so that catch/default, custom errors, and async detection all
|
|
401
|
+
* work. This is safe because `safeParse(string)` fails at the
|
|
402
|
+
* type level before any refinements execute.
|
|
403
|
+
* - *Coerced* (`z.coerce.boolean()`): runs the lazy async probe
|
|
404
|
+
* (if not yet completed), then returns the pre-conversion error
|
|
405
|
+
* or delegates to the custom `zodError` callback.
|
|
406
|
+
*/
|
|
407
|
+
function handleBooleanLiteralError(boolResult, rawInput) {
|
|
408
|
+
if (!boolInfo.isCoerced) return doSafeParse(rawInput, rawInput);
|
|
409
|
+
if (options.errors?.zodError) {
|
|
410
|
+
if (typeof options.errors.zodError !== "function") return {
|
|
411
|
+
success: false,
|
|
412
|
+
error: options.errors.zodError
|
|
413
|
+
};
|
|
414
|
+
const zodError = new zod.ZodError([{
|
|
415
|
+
code: "invalid_type",
|
|
416
|
+
expected: "boolean",
|
|
417
|
+
message: `Invalid Boolean value: ${rawInput}`,
|
|
418
|
+
path: []
|
|
419
|
+
}]);
|
|
420
|
+
return {
|
|
421
|
+
success: false,
|
|
422
|
+
error: options.errors.zodError(zodError, rawInput)
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
return boolResult;
|
|
426
|
+
}
|
|
256
427
|
const parser = {
|
|
257
428
|
$mode: "sync",
|
|
258
429
|
metavar,
|
|
259
|
-
...
|
|
430
|
+
...boolInfo.exposeChoices ? {
|
|
431
|
+
choices: Object.freeze([true, false]),
|
|
432
|
+
suggest(prefix) {
|
|
433
|
+
const allLiterals = [...BOOL_TRUE_LITERALS, ...BOOL_FALSE_LITERALS];
|
|
434
|
+
const normalizedPrefix = prefix.toLowerCase();
|
|
435
|
+
return allLiterals.filter((lit) => lit.startsWith(normalizedPrefix)).map((lit) => ({
|
|
436
|
+
kind: "literal",
|
|
437
|
+
text: lit
|
|
438
|
+
}));
|
|
439
|
+
}
|
|
440
|
+
} : choices != null && choices.length > 0 ? {
|
|
260
441
|
choices: Object.freeze(choices),
|
|
261
442
|
*suggest(prefix) {
|
|
262
443
|
for (const c of choices) if (c.startsWith(prefix)) yield {
|
|
@@ -266,34 +447,12 @@ function zod(schema, options = {}) {
|
|
|
266
447
|
}
|
|
267
448
|
} : {},
|
|
268
449
|
parse(input) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (error instanceof Error && isZodAsyncError(error)) throw new TypeError("Async Zod schemas (e.g., async refinements) are not supported by zod(). Use synchronous schemas instead.");
|
|
274
|
-
throw error;
|
|
450
|
+
if (boolInfo.isBoolean) {
|
|
451
|
+
const boolResult = preConvertBoolean(input);
|
|
452
|
+
if (!boolResult.success) return handleBooleanLiteralError(boolResult, input);
|
|
453
|
+
return doSafeParse(boolResult.value, input);
|
|
275
454
|
}
|
|
276
|
-
|
|
277
|
-
success: true,
|
|
278
|
-
value: result.data
|
|
279
|
-
};
|
|
280
|
-
if (options.errors?.zodError) return {
|
|
281
|
-
success: false,
|
|
282
|
-
error: typeof options.errors.zodError === "function" ? options.errors.zodError(result.error, input) : options.errors.zodError
|
|
283
|
-
};
|
|
284
|
-
const zodModule = schema;
|
|
285
|
-
if (typeof zodModule.constructor?.prettifyError === "function") try {
|
|
286
|
-
const pretty = zodModule.constructor.prettifyError(result.error);
|
|
287
|
-
return {
|
|
288
|
-
success: false,
|
|
289
|
-
error: __optique_core_message.message`${pretty}`
|
|
290
|
-
};
|
|
291
|
-
} catch {}
|
|
292
|
-
const firstError = result.error.issues[0];
|
|
293
|
-
return {
|
|
294
|
-
success: false,
|
|
295
|
-
error: __optique_core_message.message`${firstError?.message ?? "Validation failed"}`
|
|
296
|
-
};
|
|
455
|
+
return doSafeParse(input, input);
|
|
297
456
|
},
|
|
298
457
|
format(value) {
|
|
299
458
|
if (options.format) return options.format(value);
|
|
@@ -313,4 +472,4 @@ function zod(schema, options = {}) {
|
|
|
313
472
|
}
|
|
314
473
|
|
|
315
474
|
//#endregion
|
|
316
|
-
exports.zod = zod;
|
|
475
|
+
exports.zod = zod$1;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { message } from "@optique/core/message";
|
|
1
|
+
import { message, valueSet } from "@optique/core/message";
|
|
2
2
|
import { ensureNonEmptyString } from "@optique/core/nonempty";
|
|
3
|
+
import { ZodError } from "zod";
|
|
3
4
|
|
|
4
5
|
//#region src/index.ts
|
|
5
6
|
/**
|
|
@@ -16,6 +17,114 @@ function isZodAsyncError(error) {
|
|
|
16
17
|
if (error.message === "Async refinement encountered during synchronous parse operation. Use .parseAsync instead." || error.message === "Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead." || error.message === "Synchronous parse encountered promise.") return true;
|
|
17
18
|
return false;
|
|
18
19
|
}
|
|
20
|
+
const BOOL_TRUE_LITERALS = [
|
|
21
|
+
"true",
|
|
22
|
+
"1",
|
|
23
|
+
"yes",
|
|
24
|
+
"on"
|
|
25
|
+
];
|
|
26
|
+
const BOOL_FALSE_LITERALS = [
|
|
27
|
+
"false",
|
|
28
|
+
"0",
|
|
29
|
+
"no",
|
|
30
|
+
"off"
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Analyzes whether the given Zod schema represents a boolean type,
|
|
34
|
+
* unwrapping all known Zod wrappers. Also determines whether it is
|
|
35
|
+
* safe to expose `choices` and `suggest()` — wrappers that can narrow
|
|
36
|
+
* the accepted domain (effects, catch) suppress choice exposure.
|
|
37
|
+
*/
|
|
38
|
+
function analyzeBooleanSchema(schema) {
|
|
39
|
+
const result = analyzeBooleanInner(schema, true, /* @__PURE__ */ new WeakSet());
|
|
40
|
+
if (!result.isBoolean) return {
|
|
41
|
+
isBoolean: false,
|
|
42
|
+
exposeChoices: false,
|
|
43
|
+
isCoerced: false
|
|
44
|
+
};
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
function analyzeBooleanInner(schema, canExposeChoices, visited) {
|
|
48
|
+
if (visited.has(schema)) return {
|
|
49
|
+
isBoolean: false,
|
|
50
|
+
exposeChoices: false,
|
|
51
|
+
isCoerced: false
|
|
52
|
+
};
|
|
53
|
+
visited.add(schema);
|
|
54
|
+
const def = schema._def;
|
|
55
|
+
if (!def) return {
|
|
56
|
+
isBoolean: false,
|
|
57
|
+
exposeChoices: false,
|
|
58
|
+
isCoerced: false
|
|
59
|
+
};
|
|
60
|
+
const typeName = def.typeName ?? def.type;
|
|
61
|
+
if (typeName === "ZodBoolean" || typeName === "boolean") {
|
|
62
|
+
const hasCustomChecks = Array.isArray(def.checks) && def.checks.some((c) => c.kind === "custom" || c.type === "custom" || c._zod?.def?.check === "custom");
|
|
63
|
+
return {
|
|
64
|
+
isBoolean: true,
|
|
65
|
+
exposeChoices: canExposeChoices && !hasCustomChecks,
|
|
66
|
+
isCoerced: def.coerce === true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (typeName === "ZodOptional" || typeName === "optional" || typeName === "ZodNullable" || typeName === "nullable" || typeName === "ZodDefault" || typeName === "default" || typeName === "ZodReadonly" || typeName === "readonly" || typeName === "prefault" || typeName === "nonoptional") {
|
|
70
|
+
const innerType = def.innerType;
|
|
71
|
+
if (innerType != null) return analyzeBooleanInner(innerType, canExposeChoices, visited);
|
|
72
|
+
}
|
|
73
|
+
if (typeName === "ZodLazy" || typeName === "lazy") {
|
|
74
|
+
if (typeof def.getter === "function") return analyzeBooleanInner(def.getter(), canExposeChoices, visited);
|
|
75
|
+
}
|
|
76
|
+
if (typeName === "ZodEffects" || typeName === "effects") {
|
|
77
|
+
if (def.effect?.type === "preprocess") return {
|
|
78
|
+
isBoolean: false,
|
|
79
|
+
exposeChoices: false,
|
|
80
|
+
isCoerced: false
|
|
81
|
+
};
|
|
82
|
+
const innerSchema = def.schema;
|
|
83
|
+
if (innerSchema != null) return analyzeBooleanInner(innerSchema, false, visited);
|
|
84
|
+
}
|
|
85
|
+
if (typeName === "ZodCatch" || typeName === "catch") {
|
|
86
|
+
const innerType = def.innerType;
|
|
87
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
88
|
+
}
|
|
89
|
+
if (typeName === "ZodBranded" || typeName === "branded") {
|
|
90
|
+
const innerType = def.innerType ?? (typeof def.type === "object" && def.type != null ? def.type : void 0);
|
|
91
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
92
|
+
}
|
|
93
|
+
if (typeName === "pipe" || typeName === "ZodPipeline") {
|
|
94
|
+
const inSchema = def.in;
|
|
95
|
+
if (inSchema != null) return analyzeBooleanInner(inSchema, false, visited);
|
|
96
|
+
const innerType = def.innerType;
|
|
97
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
98
|
+
}
|
|
99
|
+
if (typeName === "pipeline") {
|
|
100
|
+
const innerType = def.innerType;
|
|
101
|
+
if (innerType != null) return analyzeBooleanInner(innerType, false, visited);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
isBoolean: false,
|
|
105
|
+
exposeChoices: false,
|
|
106
|
+
isCoerced: false
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Pre-converts a CLI string input to an actual boolean value using
|
|
111
|
+
* CLI-friendly literals (true/false, 1/0, yes/no, on/off).
|
|
112
|
+
*/
|
|
113
|
+
function preConvertBoolean(input) {
|
|
114
|
+
const normalized = input.trim().toLowerCase();
|
|
115
|
+
if (BOOL_TRUE_LITERALS.includes(normalized)) return {
|
|
116
|
+
success: true,
|
|
117
|
+
value: true
|
|
118
|
+
};
|
|
119
|
+
if (BOOL_FALSE_LITERALS.includes(normalized)) return {
|
|
120
|
+
success: true,
|
|
121
|
+
value: false
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
error: message`Invalid Boolean value: ${input}. Expected one of ${valueSet([...BOOL_TRUE_LITERALS, ...BOOL_FALSE_LITERALS], { locale: "en-US" })}.`
|
|
126
|
+
};
|
|
127
|
+
}
|
|
19
128
|
/**
|
|
20
129
|
* Infers an appropriate metavar string from a Zod schema.
|
|
21
130
|
*
|
|
@@ -228,12 +337,84 @@ function inferChoices(schema) {
|
|
|
228
337
|
*/
|
|
229
338
|
function zod(schema, options = {}) {
|
|
230
339
|
const choices = inferChoices(schema);
|
|
231
|
-
const
|
|
340
|
+
const boolInfo = analyzeBooleanSchema(schema);
|
|
341
|
+
const metavar = options.metavar ?? (boolInfo.isBoolean ? "BOOLEAN" : inferMetavar(schema));
|
|
232
342
|
ensureNonEmptyString(metavar);
|
|
343
|
+
function doSafeParse(input, rawInput) {
|
|
344
|
+
let result;
|
|
345
|
+
try {
|
|
346
|
+
result = schema.safeParse(input);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
if (error instanceof Error && isZodAsyncError(error)) throw new TypeError("Async Zod schemas (e.g., async refinements) are not supported by zod(). Use synchronous schemas instead.");
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
if (result.success) return {
|
|
352
|
+
success: true,
|
|
353
|
+
value: result.data
|
|
354
|
+
};
|
|
355
|
+
if (options.errors?.zodError) return {
|
|
356
|
+
success: false,
|
|
357
|
+
error: typeof options.errors.zodError === "function" ? options.errors.zodError(result.error, rawInput) : options.errors.zodError
|
|
358
|
+
};
|
|
359
|
+
const zodModule = schema;
|
|
360
|
+
if (typeof zodModule.constructor?.prettifyError === "function") try {
|
|
361
|
+
const pretty = zodModule.constructor.prettifyError(result.error);
|
|
362
|
+
return {
|
|
363
|
+
success: false,
|
|
364
|
+
error: message`${pretty}`
|
|
365
|
+
};
|
|
366
|
+
} catch {}
|
|
367
|
+
const firstError = result.error.issues[0];
|
|
368
|
+
return {
|
|
369
|
+
success: false,
|
|
370
|
+
error: message`${firstError?.message ?? "Validation failed"}`
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Handles a failed boolean literal pre-conversion.
|
|
375
|
+
*
|
|
376
|
+
* - *Non-coerced* (`z.boolean()`): falls through to `doSafeParse`
|
|
377
|
+
* so that catch/default, custom errors, and async detection all
|
|
378
|
+
* work. This is safe because `safeParse(string)` fails at the
|
|
379
|
+
* type level before any refinements execute.
|
|
380
|
+
* - *Coerced* (`z.coerce.boolean()`): runs the lazy async probe
|
|
381
|
+
* (if not yet completed), then returns the pre-conversion error
|
|
382
|
+
* or delegates to the custom `zodError` callback.
|
|
383
|
+
*/
|
|
384
|
+
function handleBooleanLiteralError(boolResult, rawInput) {
|
|
385
|
+
if (!boolInfo.isCoerced) return doSafeParse(rawInput, rawInput);
|
|
386
|
+
if (options.errors?.zodError) {
|
|
387
|
+
if (typeof options.errors.zodError !== "function") return {
|
|
388
|
+
success: false,
|
|
389
|
+
error: options.errors.zodError
|
|
390
|
+
};
|
|
391
|
+
const zodError = new ZodError([{
|
|
392
|
+
code: "invalid_type",
|
|
393
|
+
expected: "boolean",
|
|
394
|
+
message: `Invalid Boolean value: ${rawInput}`,
|
|
395
|
+
path: []
|
|
396
|
+
}]);
|
|
397
|
+
return {
|
|
398
|
+
success: false,
|
|
399
|
+
error: options.errors.zodError(zodError, rawInput)
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
return boolResult;
|
|
403
|
+
}
|
|
233
404
|
const parser = {
|
|
234
405
|
$mode: "sync",
|
|
235
406
|
metavar,
|
|
236
|
-
...
|
|
407
|
+
...boolInfo.exposeChoices ? {
|
|
408
|
+
choices: Object.freeze([true, false]),
|
|
409
|
+
suggest(prefix) {
|
|
410
|
+
const allLiterals = [...BOOL_TRUE_LITERALS, ...BOOL_FALSE_LITERALS];
|
|
411
|
+
const normalizedPrefix = prefix.toLowerCase();
|
|
412
|
+
return allLiterals.filter((lit) => lit.startsWith(normalizedPrefix)).map((lit) => ({
|
|
413
|
+
kind: "literal",
|
|
414
|
+
text: lit
|
|
415
|
+
}));
|
|
416
|
+
}
|
|
417
|
+
} : choices != null && choices.length > 0 ? {
|
|
237
418
|
choices: Object.freeze(choices),
|
|
238
419
|
*suggest(prefix) {
|
|
239
420
|
for (const c of choices) if (c.startsWith(prefix)) yield {
|
|
@@ -243,34 +424,12 @@ function zod(schema, options = {}) {
|
|
|
243
424
|
}
|
|
244
425
|
} : {},
|
|
245
426
|
parse(input) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (error instanceof Error && isZodAsyncError(error)) throw new TypeError("Async Zod schemas (e.g., async refinements) are not supported by zod(). Use synchronous schemas instead.");
|
|
251
|
-
throw error;
|
|
427
|
+
if (boolInfo.isBoolean) {
|
|
428
|
+
const boolResult = preConvertBoolean(input);
|
|
429
|
+
if (!boolResult.success) return handleBooleanLiteralError(boolResult, input);
|
|
430
|
+
return doSafeParse(boolResult.value, input);
|
|
252
431
|
}
|
|
253
|
-
|
|
254
|
-
success: true,
|
|
255
|
-
value: result.data
|
|
256
|
-
};
|
|
257
|
-
if (options.errors?.zodError) return {
|
|
258
|
-
success: false,
|
|
259
|
-
error: typeof options.errors.zodError === "function" ? options.errors.zodError(result.error, input) : options.errors.zodError
|
|
260
|
-
};
|
|
261
|
-
const zodModule = schema;
|
|
262
|
-
if (typeof zodModule.constructor?.prettifyError === "function") try {
|
|
263
|
-
const pretty = zodModule.constructor.prettifyError(result.error);
|
|
264
|
-
return {
|
|
265
|
-
success: false,
|
|
266
|
-
error: message`${pretty}`
|
|
267
|
-
};
|
|
268
|
-
} catch {}
|
|
269
|
-
const firstError = result.error.issues[0];
|
|
270
|
-
return {
|
|
271
|
-
success: false,
|
|
272
|
-
error: message`${firstError?.message ?? "Validation failed"}`
|
|
273
|
-
};
|
|
432
|
+
return doSafeParse(input, input);
|
|
274
433
|
},
|
|
275
434
|
format(value) {
|
|
276
435
|
if (options.format) return options.format(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/zod",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
3
|
+
"version": "1.0.0-dev.1436+4ad8f445",
|
|
4
4
|
"description": "Zod value parsers for Optique",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"zod": "^3.25.0 || ^4.0.0"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@optique/core": "1.0.0-dev.
|
|
60
|
+
"@optique/core": "1.0.0-dev.1436+4ad8f445"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@types/node": "^20.19.9",
|