@livon/schema 0.27.0-rc.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/PROMPT.md +21 -0
- package/README.md +13 -0
- package/SCHEMA.md +13 -0
- package/dist/SchemaValidationError.cjs +41 -0
- package/dist/SchemaValidationError.d.ts +20 -0
- package/dist/SchemaValidationError.js +7 -0
- package/dist/SchemaValidationError.spec.cjs +65 -0
- package/dist/SchemaValidationError.spec.d.ts +1 -0
- package/dist/SchemaValidationError.spec.js +59 -0
- package/dist/after.cjs +36 -0
- package/dist/after.d.ts +30 -0
- package/dist/after.js +2 -0
- package/dist/after.spec.cjs +54 -0
- package/dist/after.spec.d.ts +1 -0
- package/dist/after.spec.js +48 -0
- package/dist/and.cjs +36 -0
- package/dist/and.d.ts +26 -0
- package/dist/and.js +2 -0
- package/dist/and.spec.cjs +57 -0
- package/dist/and.spec.d.ts +1 -0
- package/dist/and.spec.js +51 -0
- package/dist/api.cjs +317 -0
- package/dist/api.d.ts +107 -0
- package/dist/api.js +277 -0
- package/dist/api.spec.cjs +512 -0
- package/dist/api.spec.d.ts +1 -0
- package/dist/api.spec.js +506 -0
- package/dist/array.cjs +74 -0
- package/dist/array.d.ts +25 -0
- package/dist/array.js +40 -0
- package/dist/array.spec.cjs +167 -0
- package/dist/array.spec.d.ts +1 -0
- package/dist/array.spec.js +161 -0
- package/dist/before.cjs +36 -0
- package/dist/before.d.ts +30 -0
- package/dist/before.js +2 -0
- package/dist/before.spec.cjs +54 -0
- package/dist/before.spec.d.ts +1 -0
- package/dist/before.spec.js +48 -0
- package/dist/binary.cjs +53 -0
- package/dist/binary.d.ts +24 -0
- package/dist/binary.js +19 -0
- package/dist/binary.spec.cjs +107 -0
- package/dist/binary.spec.d.ts +1 -0
- package/dist/binary.spec.js +101 -0
- package/dist/boolean.cjs +53 -0
- package/dist/boolean.d.ts +24 -0
- package/dist/boolean.js +19 -0
- package/dist/boolean.spec.cjs +96 -0
- package/dist/boolean.spec.d.ts +1 -0
- package/dist/boolean.spec.js +90 -0
- package/dist/context.cjs +125 -0
- package/dist/context.d.ts +101 -0
- package/dist/context.js +76 -0
- package/dist/context.spec.cjs +244 -0
- package/dist/context.spec.d.ts +1 -0
- package/dist/context.spec.js +238 -0
- package/dist/date.cjs +53 -0
- package/dist/date.d.ts +24 -0
- package/dist/date.js +19 -0
- package/dist/date.spec.cjs +97 -0
- package/dist/date.spec.d.ts +1 -0
- package/dist/date.spec.js +91 -0
- package/dist/doc.cjs +54 -0
- package/dist/doc.d.ts +25 -0
- package/dist/doc.js +17 -0
- package/dist/doc.spec.cjs +99 -0
- package/dist/doc.spec.d.ts +1 -0
- package/dist/doc.spec.js +93 -0
- package/dist/enumeration.cjs +74 -0
- package/dist/enumeration.d.ts +50 -0
- package/dist/enumeration.js +40 -0
- package/dist/enumeration.spec.cjs +110 -0
- package/dist/enumeration.spec.d.ts +1 -0
- package/dist/enumeration.spec.js +104 -0
- package/dist/hydrate.cjs +18 -0
- package/dist/hydrate.d.ts +1 -0
- package/dist/hydrate.js +0 -0
- package/dist/index.cjs +145 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +24 -0
- package/dist/index.spec.cjs +43 -0
- package/dist/index.spec.d.ts +1 -0
- package/dist/index.spec.js +37 -0
- package/dist/literal.cjs +55 -0
- package/dist/literal.d.ts +25 -0
- package/dist/literal.js +21 -0
- package/dist/literal.spec.cjs +93 -0
- package/dist/literal.spec.d.ts +1 -0
- package/dist/literal.spec.js +87 -0
- package/dist/number.cjs +89 -0
- package/dist/number.d.ts +84 -0
- package/dist/number.js +55 -0
- package/dist/number.spec.cjs +155 -0
- package/dist/number.spec.d.ts +1 -0
- package/dist/number.spec.js +149 -0
- package/dist/object.cjs +66 -0
- package/dist/object.d.ts +37 -0
- package/dist/object.js +32 -0
- package/dist/object.spec.cjs +171 -0
- package/dist/object.spec.d.ts +1 -0
- package/dist/object.spec.js +165 -0
- package/dist/operation.cjs +182 -0
- package/dist/operation.d.ts +197 -0
- package/dist/operation.js +133 -0
- package/dist/operation.spec.cjs +454 -0
- package/dist/operation.spec.d.ts +1 -0
- package/dist/operation.spec.js +448 -0
- package/dist/or.cjs +85 -0
- package/dist/or.d.ts +37 -0
- package/dist/or.js +51 -0
- package/dist/or.spec.cjs +204 -0
- package/dist/or.spec.d.ts +1 -0
- package/dist/or.spec.js +198 -0
- package/dist/schema.cjs +285 -0
- package/dist/schema.d.ts +132 -0
- package/dist/schema.js +233 -0
- package/dist/schema.spec.cjs +587 -0
- package/dist/schema.spec.d.ts +1 -0
- package/dist/schema.spec.js +581 -0
- package/dist/schemaFactory.cjs +125 -0
- package/dist/schemaFactory.d.ts +97 -0
- package/dist/schemaFactory.js +88 -0
- package/dist/schemaFactory.spec.cjs +197 -0
- package/dist/schemaFactory.spec.d.ts +1 -0
- package/dist/schemaFactory.spec.js +191 -0
- package/dist/schemaModule.cjs +280 -0
- package/dist/schemaModule.d.ts +97 -0
- package/dist/schemaModule.js +243 -0
- package/dist/schemaModule.spec.cjs +355 -0
- package/dist/schemaModule.spec.d.ts +1 -0
- package/dist/schemaModule.spec.js +349 -0
- package/dist/string.cjs +93 -0
- package/dist/string.d.ts +85 -0
- package/dist/string.js +59 -0
- package/dist/string.spec.cjs +158 -0
- package/dist/string.spec.d.ts +1 -0
- package/dist/string.spec.js +152 -0
- package/dist/testing/mocks/assertions.mock.cjs +48 -0
- package/dist/testing/mocks/assertions.mock.d.ts +5 -0
- package/dist/testing/mocks/assertions.mock.js +14 -0
- package/dist/testing/mocks/index.cjs +52 -0
- package/dist/testing/mocks/index.d.ts +4 -0
- package/dist/testing/mocks/index.js +3 -0
- package/dist/testing/mocks/schema.mock.cjs +120 -0
- package/dist/testing/mocks/schema.mock.d.ts +37 -0
- package/dist/testing/mocks/schema.mock.js +74 -0
- package/dist/tuple.cjs +58 -0
- package/dist/tuple.d.ts +33 -0
- package/dist/tuple.js +24 -0
- package/dist/tuple.spec.cjs +162 -0
- package/dist/tuple.spec.d.ts +1 -0
- package/dist/tuple.spec.js +156 -0
- package/dist/typeGuards.cjs +60 -0
- package/dist/typeGuards.d.ts +93 -0
- package/dist/typeGuards.js +8 -0
- package/dist/typeGuards.spec.cjs +101 -0
- package/dist/typeGuards.spec.d.ts +1 -0
- package/dist/typeGuards.spec.js +95 -0
- package/dist/types.cjs +18 -0
- package/dist/types.d.ts +289 -0
- package/dist/types.js +0 -0
- package/dist/union.cjs +74 -0
- package/dist/union.d.ts +33 -0
- package/dist/union.js +40 -0
- package/dist/union.spec.cjs +159 -0
- package/dist/union.spec.d.ts +1 -0
- package/dist/union.spec.js +153 -0
- package/package.json +47 -0
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createSchemaContext } from "./context.js";
|
|
3
|
+
import { createGuardSchema, createIssueForPath, createPrimitiveSchema, createSchema, ensureSchemaContext, fail, ok } from "./schema.js";
|
|
4
|
+
describe('schema core utilities', ()=>{
|
|
5
|
+
let context;
|
|
6
|
+
beforeAll(()=>{
|
|
7
|
+
context = createSchemaContext();
|
|
8
|
+
});
|
|
9
|
+
beforeEach(()=>{
|
|
10
|
+
context = createSchemaContext();
|
|
11
|
+
});
|
|
12
|
+
afterEach(()=>{
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
afterAll(()=>{
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
describe('createIssueForPath()', ()=>{
|
|
19
|
+
describe('happy', ()=>{
|
|
20
|
+
it('should create schema issue object when issue input is provided', ()=>{
|
|
21
|
+
const issue = createIssueForPath({
|
|
22
|
+
path: [
|
|
23
|
+
'user',
|
|
24
|
+
'name'
|
|
25
|
+
],
|
|
26
|
+
message: 'Expected non-empty value',
|
|
27
|
+
code: 'string.min',
|
|
28
|
+
context: {
|
|
29
|
+
min: 1
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
expect(issue).toEqual({
|
|
33
|
+
path: [
|
|
34
|
+
'user',
|
|
35
|
+
'name'
|
|
36
|
+
],
|
|
37
|
+
message: 'Expected non-empty value',
|
|
38
|
+
code: 'string.min',
|
|
39
|
+
context: {
|
|
40
|
+
min: 1
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('sad', ()=>{
|
|
46
|
+
it('should keep optional fields undefined when optional values are omitted', ()=>{
|
|
47
|
+
const issue = createIssueForPath({
|
|
48
|
+
path: [],
|
|
49
|
+
message: 'Invalid value'
|
|
50
|
+
});
|
|
51
|
+
expect(issue.code).toBeUndefined();
|
|
52
|
+
expect(issue.context).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('ok()', ()=>{
|
|
57
|
+
describe('happy', ()=>{
|
|
58
|
+
it('should wrap value in ok result when value is provided', ()=>{
|
|
59
|
+
const result = ok({
|
|
60
|
+
value: 'value'
|
|
61
|
+
});
|
|
62
|
+
expect(result).toEqual({
|
|
63
|
+
ok: true,
|
|
64
|
+
value: 'value'
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('sad', ()=>{
|
|
69
|
+
it('should keep undefined value when undefined is passed', ()=>{
|
|
70
|
+
const result = ok({
|
|
71
|
+
value: void 0
|
|
72
|
+
});
|
|
73
|
+
expect(result).toEqual({
|
|
74
|
+
ok: true,
|
|
75
|
+
value: void 0
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('fail()', ()=>{
|
|
81
|
+
describe('happy', ()=>{
|
|
82
|
+
it('should wrap issues and meta in fail result when both are provided', ()=>{
|
|
83
|
+
const issues = [
|
|
84
|
+
createIssueForPath({
|
|
85
|
+
path: [],
|
|
86
|
+
message: 'invalid'
|
|
87
|
+
})
|
|
88
|
+
];
|
|
89
|
+
const result = fail({
|
|
90
|
+
issues,
|
|
91
|
+
meta: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
name: 'UserName'
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
expect(result).toEqual({
|
|
97
|
+
ok: false,
|
|
98
|
+
issues,
|
|
99
|
+
meta: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
name: 'UserName'
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('sad', ()=>{
|
|
107
|
+
it('should keep meta undefined when meta is omitted', ()=>{
|
|
108
|
+
const result = fail({
|
|
109
|
+
issues: [
|
|
110
|
+
createIssueForPath({
|
|
111
|
+
path: [],
|
|
112
|
+
message: 'invalid'
|
|
113
|
+
})
|
|
114
|
+
]
|
|
115
|
+
});
|
|
116
|
+
expect(result.ok).toBe(false);
|
|
117
|
+
if (!result.ok) expect(result.meta).toBeUndefined();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('ensureSchemaContext()', ()=>{
|
|
122
|
+
describe('happy', ()=>{
|
|
123
|
+
it('should return provided context when context is provided', ()=>{
|
|
124
|
+
const providedContext = createSchemaContext();
|
|
125
|
+
const ensured = ensureSchemaContext(providedContext);
|
|
126
|
+
expect(ensured).toBe(providedContext);
|
|
127
|
+
});
|
|
128
|
+
it('should create context with request when context is omitted', ()=>{
|
|
129
|
+
const ensured = ensureSchemaContext();
|
|
130
|
+
expect(ensured.getRequestContext()).toBeDefined();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('sad', ()=>{
|
|
134
|
+
it('should still return usable context when context is omitted', ()=>{
|
|
135
|
+
const ensured = ensureSchemaContext();
|
|
136
|
+
expect(()=>ensured.state.snapshot()).not.toThrow();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('createSchema()', ()=>{
|
|
141
|
+
describe('happy', ()=>{
|
|
142
|
+
it('should parse value when validate returns ok result', ()=>{
|
|
143
|
+
const schema = createSchema({
|
|
144
|
+
name: 'StringSchema',
|
|
145
|
+
type: 'string',
|
|
146
|
+
ast: ()=>({
|
|
147
|
+
type: 'string'
|
|
148
|
+
}),
|
|
149
|
+
validate: (input)=>ok({
|
|
150
|
+
value: String(input)
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
const parsed = schema.parse(123, context);
|
|
154
|
+
expect(parsed).toBe('123');
|
|
155
|
+
});
|
|
156
|
+
it('should type value when typed is called', ()=>{
|
|
157
|
+
const schema = createSchema({
|
|
158
|
+
name: 'StringSchema',
|
|
159
|
+
type: 'string',
|
|
160
|
+
ast: ()=>({
|
|
161
|
+
type: 'string'
|
|
162
|
+
}),
|
|
163
|
+
validate: (input)=>ok({
|
|
164
|
+
value: String(input)
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
const typed = schema.typed('abc', context);
|
|
168
|
+
expect(typed).toBe('abc');
|
|
169
|
+
});
|
|
170
|
+
it('should return undefined when optional schema parses undefined', ()=>{
|
|
171
|
+
const schema = createSchema({
|
|
172
|
+
name: 'StringSchema',
|
|
173
|
+
type: 'string',
|
|
174
|
+
ast: ()=>({
|
|
175
|
+
type: 'string'
|
|
176
|
+
}),
|
|
177
|
+
validate: (input)=>'string' == typeof input ? ok({
|
|
178
|
+
value: input
|
|
179
|
+
}) : fail({
|
|
180
|
+
issues: [
|
|
181
|
+
createIssueForPath({
|
|
182
|
+
path: [],
|
|
183
|
+
message: 'Expected string'
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
})
|
|
187
|
+
});
|
|
188
|
+
const optionalSchema = schema.optional();
|
|
189
|
+
const parsed = optionalSchema.parse(void 0, context);
|
|
190
|
+
expect(parsed).toBeUndefined();
|
|
191
|
+
});
|
|
192
|
+
it('should return null when nullable schema parses null', ()=>{
|
|
193
|
+
const schema = createSchema({
|
|
194
|
+
name: 'StringSchema',
|
|
195
|
+
type: 'string',
|
|
196
|
+
ast: ()=>({
|
|
197
|
+
type: 'string'
|
|
198
|
+
}),
|
|
199
|
+
validate: (input)=>'string' == typeof input ? ok({
|
|
200
|
+
value: input
|
|
201
|
+
}) : fail({
|
|
202
|
+
issues: [
|
|
203
|
+
createIssueForPath({
|
|
204
|
+
path: [],
|
|
205
|
+
message: 'Expected string'
|
|
206
|
+
})
|
|
207
|
+
]
|
|
208
|
+
})
|
|
209
|
+
});
|
|
210
|
+
const nullableSchema = schema.nullable();
|
|
211
|
+
const parsed = nullableSchema.parse(null, context);
|
|
212
|
+
expect(parsed).toBeNull();
|
|
213
|
+
});
|
|
214
|
+
it('should merge doc into ast when describe is used', ()=>{
|
|
215
|
+
const schema = createSchema({
|
|
216
|
+
name: 'StringSchema',
|
|
217
|
+
type: 'string',
|
|
218
|
+
ast: ()=>({
|
|
219
|
+
type: 'string',
|
|
220
|
+
name: 'StringSchema',
|
|
221
|
+
doc: {
|
|
222
|
+
source: 'base'
|
|
223
|
+
}
|
|
224
|
+
}),
|
|
225
|
+
validate: (input)=>ok({
|
|
226
|
+
value: String(input)
|
|
227
|
+
})
|
|
228
|
+
});
|
|
229
|
+
const described = schema.describe({
|
|
230
|
+
summary: "description doc"
|
|
231
|
+
});
|
|
232
|
+
const ast = described.ast();
|
|
233
|
+
expect(ast.doc).toEqual({
|
|
234
|
+
source: 'base',
|
|
235
|
+
summary: "description doc"
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
it('should keep value when refine predicate returns true', ()=>{
|
|
239
|
+
const schema = createSchema({
|
|
240
|
+
name: 'NumberSchema',
|
|
241
|
+
type: 'number',
|
|
242
|
+
ast: ()=>({
|
|
243
|
+
type: 'number'
|
|
244
|
+
}),
|
|
245
|
+
validate: (input)=>ok({
|
|
246
|
+
value: Number(input)
|
|
247
|
+
})
|
|
248
|
+
});
|
|
249
|
+
const refined = schema.refine({
|
|
250
|
+
predicate: (value)=>value > 0,
|
|
251
|
+
message: 'Expected positive number',
|
|
252
|
+
code: 'number.positive'
|
|
253
|
+
});
|
|
254
|
+
const parsed = refined.parse(10, context);
|
|
255
|
+
expect(parsed).toBe(10);
|
|
256
|
+
});
|
|
257
|
+
it('should pass transformed input to base validator when before hook returns input object', ()=>{
|
|
258
|
+
const schema = createSchema({
|
|
259
|
+
name: 'StringSchema',
|
|
260
|
+
type: 'string',
|
|
261
|
+
ast: ()=>({
|
|
262
|
+
type: 'string'
|
|
263
|
+
}),
|
|
264
|
+
validate: (input)=>ok({
|
|
265
|
+
value: String(input)
|
|
266
|
+
})
|
|
267
|
+
});
|
|
268
|
+
const transformed = schema.before((input)=>({
|
|
269
|
+
input: String(input).trim()
|
|
270
|
+
}));
|
|
271
|
+
const parsed = transformed.parse(' Alice ', context);
|
|
272
|
+
expect(parsed).toBe('Alice');
|
|
273
|
+
});
|
|
274
|
+
it('should transform value when after hook returns value object', ()=>{
|
|
275
|
+
const schema = createSchema({
|
|
276
|
+
name: 'StringSchema',
|
|
277
|
+
type: 'string',
|
|
278
|
+
ast: ()=>({
|
|
279
|
+
type: 'string'
|
|
280
|
+
}),
|
|
281
|
+
validate: (input)=>ok({
|
|
282
|
+
value: String(input)
|
|
283
|
+
})
|
|
284
|
+
});
|
|
285
|
+
const transformed = schema.after((value)=>({
|
|
286
|
+
value: value.toUpperCase()
|
|
287
|
+
}));
|
|
288
|
+
const parsed = transformed.parse('alice', context);
|
|
289
|
+
expect(parsed).toBe('ALICE');
|
|
290
|
+
});
|
|
291
|
+
it('should merge schemas when and schemas both validate successfully', ()=>{
|
|
292
|
+
const left = createSchema({
|
|
293
|
+
name: 'Left',
|
|
294
|
+
type: 'left',
|
|
295
|
+
ast: ()=>({
|
|
296
|
+
type: 'left',
|
|
297
|
+
name: 'Left'
|
|
298
|
+
}),
|
|
299
|
+
validate: ()=>ok({
|
|
300
|
+
value: {
|
|
301
|
+
id: 'u-1'
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
});
|
|
305
|
+
const right = createSchema({
|
|
306
|
+
name: 'Right',
|
|
307
|
+
type: 'right',
|
|
308
|
+
ast: ()=>({
|
|
309
|
+
type: 'right',
|
|
310
|
+
name: 'Right'
|
|
311
|
+
}),
|
|
312
|
+
validate: ()=>ok({
|
|
313
|
+
value: {
|
|
314
|
+
role: 'admin'
|
|
315
|
+
}
|
|
316
|
+
})
|
|
317
|
+
});
|
|
318
|
+
const merged = left.and(right);
|
|
319
|
+
const parsed = merged.parse('raw', context);
|
|
320
|
+
const ast = merged.ast();
|
|
321
|
+
expect(parsed).toEqual({
|
|
322
|
+
id: 'u-1'
|
|
323
|
+
});
|
|
324
|
+
expect(ast.type).toBe('and');
|
|
325
|
+
expect(ast.children).toHaveLength(2);
|
|
326
|
+
});
|
|
327
|
+
it('should set fallback node name when ast result has no name', ()=>{
|
|
328
|
+
const schema = createSchema({
|
|
329
|
+
name: 'FallbackName',
|
|
330
|
+
type: 'custom',
|
|
331
|
+
ast: ()=>({
|
|
332
|
+
type: 'custom'
|
|
333
|
+
}),
|
|
334
|
+
validate: (input)=>ok({
|
|
335
|
+
value: input
|
|
336
|
+
})
|
|
337
|
+
});
|
|
338
|
+
const ast = schema.ast();
|
|
339
|
+
expect(ast.name).toBe('FallbackName');
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
describe('sad', ()=>{
|
|
343
|
+
it('should throw validation error when validate returns fail result', ()=>{
|
|
344
|
+
const schema = createSchema({
|
|
345
|
+
name: 'StringSchema',
|
|
346
|
+
type: 'string',
|
|
347
|
+
ast: ()=>({
|
|
348
|
+
type: 'string'
|
|
349
|
+
}),
|
|
350
|
+
validate: ()=>fail({
|
|
351
|
+
issues: [
|
|
352
|
+
createIssueForPath({
|
|
353
|
+
path: [],
|
|
354
|
+
message: 'Expected string',
|
|
355
|
+
code: 'string.type'
|
|
356
|
+
})
|
|
357
|
+
]
|
|
358
|
+
})
|
|
359
|
+
});
|
|
360
|
+
expect(()=>schema.parse(1, context)).toThrowError('Schema validation failed');
|
|
361
|
+
});
|
|
362
|
+
it('should fail refine when predicate returns false', ()=>{
|
|
363
|
+
const schema = createSchema({
|
|
364
|
+
name: 'NumberSchema',
|
|
365
|
+
type: 'number',
|
|
366
|
+
ast: ()=>({
|
|
367
|
+
type: 'number'
|
|
368
|
+
}),
|
|
369
|
+
validate: (input)=>ok({
|
|
370
|
+
value: Number(input)
|
|
371
|
+
})
|
|
372
|
+
});
|
|
373
|
+
const refined = schema.refine({
|
|
374
|
+
predicate: (value)=>value > 10,
|
|
375
|
+
message: 'Expected value greater than ten',
|
|
376
|
+
code: 'number.greaterThanTen'
|
|
377
|
+
});
|
|
378
|
+
const result = refined.validate(5, context);
|
|
379
|
+
expect(result).toEqual({
|
|
380
|
+
ok: false,
|
|
381
|
+
issues: [
|
|
382
|
+
{
|
|
383
|
+
path: [],
|
|
384
|
+
message: 'Expected value greater than ten',
|
|
385
|
+
code: 'number.greaterThanTen'
|
|
386
|
+
}
|
|
387
|
+
],
|
|
388
|
+
meta: expect.any(Object)
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
it('should fail before validation when before hook returns issues', ()=>{
|
|
392
|
+
const schema = createSchema({
|
|
393
|
+
name: 'StringSchema',
|
|
394
|
+
type: 'string',
|
|
395
|
+
ast: ()=>({
|
|
396
|
+
type: 'string'
|
|
397
|
+
}),
|
|
398
|
+
validate: (input)=>ok({
|
|
399
|
+
value: String(input)
|
|
400
|
+
})
|
|
401
|
+
});
|
|
402
|
+
const withBefore = schema.before(()=>({
|
|
403
|
+
issues: [
|
|
404
|
+
createIssueForPath({
|
|
405
|
+
path: [],
|
|
406
|
+
message: 'blocked by before hook'
|
|
407
|
+
})
|
|
408
|
+
]
|
|
409
|
+
}));
|
|
410
|
+
const result = withBefore.validate('value', context);
|
|
411
|
+
expect(result).toEqual({
|
|
412
|
+
ok: false,
|
|
413
|
+
issues: [
|
|
414
|
+
{
|
|
415
|
+
path: [],
|
|
416
|
+
message: 'blocked by before hook'
|
|
417
|
+
}
|
|
418
|
+
],
|
|
419
|
+
meta: expect.any(Object)
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
it('should fail after validation when after hook returns issues', ()=>{
|
|
423
|
+
const schema = createSchema({
|
|
424
|
+
name: 'StringSchema',
|
|
425
|
+
type: 'string',
|
|
426
|
+
ast: ()=>({
|
|
427
|
+
type: 'string'
|
|
428
|
+
}),
|
|
429
|
+
validate: (input)=>ok({
|
|
430
|
+
value: String(input)
|
|
431
|
+
})
|
|
432
|
+
});
|
|
433
|
+
const withAfter = schema.after(()=>({
|
|
434
|
+
issues: [
|
|
435
|
+
createIssueForPath({
|
|
436
|
+
path: [],
|
|
437
|
+
message: 'blocked by after hook'
|
|
438
|
+
})
|
|
439
|
+
]
|
|
440
|
+
}));
|
|
441
|
+
const result = withAfter.validate('value', context);
|
|
442
|
+
expect(result).toEqual({
|
|
443
|
+
ok: false,
|
|
444
|
+
issues: [
|
|
445
|
+
{
|
|
446
|
+
path: [],
|
|
447
|
+
message: 'blocked by after hook'
|
|
448
|
+
}
|
|
449
|
+
],
|
|
450
|
+
meta: expect.any(Object)
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
it('should combine issues when and schema has failing left and right branches', ()=>{
|
|
454
|
+
const leftIssue = createIssueForPath({
|
|
455
|
+
path: [
|
|
456
|
+
'left'
|
|
457
|
+
],
|
|
458
|
+
message: 'left failed'
|
|
459
|
+
});
|
|
460
|
+
const rightIssue = createIssueForPath({
|
|
461
|
+
path: [
|
|
462
|
+
'right'
|
|
463
|
+
],
|
|
464
|
+
message: 'right failed'
|
|
465
|
+
});
|
|
466
|
+
const left = createSchema({
|
|
467
|
+
name: 'Left',
|
|
468
|
+
type: 'left',
|
|
469
|
+
ast: ()=>({
|
|
470
|
+
type: 'left',
|
|
471
|
+
name: 'Left'
|
|
472
|
+
}),
|
|
473
|
+
validate: ()=>fail({
|
|
474
|
+
issues: [
|
|
475
|
+
leftIssue
|
|
476
|
+
]
|
|
477
|
+
})
|
|
478
|
+
});
|
|
479
|
+
const right = createSchema({
|
|
480
|
+
name: 'Right',
|
|
481
|
+
type: 'right',
|
|
482
|
+
ast: ()=>({
|
|
483
|
+
type: 'right',
|
|
484
|
+
name: 'Right'
|
|
485
|
+
}),
|
|
486
|
+
validate: ()=>fail({
|
|
487
|
+
issues: [
|
|
488
|
+
rightIssue
|
|
489
|
+
]
|
|
490
|
+
})
|
|
491
|
+
});
|
|
492
|
+
const merged = left.and(right);
|
|
493
|
+
const result = merged.validate('raw', context);
|
|
494
|
+
expect(result).toEqual({
|
|
495
|
+
ok: false,
|
|
496
|
+
issues: [
|
|
497
|
+
leftIssue,
|
|
498
|
+
rightIssue
|
|
499
|
+
],
|
|
500
|
+
meta: expect.any(Object)
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
describe('createGuardSchema()', ()=>{
|
|
506
|
+
describe('happy', ()=>{
|
|
507
|
+
it('should parse value when guard returns true', ()=>{
|
|
508
|
+
const schema = createGuardSchema({
|
|
509
|
+
name: 'GuardedString',
|
|
510
|
+
type: 'string',
|
|
511
|
+
guard: (input)=>'string' == typeof input,
|
|
512
|
+
message: 'Expected string',
|
|
513
|
+
code: 'string.type'
|
|
514
|
+
});
|
|
515
|
+
const parsed = schema.parse('ok', context);
|
|
516
|
+
expect(parsed).toBe('ok');
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
describe('sad', ()=>{
|
|
520
|
+
it('should fail when guard returns false', ()=>{
|
|
521
|
+
const schema = createGuardSchema({
|
|
522
|
+
name: 'GuardedString',
|
|
523
|
+
type: 'string',
|
|
524
|
+
guard: (input)=>'string' == typeof input,
|
|
525
|
+
message: 'Expected string',
|
|
526
|
+
code: 'string.type'
|
|
527
|
+
});
|
|
528
|
+
const result = schema.validate(1, context);
|
|
529
|
+
expect(result).toEqual({
|
|
530
|
+
ok: false,
|
|
531
|
+
issues: [
|
|
532
|
+
{
|
|
533
|
+
path: [],
|
|
534
|
+
message: 'Expected string',
|
|
535
|
+
code: 'string.type'
|
|
536
|
+
}
|
|
537
|
+
],
|
|
538
|
+
meta: expect.any(Object)
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
describe('createPrimitiveSchema()', ()=>{
|
|
544
|
+
describe('happy', ()=>{
|
|
545
|
+
it('should parse value when primitive guard returns true', ()=>{
|
|
546
|
+
const schema = createPrimitiveSchema({
|
|
547
|
+
name: 'PrimitiveString',
|
|
548
|
+
type: 'string',
|
|
549
|
+
guard: (input)=>'string' == typeof input,
|
|
550
|
+
message: 'Expected string',
|
|
551
|
+
code: 'string.type'
|
|
552
|
+
});
|
|
553
|
+
const parsed = schema.parse('ok', context);
|
|
554
|
+
expect(parsed).toBe('ok');
|
|
555
|
+
});
|
|
556
|
+
});
|
|
557
|
+
describe('sad', ()=>{
|
|
558
|
+
it('should fail when primitive guard returns false', ()=>{
|
|
559
|
+
const schema = createPrimitiveSchema({
|
|
560
|
+
name: 'PrimitiveString',
|
|
561
|
+
type: 'string',
|
|
562
|
+
guard: (input)=>'string' == typeof input,
|
|
563
|
+
message: 'Expected string',
|
|
564
|
+
code: 'string.type'
|
|
565
|
+
});
|
|
566
|
+
const result = schema.validate(1, context);
|
|
567
|
+
expect(result).toEqual({
|
|
568
|
+
ok: false,
|
|
569
|
+
issues: [
|
|
570
|
+
{
|
|
571
|
+
path: [],
|
|
572
|
+
message: 'Expected string',
|
|
573
|
+
code: 'string.type'
|
|
574
|
+
}
|
|
575
|
+
],
|
|
576
|
+
meta: expect.any(Object)
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
schemaFactory: ()=>schemaFactory,
|
|
28
|
+
guardFactory: ()=>guardFactory
|
|
29
|
+
});
|
|
30
|
+
const external_schema_cjs_namespaceObject = require("./schema.cjs");
|
|
31
|
+
const external_doc_cjs_namespaceObject = require("./doc.cjs");
|
|
32
|
+
const normalizeError = (error)=>{
|
|
33
|
+
if (error && 'object' == typeof error && 'message' in error) {
|
|
34
|
+
const err = error;
|
|
35
|
+
return {
|
|
36
|
+
message: err.message,
|
|
37
|
+
code: err.code,
|
|
38
|
+
context: err.context
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
message: 'Schema validation failed'
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const schemaFactory = ({ name, type, validate, ast, doc, chain })=>{
|
|
46
|
+
const docRecord = (0, external_doc_cjs_namespaceObject.normalizeDoc)(doc);
|
|
47
|
+
const astWithDoc = docRecord ? (ctx)=>{
|
|
48
|
+
const node = ast(ctx);
|
|
49
|
+
const merged = (0, external_doc_cjs_namespaceObject.mergeDoc)(node.doc, docRecord);
|
|
50
|
+
return merged ? {
|
|
51
|
+
...node,
|
|
52
|
+
doc: merged
|
|
53
|
+
} : node;
|
|
54
|
+
} : ast;
|
|
55
|
+
const base = (0, external_schema_cjs_namespaceObject.createSchema)({
|
|
56
|
+
name,
|
|
57
|
+
type,
|
|
58
|
+
ast: astWithDoc,
|
|
59
|
+
validate: (input, ctx)=>{
|
|
60
|
+
const context = (0, external_schema_cjs_namespaceObject.ensureSchemaContext)(ctx);
|
|
61
|
+
try {
|
|
62
|
+
const value = validate(input, context);
|
|
63
|
+
return (0, external_schema_cjs_namespaceObject.ok)({
|
|
64
|
+
value
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const normalized = normalizeError(error);
|
|
68
|
+
return (0, external_schema_cjs_namespaceObject.fail)({
|
|
69
|
+
issues: [
|
|
70
|
+
(0, external_schema_cjs_namespaceObject.createIssueForPath)({
|
|
71
|
+
path: [],
|
|
72
|
+
message: normalized.message,
|
|
73
|
+
code: normalized.code,
|
|
74
|
+
context: normalized.context
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const result = base;
|
|
82
|
+
if (!chain) return result;
|
|
83
|
+
Object.entries(chain).forEach(([key, operation])=>{
|
|
84
|
+
result[key] = (...args)=>schemaFactory({
|
|
85
|
+
name: `${name}.${key}`,
|
|
86
|
+
type,
|
|
87
|
+
ast,
|
|
88
|
+
validate: (input, ctx)=>{
|
|
89
|
+
const context = (0, external_schema_cjs_namespaceObject.ensureSchemaContext)(ctx);
|
|
90
|
+
const value = base.parse(input, context);
|
|
91
|
+
const next = operation(value, context)(...args);
|
|
92
|
+
return next;
|
|
93
|
+
},
|
|
94
|
+
chain: chain
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return result;
|
|
98
|
+
};
|
|
99
|
+
const guardFactory = ({ name, type, guard, message, code })=>schemaFactory({
|
|
100
|
+
name,
|
|
101
|
+
type,
|
|
102
|
+
ast: ()=>({
|
|
103
|
+
type,
|
|
104
|
+
name
|
|
105
|
+
}),
|
|
106
|
+
validate: (input)=>{
|
|
107
|
+
if (!guard(input)) {
|
|
108
|
+
const error = {
|
|
109
|
+
message,
|
|
110
|
+
code
|
|
111
|
+
};
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
return input;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
exports.guardFactory = __webpack_exports__.guardFactory;
|
|
118
|
+
exports.schemaFactory = __webpack_exports__.schemaFactory;
|
|
119
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
120
|
+
"guardFactory",
|
|
121
|
+
"schemaFactory"
|
|
122
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
123
|
+
Object.defineProperty(exports, '__esModule', {
|
|
124
|
+
value: true
|
|
125
|
+
});
|