@oh-my-pi/omptype 18.2.0 → 18.2.1
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/CHANGELOG.md +6 -0
- package/dist/js/zod.js +118 -8
- package/dist/types/zod.d.ts +13 -1
- package/package.json +1 -1
- package/src/zod.ts +142 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.1] - 2026-09-15
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `trim()`, `superRefine()`, and one-argument `record()` support to the Zod compatibility facade ([#12011](https://github.com/can1357/oh-my-pi/pull/12011) by [@bnivanov](https://github.com/bnivanov)).
|
|
10
|
+
|
|
5
11
|
## [17.3.1] - 2026-08-13
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/dist/js/zod.js
CHANGED
|
@@ -88,6 +88,25 @@ function decorate(schema, optional = false) {
|
|
|
88
88
|
return next(restrictBase(schema, ir));
|
|
89
89
|
return next(restrictBase(schema, { ...ir, min: bound, xmin: false }));
|
|
90
90
|
}
|
|
91
|
+
if (ir.k === "morph" &&
|
|
92
|
+
!schema.hasSteps &&
|
|
93
|
+
ir.out !== undefined &&
|
|
94
|
+
(ir.out.k === "string" || ir.out.k === "array")) {
|
|
95
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
96
|
+
throw new OmpTypeError("min length must be a nonnegative safe integer");
|
|
97
|
+
const out = { ...ir.out, min: ir.out.min === undefined ? bound : Math.max(ir.out.min, bound) };
|
|
98
|
+
return next(restrictBase(schema, { ...ir, out }));
|
|
99
|
+
}
|
|
100
|
+
if (ir.k === "morph" && (schema.hasSteps || ir.out === undefined)) {
|
|
101
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
102
|
+
throw new OmpTypeError("min length must be a nonnegative safe integer");
|
|
103
|
+
return next(schema.narrow((value, ctx) => {
|
|
104
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
105
|
+
return value.length >= bound || ctx.mustBe(`at least ${bound} characters`);
|
|
106
|
+
}
|
|
107
|
+
return ctx.mustBe("a string or array");
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
91
110
|
throw new OmpTypeError(`cannot apply min to ${ir.k}`);
|
|
92
111
|
},
|
|
93
112
|
max(bound) {
|
|
@@ -104,6 +123,25 @@ function decorate(schema, optional = false) {
|
|
|
104
123
|
return next(restrictBase(schema, ir));
|
|
105
124
|
return next(restrictBase(schema, { ...ir, max: bound, xmax: false }));
|
|
106
125
|
}
|
|
126
|
+
if (ir.k === "morph" &&
|
|
127
|
+
!schema.hasSteps &&
|
|
128
|
+
ir.out !== undefined &&
|
|
129
|
+
(ir.out.k === "string" || ir.out.k === "array")) {
|
|
130
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
131
|
+
throw new OmpTypeError("max length must be a nonnegative safe integer");
|
|
132
|
+
const out = { ...ir.out, max: ir.out.max === undefined ? bound : Math.min(ir.out.max, bound) };
|
|
133
|
+
return next(restrictBase(schema, { ...ir, out }));
|
|
134
|
+
}
|
|
135
|
+
if (ir.k === "morph" && (schema.hasSteps || ir.out === undefined)) {
|
|
136
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
137
|
+
throw new OmpTypeError("max length must be a nonnegative safe integer");
|
|
138
|
+
return next(schema.narrow((value, ctx) => {
|
|
139
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
140
|
+
return value.length <= bound || ctx.mustBe(`at most ${bound} characters`);
|
|
141
|
+
}
|
|
142
|
+
return ctx.mustBe("a string or array");
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
107
145
|
throw new OmpTypeError(`cannot apply max to ${ir.k}`);
|
|
108
146
|
},
|
|
109
147
|
int() {
|
|
@@ -125,10 +163,15 @@ function decorate(schema, optional = false) {
|
|
|
125
163
|
return this.min(0);
|
|
126
164
|
},
|
|
127
165
|
regex(expression, message) {
|
|
128
|
-
|
|
129
|
-
|
|
166
|
+
const ir = schema.ir;
|
|
167
|
+
const isStringLike = ir.k === "string" ||
|
|
168
|
+
(ir.k === "morph" && (ir.out?.k === "string" || (ir.out === undefined && ir.input.k === "string")));
|
|
169
|
+
if (!isStringLike)
|
|
170
|
+
throw new OmpTypeError(`cannot apply regex to ${ir.k}`);
|
|
130
171
|
const expectation = message ?? `matching ${expression}`;
|
|
131
172
|
const narrowed = schema.narrow((value, ctx) => {
|
|
173
|
+
if (typeof value !== "string")
|
|
174
|
+
return ctx.mustBe("a string");
|
|
132
175
|
expression.lastIndex = 0;
|
|
133
176
|
const matches = expression.test(value);
|
|
134
177
|
expression.lastIndex = 0;
|
|
@@ -137,9 +180,26 @@ function decorate(schema, optional = false) {
|
|
|
137
180
|
return next(narrowed);
|
|
138
181
|
},
|
|
139
182
|
url() {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
183
|
+
const ir = schema.ir;
|
|
184
|
+
if (ir.k === "string")
|
|
185
|
+
return next(restrictBase(schema, { ...ir, url: true }));
|
|
186
|
+
if (ir.k === "morph" && !schema.hasSteps && ir.out !== undefined && ir.out.k === "string") {
|
|
187
|
+
return next(restrictBase(schema, { ...ir, out: { ...ir.out, url: true } }));
|
|
188
|
+
}
|
|
189
|
+
if (ir.k === "morph" && (schema.hasSteps || ir.out === undefined)) {
|
|
190
|
+
return next(schema.narrow((value, ctx) => {
|
|
191
|
+
if (typeof value !== "string")
|
|
192
|
+
return ctx.mustBe("a string");
|
|
193
|
+
try {
|
|
194
|
+
new URL(value);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return ctx.mustBe("a valid URL");
|
|
199
|
+
}
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
throw new OmpTypeError(`cannot apply url to ${ir.k}`);
|
|
143
203
|
},
|
|
144
204
|
optional() {
|
|
145
205
|
const widened = schema.or(type.raw("undefined"));
|
|
@@ -164,6 +224,54 @@ function decorate(schema, optional = false) {
|
|
|
164
224
|
const expectation = refinementMessage(messageOrOptions);
|
|
165
225
|
return next(schema.narrow((value, ctx) => Boolean(predicate(value)) || ctx.mustBe(expectation)));
|
|
166
226
|
},
|
|
227
|
+
superRefine(refinement) {
|
|
228
|
+
return next(schema.narrow((value, ctx) => {
|
|
229
|
+
const proxy = {
|
|
230
|
+
addIssue(issue) {
|
|
231
|
+
ctx.error({
|
|
232
|
+
expected: issue.message,
|
|
233
|
+
path: issue.path ?? [],
|
|
234
|
+
...(issue.actual !== undefined ? { actual: issue.actual } : {}),
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
refinement(value, proxy);
|
|
239
|
+
return true;
|
|
240
|
+
}));
|
|
241
|
+
},
|
|
242
|
+
trim() {
|
|
243
|
+
const ir = schema.ir;
|
|
244
|
+
if (ir.k === "string" && !schema.hasSteps) {
|
|
245
|
+
let trimmed = schemaFromIR({
|
|
246
|
+
k: "morph",
|
|
247
|
+
input: { k: "string" },
|
|
248
|
+
fn: v => v.trim(),
|
|
249
|
+
out: ir,
|
|
250
|
+
});
|
|
251
|
+
if (schema.hasDefault)
|
|
252
|
+
trimmed = trimmed.default(schema.defaultValue);
|
|
253
|
+
return next(trimmed);
|
|
254
|
+
}
|
|
255
|
+
if (ir.k === "morph" || schema.hasSteps) {
|
|
256
|
+
let trimmed = schemaFromIR({
|
|
257
|
+
k: "morph",
|
|
258
|
+
input: { k: "unknown" },
|
|
259
|
+
fn: v => {
|
|
260
|
+
const r = schema(v);
|
|
261
|
+
if (r instanceof type.errors)
|
|
262
|
+
return r;
|
|
263
|
+
if (typeof r !== "string")
|
|
264
|
+
throw new OmpTypeError("trim requires a string output");
|
|
265
|
+
return r.trim();
|
|
266
|
+
},
|
|
267
|
+
out: { k: "string" },
|
|
268
|
+
});
|
|
269
|
+
if (schema.hasDefault)
|
|
270
|
+
trimmed = trimmed.default(schema.defaultValue);
|
|
271
|
+
return next(trimmed);
|
|
272
|
+
}
|
|
273
|
+
throw new OmpTypeError(`cannot apply trim to ${ir.k}`);
|
|
274
|
+
},
|
|
167
275
|
transform(transformer) {
|
|
168
276
|
return decorate(schema.pipe(value => transformer(value)), optional);
|
|
169
277
|
},
|
|
@@ -228,13 +336,15 @@ export { enumSchema as enum };
|
|
|
228
336
|
export const union = (schemas) => decorate(schemaFromIR({ k: "union", members: schemas.map(schema => embed(schema)) }));
|
|
229
337
|
export const array = (element) => decorate(schemaFromIR({ k: "array", el: embed(element) }));
|
|
230
338
|
export const object = (shape) => objectSchema(shape);
|
|
231
|
-
export
|
|
339
|
+
export function record(keyOrValueSchema, valueSchema) {
|
|
340
|
+
const keySchema = (valueSchema === undefined ? string() : keyOrValueSchema);
|
|
341
|
+
const valSchema = (valueSchema === undefined ? keyOrValueSchema : valueSchema);
|
|
232
342
|
if (!isStringKeyIR(keySchema.ir))
|
|
233
343
|
throw new OmpTypeError("record keys must use a string schema");
|
|
234
344
|
const base = schemaFromIR({
|
|
235
345
|
k: "object",
|
|
236
346
|
props: [],
|
|
237
|
-
index: embed(
|
|
347
|
+
index: embed(valSchema),
|
|
238
348
|
extras: "keep",
|
|
239
349
|
});
|
|
240
350
|
const checked = base.narrow((value, ctx) => {
|
|
@@ -245,7 +355,7 @@ export const record = (keySchema, valueSchema) => {
|
|
|
245
355
|
return true;
|
|
246
356
|
});
|
|
247
357
|
return decorate(checked);
|
|
248
|
-
}
|
|
358
|
+
}
|
|
249
359
|
export const unknown = () => decorate(schemaFromIR(type.unknown.ir));
|
|
250
360
|
export const any = () => decorate(schemaFromIR(type.unknown.ir));
|
|
251
361
|
const nullSchema = () => decorate(type.raw("null"));
|
package/dist/types/zod.d.ts
CHANGED
|
@@ -6,6 +6,15 @@ interface RefineOptions {
|
|
|
6
6
|
message?: string;
|
|
7
7
|
error?: string;
|
|
8
8
|
}
|
|
9
|
+
export interface SuperRefineIssue {
|
|
10
|
+
code?: string;
|
|
11
|
+
path?: PropertyKey[];
|
|
12
|
+
message: string;
|
|
13
|
+
actual?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface SuperRefineContext {
|
|
16
|
+
addIssue(issue: SuperRefineIssue): void;
|
|
17
|
+
}
|
|
9
18
|
export interface ZodLikeIssue {
|
|
10
19
|
path: PropertyKey[];
|
|
11
20
|
message: string;
|
|
@@ -39,6 +48,8 @@ export interface ZodLikeSchema<out Out> extends Type<Out, unknown> {
|
|
|
39
48
|
default(value: Exclude<Out, undefined> | (() => Exclude<Out, undefined>)): ZodLikeSchema<Exclude<Out, undefined>>;
|
|
40
49
|
describe(description: string): ZodLikeSchema<Out>;
|
|
41
50
|
refine(predicate: (value: Out) => unknown, messageOrOptions?: string | RefineOptions): ZodLikeSchema<Out>;
|
|
51
|
+
superRefine(refinement: (value: Out, ctx: SuperRefineContext) => void): ZodLikeSchema<Out>;
|
|
52
|
+
trim(): ZodLikeSchema<Out>;
|
|
42
53
|
transform<Next>(transformer: (value: Out) => Next): ZodLikeSchema<Next>;
|
|
43
54
|
catch(fallback: Out | (() => Out)): ZodLikeSchema<Out>;
|
|
44
55
|
strict(): ZodLikeSchema<Out>;
|
|
@@ -71,7 +82,8 @@ export { enumSchema as enum };
|
|
|
71
82
|
export declare const union: <const Schemas extends readonly [ZodLikeSchema<unknown>, ZodLikeSchema<unknown>, ...ZodLikeSchema<unknown>[]]>(schemas: Schemas) => ZodLikeSchema<UnionOutput<Schemas>>;
|
|
72
83
|
export declare const array: <Element>(element: ZodLikeSchema<Element>) => ZodLikeSchema<Element[]>;
|
|
73
84
|
export declare const object: <const S extends Shape>(shape: S) => ZodLikeSchema<Simplify<ObjectOutput<S>>>;
|
|
74
|
-
export declare
|
|
85
|
+
export declare function record<Key extends string, Value>(keySchema: ZodLikeSchema<Key>, valueSchema: ZodLikeSchema<Value>): ZodLikeSchema<Record<string, Value>>;
|
|
86
|
+
export declare function record<Value>(valueSchema: ZodLikeSchema<Value>): ZodLikeSchema<Record<string, Value>>;
|
|
75
87
|
export declare const unknown: () => ZodLikeSchema<unknown>;
|
|
76
88
|
export declare const any: () => ZodLikeSchema<unknown>;
|
|
77
89
|
declare const nullSchema: () => ZodLikeSchema<null>;
|
package/package.json
CHANGED
package/src/zod.ts
CHANGED
|
@@ -20,6 +20,17 @@ interface Decoratable<out Out> extends EmbeddableSchema {
|
|
|
20
20
|
default(value: Out | (() => Out)): Decoratable<Out>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
export interface SuperRefineIssue {
|
|
24
|
+
code?: string;
|
|
25
|
+
path?: PropertyKey[];
|
|
26
|
+
message: string;
|
|
27
|
+
actual?: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface SuperRefineContext {
|
|
31
|
+
addIssue(issue: SuperRefineIssue): void;
|
|
32
|
+
}
|
|
33
|
+
|
|
23
34
|
export interface ZodLikeIssue {
|
|
24
35
|
path: PropertyKey[];
|
|
25
36
|
message: string;
|
|
@@ -48,6 +59,8 @@ export interface ZodLikeSchema<out Out> extends Type<Out, unknown> {
|
|
|
48
59
|
default(value: Exclude<Out, undefined> | (() => Exclude<Out, undefined>)): ZodLikeSchema<Exclude<Out, undefined>>;
|
|
49
60
|
describe(description: string): ZodLikeSchema<Out>;
|
|
50
61
|
refine(predicate: (value: Out) => unknown, messageOrOptions?: string | RefineOptions): ZodLikeSchema<Out>;
|
|
62
|
+
superRefine(refinement: (value: Out, ctx: SuperRefineContext) => void): ZodLikeSchema<Out>;
|
|
63
|
+
trim(): ZodLikeSchema<Out>;
|
|
51
64
|
transform<Next>(transformer: (value: Out) => Next): ZodLikeSchema<Next>;
|
|
52
65
|
catch(fallback: Out | (() => Out)): ZodLikeSchema<Out>;
|
|
53
66
|
strict(): ZodLikeSchema<Out>;
|
|
@@ -140,6 +153,29 @@ function decorate<Out>(schema: Decoratable<Out>, optional = false): ZodLikeSchem
|
|
|
140
153
|
if (ir.min !== undefined && ir.min >= bound) return next(restrictBase(schema, ir));
|
|
141
154
|
return next(restrictBase(schema, { ...ir, min: bound, xmin: false }));
|
|
142
155
|
}
|
|
156
|
+
if (
|
|
157
|
+
ir.k === "morph" &&
|
|
158
|
+
!schema.hasSteps &&
|
|
159
|
+
ir.out !== undefined &&
|
|
160
|
+
(ir.out.k === "string" || ir.out.k === "array")
|
|
161
|
+
) {
|
|
162
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
163
|
+
throw new OmpTypeError("min length must be a nonnegative safe integer");
|
|
164
|
+
const out = { ...ir.out, min: ir.out.min === undefined ? bound : Math.max(ir.out.min, bound) };
|
|
165
|
+
return next(restrictBase(schema, { ...ir, out }));
|
|
166
|
+
}
|
|
167
|
+
if (ir.k === "morph" && (schema.hasSteps || ir.out === undefined)) {
|
|
168
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
169
|
+
throw new OmpTypeError("min length must be a nonnegative safe integer");
|
|
170
|
+
return next(
|
|
171
|
+
schema.narrow((value, ctx) => {
|
|
172
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
173
|
+
return value.length >= bound || ctx.mustBe(`at least ${bound} characters`);
|
|
174
|
+
}
|
|
175
|
+
return ctx.mustBe("a string or array");
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
143
179
|
throw new OmpTypeError(`cannot apply min to ${ir.k}`);
|
|
144
180
|
},
|
|
145
181
|
max(bound: number): ZodLikeSchema<Out> {
|
|
@@ -154,6 +190,29 @@ function decorate<Out>(schema: Decoratable<Out>, optional = false): ZodLikeSchem
|
|
|
154
190
|
if (ir.max !== undefined && ir.max <= bound) return next(restrictBase(schema, ir));
|
|
155
191
|
return next(restrictBase(schema, { ...ir, max: bound, xmax: false }));
|
|
156
192
|
}
|
|
193
|
+
if (
|
|
194
|
+
ir.k === "morph" &&
|
|
195
|
+
!schema.hasSteps &&
|
|
196
|
+
ir.out !== undefined &&
|
|
197
|
+
(ir.out.k === "string" || ir.out.k === "array")
|
|
198
|
+
) {
|
|
199
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
200
|
+
throw new OmpTypeError("max length must be a nonnegative safe integer");
|
|
201
|
+
const out = { ...ir.out, max: ir.out.max === undefined ? bound : Math.min(ir.out.max, bound) };
|
|
202
|
+
return next(restrictBase(schema, { ...ir, out }));
|
|
203
|
+
}
|
|
204
|
+
if (ir.k === "morph" && (schema.hasSteps || ir.out === undefined)) {
|
|
205
|
+
if (!Number.isSafeInteger(bound) || bound < 0)
|
|
206
|
+
throw new OmpTypeError("max length must be a nonnegative safe integer");
|
|
207
|
+
return next(
|
|
208
|
+
schema.narrow((value, ctx) => {
|
|
209
|
+
if (typeof value === "string" || Array.isArray(value)) {
|
|
210
|
+
return value.length <= bound || ctx.mustBe(`at most ${bound} characters`);
|
|
211
|
+
}
|
|
212
|
+
return ctx.mustBe("a string or array");
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
215
|
+
}
|
|
157
216
|
throw new OmpTypeError(`cannot apply max to ${ir.k}`);
|
|
158
217
|
},
|
|
159
218
|
int(): ZodLikeSchema<Out> {
|
|
@@ -171,19 +230,41 @@ function decorate<Out>(schema: Decoratable<Out>, optional = false): ZodLikeSchem
|
|
|
171
230
|
return this.min(0);
|
|
172
231
|
},
|
|
173
232
|
regex(expression: RegExp, message?: string): ZodLikeSchema<Out> {
|
|
174
|
-
|
|
233
|
+
const ir = schema.ir;
|
|
234
|
+
const isStringLike =
|
|
235
|
+
ir.k === "string" ||
|
|
236
|
+
(ir.k === "morph" && (ir.out?.k === "string" || (ir.out === undefined && ir.input.k === "string")));
|
|
237
|
+
if (!isStringLike) throw new OmpTypeError(`cannot apply regex to ${ir.k}`);
|
|
175
238
|
const expectation = message ?? `matching ${expression}`;
|
|
176
239
|
const narrowed = schema.narrow((value, ctx) => {
|
|
240
|
+
if (typeof value !== "string") return ctx.mustBe("a string");
|
|
177
241
|
expression.lastIndex = 0;
|
|
178
|
-
const matches = expression.test(value
|
|
242
|
+
const matches = expression.test(value);
|
|
179
243
|
expression.lastIndex = 0;
|
|
180
244
|
return matches || ctx.mustBe(expectation);
|
|
181
245
|
});
|
|
182
246
|
return next(narrowed);
|
|
183
247
|
},
|
|
184
248
|
url(): ZodLikeSchema<Out> {
|
|
185
|
-
|
|
186
|
-
return next(restrictBase(schema, { ...
|
|
249
|
+
const ir = schema.ir;
|
|
250
|
+
if (ir.k === "string") return next(restrictBase(schema, { ...ir, url: true }));
|
|
251
|
+
if (ir.k === "morph" && !schema.hasSteps && ir.out !== undefined && ir.out.k === "string") {
|
|
252
|
+
return next(restrictBase(schema, { ...ir, out: { ...ir.out, url: true } }));
|
|
253
|
+
}
|
|
254
|
+
if (ir.k === "morph" && (schema.hasSteps || ir.out === undefined)) {
|
|
255
|
+
return next(
|
|
256
|
+
schema.narrow((value, ctx) => {
|
|
257
|
+
if (typeof value !== "string") return ctx.mustBe("a string");
|
|
258
|
+
try {
|
|
259
|
+
new URL(value);
|
|
260
|
+
return true;
|
|
261
|
+
} catch {
|
|
262
|
+
return ctx.mustBe("a valid URL");
|
|
263
|
+
}
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
throw new OmpTypeError(`cannot apply url to ${ir.k}`);
|
|
187
268
|
},
|
|
188
269
|
optional(): ZodLikeSchema<Out | undefined> & OptionalSchemaMarker {
|
|
189
270
|
const widened = schema.or(type.raw("undefined")) as Decoratable<Out | undefined>;
|
|
@@ -210,6 +291,52 @@ function decorate<Out>(schema: Decoratable<Out>, optional = false): ZodLikeSchem
|
|
|
210
291
|
const expectation = refinementMessage(messageOrOptions);
|
|
211
292
|
return next(schema.narrow((value, ctx) => Boolean(predicate(value)) || ctx.mustBe(expectation)));
|
|
212
293
|
},
|
|
294
|
+
superRefine(refinement: (value: Out, ctx: SuperRefineContext) => void): ZodLikeSchema<Out> {
|
|
295
|
+
return next(
|
|
296
|
+
schema.narrow((value, ctx) => {
|
|
297
|
+
const proxy: SuperRefineContext = {
|
|
298
|
+
addIssue(issue) {
|
|
299
|
+
ctx.error({
|
|
300
|
+
expected: issue.message,
|
|
301
|
+
path: issue.path ?? [],
|
|
302
|
+
...(issue.actual !== undefined ? { actual: issue.actual } : {}),
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
refinement(value, proxy);
|
|
307
|
+
return true;
|
|
308
|
+
}),
|
|
309
|
+
);
|
|
310
|
+
},
|
|
311
|
+
trim(): ZodLikeSchema<Out> {
|
|
312
|
+
const ir = schema.ir;
|
|
313
|
+
if (ir.k === "string" && !schema.hasSteps) {
|
|
314
|
+
let trimmed = schemaFromIR<Out>({
|
|
315
|
+
k: "morph",
|
|
316
|
+
input: { k: "string" },
|
|
317
|
+
fn: v => (v as string).trim(),
|
|
318
|
+
out: ir,
|
|
319
|
+
});
|
|
320
|
+
if (schema.hasDefault) trimmed = trimmed.default(schema.defaultValue as Out | (() => Out));
|
|
321
|
+
return next(trimmed);
|
|
322
|
+
}
|
|
323
|
+
if (ir.k === "morph" || schema.hasSteps) {
|
|
324
|
+
let trimmed = schemaFromIR<Out>({
|
|
325
|
+
k: "morph",
|
|
326
|
+
input: { k: "unknown" },
|
|
327
|
+
fn: v => {
|
|
328
|
+
const r = schema(v);
|
|
329
|
+
if (r instanceof type.errors) return r;
|
|
330
|
+
if (typeof r !== "string") throw new OmpTypeError("trim requires a string output");
|
|
331
|
+
return r.trim();
|
|
332
|
+
},
|
|
333
|
+
out: { k: "string" },
|
|
334
|
+
});
|
|
335
|
+
if (schema.hasDefault) trimmed = trimmed.default(schema.defaultValue as Out | (() => Out));
|
|
336
|
+
return next(trimmed);
|
|
337
|
+
}
|
|
338
|
+
throw new OmpTypeError(`cannot apply trim to ${ir.k}`);
|
|
339
|
+
},
|
|
213
340
|
transform<Next>(transformer: (value: Out) => Next): ZodLikeSchema<Next> {
|
|
214
341
|
return decorate(
|
|
215
342
|
schema.pipe(value => transformer(value)),
|
|
@@ -303,15 +430,22 @@ export const array = <Element>(element: ZodLikeSchema<Element>): ZodLikeSchema<E
|
|
|
303
430
|
decorate(schemaFromIR({ k: "array", el: embed(element) }));
|
|
304
431
|
export const object = <const S extends Shape>(shape: S): ZodLikeSchema<Simplify<ObjectOutput<S>>> =>
|
|
305
432
|
objectSchema(shape);
|
|
306
|
-
export
|
|
433
|
+
export function record<Key extends string, Value>(
|
|
307
434
|
keySchema: ZodLikeSchema<Key>,
|
|
308
435
|
valueSchema: ZodLikeSchema<Value>,
|
|
309
|
-
): ZodLikeSchema<Record<string, Value
|
|
436
|
+
): ZodLikeSchema<Record<string, Value>>;
|
|
437
|
+
export function record<Value>(valueSchema: ZodLikeSchema<Value>): ZodLikeSchema<Record<string, Value>>;
|
|
438
|
+
export function record<Key extends string, Value>(
|
|
439
|
+
keyOrValueSchema: ZodLikeSchema<Key> | ZodLikeSchema<Value>,
|
|
440
|
+
valueSchema?: ZodLikeSchema<Value>,
|
|
441
|
+
): ZodLikeSchema<Record<string, Value>> {
|
|
442
|
+
const keySchema = (valueSchema === undefined ? string() : keyOrValueSchema) as ZodLikeSchema<Key>;
|
|
443
|
+
const valSchema = (valueSchema === undefined ? keyOrValueSchema : valueSchema) as ZodLikeSchema<Value>;
|
|
310
444
|
if (!isStringKeyIR(keySchema.ir)) throw new OmpTypeError("record keys must use a string schema");
|
|
311
445
|
const base = schemaFromIR<Record<string, Value>>({
|
|
312
446
|
k: "object",
|
|
313
447
|
props: [],
|
|
314
|
-
index: embed(
|
|
448
|
+
index: embed(valSchema),
|
|
315
449
|
extras: "keep",
|
|
316
450
|
});
|
|
317
451
|
const checked = base.narrow((value, ctx: NarrowContext) => {
|
|
@@ -321,7 +455,7 @@ export const record = <Key extends string, Value>(
|
|
|
321
455
|
return true;
|
|
322
456
|
});
|
|
323
457
|
return decorate(checked);
|
|
324
|
-
}
|
|
458
|
+
}
|
|
325
459
|
export const unknown = (): ZodLikeSchema<unknown> => decorate(schemaFromIR(type.unknown.ir));
|
|
326
460
|
export const any = (): ZodLikeSchema<unknown> => decorate(schemaFromIR(type.unknown.ir));
|
|
327
461
|
const nullSchema = (): ZodLikeSchema<null> => decorate(type.raw("null") as unknown as Decoratable<null>);
|