functionalscript 0.12.0 → 0.12.2
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/djs/serializer/test.f.d.ts +3 -3
- package/json/module.f.js +0 -4
- package/package.json +1 -1
- package/types/rtti/module.f.d.ts +11 -53
- package/types/rtti/module.f.js +2 -0
- package/types/rtti/ts/module.f.d.ts +12 -9
- package/types/rtti/ts/module.f.js +1 -1
- package/types/rtti/validate/module.f.js +27 -17
- package/types/rtti/validate/test.f.d.ts +14 -0
- package/types/rtti/validate/test.f.js +99 -25
|
@@ -6,20 +6,20 @@ declare const _default: {
|
|
|
6
6
|
testSort?: never;
|
|
7
7
|
testIdentity?: never;
|
|
8
8
|
} | {
|
|
9
|
-
testSort: () => void;
|
|
10
|
-
testIdentity: () => void;
|
|
11
9
|
testPrimitives?: never;
|
|
12
10
|
testArray?: never;
|
|
13
11
|
testObj?: never;
|
|
12
|
+
testSort: () => void;
|
|
13
|
+
testIdentity: () => void;
|
|
14
14
|
})[];
|
|
15
15
|
stringifyAsTree: ({
|
|
16
16
|
sort: () => void;
|
|
17
17
|
identity: () => void;
|
|
18
18
|
stringify?: never;
|
|
19
19
|
} | {
|
|
20
|
-
stringify: () => void;
|
|
21
20
|
sort?: never;
|
|
22
21
|
identity?: never;
|
|
22
|
+
stringify: () => void;
|
|
23
23
|
})[];
|
|
24
24
|
};
|
|
25
25
|
export default _default;
|
package/json/module.f.js
CHANGED
|
@@ -60,7 +60,3 @@ export const serialize = sort => {
|
|
|
60
60
|
*/
|
|
61
61
|
export const stringify = sort => compose(serialize(sort))(concat);
|
|
62
62
|
export const parse = JSON.parse;
|
|
63
|
-
/*
|
|
64
|
-
export const isObject = (value: Unknown): value is Object =>
|
|
65
|
-
typeof value === 'object' && value !== null && !(value instanceof Array)
|
|
66
|
-
*/
|
package/package.json
CHANGED
package/types/rtti/module.f.d.ts
CHANGED
|
@@ -1,46 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime type information (RTTI) — a type-safe schema system for describing and
|
|
3
|
-
* converting TypeScript types.
|
|
4
|
-
*
|
|
5
|
-
* ## Core concepts
|
|
6
|
-
*
|
|
7
|
-
* A `Type` is either a `Const` (used directly as its own schema) or a `Thunk`
|
|
8
|
-
* (a zero-argument function returning an `Info` descriptor). Thunks are the
|
|
9
|
-
* primary building block: they enable lazy evaluation and recursive type definitions.
|
|
10
|
-
*
|
|
11
|
-
* ```
|
|
12
|
-
* Type = Const | Thunk
|
|
13
|
-
* Thunk = () => Info
|
|
14
|
-
* Info = ['const', Const] | Info0<Tag0> | Info1<Tag1, Type>
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* ## Nullary schemas (no type parameter)
|
|
18
|
-
*
|
|
19
|
-
* `boolean`, `number`, `string`, `bigint`, `unknown` are pre-built `Thunk` values
|
|
20
|
-
* that describe primitive types. Each is a `Type0<Tag0>` — a thunk returning a
|
|
21
|
-
* single-element tag tuple.
|
|
22
|
-
*
|
|
23
|
-
* ## Unary schemas (one type parameter)
|
|
24
|
-
*
|
|
25
|
-
* `array(t)` and `record(t)` construct `Thunk` values parameterized by an inner
|
|
26
|
-
* `Type`. They return `Type1` thunks wrapping an `Info1` tuple.
|
|
27
|
-
*
|
|
28
|
-
* ## Const schemas
|
|
29
|
-
*
|
|
30
|
-
* Any `Primitive`, `Struct` (plain object), or `Tuple` (readonly array) can be
|
|
31
|
-
* used directly as a schema — it describes exactly the shape of that value.
|
|
32
|
-
* Inside a recursive `Thunk`-based definition, wrap consts with `() => ['const', c]`
|
|
33
|
-
* to keep the schema uniform.
|
|
34
|
-
*
|
|
35
|
-
* ## Converting to TypeScript types
|
|
36
|
-
*
|
|
37
|
-
* See `./ts/module.f.ts` for `Ts<T>` and the `*Ts` transformer types.
|
|
38
|
-
*/
|
|
39
|
-
import type { Primitive } from '../../djs/module.f.ts';
|
|
40
1
|
import { type Includes } from '../array/module.f.ts';
|
|
41
|
-
export type ConstObject = Struct | Tuple;
|
|
42
2
|
/** A constant schema: a primitive literal, a struct object, or a tuple. */
|
|
43
|
-
export type Const =
|
|
3
|
+
export type Const = null | boolean | number | string | undefined | bigint | {
|
|
4
|
+
readonly [K in string]: Type;
|
|
5
|
+
} | readonly Type[];
|
|
6
|
+
export type ConstObject = Struct | Tuple;
|
|
44
7
|
/** A struct schema: plain object whose values are nested `Type`s. */
|
|
45
8
|
export type Struct = {
|
|
46
9
|
readonly [K in string]: Type;
|
|
@@ -53,18 +16,9 @@ export declare const tag0List: readonly ["bigint", "boolean", "number", "string"
|
|
|
53
16
|
/** Tags for nullary (zero-parameter) type schemas. */
|
|
54
17
|
export type Tag0 = typeof tag0List[number];
|
|
55
18
|
/** Info tuple for a nullary tag: `readonly[tag]`. */
|
|
56
|
-
export type Info0<T extends Tag0> = readonly [T];
|
|
57
|
-
/**
|
|
58
|
-
* The descriptor returned by a `Thunk`. One of:
|
|
59
|
-
* - `['const', Const]` — a constant/literal schema (used in recursive thunks)
|
|
60
|
-
* - `Info0<Tag0>` — a nullary primitive tag
|
|
61
|
-
* - `Info1<Tag1, Type>` — a unary parametric tag with an inner type
|
|
62
|
-
*/
|
|
63
|
-
export type Info = readonly ['const', Const] | Info0<Tag0> | Info1<Tag1, Type>;
|
|
64
|
-
/** A lazy schema: a zero-argument function returning an `Info` descriptor. */
|
|
65
|
-
export type Thunk = () => Info;
|
|
19
|
+
export type Info0<T extends Tag0> = T extends Tag0 ? readonly [T] : never;
|
|
66
20
|
/** Any schema: a `Const` used directly, or a `Thunk` for tag-based/recursive schemas. */
|
|
67
|
-
export type Type = Const |
|
|
21
|
+
export type Type = (() => (readonly ['const', Const] | readonly ['bigint'] | readonly ['boolean'] | readonly ['number'] | readonly ['string'] | readonly ['unknown'] | readonly ['array', Type] | readonly ['record', Type] | readonly ['or', ...readonly Type[]])) | Const;
|
|
68
22
|
/** The type of a nullary thunk for `Tag0`. */
|
|
69
23
|
type Type0<T extends Tag0> = () => Info0<T>;
|
|
70
24
|
/** Schema type for `boolean`. */
|
|
@@ -92,7 +46,7 @@ export declare const isTag1: Includes<string, typeof tag1List>;
|
|
|
92
46
|
/** Tags for unary (one-parameter) type schemas. */
|
|
93
47
|
export type Tag1 = typeof tag1List[number];
|
|
94
48
|
/** Info tuple for a unary tag: `readonly[tag, innerType]`. */
|
|
95
|
-
export type Info1<K extends Tag1, T extends Type> = readonly [K, T];
|
|
49
|
+
export type Info1<K extends Tag1, T extends Type> = K extends Tag1 ? readonly [K, T] : never;
|
|
96
50
|
/** The type of a unary thunk for `Tag1` with inner type `T`. */
|
|
97
51
|
export type Type1<K extends Tag1, T extends Type> = () => Info1<K, T>;
|
|
98
52
|
type MakeType1<K extends Tag1> = <T extends Type>(t: T) => Type1<K, T>;
|
|
@@ -104,4 +58,8 @@ export declare const array: MakeType1<'array'>;
|
|
|
104
58
|
export type Record<T extends Type> = Type1<'record', T>;
|
|
105
59
|
/** Constructs a schema that validates `{ readonly[K in string]: Ts<T> }`. */
|
|
106
60
|
export declare const record: MakeType1<'record'>;
|
|
61
|
+
/** Schema type for a union of types `T`. */
|
|
62
|
+
export type Or<T extends readonly Type[]> = () => readonly ['or', ...T];
|
|
63
|
+
/** Constructs a schema that validates a value matching any of the given schemas. */
|
|
64
|
+
export declare const or: <T extends readonly Type[]>(...types: T) => Or<T>;
|
|
107
65
|
export {};
|
package/types/rtti/module.f.js
CHANGED
|
@@ -19,3 +19,5 @@ const type1 = (key) => t => () => [key, t];
|
|
|
19
19
|
export const array = type1('array');
|
|
20
20
|
/** Constructs a schema that validates `{ readonly[K in string]: Ts<T> }`. */
|
|
21
21
|
export const record = type1('record');
|
|
22
|
+
/** Constructs a schema that validates a value matching any of the given schemas. */
|
|
23
|
+
export const or = (...types) => () => ['or', ...types];
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Tag0, Tag1,
|
|
1
|
+
import type { Unknown as DjsUnknown } from '../../../djs/module.f.ts';
|
|
2
|
+
import type { Tag0, Tag1, Struct, Tuple, Type } from '../module.f.ts';
|
|
3
3
|
import type { ReadonlyRecord } from '../../object/module.f.ts';
|
|
4
4
|
/** Maps a `Tag0` to its TypeScript type. */
|
|
5
5
|
export type Info0Ts<T extends Tag0> = T extends 'boolean' ? boolean : T extends 'number' ? number : T extends 'string' ? string : T extends 'bigint' ? bigint : T extends 'unknown' ? DjsUnknown : never;
|
|
6
6
|
/** Maps a `Const` schema to its TypeScript type. */
|
|
7
|
-
export type ConstTs<T
|
|
7
|
+
export type ConstTs<T> = T extends readonly Type[] ? TupleTs<T> : T extends {
|
|
8
|
+
readonly [k in string]: Type;
|
|
9
|
+
} ? {
|
|
10
|
+
readonly [K in keyof T]: Ts<T[K]>;
|
|
11
|
+
} : T;
|
|
8
12
|
/** Maps a `Tag1` and inner type to its TypeScript type. */
|
|
9
13
|
export type Info1Ts<K extends Tag1, T extends Type> = K extends 'array' ? ArrayTs<T> : K extends 'record' ? RecordTs<T> : never;
|
|
10
|
-
/** Maps an `Info` descriptor to its TypeScript type. */
|
|
11
|
-
export type InfoTs<T extends Info> = T extends readonly ['const', infer C extends Const] ? ConstTs<C> : T extends Info0<infer K extends Tag0> ? Info0Ts<K> : T extends Info1<infer K extends Tag1, infer I extends Type> ? Info1Ts<K, I> : never;
|
|
12
14
|
/** Maps an array schema `T` to `readonly Ts<T>[]`. */
|
|
13
15
|
export type ArrayTs<T extends Type> = ReadonlyArray<Ts<T>>;
|
|
14
16
|
/** Maps a record schema `T` to `{ readonly[K in string]: Ts<T> }`. */
|
|
15
17
|
export type RecordTs<T extends Type> = ReadonlyRecord<string, Ts<T>>;
|
|
16
|
-
|
|
18
|
+
/** Maps a tuple schema to a readonly tuple of resolved types. */
|
|
19
|
+
export type TupleTs<T extends Tuple> = {
|
|
17
20
|
readonly [K in keyof T]: Ts<T[K]>;
|
|
18
21
|
};
|
|
19
|
-
/** Maps a tuple schema to a readonly tuple of resolved types. */
|
|
20
|
-
export type TupleTs<T extends Tuple> = ClosedTupleTs<T>;
|
|
21
22
|
/** Maps a struct schema to a readonly object of resolved types. */
|
|
22
23
|
export type StructTs<T extends Struct> = {
|
|
23
24
|
readonly [K in keyof T]: Ts<T[K]>;
|
|
@@ -36,4 +37,6 @@ export type StructTs<T extends Struct> = {
|
|
|
36
37
|
* type D = Ts<{ x: typeof boolean }> // { readonly x: boolean }
|
|
37
38
|
* ```
|
|
38
39
|
*/
|
|
39
|
-
export type Ts<T extends Type> = T extends () =>
|
|
40
|
+
export type Ts<T extends Type> = T extends () => infer I ? (I extends readonly ['const', infer C] ? ConstTs<C> : I extends readonly ['boolean'] ? boolean : I extends readonly ['number'] ? number : I extends readonly ['string'] ? string : I extends readonly ['bigint'] ? bigint : I extends readonly ['unknown'] ? DjsUnknown : I extends readonly ['array', infer E extends Type] ? readonly Ts<E>[] : I extends readonly ['record', infer E extends Type] ? {
|
|
41
|
+
readonly [K in string]: Ts<E>;
|
|
42
|
+
} : I extends readonly ['or', ...infer A extends readonly Type[]] ? Ts<A[number]> : never) : ConstTs<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
@@ -3,6 +3,7 @@ import { error, ok } from "../../result/module.f.js";
|
|
|
3
3
|
import { isArray as commonIsArray } from "../../array/module.f.js";
|
|
4
4
|
import { isObject as commonIsObject } from "../../object/module.f.js";
|
|
5
5
|
import { identity } from "../../function/module.f.js";
|
|
6
|
+
import { todo } from "../../../dev/module.f.js";
|
|
6
7
|
/**
|
|
7
8
|
* Builds a validator for `array` or `record` schemas.
|
|
8
9
|
* The inner item validator is instantiated lazily (only when the container is
|
|
@@ -36,20 +37,6 @@ const tag1Validate = ([tag, item]) => tag === 'array'
|
|
|
36
37
|
: recordValidate(item);
|
|
37
38
|
/** Validates a `Tag0` primitive schema using `typeof`. */
|
|
38
39
|
const primitive0Validate = (tag) => value => typeof value === tag ? ok(value) : error('unexpected value');
|
|
39
|
-
/** Validates a `Thunk` schema by evaluating it once and dispatching on the resulting `Info` tag. */
|
|
40
|
-
const thunkValidate = (rtti) => {
|
|
41
|
-
const info = rtti();
|
|
42
|
-
const [tag, value] = info;
|
|
43
|
-
switch (tag) {
|
|
44
|
-
case 'const':
|
|
45
|
-
return constValidate(value);
|
|
46
|
-
case 'unknown':
|
|
47
|
-
return ok;
|
|
48
|
-
}
|
|
49
|
-
return isTag1(tag)
|
|
50
|
-
? tag1Validate(info)
|
|
51
|
-
: primitive0Validate(tag);
|
|
52
|
-
};
|
|
53
40
|
/**
|
|
54
41
|
* Builds a validator for `Tuple` or `Struct` const schemas.
|
|
55
42
|
* Iterates over the schema's entries and validates each corresponding
|
|
@@ -80,6 +67,18 @@ const constPrimitiveValidate = (rtti) => value => rtti === value
|
|
|
80
67
|
const constValidate = (rtti) => typeof rtti === 'object' && rtti !== null
|
|
81
68
|
? constObjectValidate(rtti)
|
|
82
69
|
: constPrimitiveValidate(rtti);
|
|
70
|
+
const orValidate = (rtti) => {
|
|
71
|
+
const all = rtti.map(r => validate(r));
|
|
72
|
+
return value => {
|
|
73
|
+
for (const i of all) {
|
|
74
|
+
const r = i(value);
|
|
75
|
+
if (r[0] === 'ok') {
|
|
76
|
+
return r;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return error('no match');
|
|
80
|
+
};
|
|
81
|
+
};
|
|
83
82
|
/**
|
|
84
83
|
* Creates a validator function for the given RTTI schema.
|
|
85
84
|
*
|
|
@@ -95,6 +94,17 @@ const constValidate = (rtti) => typeof rtti === 'object' && rtti !== null
|
|
|
95
94
|
* v(['a', 'b']) // ['error', 'unexpected value']
|
|
96
95
|
* ```
|
|
97
96
|
*/
|
|
98
|
-
export const validate = (rtti) =>
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
export const validate = (rtti) => {
|
|
98
|
+
if (typeof rtti === 'function') {
|
|
99
|
+
const [tag, ...value] = rtti();
|
|
100
|
+
switch (tag) {
|
|
101
|
+
case 'const': return constValidate(value[0]);
|
|
102
|
+
case 'array': return arrayValidate(value[0]);
|
|
103
|
+
case 'record': return recordValidate(value[0]);
|
|
104
|
+
case 'unknown': return ok;
|
|
105
|
+
case 'or': return orValidate(value);
|
|
106
|
+
}
|
|
107
|
+
return primitive0Validate(tag);
|
|
108
|
+
}
|
|
109
|
+
return constValidate(rtti);
|
|
110
|
+
};
|
|
@@ -68,6 +68,20 @@ declare const _default: {
|
|
|
68
68
|
constThunk: {
|
|
69
69
|
primitive: () => void;
|
|
70
70
|
};
|
|
71
|
+
or: {
|
|
72
|
+
consts: {
|
|
73
|
+
ok: () => void;
|
|
74
|
+
error: () => void;
|
|
75
|
+
};
|
|
76
|
+
thunks: {
|
|
77
|
+
ok: () => void;
|
|
78
|
+
error: () => void;
|
|
79
|
+
};
|
|
80
|
+
mixed: {
|
|
81
|
+
ok: () => void;
|
|
82
|
+
error: () => void;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
71
85
|
recursive: {
|
|
72
86
|
arrayOfArrays: () => void;
|
|
73
87
|
recordOfRecords: () => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validate } from "./module.f.js";
|
|
2
|
-
import { boolean, number, string, bigint, unknown, array, record } from "../module.f.js";
|
|
2
|
+
import { boolean, number, string, bigint, unknown, array, record, or } from "../module.f.js";
|
|
3
3
|
const assertOk = ([k]) => { if (k !== 'ok') {
|
|
4
4
|
throw 'expected ok';
|
|
5
5
|
} };
|
|
@@ -19,21 +19,27 @@ export default {
|
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
21
|
number: {
|
|
22
|
-
ok: () =>
|
|
22
|
+
ok: () => {
|
|
23
|
+
assertOk(validate(number)(42));
|
|
24
|
+
},
|
|
23
25
|
error: () => {
|
|
24
26
|
assertError(validate(number)('42'));
|
|
25
27
|
assertError(validate(number)(42n));
|
|
26
28
|
},
|
|
27
29
|
},
|
|
28
30
|
string: {
|
|
29
|
-
ok: () =>
|
|
31
|
+
ok: () => {
|
|
32
|
+
assertOk(validate(string)('hello'));
|
|
33
|
+
},
|
|
30
34
|
error: () => {
|
|
31
35
|
assertError(validate(string)(42));
|
|
32
36
|
assertError(validate(string)(null));
|
|
33
37
|
},
|
|
34
38
|
},
|
|
35
39
|
bigint: {
|
|
36
|
-
ok: () =>
|
|
40
|
+
ok: () => {
|
|
41
|
+
assertOk(validate(bigint)(4n));
|
|
42
|
+
},
|
|
37
43
|
error: () => {
|
|
38
44
|
assertError(validate(bigint)(4));
|
|
39
45
|
assertError(validate(bigint)('4'));
|
|
@@ -51,34 +57,49 @@ export default {
|
|
|
51
57
|
},
|
|
52
58
|
const: {
|
|
53
59
|
null: {
|
|
54
|
-
ok: () =>
|
|
60
|
+
ok: () => {
|
|
61
|
+
assertOk(validate(null)(null));
|
|
62
|
+
},
|
|
55
63
|
error: () => {
|
|
56
64
|
assertError(validate(null)(undefined));
|
|
57
65
|
assertError(validate(null)(0));
|
|
58
66
|
},
|
|
59
67
|
},
|
|
60
68
|
undefined: {
|
|
61
|
-
ok: () =>
|
|
69
|
+
ok: () => {
|
|
70
|
+
assertOk(validate(undefined)(undefined));
|
|
71
|
+
},
|
|
62
72
|
error: () => assertError(validate(undefined)(null)),
|
|
63
73
|
},
|
|
64
74
|
number: {
|
|
65
|
-
ok: () =>
|
|
75
|
+
ok: () => {
|
|
76
|
+
assertOk(validate(42)(42));
|
|
77
|
+
},
|
|
66
78
|
error: () => assertError(validate(42)(43)),
|
|
67
79
|
},
|
|
68
80
|
string: {
|
|
69
|
-
ok: () =>
|
|
81
|
+
ok: () => {
|
|
82
|
+
assertOk(validate('hello')('hello'));
|
|
83
|
+
},
|
|
70
84
|
error: () => assertError(validate('hello')('world')),
|
|
71
85
|
},
|
|
72
86
|
bigint: {
|
|
73
|
-
ok: () =>
|
|
87
|
+
ok: () => {
|
|
88
|
+
assertOk(validate(7n)(7n));
|
|
89
|
+
},
|
|
74
90
|
error: () => assertError(validate(7n)(8n)),
|
|
75
91
|
},
|
|
76
92
|
boolean: {
|
|
77
|
-
ok: () =>
|
|
93
|
+
ok: () => {
|
|
94
|
+
assertOk(validate(true)(true));
|
|
95
|
+
},
|
|
78
96
|
error: () => assertError(validate(true)(false)),
|
|
79
97
|
},
|
|
80
98
|
tuple: {
|
|
81
|
-
ok: () =>
|
|
99
|
+
ok: () => {
|
|
100
|
+
const t = [42, 'hello'];
|
|
101
|
+
assertOk(validate(t)([42, 'hello']));
|
|
102
|
+
},
|
|
82
103
|
extraItems: () => assertOk(validate([42])([42, 'extra'])),
|
|
83
104
|
error: () => {
|
|
84
105
|
assertError(validate([42])([99]));
|
|
@@ -86,7 +107,10 @@ export default {
|
|
|
86
107
|
},
|
|
87
108
|
},
|
|
88
109
|
struct: {
|
|
89
|
-
ok: () =>
|
|
110
|
+
ok: () => {
|
|
111
|
+
const t = { a: 42, b: 'hello' };
|
|
112
|
+
assertOk(validate(t)({ a: 42, b: 'hello' }));
|
|
113
|
+
},
|
|
90
114
|
extraKeys: () => assertOk(validate({ a: 42 })({ a: 42, b: 'extra' })),
|
|
91
115
|
error: () => {
|
|
92
116
|
assertError(validate({ a: 42 })({ a: 99 }));
|
|
@@ -96,20 +120,27 @@ export default {
|
|
|
96
120
|
},
|
|
97
121
|
array: {
|
|
98
122
|
empty: () => assertOk(validate(array(number))([])),
|
|
99
|
-
ok: () =>
|
|
123
|
+
ok: () => {
|
|
124
|
+
const t = array(number);
|
|
125
|
+
assertOk(validate(array(number))([1, 2, 3]));
|
|
126
|
+
},
|
|
100
127
|
error: () => {
|
|
101
128
|
assertError(validate(array(number))([1, 'two', 3]));
|
|
102
129
|
assertError(validate(array(number))({}));
|
|
103
130
|
assertError(validate(array(number))(null));
|
|
104
131
|
},
|
|
105
132
|
nested: () => {
|
|
133
|
+
const t = array(array(boolean));
|
|
106
134
|
assertOk(validate(array(array(boolean)))([[true, false], [false]]));
|
|
107
135
|
assertError(validate(array(array(boolean)))([[true, 42]]));
|
|
108
136
|
},
|
|
109
137
|
},
|
|
110
138
|
record: {
|
|
111
139
|
empty: () => assertOk(validate(record(number))({})),
|
|
112
|
-
ok: () =>
|
|
140
|
+
ok: () => {
|
|
141
|
+
const t = record(string);
|
|
142
|
+
assertOk(validate(t)({ a: 'hello', b: 'world' }));
|
|
143
|
+
},
|
|
113
144
|
error: () => {
|
|
114
145
|
assertError(validate(record(number))({ a: 1, b: 'two' }));
|
|
115
146
|
assertError(validate(record(number))(null));
|
|
@@ -118,26 +149,69 @@ export default {
|
|
|
118
149
|
},
|
|
119
150
|
constThunk: {
|
|
120
151
|
primitive: () => {
|
|
121
|
-
|
|
122
|
-
|
|
152
|
+
const t = () => ['const', 7n];
|
|
153
|
+
assertOk(validate(t)(7n));
|
|
154
|
+
assertError(validate(t)(8n));
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
or: {
|
|
158
|
+
consts: {
|
|
159
|
+
ok: () => {
|
|
160
|
+
const t = or(...[false, 42, 'hello']);
|
|
161
|
+
assertOk(validate(t)(false));
|
|
162
|
+
assertOk(validate(t)(42));
|
|
163
|
+
assertOk(validate(t)('hello'));
|
|
164
|
+
},
|
|
165
|
+
error: () => {
|
|
166
|
+
const t = or(...[false, 42, 'hello']);
|
|
167
|
+
assertError(validate(t)(true));
|
|
168
|
+
assertError(validate(t)(43));
|
|
169
|
+
assertError(validate(t)('world'));
|
|
170
|
+
assertError(validate(t)(null));
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
thunks: {
|
|
174
|
+
ok: () => {
|
|
175
|
+
const t = or(number, string);
|
|
176
|
+
assertOk(validate(t)(42));
|
|
177
|
+
assertOk(validate(t)('hello'));
|
|
178
|
+
},
|
|
179
|
+
error: () => {
|
|
180
|
+
const t = or(number, string);
|
|
181
|
+
assertError(validate(t)(true));
|
|
182
|
+
assertError(validate(t)(null));
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
mixed: {
|
|
186
|
+
ok: () => {
|
|
187
|
+
const t = or(42, string);
|
|
188
|
+
assertOk(validate(t)(42));
|
|
189
|
+
assertOk(validate(t)('hello'));
|
|
190
|
+
},
|
|
191
|
+
error: () => {
|
|
192
|
+
const t = or(42, string);
|
|
193
|
+
assertError(validate(t)(43));
|
|
194
|
+
assertError(validate(t)(null));
|
|
195
|
+
},
|
|
123
196
|
},
|
|
124
197
|
},
|
|
125
198
|
recursive: {
|
|
126
199
|
arrayOfArrays: () => {
|
|
127
200
|
// self-referential schema: an array whose elements are also arrays of the same type
|
|
128
201
|
const list = () => ['array', list];
|
|
129
|
-
|
|
130
|
-
assertOk(
|
|
131
|
-
assertOk(
|
|
132
|
-
assertOk(
|
|
133
|
-
assertError(
|
|
134
|
-
assertError(
|
|
202
|
+
const v = validate(list);
|
|
203
|
+
assertOk(v([]));
|
|
204
|
+
assertOk(v([[], []]));
|
|
205
|
+
assertOk(v([[[], []], []]));
|
|
206
|
+
assertError(v([42]));
|
|
207
|
+
assertError(v(null));
|
|
135
208
|
},
|
|
136
209
|
recordOfRecords: () => {
|
|
137
210
|
const tree = () => ['record', tree];
|
|
138
|
-
|
|
139
|
-
assertOk(
|
|
140
|
-
|
|
211
|
+
const v = validate(tree);
|
|
212
|
+
assertOk(v({}));
|
|
213
|
+
assertOk(v({ a: {}, b: { c: {} } }));
|
|
214
|
+
assertError(v({ a: 42 }));
|
|
141
215
|
},
|
|
142
216
|
},
|
|
143
217
|
};
|