@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,149 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { number } from "./number.js";
|
|
3
|
+
import { schemaFactory } from "./schemaFactory.js";
|
|
4
|
+
import { isNumber } from "./typeGuards.js";
|
|
5
|
+
import { captureThrow, createSchemaContextMock, createSchemaFactoryMock } from "./testing/mocks/index.js";
|
|
6
|
+
vi.mock('./schemaFactory.js', ()=>({
|
|
7
|
+
schemaFactory: vi.fn()
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('./typeGuards.js', ()=>({
|
|
10
|
+
isNumber: vi.fn()
|
|
11
|
+
}));
|
|
12
|
+
const schemaFactoryMock = vi.mocked(schemaFactory);
|
|
13
|
+
const isNumberMock = vi.mocked(isNumber);
|
|
14
|
+
const schemaContextMock = createSchemaContextMock();
|
|
15
|
+
const schemaFactoryImplementation = createSchemaFactoryMock();
|
|
16
|
+
const getFactoryInput = ()=>{
|
|
17
|
+
const call = schemaFactoryMock.mock.calls[0];
|
|
18
|
+
if (!call) throw new Error('schemaFactory should be called once before reading input');
|
|
19
|
+
return call[0];
|
|
20
|
+
};
|
|
21
|
+
describe('number()', ()=>{
|
|
22
|
+
beforeAll(()=>{
|
|
23
|
+
schemaFactoryMock.mockImplementation(schemaFactoryImplementation);
|
|
24
|
+
});
|
|
25
|
+
beforeEach(()=>{
|
|
26
|
+
schemaFactoryMock.mockClear();
|
|
27
|
+
schemaFactoryImplementation.mockClear();
|
|
28
|
+
isNumberMock.mockReset();
|
|
29
|
+
isNumberMock.mockReturnValue(true);
|
|
30
|
+
});
|
|
31
|
+
afterEach(()=>{
|
|
32
|
+
isNumberMock.mockClear();
|
|
33
|
+
});
|
|
34
|
+
afterAll(()=>{
|
|
35
|
+
schemaFactoryMock.mockReset();
|
|
36
|
+
schemaFactoryImplementation.mockReset();
|
|
37
|
+
isNumberMock.mockReset();
|
|
38
|
+
});
|
|
39
|
+
describe('happy', ()=>{
|
|
40
|
+
it('should delegate to schemaFactory when number schema is created', ()=>{
|
|
41
|
+
const result = number();
|
|
42
|
+
expect(schemaFactoryMock).toHaveBeenCalledTimes(1);
|
|
43
|
+
const factoryInput = getFactoryInput();
|
|
44
|
+
expect(factoryInput.name).toBe('number');
|
|
45
|
+
expect(factoryInput.type).toBe('number');
|
|
46
|
+
expect(factoryInput.ast(schemaContextMock)).toEqual({
|
|
47
|
+
type: 'number',
|
|
48
|
+
name: 'number'
|
|
49
|
+
});
|
|
50
|
+
expect(Object.keys(factoryInput.chain)).toEqual([
|
|
51
|
+
'min',
|
|
52
|
+
'max',
|
|
53
|
+
'int',
|
|
54
|
+
'positive'
|
|
55
|
+
]);
|
|
56
|
+
expect(result).toBe(schemaFactoryMock.mock.results[0]?.value);
|
|
57
|
+
});
|
|
58
|
+
it('should pass custom metadata to schemaFactory when options are provided', ()=>{
|
|
59
|
+
const doc = {
|
|
60
|
+
summary: 'number doc'
|
|
61
|
+
};
|
|
62
|
+
number({
|
|
63
|
+
name: 'Count',
|
|
64
|
+
doc
|
|
65
|
+
});
|
|
66
|
+
const factoryInput = getFactoryInput();
|
|
67
|
+
expect(factoryInput.name).toBe('Count');
|
|
68
|
+
expect(factoryInput.doc).toEqual(doc);
|
|
69
|
+
expect(factoryInput.ast(schemaContextMock)).toEqual({
|
|
70
|
+
type: 'number',
|
|
71
|
+
name: 'Count'
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
it('should validate input through isNumber when input is number', ()=>{
|
|
75
|
+
number();
|
|
76
|
+
const factoryInput = getFactoryInput();
|
|
77
|
+
const parsed = factoryInput.validate(42, schemaContextMock);
|
|
78
|
+
expect(parsed).toBe(42);
|
|
79
|
+
expect(isNumberMock).toHaveBeenCalledWith(42);
|
|
80
|
+
});
|
|
81
|
+
it('should return input for all chain methods when constraints are valid', ()=>{
|
|
82
|
+
number();
|
|
83
|
+
const factoryInput = getFactoryInput();
|
|
84
|
+
expect(factoryInput.chain.min(5, schemaContextMock)(1)).toBe(5);
|
|
85
|
+
expect(factoryInput.chain.max(5, schemaContextMock)(8)).toBe(5);
|
|
86
|
+
expect(factoryInput.chain.int(5, schemaContextMock)()).toBe(5);
|
|
87
|
+
expect(factoryInput.chain.positive(5, schemaContextMock)()).toBe(5);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('sad', ()=>{
|
|
91
|
+
it('should throw schema error payload when input is not number', ()=>{
|
|
92
|
+
isNumberMock.mockReturnValue(false);
|
|
93
|
+
number();
|
|
94
|
+
const factoryInput = getFactoryInput();
|
|
95
|
+
const thrown = captureThrow(()=>factoryInput.validate('x', schemaContextMock));
|
|
96
|
+
expect(thrown.threw).toBe(true);
|
|
97
|
+
expect(thrown.value).toEqual({
|
|
98
|
+
message: 'Data is not a number',
|
|
99
|
+
code: 'number.type'
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
it('should throw min error when value is below minimum', ()=>{
|
|
103
|
+
number();
|
|
104
|
+
const factoryInput = getFactoryInput();
|
|
105
|
+
const thrown = captureThrow(()=>factoryInput.chain.min(1, schemaContextMock)(5));
|
|
106
|
+
expect(thrown.threw).toBe(true);
|
|
107
|
+
expect(thrown.value).toEqual({
|
|
108
|
+
message: 'Expected number >= 5',
|
|
109
|
+
code: 'number.min',
|
|
110
|
+
context: {
|
|
111
|
+
min: 5
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
it('should throw max error when value is above maximum', ()=>{
|
|
116
|
+
number();
|
|
117
|
+
const factoryInput = getFactoryInput();
|
|
118
|
+
const thrown = captureThrow(()=>factoryInput.chain.max(10, schemaContextMock)(8));
|
|
119
|
+
expect(thrown.threw).toBe(true);
|
|
120
|
+
expect(thrown.value).toEqual({
|
|
121
|
+
message: 'Expected number <= 8',
|
|
122
|
+
code: 'number.max',
|
|
123
|
+
context: {
|
|
124
|
+
max: 8
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
it('should throw int error when value is not integer', ()=>{
|
|
129
|
+
number();
|
|
130
|
+
const factoryInput = getFactoryInput();
|
|
131
|
+
const thrown = captureThrow(()=>factoryInput.chain.int(2.5, schemaContextMock)());
|
|
132
|
+
expect(thrown.threw).toBe(true);
|
|
133
|
+
expect(thrown.value).toEqual({
|
|
134
|
+
message: 'Expected integer',
|
|
135
|
+
code: 'number.int'
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
it('should throw positive error when value is not positive', ()=>{
|
|
139
|
+
number();
|
|
140
|
+
const factoryInput = getFactoryInput();
|
|
141
|
+
const thrown = captureThrow(()=>factoryInput.chain.positive(0, schemaContextMock)());
|
|
142
|
+
expect(thrown.threw).toBe(true);
|
|
143
|
+
expect(thrown.value).toEqual({
|
|
144
|
+
message: 'Expected positive number',
|
|
145
|
+
code: 'number.positive'
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
package/dist/object.cjs
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
object: ()=>object
|
|
28
|
+
});
|
|
29
|
+
const external_schemaFactory_cjs_namespaceObject = require("./schemaFactory.cjs");
|
|
30
|
+
const external_typeGuards_cjs_namespaceObject = require("./typeGuards.cjs");
|
|
31
|
+
const object = ({ name, shape, doc })=>(0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
32
|
+
name,
|
|
33
|
+
type: 'object',
|
|
34
|
+
doc,
|
|
35
|
+
ast: (ctx)=>{
|
|
36
|
+
const build = ctx.getBuildContext();
|
|
37
|
+
return {
|
|
38
|
+
type: 'object',
|
|
39
|
+
name,
|
|
40
|
+
children: Object.entries(shape).map(([key, schema])=>({
|
|
41
|
+
type: 'field',
|
|
42
|
+
name: key,
|
|
43
|
+
children: [
|
|
44
|
+
schema.ast(build ?? void 0)
|
|
45
|
+
]
|
|
46
|
+
}))
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
validate: (input, ctx)=>{
|
|
50
|
+
if (!(0, external_typeGuards_cjs_namespaceObject.isRecord)(input)) throw {
|
|
51
|
+
message: 'Expected object',
|
|
52
|
+
code: 'object.type'
|
|
53
|
+
};
|
|
54
|
+
return Object.entries(shape).reduce((acc, [key, schema])=>({
|
|
55
|
+
...acc,
|
|
56
|
+
[key]: schema.parse(input[key], ctx)
|
|
57
|
+
}), {});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
exports.object = __webpack_exports__.object;
|
|
61
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
62
|
+
"object"
|
|
63
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
64
|
+
Object.defineProperty(exports, '__esModule', {
|
|
65
|
+
value: true
|
|
66
|
+
});
|
package/dist/object.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SchemaWithChain } from './schemaFactory.js';
|
|
2
|
+
import { Schema, Shape, SchemaDoc } from './types.js';
|
|
3
|
+
type AnySchema = Schema<any>;
|
|
4
|
+
export interface ObjectSchemaInput<TShape extends Shape> {
|
|
5
|
+
name: string;
|
|
6
|
+
shape: TShape;
|
|
7
|
+
doc?: SchemaDoc;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* object is part of the public LIVON API.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Parameter and return types are defined in the TypeScript signature.
|
|
14
|
+
*
|
|
15
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/object
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Creates an object schema with id and age fields.
|
|
19
|
+
* const User = object({
|
|
20
|
+
* name: 'user',
|
|
21
|
+
* shape: {
|
|
22
|
+
* id: string(),
|
|
23
|
+
* age: number(),
|
|
24
|
+
* },
|
|
25
|
+
* });
|
|
26
|
+
* User.parse({ id: 'u1', age: 21 });
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Extends object validation to also allow null.
|
|
30
|
+
* const MaybeUser = object({
|
|
31
|
+
* name: 'user',
|
|
32
|
+
* shape: { id: string() },
|
|
33
|
+
* }).nullable();
|
|
34
|
+
* MaybeUser.parse(null);
|
|
35
|
+
*/
|
|
36
|
+
export declare const object: <TShape extends Record<string, AnySchema>>({ name, shape, doc, }: ObjectSchemaInput<TShape>) => SchemaWithChain<{ [K in keyof TShape]: ReturnType<TShape[K]["parse"]>; }, {}>;
|
|
37
|
+
export {};
|
package/dist/object.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { schemaFactory } from "./schemaFactory.js";
|
|
2
|
+
import { isRecord } from "./typeGuards.js";
|
|
3
|
+
const object = ({ name, shape, doc })=>schemaFactory({
|
|
4
|
+
name,
|
|
5
|
+
type: 'object',
|
|
6
|
+
doc,
|
|
7
|
+
ast: (ctx)=>{
|
|
8
|
+
const build = ctx.getBuildContext();
|
|
9
|
+
return {
|
|
10
|
+
type: 'object',
|
|
11
|
+
name,
|
|
12
|
+
children: Object.entries(shape).map(([key, schema])=>({
|
|
13
|
+
type: 'field',
|
|
14
|
+
name: key,
|
|
15
|
+
children: [
|
|
16
|
+
schema.ast(build ?? void 0)
|
|
17
|
+
]
|
|
18
|
+
}))
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
validate: (input, ctx)=>{
|
|
22
|
+
if (!isRecord(input)) throw {
|
|
23
|
+
message: 'Expected object',
|
|
24
|
+
code: 'object.type'
|
|
25
|
+
};
|
|
26
|
+
return Object.entries(shape).reduce((acc, [key, schema])=>({
|
|
27
|
+
...acc,
|
|
28
|
+
[key]: schema.parse(input[key], ctx)
|
|
29
|
+
}), {});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
export { object };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_exports__ = {};
|
|
3
|
+
const external_vitest_namespaceObject = require("vitest");
|
|
4
|
+
const external_object_cjs_namespaceObject = require("./object.cjs");
|
|
5
|
+
const external_schemaFactory_cjs_namespaceObject = require("./schemaFactory.cjs");
|
|
6
|
+
const external_typeGuards_cjs_namespaceObject = require("./typeGuards.cjs");
|
|
7
|
+
const index_cjs_namespaceObject = require("./testing/mocks/index.cjs");
|
|
8
|
+
external_vitest_namespaceObject.vi.mock('./schemaFactory.js', ()=>({
|
|
9
|
+
schemaFactory: external_vitest_namespaceObject.vi.fn()
|
|
10
|
+
}));
|
|
11
|
+
external_vitest_namespaceObject.vi.mock('./typeGuards.js', ()=>({
|
|
12
|
+
isRecord: external_vitest_namespaceObject.vi.fn()
|
|
13
|
+
}));
|
|
14
|
+
const schemaFactoryMock = external_vitest_namespaceObject.vi.mocked(external_schemaFactory_cjs_namespaceObject.schemaFactory);
|
|
15
|
+
const isRecordMock = external_vitest_namespaceObject.vi.mocked(external_typeGuards_cjs_namespaceObject.isRecord);
|
|
16
|
+
const schemaFactoryImplementation = (0, index_cjs_namespaceObject.createSchemaFactoryMock)();
|
|
17
|
+
const buildContextMock = {
|
|
18
|
+
buildId: 'build-object',
|
|
19
|
+
builder: {
|
|
20
|
+
add: external_vitest_namespaceObject.vi.fn((node)=>node),
|
|
21
|
+
getAll: external_vitest_namespaceObject.vi.fn(()=>[])
|
|
22
|
+
},
|
|
23
|
+
schemaPath: [],
|
|
24
|
+
buildOptions: {}
|
|
25
|
+
};
|
|
26
|
+
const schemaContextMock = (0, index_cjs_namespaceObject.createSchemaContextMock)({
|
|
27
|
+
buildContext: buildContextMock
|
|
28
|
+
});
|
|
29
|
+
const idSchemaMock = (0, index_cjs_namespaceObject.createBaseSchemaMock)({
|
|
30
|
+
name: 'idSchema',
|
|
31
|
+
parse: external_vitest_namespaceObject.vi.fn((value)=>`id:${String(value)}`),
|
|
32
|
+
ast: external_vitest_namespaceObject.vi.fn(()=>({
|
|
33
|
+
type: 'string',
|
|
34
|
+
name: 'Id'
|
|
35
|
+
}))
|
|
36
|
+
});
|
|
37
|
+
const ageSchemaMock = (0, index_cjs_namespaceObject.createBaseSchemaMock)({
|
|
38
|
+
name: 'ageSchema',
|
|
39
|
+
parse: external_vitest_namespaceObject.vi.fn((value)=>Number(value)),
|
|
40
|
+
ast: external_vitest_namespaceObject.vi.fn(()=>({
|
|
41
|
+
type: 'number',
|
|
42
|
+
name: 'Age'
|
|
43
|
+
}))
|
|
44
|
+
});
|
|
45
|
+
const getFactoryInput = ()=>{
|
|
46
|
+
const call = schemaFactoryMock.mock.calls[0];
|
|
47
|
+
if (!call) throw new Error('schemaFactory should be called once before reading input');
|
|
48
|
+
return call[0];
|
|
49
|
+
};
|
|
50
|
+
(0, external_vitest_namespaceObject.describe)('object()', ()=>{
|
|
51
|
+
(0, external_vitest_namespaceObject.beforeAll)(()=>{
|
|
52
|
+
schemaFactoryMock.mockImplementation(schemaFactoryImplementation);
|
|
53
|
+
isRecordMock.mockImplementation((value)=>'object' == typeof value && null !== value && !Array.isArray(value));
|
|
54
|
+
});
|
|
55
|
+
(0, external_vitest_namespaceObject.beforeEach)(()=>{
|
|
56
|
+
schemaFactoryMock.mockClear();
|
|
57
|
+
schemaFactoryImplementation.mockClear();
|
|
58
|
+
isRecordMock.mockClear();
|
|
59
|
+
external_vitest_namespaceObject.vi.mocked(idSchemaMock.parse).mockClear();
|
|
60
|
+
external_vitest_namespaceObject.vi.mocked(idSchemaMock.ast).mockClear();
|
|
61
|
+
external_vitest_namespaceObject.vi.mocked(ageSchemaMock.parse).mockClear();
|
|
62
|
+
external_vitest_namespaceObject.vi.mocked(ageSchemaMock.ast).mockClear();
|
|
63
|
+
});
|
|
64
|
+
(0, external_vitest_namespaceObject.afterEach)(()=>{
|
|
65
|
+
external_vitest_namespaceObject.vi.mocked(idSchemaMock.parse).mockClear();
|
|
66
|
+
external_vitest_namespaceObject.vi.mocked(ageSchemaMock.parse).mockClear();
|
|
67
|
+
});
|
|
68
|
+
(0, external_vitest_namespaceObject.afterAll)(()=>{
|
|
69
|
+
schemaFactoryMock.mockReset();
|
|
70
|
+
schemaFactoryImplementation.mockReset();
|
|
71
|
+
isRecordMock.mockReset();
|
|
72
|
+
});
|
|
73
|
+
(0, external_vitest_namespaceObject.describe)('happy', ()=>{
|
|
74
|
+
(0, external_vitest_namespaceObject.it)('should delegate to schemaFactory when object schema is created', ()=>{
|
|
75
|
+
const result = (0, external_object_cjs_namespaceObject.object)({
|
|
76
|
+
name: 'User',
|
|
77
|
+
shape: {
|
|
78
|
+
id: idSchemaMock,
|
|
79
|
+
age: ageSchemaMock
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
(0, external_vitest_namespaceObject.expect)(schemaFactoryMock).toHaveBeenCalledTimes(1);
|
|
83
|
+
const factoryInput = getFactoryInput();
|
|
84
|
+
(0, external_vitest_namespaceObject.expect)(factoryInput.name).toBe('User');
|
|
85
|
+
(0, external_vitest_namespaceObject.expect)(factoryInput.type).toBe('object');
|
|
86
|
+
(0, external_vitest_namespaceObject.expect)(result).toBe(schemaFactoryMock.mock.results[0]?.value);
|
|
87
|
+
});
|
|
88
|
+
(0, external_vitest_namespaceObject.it)('should build field ast nodes when shape entries are provided', ()=>{
|
|
89
|
+
(0, external_object_cjs_namespaceObject.object)({
|
|
90
|
+
name: 'User',
|
|
91
|
+
shape: {
|
|
92
|
+
id: idSchemaMock,
|
|
93
|
+
age: ageSchemaMock
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const factoryInput = getFactoryInput();
|
|
97
|
+
const ast = factoryInput.ast(schemaContextMock);
|
|
98
|
+
(0, external_vitest_namespaceObject.expect)(ast).toEqual({
|
|
99
|
+
type: 'object',
|
|
100
|
+
name: 'User',
|
|
101
|
+
children: [
|
|
102
|
+
{
|
|
103
|
+
type: 'field',
|
|
104
|
+
name: 'id',
|
|
105
|
+
children: [
|
|
106
|
+
{
|
|
107
|
+
type: 'string',
|
|
108
|
+
name: 'Id'
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
type: 'field',
|
|
114
|
+
name: 'age',
|
|
115
|
+
children: [
|
|
116
|
+
{
|
|
117
|
+
type: 'number',
|
|
118
|
+
name: 'Age'
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
});
|
|
124
|
+
(0, external_vitest_namespaceObject.expect)(idSchemaMock.ast).toHaveBeenCalledWith(buildContextMock);
|
|
125
|
+
(0, external_vitest_namespaceObject.expect)(ageSchemaMock.ast).toHaveBeenCalledWith(buildContextMock);
|
|
126
|
+
});
|
|
127
|
+
(0, external_vitest_namespaceObject.it)('should parse each field when input is a record', ()=>{
|
|
128
|
+
(0, external_object_cjs_namespaceObject.object)({
|
|
129
|
+
name: 'User',
|
|
130
|
+
shape: {
|
|
131
|
+
id: idSchemaMock,
|
|
132
|
+
age: ageSchemaMock
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
const factoryInput = getFactoryInput();
|
|
136
|
+
const parsed = factoryInput.validate({
|
|
137
|
+
id: 'u1',
|
|
138
|
+
age: '21'
|
|
139
|
+
}, schemaContextMock);
|
|
140
|
+
(0, external_vitest_namespaceObject.expect)(parsed).toEqual({
|
|
141
|
+
id: 'id:u1',
|
|
142
|
+
age: 21
|
|
143
|
+
});
|
|
144
|
+
(0, external_vitest_namespaceObject.expect)(idSchemaMock.parse).toHaveBeenCalledWith('u1', schemaContextMock);
|
|
145
|
+
(0, external_vitest_namespaceObject.expect)(ageSchemaMock.parse).toHaveBeenCalledWith('21', schemaContextMock);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
(0, external_vitest_namespaceObject.describe)('sad', ()=>{
|
|
149
|
+
(0, external_vitest_namespaceObject.it)('should throw object.type when input is not a record', ()=>{
|
|
150
|
+
isRecordMock.mockReturnValueOnce(false);
|
|
151
|
+
(0, external_object_cjs_namespaceObject.object)({
|
|
152
|
+
name: 'User',
|
|
153
|
+
shape: {
|
|
154
|
+
id: idSchemaMock,
|
|
155
|
+
age: ageSchemaMock
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
const factoryInput = getFactoryInput();
|
|
159
|
+
const thrown = (0, index_cjs_namespaceObject.captureThrow)(()=>factoryInput.validate('x', schemaContextMock));
|
|
160
|
+
(0, external_vitest_namespaceObject.expect)(thrown.threw).toBe(true);
|
|
161
|
+
(0, external_vitest_namespaceObject.expect)(thrown.value).toEqual({
|
|
162
|
+
message: 'Expected object',
|
|
163
|
+
code: 'object.type'
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
169
|
+
Object.defineProperty(exports, '__esModule', {
|
|
170
|
+
value: true
|
|
171
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { object } from "./object.js";
|
|
3
|
+
import { schemaFactory } from "./schemaFactory.js";
|
|
4
|
+
import { isRecord } from "./typeGuards.js";
|
|
5
|
+
import { captureThrow, createBaseSchemaMock, createSchemaContextMock, createSchemaFactoryMock } from "./testing/mocks/index.js";
|
|
6
|
+
vi.mock('./schemaFactory.js', ()=>({
|
|
7
|
+
schemaFactory: vi.fn()
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('./typeGuards.js', ()=>({
|
|
10
|
+
isRecord: vi.fn()
|
|
11
|
+
}));
|
|
12
|
+
const schemaFactoryMock = vi.mocked(schemaFactory);
|
|
13
|
+
const isRecordMock = vi.mocked(isRecord);
|
|
14
|
+
const schemaFactoryImplementation = createSchemaFactoryMock();
|
|
15
|
+
const buildContextMock = {
|
|
16
|
+
buildId: 'build-object',
|
|
17
|
+
builder: {
|
|
18
|
+
add: vi.fn((node)=>node),
|
|
19
|
+
getAll: vi.fn(()=>[])
|
|
20
|
+
},
|
|
21
|
+
schemaPath: [],
|
|
22
|
+
buildOptions: {}
|
|
23
|
+
};
|
|
24
|
+
const schemaContextMock = createSchemaContextMock({
|
|
25
|
+
buildContext: buildContextMock
|
|
26
|
+
});
|
|
27
|
+
const idSchemaMock = createBaseSchemaMock({
|
|
28
|
+
name: 'idSchema',
|
|
29
|
+
parse: vi.fn((value)=>`id:${String(value)}`),
|
|
30
|
+
ast: vi.fn(()=>({
|
|
31
|
+
type: 'string',
|
|
32
|
+
name: 'Id'
|
|
33
|
+
}))
|
|
34
|
+
});
|
|
35
|
+
const ageSchemaMock = createBaseSchemaMock({
|
|
36
|
+
name: 'ageSchema',
|
|
37
|
+
parse: vi.fn((value)=>Number(value)),
|
|
38
|
+
ast: vi.fn(()=>({
|
|
39
|
+
type: 'number',
|
|
40
|
+
name: 'Age'
|
|
41
|
+
}))
|
|
42
|
+
});
|
|
43
|
+
const getFactoryInput = ()=>{
|
|
44
|
+
const call = schemaFactoryMock.mock.calls[0];
|
|
45
|
+
if (!call) throw new Error('schemaFactory should be called once before reading input');
|
|
46
|
+
return call[0];
|
|
47
|
+
};
|
|
48
|
+
describe('object()', ()=>{
|
|
49
|
+
beforeAll(()=>{
|
|
50
|
+
schemaFactoryMock.mockImplementation(schemaFactoryImplementation);
|
|
51
|
+
isRecordMock.mockImplementation((value)=>'object' == typeof value && null !== value && !Array.isArray(value));
|
|
52
|
+
});
|
|
53
|
+
beforeEach(()=>{
|
|
54
|
+
schemaFactoryMock.mockClear();
|
|
55
|
+
schemaFactoryImplementation.mockClear();
|
|
56
|
+
isRecordMock.mockClear();
|
|
57
|
+
vi.mocked(idSchemaMock.parse).mockClear();
|
|
58
|
+
vi.mocked(idSchemaMock.ast).mockClear();
|
|
59
|
+
vi.mocked(ageSchemaMock.parse).mockClear();
|
|
60
|
+
vi.mocked(ageSchemaMock.ast).mockClear();
|
|
61
|
+
});
|
|
62
|
+
afterEach(()=>{
|
|
63
|
+
vi.mocked(idSchemaMock.parse).mockClear();
|
|
64
|
+
vi.mocked(ageSchemaMock.parse).mockClear();
|
|
65
|
+
});
|
|
66
|
+
afterAll(()=>{
|
|
67
|
+
schemaFactoryMock.mockReset();
|
|
68
|
+
schemaFactoryImplementation.mockReset();
|
|
69
|
+
isRecordMock.mockReset();
|
|
70
|
+
});
|
|
71
|
+
describe('happy', ()=>{
|
|
72
|
+
it('should delegate to schemaFactory when object schema is created', ()=>{
|
|
73
|
+
const result = object({
|
|
74
|
+
name: 'User',
|
|
75
|
+
shape: {
|
|
76
|
+
id: idSchemaMock,
|
|
77
|
+
age: ageSchemaMock
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
expect(schemaFactoryMock).toHaveBeenCalledTimes(1);
|
|
81
|
+
const factoryInput = getFactoryInput();
|
|
82
|
+
expect(factoryInput.name).toBe('User');
|
|
83
|
+
expect(factoryInput.type).toBe('object');
|
|
84
|
+
expect(result).toBe(schemaFactoryMock.mock.results[0]?.value);
|
|
85
|
+
});
|
|
86
|
+
it('should build field ast nodes when shape entries are provided', ()=>{
|
|
87
|
+
object({
|
|
88
|
+
name: 'User',
|
|
89
|
+
shape: {
|
|
90
|
+
id: idSchemaMock,
|
|
91
|
+
age: ageSchemaMock
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const factoryInput = getFactoryInput();
|
|
95
|
+
const ast = factoryInput.ast(schemaContextMock);
|
|
96
|
+
expect(ast).toEqual({
|
|
97
|
+
type: 'object',
|
|
98
|
+
name: 'User',
|
|
99
|
+
children: [
|
|
100
|
+
{
|
|
101
|
+
type: 'field',
|
|
102
|
+
name: 'id',
|
|
103
|
+
children: [
|
|
104
|
+
{
|
|
105
|
+
type: 'string',
|
|
106
|
+
name: 'Id'
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: 'field',
|
|
112
|
+
name: 'age',
|
|
113
|
+
children: [
|
|
114
|
+
{
|
|
115
|
+
type: 'number',
|
|
116
|
+
name: 'Age'
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
});
|
|
122
|
+
expect(idSchemaMock.ast).toHaveBeenCalledWith(buildContextMock);
|
|
123
|
+
expect(ageSchemaMock.ast).toHaveBeenCalledWith(buildContextMock);
|
|
124
|
+
});
|
|
125
|
+
it('should parse each field when input is a record', ()=>{
|
|
126
|
+
object({
|
|
127
|
+
name: 'User',
|
|
128
|
+
shape: {
|
|
129
|
+
id: idSchemaMock,
|
|
130
|
+
age: ageSchemaMock
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
const factoryInput = getFactoryInput();
|
|
134
|
+
const parsed = factoryInput.validate({
|
|
135
|
+
id: 'u1',
|
|
136
|
+
age: '21'
|
|
137
|
+
}, schemaContextMock);
|
|
138
|
+
expect(parsed).toEqual({
|
|
139
|
+
id: 'id:u1',
|
|
140
|
+
age: 21
|
|
141
|
+
});
|
|
142
|
+
expect(idSchemaMock.parse).toHaveBeenCalledWith('u1', schemaContextMock);
|
|
143
|
+
expect(ageSchemaMock.parse).toHaveBeenCalledWith('21', schemaContextMock);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('sad', ()=>{
|
|
147
|
+
it('should throw object.type when input is not a record', ()=>{
|
|
148
|
+
isRecordMock.mockReturnValueOnce(false);
|
|
149
|
+
object({
|
|
150
|
+
name: 'User',
|
|
151
|
+
shape: {
|
|
152
|
+
id: idSchemaMock,
|
|
153
|
+
age: ageSchemaMock
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
const factoryInput = getFactoryInput();
|
|
157
|
+
const thrown = captureThrow(()=>factoryInput.validate('x', schemaContextMock));
|
|
158
|
+
expect(thrown.threw).toBe(true);
|
|
159
|
+
expect(thrown.value).toEqual({
|
|
160
|
+
message: 'Expected object',
|
|
161
|
+
code: 'object.type'
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|