functionalscript 0.11.10 → 0.12.0

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/html/module.f.js CHANGED
@@ -2,6 +2,7 @@ import { map, flatMap, flat, concat as listConcat } from "../types/list/module.f
2
2
  import { concat, concat as stringConcat } from "../types/string/module.f.js";
3
3
  import { compose } from "../types/function/module.f.js";
4
4
  import { stringToList } from "../text/utf16/module.f.js";
5
+ import { includes } from "../types/array/module.f.js";
5
6
  const { fromCharCode } = String;
6
7
  const { entries } = Object;
7
8
  /**
@@ -62,6 +63,8 @@ const parseElement = (e) => {
62
63
  [tag, item1, list] :
63
64
  [tag, {}, [item1, ...list]];
64
65
  };
66
+ const isVoidTag = includes(voidTagList);
67
+ const isRawText = includes(rawText);
65
68
  /**
66
69
  * Converts a FunctionalScript element into a list of HTML string chunks.
67
70
  *
@@ -71,10 +74,10 @@ const parseElement = (e) => {
71
74
  export const element = (e) => {
72
75
  const [tag, a, n] = parseElement(e);
73
76
  const open = flat([[`<`, tag], attributes(a), [`>`]]);
74
- if (voidTagList.includes(tag)) {
77
+ if (isVoidTag(tag)) {
75
78
  return open;
76
79
  }
77
- return flat([open, rawText.includes(tag) ? [rawMap(n)] : nodes(n), ['</', tag, '>']]);
80
+ return flat([open, isRawText(tag) ? [rawMap(n)] : nodes(n), ['</', tag, '>']]);
78
81
  };
79
82
  /**
80
83
  * Builds a complete HTML document by prepending `<!DOCTYPE html>`.
@@ -17,5 +17,4 @@ export declare const serialize: (mapEntries: MapEntries) => (value: Unknown) =>
17
17
  */
18
18
  export declare const stringify: (mapEntries: MapEntries) => (value: Unknown) => string;
19
19
  export declare const parse: (value: string) => Unknown;
20
- export declare const isObject: (value: Unknown) => value is Object;
21
20
  export {};
