@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,448 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createSchemaContext } from "./context.js";
|
|
3
|
+
import { fieldOperation, operation, runFieldOperation, runOperation, withFieldOperationName, withOperationName } from "./operation.js";
|
|
4
|
+
import { string } from "./string.js";
|
|
5
|
+
import { createBaseSchemaMock } from "./testing/mocks/index.js";
|
|
6
|
+
describe('operation utilities', ()=>{
|
|
7
|
+
let context;
|
|
8
|
+
beforeAll(()=>{
|
|
9
|
+
context = createSchemaContext();
|
|
10
|
+
});
|
|
11
|
+
beforeEach(()=>{
|
|
12
|
+
context = createSchemaContext();
|
|
13
|
+
});
|
|
14
|
+
afterEach(()=>{
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
afterAll(()=>{
|
|
18
|
+
vi.restoreAllMocks();
|
|
19
|
+
});
|
|
20
|
+
describe('operation()', ()=>{
|
|
21
|
+
describe('happy', ()=>{
|
|
22
|
+
it('should return operation payload when output schema is provided', ()=>{
|
|
23
|
+
const inputSchema = createBaseSchemaMock({
|
|
24
|
+
name: 'Input',
|
|
25
|
+
type: 'input',
|
|
26
|
+
outputValue: {
|
|
27
|
+
id: 'u-1'
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const outputSchema = createBaseSchemaMock({
|
|
31
|
+
name: 'Output',
|
|
32
|
+
type: 'output',
|
|
33
|
+
outputValue: {
|
|
34
|
+
ok: true
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const exec = vi.fn(async ()=>({
|
|
38
|
+
ok: true
|
|
39
|
+
}));
|
|
40
|
+
const result = operation({
|
|
41
|
+
input: inputSchema,
|
|
42
|
+
output: outputSchema,
|
|
43
|
+
exec,
|
|
44
|
+
doc: {
|
|
45
|
+
summary: 'operation doc'
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
expect(result.type).toBe('operation');
|
|
49
|
+
expect(result.input).toBe(inputSchema);
|
|
50
|
+
expect(result.output).toBe(outputSchema);
|
|
51
|
+
expect(result.exec).toBe(exec);
|
|
52
|
+
expect(result.doc).toEqual({
|
|
53
|
+
summary: 'operation doc'
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('sad', ()=>{
|
|
58
|
+
it('should keep output undefined when output schema is omitted', ()=>{
|
|
59
|
+
const inputSchema = createBaseSchemaMock({
|
|
60
|
+
outputValue: 'input'
|
|
61
|
+
});
|
|
62
|
+
const result = operation({
|
|
63
|
+
input: inputSchema,
|
|
64
|
+
exec: (input)=>input.length
|
|
65
|
+
});
|
|
66
|
+
expect(result.output).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('fieldOperation()', ()=>{
|
|
71
|
+
describe('happy', ()=>{
|
|
72
|
+
it('should normalize shape dependsOn and shape input when shape values are provided', ()=>{
|
|
73
|
+
const result = fieldOperation({
|
|
74
|
+
dependsOn: {
|
|
75
|
+
id: string()
|
|
76
|
+
},
|
|
77
|
+
input: {
|
|
78
|
+
name: string()
|
|
79
|
+
},
|
|
80
|
+
exec: ()=>'ok'
|
|
81
|
+
});
|
|
82
|
+
expect(result.type).toBe('field');
|
|
83
|
+
expect(result.dependsOn.name).toBe('dependsOn');
|
|
84
|
+
expect(result.input?.name).toBe('input');
|
|
85
|
+
});
|
|
86
|
+
it('should keep provided schema dependsOn without wrapping when schema is provided', ()=>{
|
|
87
|
+
const dependsOn = createBaseSchemaMock({
|
|
88
|
+
name: 'DependsOnSchema',
|
|
89
|
+
type: 'dependsOn',
|
|
90
|
+
outputValue: {
|
|
91
|
+
id: 'u-1'
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const result = fieldOperation({
|
|
95
|
+
dependsOn,
|
|
96
|
+
exec: ()=>'ok'
|
|
97
|
+
});
|
|
98
|
+
expect(result.dependsOn).toBe(dependsOn);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe('sad', ()=>{
|
|
102
|
+
it('should keep output undefined when output is omitted', ()=>{
|
|
103
|
+
const dependsOn = createBaseSchemaMock({
|
|
104
|
+
outputValue: {
|
|
105
|
+
id: 'u-1'
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const result = fieldOperation({
|
|
109
|
+
dependsOn,
|
|
110
|
+
exec: ()=>'ok'
|
|
111
|
+
});
|
|
112
|
+
expect(result.output).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('withOperationName()', ()=>{
|
|
117
|
+
describe('happy', ()=>{
|
|
118
|
+
it('should set operation name when wrapper is used', ()=>{
|
|
119
|
+
const op = operation({
|
|
120
|
+
input: createBaseSchemaMock({
|
|
121
|
+
outputValue: 'value'
|
|
122
|
+
}),
|
|
123
|
+
exec: ()=>'ok'
|
|
124
|
+
});
|
|
125
|
+
const named = withOperationName({
|
|
126
|
+
name: 'createUser',
|
|
127
|
+
operation: op
|
|
128
|
+
});
|
|
129
|
+
expect(named.name).toBe('createUser');
|
|
130
|
+
expect(named.type).toBe('operation');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('sad', ()=>{
|
|
134
|
+
it('should preserve original operation members when name is injected', ()=>{
|
|
135
|
+
const exec = vi.fn(async ()=>'ok');
|
|
136
|
+
const op = operation({
|
|
137
|
+
input: createBaseSchemaMock({
|
|
138
|
+
outputValue: 'value'
|
|
139
|
+
}),
|
|
140
|
+
exec
|
|
141
|
+
});
|
|
142
|
+
const named = withOperationName({
|
|
143
|
+
name: 'createUser',
|
|
144
|
+
operation: op
|
|
145
|
+
});
|
|
146
|
+
expect(named.exec).toBe(exec);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
describe('withFieldOperationName()', ()=>{
|
|
151
|
+
describe('happy', ()=>{
|
|
152
|
+
it('should set field operation name when wrapper is used', ()=>{
|
|
153
|
+
const op = fieldOperation({
|
|
154
|
+
dependsOn: createBaseSchemaMock({
|
|
155
|
+
outputValue: {
|
|
156
|
+
id: 'u-1'
|
|
157
|
+
}
|
|
158
|
+
}),
|
|
159
|
+
exec: ()=>'ok'
|
|
160
|
+
});
|
|
161
|
+
const named = withFieldOperationName({
|
|
162
|
+
name: 'user.displayName',
|
|
163
|
+
operation: op
|
|
164
|
+
});
|
|
165
|
+
expect(named.name).toBe('user.displayName');
|
|
166
|
+
expect(named.type).toBe('field');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe('sad', ()=>{
|
|
170
|
+
it('should preserve original field operation members when name is injected', ()=>{
|
|
171
|
+
const exec = vi.fn(async ()=>'ok');
|
|
172
|
+
const dependsOn = createBaseSchemaMock({
|
|
173
|
+
outputValue: {
|
|
174
|
+
id: 'u-1'
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
const op = fieldOperation({
|
|
178
|
+
dependsOn,
|
|
179
|
+
exec
|
|
180
|
+
});
|
|
181
|
+
const named = withFieldOperationName({
|
|
182
|
+
name: 'user.displayName',
|
|
183
|
+
operation: op
|
|
184
|
+
});
|
|
185
|
+
expect(named.dependsOn).toBe(dependsOn);
|
|
186
|
+
expect(named.exec).toBe(exec);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe('runOperation()', ()=>{
|
|
191
|
+
describe('happy', ()=>{
|
|
192
|
+
it('should parse input and output and publish to all rooms when publish hook returns payload', async ()=>{
|
|
193
|
+
const parsedInput = {
|
|
194
|
+
id: 'u-1'
|
|
195
|
+
};
|
|
196
|
+
const parsedOutput = {
|
|
197
|
+
id: 'result'
|
|
198
|
+
};
|
|
199
|
+
const inputSchema = createBaseSchemaMock({
|
|
200
|
+
outputValue: parsedInput
|
|
201
|
+
});
|
|
202
|
+
const outputSchema = createBaseSchemaMock({
|
|
203
|
+
outputValue: parsedOutput
|
|
204
|
+
});
|
|
205
|
+
const publisher = vi.fn(async ()=>void 0);
|
|
206
|
+
const publishHook = vi.fn(()=>({
|
|
207
|
+
event: 'created'
|
|
208
|
+
}));
|
|
209
|
+
const exec = vi.fn(async ()=>parsedOutput);
|
|
210
|
+
context = createSchemaContext({
|
|
211
|
+
request: {
|
|
212
|
+
publisher
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
const op = operation({
|
|
216
|
+
input: inputSchema,
|
|
217
|
+
output: outputSchema,
|
|
218
|
+
publish: {
|
|
219
|
+
userCreated: publishHook
|
|
220
|
+
},
|
|
221
|
+
rooms: ()=>[
|
|
222
|
+
'room-a',
|
|
223
|
+
'room-b'
|
|
224
|
+
],
|
|
225
|
+
ack: {
|
|
226
|
+
required: true,
|
|
227
|
+
mode: 'handled'
|
|
228
|
+
},
|
|
229
|
+
exec
|
|
230
|
+
});
|
|
231
|
+
const result = await runOperation(op, {
|
|
232
|
+
rawInput: true
|
|
233
|
+
}, context);
|
|
234
|
+
expect(exec).toHaveBeenCalledWith(parsedInput, context);
|
|
235
|
+
expect(outputSchema.parse).toHaveBeenCalledWith(parsedOutput, context);
|
|
236
|
+
expect(publishHook).toHaveBeenCalledWith(parsedOutput, context);
|
|
237
|
+
expect(publisher).toHaveBeenCalledTimes(2);
|
|
238
|
+
expect(publisher).toHaveBeenNthCalledWith(1, {
|
|
239
|
+
topic: 'userCreated',
|
|
240
|
+
payload: {
|
|
241
|
+
event: 'created'
|
|
242
|
+
},
|
|
243
|
+
input: parsedInput,
|
|
244
|
+
ack: {
|
|
245
|
+
required: true,
|
|
246
|
+
mode: 'handled'
|
|
247
|
+
},
|
|
248
|
+
meta: {
|
|
249
|
+
room: 'room-a'
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
expect(publisher).toHaveBeenNthCalledWith(2, {
|
|
253
|
+
topic: 'userCreated',
|
|
254
|
+
payload: {
|
|
255
|
+
event: 'created'
|
|
256
|
+
},
|
|
257
|
+
input: parsedInput,
|
|
258
|
+
ack: {
|
|
259
|
+
required: true,
|
|
260
|
+
mode: 'handled'
|
|
261
|
+
},
|
|
262
|
+
meta: {
|
|
263
|
+
room: 'room-b'
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
expect(result).toEqual(parsedOutput);
|
|
267
|
+
});
|
|
268
|
+
it('should skip publish when request publisher is missing', async ()=>{
|
|
269
|
+
const inputSchema = createBaseSchemaMock({
|
|
270
|
+
outputValue: 'parsed-input'
|
|
271
|
+
});
|
|
272
|
+
const outputSchema = createBaseSchemaMock({
|
|
273
|
+
outputValue: 'parsed-output'
|
|
274
|
+
});
|
|
275
|
+
const publishHook = vi.fn(()=>'payload');
|
|
276
|
+
const exec = vi.fn(async ()=>'result');
|
|
277
|
+
context = createSchemaContext();
|
|
278
|
+
const op = operation({
|
|
279
|
+
input: inputSchema,
|
|
280
|
+
output: outputSchema,
|
|
281
|
+
publish: {
|
|
282
|
+
topic: publishHook
|
|
283
|
+
},
|
|
284
|
+
exec
|
|
285
|
+
});
|
|
286
|
+
const result = await runOperation(op, 'raw-input', context);
|
|
287
|
+
expect(result).toBe('parsed-output');
|
|
288
|
+
expect(publishHook).not.toHaveBeenCalled();
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
describe('sad', ()=>{
|
|
292
|
+
it('should report publish hook errors when publish hook throws', async ()=>{
|
|
293
|
+
const inputSchema = createBaseSchemaMock({
|
|
294
|
+
outputValue: 'parsed-input'
|
|
295
|
+
});
|
|
296
|
+
const publisher = vi.fn(async ()=>void 0);
|
|
297
|
+
const publishHookError = new Error('hook failed');
|
|
298
|
+
const publishHook = vi.fn(()=>{
|
|
299
|
+
throw publishHookError;
|
|
300
|
+
});
|
|
301
|
+
const onPublishError = vi.fn();
|
|
302
|
+
const logger = {
|
|
303
|
+
error: vi.fn()
|
|
304
|
+
};
|
|
305
|
+
context = createSchemaContext({
|
|
306
|
+
request: {
|
|
307
|
+
publisher,
|
|
308
|
+
onPublishError,
|
|
309
|
+
logger
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
const op = operation({
|
|
313
|
+
input: inputSchema,
|
|
314
|
+
exec: async ()=>'output',
|
|
315
|
+
publish: {
|
|
316
|
+
topic: publishHook
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
await runOperation(op, 'raw-input', context);
|
|
320
|
+
expect(onPublishError).toHaveBeenCalledWith(publishHookError, {
|
|
321
|
+
topic: 'topic',
|
|
322
|
+
phase: 'publish-hook'
|
|
323
|
+
});
|
|
324
|
+
expect(logger.error).toHaveBeenCalled();
|
|
325
|
+
});
|
|
326
|
+
it('should report publisher errors when publisher throws', async ()=>{
|
|
327
|
+
const inputSchema = createBaseSchemaMock({
|
|
328
|
+
outputValue: 'parsed-input'
|
|
329
|
+
});
|
|
330
|
+
const publisherError = new Error('publisher failed');
|
|
331
|
+
const publisher = vi.fn(async ()=>{
|
|
332
|
+
throw publisherError;
|
|
333
|
+
});
|
|
334
|
+
const onPublishError = vi.fn();
|
|
335
|
+
const logger = {
|
|
336
|
+
error: vi.fn()
|
|
337
|
+
};
|
|
338
|
+
context = createSchemaContext({
|
|
339
|
+
request: {
|
|
340
|
+
publisher,
|
|
341
|
+
onPublishError,
|
|
342
|
+
logger
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
const op = operation({
|
|
346
|
+
input: inputSchema,
|
|
347
|
+
exec: async ()=>'output',
|
|
348
|
+
publish: {
|
|
349
|
+
topic: ()=>({
|
|
350
|
+
ok: true
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
await runOperation(op, 'raw-input', context);
|
|
355
|
+
expect(onPublishError).toHaveBeenCalledWith(publisherError, {
|
|
356
|
+
topic: 'topic',
|
|
357
|
+
phase: 'publisher'
|
|
358
|
+
});
|
|
359
|
+
expect(logger.error).toHaveBeenCalled();
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
describe('runFieldOperation()', ()=>{
|
|
364
|
+
describe('happy', ()=>{
|
|
365
|
+
it('should parse dependsOn and input and output when input and output schemas are provided', async ()=>{
|
|
366
|
+
const parsedDependsOn = {
|
|
367
|
+
id: 'u-1'
|
|
368
|
+
};
|
|
369
|
+
const parsedInput = {
|
|
370
|
+
field: 'name'
|
|
371
|
+
};
|
|
372
|
+
const parsedOutput = {
|
|
373
|
+
value: 'Alice'
|
|
374
|
+
};
|
|
375
|
+
const dependsOnSchema = createBaseSchemaMock({
|
|
376
|
+
outputValue: parsedDependsOn
|
|
377
|
+
});
|
|
378
|
+
const inputSchema = createBaseSchemaMock({
|
|
379
|
+
outputValue: parsedInput
|
|
380
|
+
});
|
|
381
|
+
const outputSchema = createBaseSchemaMock({
|
|
382
|
+
outputValue: parsedOutput
|
|
383
|
+
});
|
|
384
|
+
const exec = vi.fn(async ()=>({
|
|
385
|
+
raw: true
|
|
386
|
+
}));
|
|
387
|
+
const op = fieldOperation({
|
|
388
|
+
dependsOn: dependsOnSchema,
|
|
389
|
+
input: inputSchema,
|
|
390
|
+
output: outputSchema,
|
|
391
|
+
exec
|
|
392
|
+
});
|
|
393
|
+
const result = await runFieldOperation(op, {
|
|
394
|
+
rawDependsOn: true
|
|
395
|
+
}, {
|
|
396
|
+
rawInput: true
|
|
397
|
+
}, context);
|
|
398
|
+
expect(dependsOnSchema.parse).toHaveBeenCalledWith({
|
|
399
|
+
rawDependsOn: true
|
|
400
|
+
}, context);
|
|
401
|
+
expect(inputSchema.parse).toHaveBeenCalledWith({
|
|
402
|
+
rawInput: true
|
|
403
|
+
}, context);
|
|
404
|
+
expect(exec).toHaveBeenCalledWith(parsedDependsOn, parsedInput, context);
|
|
405
|
+
expect(outputSchema.parse).toHaveBeenCalledWith({
|
|
406
|
+
raw: true
|
|
407
|
+
}, context);
|
|
408
|
+
expect(result).toEqual(parsedOutput);
|
|
409
|
+
});
|
|
410
|
+
it('should treat second parameter as context when input schema is missing', async ()=>{
|
|
411
|
+
const parsedDependsOn = {
|
|
412
|
+
id: 'u-1'
|
|
413
|
+
};
|
|
414
|
+
const dependsOnSchema = createBaseSchemaMock({
|
|
415
|
+
outputValue: parsedDependsOn
|
|
416
|
+
});
|
|
417
|
+
const exec = vi.fn(async ()=>'resolved');
|
|
418
|
+
const op = fieldOperation({
|
|
419
|
+
dependsOn: dependsOnSchema,
|
|
420
|
+
exec
|
|
421
|
+
});
|
|
422
|
+
const result = await runFieldOperation(op, {
|
|
423
|
+
rawDependsOn: true
|
|
424
|
+
}, context);
|
|
425
|
+
expect(exec).toHaveBeenCalledWith(parsedDependsOn, context);
|
|
426
|
+
expect(result).toBe('resolved');
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
describe('sad', ()=>{
|
|
430
|
+
it('should create request context when context has no request before execution', async ()=>{
|
|
431
|
+
const dependsOnSchema = createBaseSchemaMock({
|
|
432
|
+
outputValue: {
|
|
433
|
+
id: 'u-1'
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
context = createSchemaContext();
|
|
437
|
+
const op = fieldOperation({
|
|
438
|
+
dependsOn: dependsOnSchema,
|
|
439
|
+
exec: async ()=>'ok'
|
|
440
|
+
});
|
|
441
|
+
await runFieldOperation(op, {
|
|
442
|
+
rawDependsOn: true
|
|
443
|
+
}, context);
|
|
444
|
+
expect(context.getRequestContext()).toBeDefined();
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
});
|
package/dist/or.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
or: ()=>or
|
|
28
|
+
});
|
|
29
|
+
const external_schemaFactory_cjs_namespaceObject = require("./schemaFactory.cjs");
|
|
30
|
+
const resolveOrMatch = ({ input, ctx, options, discriminator })=>{
|
|
31
|
+
if (discriminator) {
|
|
32
|
+
const selected = discriminator(input, ctx);
|
|
33
|
+
if (selected) {
|
|
34
|
+
if (!options.includes(selected)) throw {
|
|
35
|
+
message: 'Discriminator selected an unknown schema option.',
|
|
36
|
+
code: 'or.discriminator'
|
|
37
|
+
};
|
|
38
|
+
return selected.parse(input, ctx);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const matches = options.map((option)=>{
|
|
42
|
+
try {
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
value: option.parse(input, ctx)
|
|
46
|
+
};
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
error
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}).find((result)=>result.ok);
|
|
54
|
+
if (!matches) throw {
|
|
55
|
+
message: 'No union match',
|
|
56
|
+
code: 'union.match'
|
|
57
|
+
};
|
|
58
|
+
return matches.value;
|
|
59
|
+
};
|
|
60
|
+
const or = ({ name, options, discriminator, doc })=>(0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
61
|
+
name,
|
|
62
|
+
type: 'or',
|
|
63
|
+
doc,
|
|
64
|
+
ast: (ctx)=>{
|
|
65
|
+
const build = ctx.getBuildContext();
|
|
66
|
+
return {
|
|
67
|
+
type: 'union',
|
|
68
|
+
name,
|
|
69
|
+
children: options.map((option)=>option.ast(build ?? void 0))
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
validate: (input, ctx)=>resolveOrMatch({
|
|
73
|
+
input,
|
|
74
|
+
ctx,
|
|
75
|
+
options,
|
|
76
|
+
discriminator
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
exports.or = __webpack_exports__.or;
|
|
80
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
81
|
+
"or"
|
|
82
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
83
|
+
Object.defineProperty(exports, '__esModule', {
|
|
84
|
+
value: true
|
|
85
|
+
});
|
package/dist/or.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Schema, SchemaContext, SchemaDoc } from './types.js';
|
|
2
|
+
type AnySchema = Schema<any>;
|
|
3
|
+
export interface OrSchemaDiscriminator<TValues extends readonly AnySchema[]> {
|
|
4
|
+
(input: unknown, ctx: SchemaContext): TValues[number] | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface OrSchemaInput<TValues extends readonly AnySchema[]> {
|
|
7
|
+
name: string;
|
|
8
|
+
options: TValues;
|
|
9
|
+
discriminator?: OrSchemaDiscriminator<TValues>;
|
|
10
|
+
doc?: SchemaDoc;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* or is part of the public LIVON API.
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* Parameter and return types are defined in the TypeScript signature.
|
|
17
|
+
*
|
|
18
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/or
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // Creates an or-schema that accepts either string or number identifiers.
|
|
22
|
+
* const Identifier = or({
|
|
23
|
+
* name: 'identifier',
|
|
24
|
+
* options: [string(), number()] as const,
|
|
25
|
+
* });
|
|
26
|
+
* Identifier.parse('user-1');
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Extends the or-schema to also allow undefined.
|
|
30
|
+
* const OptionalIdentifier = or({
|
|
31
|
+
* name: 'identifier',
|
|
32
|
+
* options: [string(), number()] as const,
|
|
33
|
+
* }).optional();
|
|
34
|
+
* OptionalIdentifier.parse(undefined);
|
|
35
|
+
*/
|
|
36
|
+
export declare const or: <TValues extends readonly AnySchema[]>({ name, options, discriminator, doc, }: OrSchemaInput<TValues>) => import("./schemaFactory.js").SchemaWithChain<ReturnType<TValues[number]["parse"]>, import("./schemaFactory.js").SchemaFactoryChainDefinition<ReturnType<TValues[number]["parse"]>>>;
|
|
37
|
+
export {};
|
package/dist/or.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { schemaFactory } from "./schemaFactory.js";
|
|
2
|
+
const resolveOrMatch = ({ input, ctx, options, discriminator })=>{
|
|
3
|
+
if (discriminator) {
|
|
4
|
+
const selected = discriminator(input, ctx);
|
|
5
|
+
if (selected) {
|
|
6
|
+
if (!options.includes(selected)) throw {
|
|
7
|
+
message: 'Discriminator selected an unknown schema option.',
|
|
8
|
+
code: 'or.discriminator'
|
|
9
|
+
};
|
|
10
|
+
return selected.parse(input, ctx);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const matches = options.map((option)=>{
|
|
14
|
+
try {
|
|
15
|
+
return {
|
|
16
|
+
ok: true,
|
|
17
|
+
value: option.parse(input, ctx)
|
|
18
|
+
};
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
error
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}).find((result)=>result.ok);
|
|
26
|
+
if (!matches) throw {
|
|
27
|
+
message: 'No union match',
|
|
28
|
+
code: 'union.match'
|
|
29
|
+
};
|
|
30
|
+
return matches.value;
|
|
31
|
+
};
|
|
32
|
+
const or = ({ name, options, discriminator, doc })=>schemaFactory({
|
|
33
|
+
name,
|
|
34
|
+
type: 'or',
|
|
35
|
+
doc,
|
|
36
|
+
ast: (ctx)=>{
|
|
37
|
+
const build = ctx.getBuildContext();
|
|
38
|
+
return {
|
|
39
|
+
type: 'union',
|
|
40
|
+
name,
|
|
41
|
+
children: options.map((option)=>option.ast(build ?? void 0))
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
validate: (input, ctx)=>resolveOrMatch({
|
|
45
|
+
input,
|
|
46
|
+
ctx,
|
|
47
|
+
options,
|
|
48
|
+
discriminator
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
export { or };
|