@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,97 @@
|
|
|
1
|
+
import { Schema, SchemaContext, SchemaDoc } from './types.js';
|
|
2
|
+
import { TypeGuard } from './typeGuards.js';
|
|
3
|
+
export interface SchemaFactoryErrorLike {
|
|
4
|
+
message: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
context?: Readonly<Record<string, unknown>>;
|
|
7
|
+
}
|
|
8
|
+
export interface SchemaFactoryValidate<T> {
|
|
9
|
+
(input: unknown, ctx: SchemaContext): T;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Defines one chain operation for a schema value.
|
|
13
|
+
*
|
|
14
|
+
* @typeParam TValue - Current schema output type.
|
|
15
|
+
* @typeParam TArgs - Operation argument tuple.
|
|
16
|
+
* @typeParam TNext - Output type after applying the operation.
|
|
17
|
+
*
|
|
18
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/schema-factory
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* interface MinChain {
|
|
22
|
+
* (value: number): (min: number) => number;
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
export interface SchemaFactoryChainOperation<TValue, TArgs extends readonly unknown[], TNext> {
|
|
26
|
+
(value: TValue, ctx: SchemaContext): (...args: TArgs) => TNext;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Map of chain operation names to chain operation implementations.
|
|
30
|
+
*
|
|
31
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/schema-factory
|
|
32
|
+
*/
|
|
33
|
+
export type SchemaFactoryChainDefinition<TValue> = Record<string, SchemaFactoryChainOperation<TValue, readonly any[], any>>;
|
|
34
|
+
/**
|
|
35
|
+
* Public chain method surface inferred from a chain definition.
|
|
36
|
+
*
|
|
37
|
+
* Every chain method returns a new schema that keeps the same chain API.
|
|
38
|
+
*
|
|
39
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/schema-factory
|
|
40
|
+
*/
|
|
41
|
+
export type SchemaChainMethods<TChain extends SchemaFactoryChainDefinition<any>> = {
|
|
42
|
+
[K in keyof TChain]: TChain[K] extends SchemaFactoryChainOperation<any, infer TArgs, infer TNext> ? (...args: TArgs) => SchemaWithChain<TNext, TChain> : never;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Schema type enriched with fluent chain methods.
|
|
46
|
+
*
|
|
47
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/schema-factory
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const Name = string().min(3).max(50);
|
|
51
|
+
*/
|
|
52
|
+
export type SchemaWithChain<TValue, TChain extends SchemaFactoryChainDefinition<TValue>> = Schema<TValue> & SchemaChainMethods<TChain>;
|
|
53
|
+
export interface SchemaFactoryInput<TValue, TChain extends SchemaFactoryChainDefinition<TValue>> {
|
|
54
|
+
name: string;
|
|
55
|
+
type: string;
|
|
56
|
+
validate: SchemaFactoryValidate<TValue>;
|
|
57
|
+
ast: (ctx: SchemaContext) => ReturnType<Schema<TValue>['ast']>;
|
|
58
|
+
doc?: SchemaDoc;
|
|
59
|
+
chain?: TChain;
|
|
60
|
+
}
|
|
61
|
+
export interface SchemaFactory {
|
|
62
|
+
<TValue, TChain extends SchemaFactoryChainDefinition<TValue> = SchemaFactoryChainDefinition<TValue>>(input: SchemaFactoryInput<TValue, TChain>): SchemaWithChain<TValue, TChain>;
|
|
63
|
+
}
|
|
64
|
+
export interface GuardFactoryInput<T> {
|
|
65
|
+
name: string;
|
|
66
|
+
type: string;
|
|
67
|
+
guard: TypeGuard<T>;
|
|
68
|
+
message: string;
|
|
69
|
+
code?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface GuardFactory {
|
|
72
|
+
<T>(input: GuardFactoryInput<T>): Schema<T>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* schemaFactory is part of the public LIVON API.
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* Parameter and return types are defined in the TypeScript signature.
|
|
79
|
+
*
|
|
80
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/schema-factory
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const result = schemaFactory(undefined as never);
|
|
84
|
+
*/
|
|
85
|
+
export declare const schemaFactory: <TValue, TChain extends SchemaFactoryChainDefinition<TValue> = SchemaFactoryChainDefinition<TValue>>({ name, type, validate, ast, doc, chain, }: SchemaFactoryInput<TValue, TChain>) => SchemaWithChain<TValue, TChain>;
|
|
86
|
+
/**
|
|
87
|
+
* guardFactory is part of the public LIVON API.
|
|
88
|
+
*
|
|
89
|
+
* @remarks
|
|
90
|
+
* Parameter and return types are defined in the TypeScript signature.
|
|
91
|
+
*
|
|
92
|
+
* @see https://live-input-vector-output-node.github.io/livon-ts/docs/schema/schema-factory
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const result = guardFactory(undefined as never);
|
|
96
|
+
*/
|
|
97
|
+
export declare const guardFactory: GuardFactory;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createIssueForPath, createSchema, ensureSchemaContext, fail, ok } from "./schema.js";
|
|
2
|
+
import { mergeDoc, normalizeDoc } from "./doc.js";
|
|
3
|
+
const normalizeError = (error)=>{
|
|
4
|
+
if (error && 'object' == typeof error && 'message' in error) {
|
|
5
|
+
const err = error;
|
|
6
|
+
return {
|
|
7
|
+
message: err.message,
|
|
8
|
+
code: err.code,
|
|
9
|
+
context: err.context
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
message: 'Schema validation failed'
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
const schemaFactory = ({ name, type, validate, ast, doc, chain })=>{
|
|
17
|
+
const docRecord = normalizeDoc(doc);
|
|
18
|
+
const astWithDoc = docRecord ? (ctx)=>{
|
|
19
|
+
const node = ast(ctx);
|
|
20
|
+
const merged = mergeDoc(node.doc, docRecord);
|
|
21
|
+
return merged ? {
|
|
22
|
+
...node,
|
|
23
|
+
doc: merged
|
|
24
|
+
} : node;
|
|
25
|
+
} : ast;
|
|
26
|
+
const base = createSchema({
|
|
27
|
+
name,
|
|
28
|
+
type,
|
|
29
|
+
ast: astWithDoc,
|
|
30
|
+
validate: (input, ctx)=>{
|
|
31
|
+
const context = ensureSchemaContext(ctx);
|
|
32
|
+
try {
|
|
33
|
+
const value = validate(input, context);
|
|
34
|
+
return ok({
|
|
35
|
+
value
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const normalized = normalizeError(error);
|
|
39
|
+
return fail({
|
|
40
|
+
issues: [
|
|
41
|
+
createIssueForPath({
|
|
42
|
+
path: [],
|
|
43
|
+
message: normalized.message,
|
|
44
|
+
code: normalized.code,
|
|
45
|
+
context: normalized.context
|
|
46
|
+
})
|
|
47
|
+
]
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const result = base;
|
|
53
|
+
if (!chain) return result;
|
|
54
|
+
Object.entries(chain).forEach(([key, operation])=>{
|
|
55
|
+
result[key] = (...args)=>schemaFactory({
|
|
56
|
+
name: `${name}.${key}`,
|
|
57
|
+
type,
|
|
58
|
+
ast,
|
|
59
|
+
validate: (input, ctx)=>{
|
|
60
|
+
const context = ensureSchemaContext(ctx);
|
|
61
|
+
const value = base.parse(input, context);
|
|
62
|
+
const next = operation(value, context)(...args);
|
|
63
|
+
return next;
|
|
64
|
+
},
|
|
65
|
+
chain: chain
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
70
|
+
const guardFactory = ({ name, type, guard, message, code })=>schemaFactory({
|
|
71
|
+
name,
|
|
72
|
+
type,
|
|
73
|
+
ast: ()=>({
|
|
74
|
+
type,
|
|
75
|
+
name
|
|
76
|
+
}),
|
|
77
|
+
validate: (input)=>{
|
|
78
|
+
if (!guard(input)) {
|
|
79
|
+
const error = {
|
|
80
|
+
message,
|
|
81
|
+
code
|
|
82
|
+
};
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
return input;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
export { guardFactory, schemaFactory };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_exports__ = {};
|
|
3
|
+
const external_vitest_namespaceObject = require("vitest");
|
|
4
|
+
const external_context_cjs_namespaceObject = require("./context.cjs");
|
|
5
|
+
const index_cjs_namespaceObject = require("./testing/mocks/index.cjs");
|
|
6
|
+
const external_schemaFactory_cjs_namespaceObject = require("./schemaFactory.cjs");
|
|
7
|
+
(0, external_vitest_namespaceObject.describe)('schemaFactory()', ()=>{
|
|
8
|
+
let astNode;
|
|
9
|
+
let context;
|
|
10
|
+
(0, external_vitest_namespaceObject.beforeAll)(()=>{
|
|
11
|
+
astNode = {
|
|
12
|
+
type: 'custom',
|
|
13
|
+
name: 'Custom'
|
|
14
|
+
};
|
|
15
|
+
context = (0, external_context_cjs_namespaceObject.createSchemaContext)();
|
|
16
|
+
});
|
|
17
|
+
(0, external_vitest_namespaceObject.beforeEach)(()=>{
|
|
18
|
+
astNode = {
|
|
19
|
+
type: 'custom',
|
|
20
|
+
name: 'Custom'
|
|
21
|
+
};
|
|
22
|
+
context = (0, external_context_cjs_namespaceObject.createSchemaContext)();
|
|
23
|
+
});
|
|
24
|
+
(0, external_vitest_namespaceObject.afterEach)(()=>{
|
|
25
|
+
external_vitest_namespaceObject.vi.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
(0, external_vitest_namespaceObject.afterAll)(()=>{
|
|
28
|
+
external_vitest_namespaceObject.vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
(0, external_vitest_namespaceObject.describe)('happy', ()=>{
|
|
31
|
+
(0, external_vitest_namespaceObject.it)('should create schema that parses validated value when validate succeeds', ()=>{
|
|
32
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
33
|
+
name: 'Custom',
|
|
34
|
+
type: 'custom',
|
|
35
|
+
ast: ()=>astNode,
|
|
36
|
+
validate: (input)=>String(input)
|
|
37
|
+
});
|
|
38
|
+
const parsed = schema.parse(123, context);
|
|
39
|
+
(0, external_vitest_namespaceObject.expect)(parsed).toBe('123');
|
|
40
|
+
(0, external_vitest_namespaceObject.expect)(schema.name).toBe('Custom');
|
|
41
|
+
(0, external_vitest_namespaceObject.expect)(schema.type).toBe('custom');
|
|
42
|
+
});
|
|
43
|
+
(0, external_vitest_namespaceObject.it)('should merge schema level doc into ast when doc is provided', ()=>{
|
|
44
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
45
|
+
name: 'WithDoc',
|
|
46
|
+
type: 'custom',
|
|
47
|
+
doc: {
|
|
48
|
+
summary: 'Schema doc'
|
|
49
|
+
},
|
|
50
|
+
ast: ()=>({
|
|
51
|
+
type: 'custom',
|
|
52
|
+
name: 'WithDoc',
|
|
53
|
+
doc: {
|
|
54
|
+
source: 'internal'
|
|
55
|
+
}
|
|
56
|
+
}),
|
|
57
|
+
validate: (input)=>input
|
|
58
|
+
});
|
|
59
|
+
const ast = schema.ast();
|
|
60
|
+
(0, external_vitest_namespaceObject.expect)(ast.doc).toEqual({
|
|
61
|
+
source: 'internal',
|
|
62
|
+
summary: 'Schema doc'
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
(0, external_vitest_namespaceObject.it)('should build chained schema when chain method is called', ()=>{
|
|
66
|
+
const plusOperation = external_vitest_namespaceObject.vi.fn((value, _ctx)=>(step)=>value + step);
|
|
67
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
68
|
+
name: 'Score',
|
|
69
|
+
type: 'number',
|
|
70
|
+
ast: ()=>({
|
|
71
|
+
type: 'number',
|
|
72
|
+
name: 'Score'
|
|
73
|
+
}),
|
|
74
|
+
validate: (input)=>Number(input),
|
|
75
|
+
chain: {
|
|
76
|
+
plus: plusOperation
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
const plusSchema = schema.plus(2);
|
|
80
|
+
const parsed = plusSchema.parse(3, context);
|
|
81
|
+
(0, external_vitest_namespaceObject.expect)(parsed).toBe(5);
|
|
82
|
+
(0, external_vitest_namespaceObject.expect)(plusOperation).toHaveBeenCalledWith(3, context);
|
|
83
|
+
(0, external_vitest_namespaceObject.expect)(plusSchema.name).toBe('Score.plus');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
(0, external_vitest_namespaceObject.describe)('sad', ()=>{
|
|
87
|
+
(0, external_vitest_namespaceObject.it)('should convert thrown object into schema issue when validate throws error-like value', ()=>{
|
|
88
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
89
|
+
name: 'Failing',
|
|
90
|
+
type: 'custom',
|
|
91
|
+
ast: ()=>({
|
|
92
|
+
type: 'custom',
|
|
93
|
+
name: 'Failing'
|
|
94
|
+
}),
|
|
95
|
+
validate: ()=>{
|
|
96
|
+
throw {
|
|
97
|
+
message: 'Validation exploded',
|
|
98
|
+
code: 'custom.fail',
|
|
99
|
+
context: {
|
|
100
|
+
reason: 'test'
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const thrown = (0, index_cjs_namespaceObject.captureThrow)(()=>schema.parse('x', context));
|
|
106
|
+
(0, external_vitest_namespaceObject.expect)(thrown.threw).toBe(true);
|
|
107
|
+
(0, external_vitest_namespaceObject.expect)(thrown.value).toMatchObject({
|
|
108
|
+
message: 'Schema validation failed',
|
|
109
|
+
issues: [
|
|
110
|
+
{
|
|
111
|
+
message: 'Validation exploded',
|
|
112
|
+
code: 'custom.fail',
|
|
113
|
+
context: {
|
|
114
|
+
reason: 'test'
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
(0, external_vitest_namespaceObject.it)('should convert thrown primitive into default validation message when validate throws non-object', ()=>{
|
|
121
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.schemaFactory)({
|
|
122
|
+
name: 'PrimitiveThrow',
|
|
123
|
+
type: 'custom',
|
|
124
|
+
ast: ()=>({
|
|
125
|
+
type: 'custom',
|
|
126
|
+
name: 'PrimitiveThrow'
|
|
127
|
+
}),
|
|
128
|
+
validate: ()=>{
|
|
129
|
+
throw 'primitive failure';
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const thrown = (0, index_cjs_namespaceObject.captureThrow)(()=>schema.parse('x', context));
|
|
133
|
+
(0, external_vitest_namespaceObject.expect)(thrown.threw).toBe(true);
|
|
134
|
+
(0, external_vitest_namespaceObject.expect)(thrown.value).toMatchObject({
|
|
135
|
+
issues: [
|
|
136
|
+
{
|
|
137
|
+
message: 'Schema validation failed'
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
(0, external_vitest_namespaceObject.describe)('guardFactory()', ()=>{
|
|
145
|
+
let context;
|
|
146
|
+
(0, external_vitest_namespaceObject.beforeAll)(()=>{
|
|
147
|
+
context = (0, external_context_cjs_namespaceObject.createSchemaContext)();
|
|
148
|
+
});
|
|
149
|
+
(0, external_vitest_namespaceObject.beforeEach)(()=>{
|
|
150
|
+
context = (0, external_context_cjs_namespaceObject.createSchemaContext)();
|
|
151
|
+
});
|
|
152
|
+
(0, external_vitest_namespaceObject.afterEach)(()=>{
|
|
153
|
+
external_vitest_namespaceObject.vi.clearAllMocks();
|
|
154
|
+
});
|
|
155
|
+
(0, external_vitest_namespaceObject.afterAll)(()=>{
|
|
156
|
+
external_vitest_namespaceObject.vi.restoreAllMocks();
|
|
157
|
+
});
|
|
158
|
+
(0, external_vitest_namespaceObject.describe)('happy', ()=>{
|
|
159
|
+
(0, external_vitest_namespaceObject.it)('should return input value when guard accepts input', ()=>{
|
|
160
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.guardFactory)({
|
|
161
|
+
name: 'GuardedString',
|
|
162
|
+
type: 'string',
|
|
163
|
+
guard: (input)=>'string' == typeof input,
|
|
164
|
+
message: 'Expected string',
|
|
165
|
+
code: 'string.type'
|
|
166
|
+
});
|
|
167
|
+
const parsed = schema.parse('ok', context);
|
|
168
|
+
(0, external_vitest_namespaceObject.expect)(parsed).toBe('ok');
|
|
169
|
+
(0, external_vitest_namespaceObject.expect)(schema.ast().type).toBe('string');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
(0, external_vitest_namespaceObject.describe)('sad', ()=>{
|
|
173
|
+
(0, external_vitest_namespaceObject.it)('should throw schema validation error when guard rejects input', ()=>{
|
|
174
|
+
const schema = (0, external_schemaFactory_cjs_namespaceObject.guardFactory)({
|
|
175
|
+
name: 'GuardedString',
|
|
176
|
+
type: 'string',
|
|
177
|
+
guard: (input)=>'string' == typeof input,
|
|
178
|
+
message: 'Expected string',
|
|
179
|
+
code: 'string.type'
|
|
180
|
+
});
|
|
181
|
+
const thrown = (0, index_cjs_namespaceObject.captureThrow)(()=>schema.parse(1, context));
|
|
182
|
+
(0, external_vitest_namespaceObject.expect)(thrown.threw).toBe(true);
|
|
183
|
+
(0, external_vitest_namespaceObject.expect)(thrown.value).toMatchObject({
|
|
184
|
+
issues: [
|
|
185
|
+
{
|
|
186
|
+
message: 'Expected string',
|
|
187
|
+
code: 'string.type'
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
195
|
+
Object.defineProperty(exports, '__esModule', {
|
|
196
|
+
value: true
|
|
197
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createSchemaContext } from "./context.js";
|
|
3
|
+
import { captureThrow } from "./testing/mocks/index.js";
|
|
4
|
+
import { guardFactory, schemaFactory } from "./schemaFactory.js";
|
|
5
|
+
describe('schemaFactory()', ()=>{
|
|
6
|
+
let astNode;
|
|
7
|
+
let context;
|
|
8
|
+
beforeAll(()=>{
|
|
9
|
+
astNode = {
|
|
10
|
+
type: 'custom',
|
|
11
|
+
name: 'Custom'
|
|
12
|
+
};
|
|
13
|
+
context = createSchemaContext();
|
|
14
|
+
});
|
|
15
|
+
beforeEach(()=>{
|
|
16
|
+
astNode = {
|
|
17
|
+
type: 'custom',
|
|
18
|
+
name: 'Custom'
|
|
19
|
+
};
|
|
20
|
+
context = createSchemaContext();
|
|
21
|
+
});
|
|
22
|
+
afterEach(()=>{
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
afterAll(()=>{
|
|
26
|
+
vi.restoreAllMocks();
|
|
27
|
+
});
|
|
28
|
+
describe('happy', ()=>{
|
|
29
|
+
it('should create schema that parses validated value when validate succeeds', ()=>{
|
|
30
|
+
const schema = schemaFactory({
|
|
31
|
+
name: 'Custom',
|
|
32
|
+
type: 'custom',
|
|
33
|
+
ast: ()=>astNode,
|
|
34
|
+
validate: (input)=>String(input)
|
|
35
|
+
});
|
|
36
|
+
const parsed = schema.parse(123, context);
|
|
37
|
+
expect(parsed).toBe('123');
|
|
38
|
+
expect(schema.name).toBe('Custom');
|
|
39
|
+
expect(schema.type).toBe('custom');
|
|
40
|
+
});
|
|
41
|
+
it('should merge schema level doc into ast when doc is provided', ()=>{
|
|
42
|
+
const schema = schemaFactory({
|
|
43
|
+
name: 'WithDoc',
|
|
44
|
+
type: 'custom',
|
|
45
|
+
doc: {
|
|
46
|
+
summary: 'Schema doc'
|
|
47
|
+
},
|
|
48
|
+
ast: ()=>({
|
|
49
|
+
type: 'custom',
|
|
50
|
+
name: 'WithDoc',
|
|
51
|
+
doc: {
|
|
52
|
+
source: 'internal'
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
validate: (input)=>input
|
|
56
|
+
});
|
|
57
|
+
const ast = schema.ast();
|
|
58
|
+
expect(ast.doc).toEqual({
|
|
59
|
+
source: 'internal',
|
|
60
|
+
summary: 'Schema doc'
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('should build chained schema when chain method is called', ()=>{
|
|
64
|
+
const plusOperation = vi.fn((value, _ctx)=>(step)=>value + step);
|
|
65
|
+
const schema = schemaFactory({
|
|
66
|
+
name: 'Score',
|
|
67
|
+
type: 'number',
|
|
68
|
+
ast: ()=>({
|
|
69
|
+
type: 'number',
|
|
70
|
+
name: 'Score'
|
|
71
|
+
}),
|
|
72
|
+
validate: (input)=>Number(input),
|
|
73
|
+
chain: {
|
|
74
|
+
plus: plusOperation
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
const plusSchema = schema.plus(2);
|
|
78
|
+
const parsed = plusSchema.parse(3, context);
|
|
79
|
+
expect(parsed).toBe(5);
|
|
80
|
+
expect(plusOperation).toHaveBeenCalledWith(3, context);
|
|
81
|
+
expect(plusSchema.name).toBe('Score.plus');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('sad', ()=>{
|
|
85
|
+
it('should convert thrown object into schema issue when validate throws error-like value', ()=>{
|
|
86
|
+
const schema = schemaFactory({
|
|
87
|
+
name: 'Failing',
|
|
88
|
+
type: 'custom',
|
|
89
|
+
ast: ()=>({
|
|
90
|
+
type: 'custom',
|
|
91
|
+
name: 'Failing'
|
|
92
|
+
}),
|
|
93
|
+
validate: ()=>{
|
|
94
|
+
throw {
|
|
95
|
+
message: 'Validation exploded',
|
|
96
|
+
code: 'custom.fail',
|
|
97
|
+
context: {
|
|
98
|
+
reason: 'test'
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const thrown = captureThrow(()=>schema.parse('x', context));
|
|
104
|
+
expect(thrown.threw).toBe(true);
|
|
105
|
+
expect(thrown.value).toMatchObject({
|
|
106
|
+
message: 'Schema validation failed',
|
|
107
|
+
issues: [
|
|
108
|
+
{
|
|
109
|
+
message: 'Validation exploded',
|
|
110
|
+
code: 'custom.fail',
|
|
111
|
+
context: {
|
|
112
|
+
reason: 'test'
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it('should convert thrown primitive into default validation message when validate throws non-object', ()=>{
|
|
119
|
+
const schema = schemaFactory({
|
|
120
|
+
name: 'PrimitiveThrow',
|
|
121
|
+
type: 'custom',
|
|
122
|
+
ast: ()=>({
|
|
123
|
+
type: 'custom',
|
|
124
|
+
name: 'PrimitiveThrow'
|
|
125
|
+
}),
|
|
126
|
+
validate: ()=>{
|
|
127
|
+
throw 'primitive failure';
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
const thrown = captureThrow(()=>schema.parse('x', context));
|
|
131
|
+
expect(thrown.threw).toBe(true);
|
|
132
|
+
expect(thrown.value).toMatchObject({
|
|
133
|
+
issues: [
|
|
134
|
+
{
|
|
135
|
+
message: 'Schema validation failed'
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('guardFactory()', ()=>{
|
|
143
|
+
let context;
|
|
144
|
+
beforeAll(()=>{
|
|
145
|
+
context = createSchemaContext();
|
|
146
|
+
});
|
|
147
|
+
beforeEach(()=>{
|
|
148
|
+
context = createSchemaContext();
|
|
149
|
+
});
|
|
150
|
+
afterEach(()=>{
|
|
151
|
+
vi.clearAllMocks();
|
|
152
|
+
});
|
|
153
|
+
afterAll(()=>{
|
|
154
|
+
vi.restoreAllMocks();
|
|
155
|
+
});
|
|
156
|
+
describe('happy', ()=>{
|
|
157
|
+
it('should return input value when guard accepts input', ()=>{
|
|
158
|
+
const schema = guardFactory({
|
|
159
|
+
name: 'GuardedString',
|
|
160
|
+
type: 'string',
|
|
161
|
+
guard: (input)=>'string' == typeof input,
|
|
162
|
+
message: 'Expected string',
|
|
163
|
+
code: 'string.type'
|
|
164
|
+
});
|
|
165
|
+
const parsed = schema.parse('ok', context);
|
|
166
|
+
expect(parsed).toBe('ok');
|
|
167
|
+
expect(schema.ast().type).toBe('string');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe('sad', ()=>{
|
|
171
|
+
it('should throw schema validation error when guard rejects input', ()=>{
|
|
172
|
+
const schema = guardFactory({
|
|
173
|
+
name: 'GuardedString',
|
|
174
|
+
type: 'string',
|
|
175
|
+
guard: (input)=>'string' == typeof input,
|
|
176
|
+
message: 'Expected string',
|
|
177
|
+
code: 'string.type'
|
|
178
|
+
});
|
|
179
|
+
const thrown = captureThrow(()=>schema.parse(1, context));
|
|
180
|
+
expect(thrown.threw).toBe(true);
|
|
181
|
+
expect(thrown.value).toMatchObject({
|
|
182
|
+
issues: [
|
|
183
|
+
{
|
|
184
|
+
message: 'Expected string',
|
|
185
|
+
code: 'string.type'
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|