package/json/module.f.js CHANGED
@@ -60,4 +60,7 @@ export const serialize = sort => {
60
60
  */
61
61
  export const stringify = sort => compose(serialize(sort))(concat);
62
62
  export const parse = JSON.parse;
63
- export const isObject = (value) => typeof value === 'object' && value !== null && !(value instanceof Array);
63
+ /*
64
+ export const isObject = (value: Unknown): value is Object =>
65
+ typeof value === 'object' && value !== null && !(value instanceof Array)
66
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.11.10",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * @module
5
5
  */
6
+ export declare const isArray: (value: unknown) => value is readonly unknown[];
6
7
  export type Array1<T> = readonly [T];
7
8
  export type Index1 = 0;
8
9
  export type Array2<T> = readonly [T, T];
@@ -37,3 +38,5 @@ export declare const splitLast: <T>(a: readonly T[]) => readonly [readonly T[],
37
38
  * we may minimize memory a number of memory allocations.
38
39
  */
39
40
  export declare const empty: readonly [];
41
+ export type Includes<I, T extends readonly I[]> = (v: I) => v is T[number];
42
+ export declare const includes: <I, T extends readonly I[]>(a: T) => (v: I) => v is T[number];
@@ -4,6 +4,7 @@
4
4
  * @module
5
5
  */
6
6
  import { map } from "../nullable/module.f.js";
7
+ export const isArray = (value) => value instanceof Array;
7
8
  export const isArray2 = (a) => a.length === 2;
8
9
  const uncheckTail = (a) => a.slice(1);
9
10
  const uncheckHead = (a) => a.slice(0, -1);
@@ -34,3 +35,4 @@ export const splitLast = (a) => {
34
35
  * we may minimize memory a number of memory allocations.
35
36
  */
36
37
  export const empty = [];
38
+ export const includes = (a) => (v) => a.includes(v);
@@ -15,7 +15,7 @@ export declare const fromMap: <T>(m: OrderedMap<T>) => Map<T>;
15
15
  * https://stackoverflow.com/questions/57571664/typescript-type-for-an-object-with-only-one-key-no-union-type-allowed-as-a-key
16
16
  */
17
17
  export type OneKey<K extends string, V> = {
18
- [P in K]: (Record<P, V> & Partial<Record<Exclude<K, P>, never>>) extends infer O ? {
18
+ [P in K]: (ReadonlyRecord<P, V> & Partial<ReadonlyRecord<Exclude<K, P>, never>>) extends infer O ? {
19
19
  [Q in keyof O]: O[Q];
20
20
  } : never;
21
21
  }[K];
@@ -25,4 +25,8 @@ export type OneKey<K extends string, V> = {
25
25
  export type NotUnion<T, U = T> = T extends unknown ? [
26
26
  U
27
27
  ] extends [T] ? T : never : never;
28
- export type SingleProperty<T extends Record<string, never>> = keyof T extends NotUnion<keyof T> ? T : never;
28
+ export type SingleProperty<T extends ReadonlyRecord<string, never>> = keyof T extends NotUnion<keyof T> ? T : never;
29
+ export declare const isObject: (value: unknown) => value is { readonly [k in string]: unknown; };
30
+ export type ReadonlyRecord<S extends string, T> = {
31
+ readonly [K in S]: T;
32
+ };
@@ -1,3 +1,4 @@
1
+ import { isArray } from "../array/module.f.js";
1
2
  import { iterable } from "../list/module.f.js";
2
3
  import { entries as mapEntries, fromEntries as mapFromEntries } from "../ordered_map/module.f.js";
3
4
  const { getOwnPropertyDescriptor, fromEntries: objectFromEntries } = Object;
@@ -8,3 +9,4 @@ export const at = name => object => {
8
9
  export const sort = e => mapEntries(mapFromEntries(e));
9
10
  export const fromEntries = e => objectFromEntries(iterable(e));
10
11
  export const fromMap = m => fromEntries(mapEntries(m));
12
+ export const isObject = (value) => typeof value === 'object' && !isArray(value) && value !== null;
@@ -0,0 +1,107 @@
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
+ import { type Includes } from '../array/module.f.ts';
41
+ export type ConstObject = Struct | Tuple;
42
+ /** A constant schema: a primitive literal, a struct object, or a tuple. */
43
+ export type Const = Primitive | ConstObject;
44
+ /** A struct schema: plain object whose values are nested `Type`s. */
45
+ export type Struct = {
46
+ readonly [K in string]: Type;
47
+ };
48
+ /** A tuple schema: readonly array whose elements are nested `Type`s. */
49
+ export type Tuple = readonly Type[];
50
+ declare const primitive0List: readonly ["bigint", "boolean", "number", "string"];
51
+ export type Primitive0 = typeof primitive0List[number];
52
+ export declare const tag0List: readonly ["bigint", "boolean", "number", "string", "unknown"];
53
+ /** Tags for nullary (zero-parameter) type schemas. */
54
+ export type Tag0 = typeof tag0List[number];
55
+ /** 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;
66
+ /** Any schema: a `Const` used directly, or a `Thunk` for tag-based/recursive schemas. */
67
+ export type Type = Const | Thunk;
68
+ /** The type of a nullary thunk for `Tag0`. */
69
+ type Type0<T extends Tag0> = () => Info0<T>;
70
+ /** Schema type for `boolean`. */
71
+ export type Boolean = Type0<'boolean'>;
72
+ /** Schema that validates `boolean` values. */
73
+ export declare const boolean: Boolean;
74
+ /** Schema type for `number`. */
75
+ export type Number = Type0<'number'>;
76
+ /** Schema that validates `number` values. */
77
+ export declare const number: Number;
78
+ /** Schema type for `string`. */
79
+ export type String = Type0<'string'>;
80
+ /** Schema that validates `string` values. */
81
+ export declare const string: String;
82
+ /** Schema type for `bigint`. */
83
+ export type Bigint = Type0<'bigint'>;
84
+ /** Schema that validates `bigint` values. */
85
+ export declare const bigint: Bigint;
86
+ /** Schema type for any DJS value (`Primitive | UnknownRecord | UnknownArray`). */
87
+ export type Unknown = Type0<'unknown'>;
88
+ /** Schema that validates any DJS-compatible value. */
89
+ export declare const unknown: Unknown;
90
+ declare const tag1List: readonly ["array", "record"];
91
+ export declare const isTag1: Includes<string, typeof tag1List>;
92
+ /** Tags for unary (one-parameter) type schemas. */
93
+ export type Tag1 = typeof tag1List[number];
94
+ /** Info tuple for a unary tag: `readonly[tag, innerType]`. */
95
+ export type Info1<K extends Tag1, T extends Type> = readonly [K, T];
96
+ /** The type of a unary thunk for `Tag1` with inner type `T`. */
97
+ export type Type1<K extends Tag1, T extends Type> = () => Info1<K, T>;
98
+ type MakeType1<K extends Tag1> = <T extends Type>(t: T) => Type1<K, T>;
99
+ /** Schema type for a readonly array with element type `T`. */
100
+ export type Array<T extends Type> = Type1<'array', T>;
101
+ /** Constructs a schema that validates `readonly Ts<T>[]`. */
102
+ export declare const array: MakeType1<'array'>;
103
+ /** Schema type for a record (index signature) with value type `T`. */
104
+ export type Record<T extends Type> = Type1<'record', T>;
105
+ /** Constructs a schema that validates `{ readonly[K in string]: Ts<T> }`. */
106
+ export declare const record: MakeType1<'record'>;
107
+ export {};
@@ -0,0 +1,21 @@
1
+ import { includes } from "../array/module.f.js";
2
+ const primitive0List = ['bigint', 'boolean', 'number', 'string'];
3
+ export const tag0List = [...primitive0List, 'unknown'];
4
+ const type0 = (tag) => () => [tag];
5
+ /** Schema that validates `boolean` values. */
6
+ export const boolean = type0('boolean');
7
+ /** Schema that validates `number` values. */
8
+ export const number = type0('number');
9
+ /** Schema that validates `string` values. */
10
+ export const string = type0('string');
11
+ /** Schema that validates `bigint` values. */
12
+ export const bigint = type0('bigint');
13
+ /** Schema that validates any DJS-compatible value. */
14
+ export const unknown = type0('unknown');
15
+ const tag1List = ['array', 'record'];
16
+ export const isTag1 = includes(tag1List);
17
+ const type1 = (key) => t => () => [key, t];
18
+ /** Constructs a schema that validates `readonly Ts<T>[]`. */
19
+ export const array = type1('array');
20
+ /** Constructs a schema that validates `{ readonly[K in string]: Ts<T> }`. */
21
+ export const record = type1('record');
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ typeof: {
3
+ [k: string]: (() => void)[];
4
+ };
5
+ };
6
+ export default _default;
@@ -0,0 +1,22 @@
1
+ const tests = {
2
+ undefined: [undefined],
3
+ boolean: [true, false],
4
+ string: ['hello'],
5
+ number: [3],
6
+ bigint: [4n],
7
+ object: [null, {}, []],
8
+ function: [() => undefined]
9
+ };
10
+ const assertOk = ([k]) => { if (k !== 'ok') {
11
+ throw 'expected ok';
12
+ } };
13
+ const assertError = ([k]) => { if (k !== 'error') {
14
+ throw 'expected error';
15
+ } };
16
+ export default {
17
+ typeof: Object.fromEntries(Object.entries(tests).map(([k, a]) => [k, a.map(v => () => {
18
+ if (typeof v !== k) {
19
+ throw `typeof ${v} !== ${k}`;
20
+ }
21
+ })])),
22
+ };
@@ -0,0 +1,39 @@
1
+ import type { Primitive, Unknown as DjsUnknown } from '../../../djs/module.f.ts';
2
+ import type { Tag0, Tag1, Const, Struct, Tuple, Info0, Info1, Info, Type } from '../module.f.ts';
3
+ import type { ReadonlyRecord } from '../../object/module.f.ts';
4
+ /** Maps a `Tag0` to its TypeScript type. */
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
+ /** Maps a `Const` schema to its TypeScript type. */
7
+ export type ConstTs<T extends Const> = T extends Primitive ? T : T extends Tuple ? TupleTs<T> : T extends Struct ? StructTs<T> : never;
8
+ /** Maps a `Tag1` and inner type to its TypeScript type. */
9
+ 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
+ /** Maps an array schema `T` to `readonly Ts<T>[]`. */
13
+ export type ArrayTs<T extends Type> = ReadonlyArray<Ts<T>>;
14
+ /** Maps a record schema `T` to `{ readonly[K in string]: Ts<T> }`. */
15
+ export type RecordTs<T extends Type> = ReadonlyRecord<string, Ts<T>>;
16
+ export type ClosedTupleTs<T extends Tuple> = {
17
+ readonly [K in keyof T]: Ts<T[K]>;
18
+ };
19
+ /** Maps a tuple schema to a readonly tuple of resolved types. */
20
+ export type TupleTs<T extends Tuple> = ClosedTupleTs<T>;
21
+ /** Maps a struct schema to a readonly object of resolved types. */
22
+ export type StructTs<T extends Struct> = {
23
+ readonly [K in keyof T]: Ts<T[K]>;
24
+ };
25
+ /**
26
+ * Converts a schema `Type` to its corresponding TypeScript type.
27
+ *
28
+ * - `Thunk` → evaluates the returned `Info` via `InfoTs`
29
+ * - `Const` → resolves via `ConstTs` (primitives map to themselves; structs/tuples recurse)
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * type A = Ts<typeof string> // string
34
+ * type B = Ts<4> // 4
35
+ * type C = Ts<Array<typeof number>> // readonly number[]
36
+ * type D = Ts<{ x: typeof boolean }> // { readonly x: boolean }
37
+ * ```
38
+ */
39
+ export type Ts<T extends Type> = T extends () => (infer I extends Info) ? InfoTs<I> : T extends Const ? ConstTs<T> : never;
@@ -0,0 +1 @@
1
+ import { string, unknown } from "../module.f.js";
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Runtime validation of unknown values against RTTI schemas.
3
+ *
4
+ * The main entry point is `validate(rtti)`, which takes a schema `Type` and returns
5
+ * a `Validate<T>` function. When called with an unknown value, it returns a `Result`
6
+ * that is either `['ok', typedValue]` or `['error', message]`.
7
+ *
8
+ * ## Dispatch strategy
9
+ *
10
+ * - **`Thunk`** schemas are evaluated lazily: the thunk is called once to obtain an
11
+ * `Info` descriptor, then dispatched by tag:
12
+ * - `'const'` — delegates to `constValidate`
13
+ * - `'unknown'` — always succeeds (any DJS value is valid)
14
+ * - `Tag1` (`'array'`, `'record'`) — delegates to `containerValidate`
15
+ * - `Tag0` (`'boolean'`, `'number'`, `'string'`, `'bigint'`) — uses `typeof` check
16
+ * - **`Const`** schemas (primitives, tuples, structs) validate by exact equality or
17
+ * recursive field/element checking.
18
+ *
19
+ * ## Recursion safety
20
+ *
21
+ * For `array` and `record` schemas, the inner item validator is instantiated lazily —
22
+ * only after confirming the container is non-empty. This prevents infinite recursion
23
+ * when validating recursive schemas like `const list = () => ['array', list]`.
24
+ *
25
+ * @module
26
+ */
27
+ import type { Unknown } from '../../../djs/module.f.ts';
28
+ import { type Type } from '../module.f.ts';
29
+ import { type Result as CommonResult } from '../../result/module.f.ts';
30
+ import type { Ts } from '../ts/module.f.ts';
31
+ /** Validation result: either the typed value or an error message. */
32
+ export type Result<T extends Type> = CommonResult<Ts<T>, string>;
33
+ /** A function that validates an unknown value against schema `T`. */
34
+ export type Validate<T extends Type> = (value: Unknown) => Result<T>;
35
+ /**
36
+ * Creates a validator function for the given RTTI schema.
37
+ *
38
+ * @param rtti - A schema `Type`: a `Thunk` for tag-based schemas, or a `Const`
39
+ * (primitive literal, tuple, or struct) for exact-value schemas.
40
+ * @returns A `Validate<T>` function that checks an unknown value and returns
41
+ * `['ok', value]` or `['error', message]`.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const v = validate(array(number))
46
+ * v([1, 2, 3]) // ['ok', [1, 2, 3]]
47
+ * v(['a', 'b']) // ['error', 'unexpected value']
48
+ * ```
49
+ */
50
+ export declare const validate: <T extends Type>(rtti: T) => Validate<T>;
@@ -0,0 +1,100 @@
1
+ import { isTag1 } from "../module.f.js";
2
+ import { error, ok } from "../../result/module.f.js";
3
+ import { isArray as commonIsArray } from "../../array/module.f.js";
4
+ import { isObject as commonIsObject } from "../../object/module.f.js";
5
+ import { identity } from "../../function/module.f.js";
6
+ /**
7
+ * Builds a validator for `array` or `record` schemas.
8
+ * The inner item validator is instantiated lazily (only when the container is
9
+ * non-empty) to avoid infinite recursion with recursive schemas.
10
+ */
11
+ const containerValidate = (isContainer, getItems) => (item) => value => {
12
+ if (!isContainer(value)) {
13
+ return error('unexpected value');
14
+ }
15
+ const items = getItems(value);
16
+ if (items.length === 0) {
17
+ return ok(value);
18
+ }
19
+ // Note: we shouldn't instantiate `itemValidate` until we make sure `items` is not empty.
20
+ // Otherwise, we can get infinite recursion on empty arrays and objects
21
+ const itemValidate = validate(item);
22
+ for (const i of items) {
23
+ const r = itemValidate(i);
24
+ if (r[0] === 'error') {
25
+ return r;
26
+ }
27
+ }
28
+ return ok(value);
29
+ };
30
+ const isArray = value => commonIsArray(value);
31
+ const arrayValidate = containerValidate(isArray, identity);
32
+ const isObject = value => commonIsObject(value);
33
+ const recordValidate = containerValidate(isObject, Object.values);
34
+ const tag1Validate = ([tag, item]) => tag === 'array'
35
+ ? arrayValidate(item)
36
+ : recordValidate(item);
37
+ /** Validates a `Tag0` primitive schema using `typeof`. */
38
+ 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
+ /**
54
+ * Builds a validator for `Tuple` or `Struct` const schemas.
55
+ * Iterates over the schema's entries and validates each corresponding
56
+ * element/property of the value.
57
+ */
58
+ const constContainerValidate = (isContainer, getItem) => (rtti) => value => {
59
+ if (!isContainer(value)) {
60
+ return error('unexpected value');
61
+ }
62
+ for (const [k, v] of Object.entries(rtti)) {
63
+ const item = getItem(value, k);
64
+ const r = validate(v)(item);
65
+ if (r[0] === 'error') {
66
+ return r;
67
+ }
68
+ }
69
+ return ok(value);
70
+ };
71
+ const tupleValidate = constContainerValidate(isArray, (value, k) => value[Number(k)]);
72
+ const structValidate = constContainerValidate(isObject, (value, k) => value[k]);
73
+ const constObjectValidate = (rtti) => commonIsArray(rtti)
74
+ ? tupleValidate(rtti)
75
+ : structValidate(rtti);
76
+ /** Validates a primitive `Const` schema using strict equality (`===`). */
77
+ const constPrimitiveValidate = (rtti) => value => rtti === value
78
+ ? ok(value)
79
+ : error('unexpected value');
80
+ const constValidate = (rtti) => typeof rtti === 'object' && rtti !== null
81
+ ? constObjectValidate(rtti)
82
+ : constPrimitiveValidate(rtti);
83
+ /**
84
+ * Creates a validator function for the given RTTI schema.
85
+ *
86
+ * @param rtti - A schema `Type`: a `Thunk` for tag-based schemas, or a `Const`
87
+ * (primitive literal, tuple, or struct) for exact-value schemas.
88
+ * @returns A `Validate<T>` function that checks an unknown value and returns
89
+ * `['ok', value]` or `['error', message]`.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const v = validate(array(number))
94
+ * v([1, 2, 3]) // ['ok', [1, 2, 3]]
95
+ * v(['a', 'b']) // ['error', 'unexpected value']
96
+ * ```
97
+ */
98
+ export const validate = (rtti) => typeof rtti === 'function'
99
+ ? thunkValidate(rtti)
100
+ : constValidate(rtti);
@@ -0,0 +1,76 @@
1
+ declare const _default: {
2
+ boolean: {
3
+ ok: () => void;
4
+ error: () => void;
5
+ };
6
+ number: {
7
+ ok: () => void;
8
+ error: () => void;
9
+ };
10
+ string: {
11
+ ok: () => void;
12
+ error: () => void;
13
+ };
14
+ bigint: {
15
+ ok: () => void;
16
+ error: () => void;
17
+ };
18
+ unknown: {
19
+ ok: () => void;
20
+ };
21
+ const: {
22
+ null: {
23
+ ok: () => void;
24
+ error: () => void;
25
+ };
26
+ undefined: {
27
+ ok: () => void;
28
+ error: () => void;
29
+ };
30
+ number: {
31
+ ok: () => void;
32
+ error: () => void;
33
+ };
34
+ string: {
35
+ ok: () => void;
36
+ error: () => void;
37
+ };
38
+ bigint: {
39
+ ok: () => void;
40
+ error: () => void;
41
+ };
42
+ boolean: {
43
+ ok: () => void;
44
+ error: () => void;
45
+ };
46
+ tuple: {
47
+ ok: () => void;
48
+ extraItems: () => void;
49
+ error: () => void;
50
+ };
51
+ struct: {
52
+ ok: () => void;
53
+ extraKeys: () => void;
54
+ error: () => void;
55
+ };
56
+ };
57
+ array: {
58
+ empty: () => void;
59
+ ok: () => void;
60
+ error: () => void;
61
+ nested: () => void;
62
+ };
63
+ record: {
64
+ empty: () => void;
65
+ ok: () => void;
66
+ error: () => void;
67
+ };
68
+ constThunk: {
69
+ primitive: () => void;
70
+ };
71
+ recursive: {
72
+ arrayOfArrays: () => void;
73
+ recordOfRecords: () => void;
74
+ };
75
+ };
76
+ export default _default;
@@ -0,0 +1,143 @@
1
+ import { validate } from "./module.f.js";
2
+ import { boolean, number, string, bigint, unknown, array, record } from "../module.f.js";
3
+ const assertOk = ([k]) => { if (k !== 'ok') {
4
+ throw 'expected ok';
5
+ } };
6
+ const assertError = ([k]) => { if (k !== 'error') {
7
+ throw 'expected error';
8
+ } };
9
+ export default {
10
+ boolean: {
11
+ ok: () => {
12
+ assertOk(validate(boolean)(true));
13
+ assertOk(validate(boolean)(false));
14
+ },
15
+ error: () => {
16
+ assertError(validate(boolean)(0));
17
+ assertError(validate(boolean)('true'));
18
+ assertError(validate(boolean)(null));
19
+ },
20
+ },
21
+ number: {
22
+ ok: () => assertOk(validate(number)(42)),
23
+ error: () => {
24
+ assertError(validate(number)('42'));
25
+ assertError(validate(number)(42n));
26
+ },
27
+ },
28
+ string: {
29
+ ok: () => assertOk(validate(string)('hello')),
30
+ error: () => {
31
+ assertError(validate(string)(42));
32
+ assertError(validate(string)(null));
33
+ },
34
+ },
35
+ bigint: {
36
+ ok: () => assertOk(validate(bigint)(4n)),
37
+ error: () => {
38
+ assertError(validate(bigint)(4));
39
+ assertError(validate(bigint)('4'));
40
+ },
41
+ },
42
+ unknown: {
43
+ ok: () => {
44
+ assertOk(validate(unknown)(null));
45
+ assertOk(validate(unknown)(42));
46
+ assertOk(validate(unknown)('hello'));
47
+ assertOk(validate(unknown)(true));
48
+ assertOk(validate(unknown)({}));
49
+ assertOk(validate(unknown)([]));
50
+ },
51
+ },
52
+ const: {
53
+ null: {
54
+ ok: () => assertOk(validate(null)(null)),
55
+ error: () => {
56
+ assertError(validate(null)(undefined));
57
+ assertError(validate(null)(0));
58
+ },
59
+ },
60
+ undefined: {
61
+ ok: () => assertOk(validate(undefined)(undefined)),
62
+ error: () => assertError(validate(undefined)(null)),
63
+ },
64
+ number: {
65
+ ok: () => assertOk(validate(42)(42)),
66
+ error: () => assertError(validate(42)(43)),
67
+ },
68
+ string: {
69
+ ok: () => assertOk(validate('hello')('hello')),
70
+ error: () => assertError(validate('hello')('world')),
71
+ },
72
+ bigint: {
73
+ ok: () => assertOk(validate(7n)(7n)),
74
+ error: () => assertError(validate(7n)(8n)),
75
+ },
76
+ boolean: {
77
+ ok: () => assertOk(validate(true)(true)),
78
+ error: () => assertError(validate(true)(false)),
79
+ },
80
+ tuple: {
81
+ ok: () => assertOk(validate([42, 'hello'])([42, 'hello'])),
82
+ extraItems: () => assertOk(validate([42])([42, 'extra'])),
83
+ error: () => {
84
+ assertError(validate([42])([99]));
85
+ assertError(validate([42])({}));
86
+ },
87
+ },
88
+ struct: {
89
+ ok: () => assertOk(validate({ a: 42, b: 'hello' })({ a: 42, b: 'hello' })),
90
+ extraKeys: () => assertOk(validate({ a: 42 })({ a: 42, b: 'extra' })),
91
+ error: () => {
92
+ assertError(validate({ a: 42 })({ a: 99 }));
93
+ assertError(validate({ a: 42 })([]));
94
+ },
95
+ },
96
+ },
97
+ array: {
98
+ empty: () => assertOk(validate(array(number))([])),
99
+ ok: () => assertOk(validate(array(number))([1, 2, 3])),
100
+ error: () => {
101
+ assertError(validate(array(number))([1, 'two', 3]));
102
+ assertError(validate(array(number))({}));
103
+ assertError(validate(array(number))(null));
104
+ },
105
+ nested: () => {
106
+ assertOk(validate(array(array(boolean)))([[true, false], [false]]));
107
+ assertError(validate(array(array(boolean)))([[true, 42]]));
108
+ },
109
+ },
110
+ record: {
111
+ empty: () => assertOk(validate(record(number))({})),
112
+ ok: () => assertOk(validate(record(string))({ a: 'hello', b: 'world' })),
113
+ error: () => {
114
+ assertError(validate(record(number))({ a: 1, b: 'two' }));
115
+ assertError(validate(record(number))(null));
116
+ assertError(validate(record(number))([]));
117
+ },
118
+ },
119
+ constThunk: {
120
+ primitive: () => {
121
+ assertOk(validate(() => ['const', 7n])(7n));
122
+ assertError(validate(() => ['const', 7n])(8n));
123
+ },
124
+ },
125
+ recursive: {
126
+ arrayOfArrays: () => {
127
+ // self-referential schema: an array whose elements are also arrays of the same type
128
+ const list = () => ['array', list];
129
+ // @ts-ignore see issue # 127
130
+ assertOk(validate(list)([]));
131
+ assertOk(validate(list)([[], []]));
132
+ assertOk(validate(list)([[[], []], []]));
133
+ assertError(validate(list)([42]));
134
+ assertError(validate(list)(null));
135
+ },
136
+ recordOfRecords: () => {
137
+ const tree = () => ['record', tree];
138
+ assertOk(validate(tree)({}));
139
+ assertOk(validate(tree)({ a: {}, b: { c: {} } }));
140
+ assertError(validate(tree)({ a: 42 }));
141
+ },
142
+ },
143
+ };
@@ -0,0 +1,2 @@
1
+ export type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
2
+ export type Assert<T extends true> = T;
@@ -0,0 +1 @@
1
+ export {};