typesea 0.1.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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +320 -0
- package/dist/adapters/index.d.ts +152 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +396 -0
- package/dist/aot/index.d.ts +33 -0
- package/dist/aot/index.d.ts.map +1 -0
- package/dist/aot/index.js +295 -0
- package/dist/async/index.d.ts +111 -0
- package/dist/async/index.d.ts.map +1 -0
- package/dist/async/index.js +221 -0
- package/dist/builders/composite.d.ts +31 -0
- package/dist/builders/composite.d.ts.map +1 -0
- package/dist/builders/composite.js +165 -0
- package/dist/builders/index.d.ts +11 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +9 -0
- package/dist/builders/modifier.d.ts +26 -0
- package/dist/builders/modifier.d.ts.map +1 -0
- package/dist/builders/modifier.js +67 -0
- package/dist/builders/object/guard.d.ts +62 -0
- package/dist/builders/object/guard.d.ts.map +1 -0
- package/dist/builders/object/guard.js +113 -0
- package/dist/builders/object/index.d.ts +7 -0
- package/dist/builders/object/index.d.ts.map +1 -0
- package/dist/builders/object/index.js +5 -0
- package/dist/builders/object/schema.d.ts +44 -0
- package/dist/builders/object/schema.d.ts.map +1 -0
- package/dist/builders/object/schema.js +257 -0
- package/dist/builders/object/types.d.ts +63 -0
- package/dist/builders/object/types.d.ts.map +1 -0
- package/dist/builders/object/types.js +5 -0
- package/dist/builders/scalar.d.ts +39 -0
- package/dist/builders/scalar.d.ts.map +1 -0
- package/dist/builders/scalar.js +63 -0
- package/dist/builders/table.d.ts +53 -0
- package/dist/builders/table.d.ts.map +1 -0
- package/dist/builders/table.js +48 -0
- package/dist/builders/types.d.ts +26 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/builders/types.js +5 -0
- package/dist/compile/check-composite.d.ts +34 -0
- package/dist/compile/check-composite.d.ts.map +1 -0
- package/dist/compile/check-composite.js +117 -0
- package/dist/compile/check-scalar.d.ts +24 -0
- package/dist/compile/check-scalar.d.ts.map +1 -0
- package/dist/compile/check-scalar.js +73 -0
- package/dist/compile/check.d.ts +15 -0
- package/dist/compile/check.d.ts.map +1 -0
- package/dist/compile/check.js +98 -0
- package/dist/compile/context.d.ts +35 -0
- package/dist/compile/context.d.ts.map +1 -0
- package/dist/compile/context.js +72 -0
- package/dist/compile/graph-predicate.d.ts +19 -0
- package/dist/compile/graph-predicate.d.ts.map +1 -0
- package/dist/compile/graph-predicate.js +460 -0
- package/dist/compile/guard.d.ts +41 -0
- package/dist/compile/guard.d.ts.map +1 -0
- package/dist/compile/guard.js +180 -0
- package/dist/compile/index.d.ts +8 -0
- package/dist/compile/index.d.ts.map +1 -0
- package/dist/compile/index.js +6 -0
- package/dist/compile/issue.d.ts +18 -0
- package/dist/compile/issue.d.ts.map +1 -0
- package/dist/compile/issue.js +28 -0
- package/dist/compile/names.d.ts +16 -0
- package/dist/compile/names.d.ts.map +1 -0
- package/dist/compile/names.js +82 -0
- package/dist/compile/predicate.d.ts +23 -0
- package/dist/compile/predicate.d.ts.map +1 -0
- package/dist/compile/predicate.js +317 -0
- package/dist/compile/runtime.d.ts +55 -0
- package/dist/compile/runtime.d.ts.map +1 -0
- package/dist/compile/runtime.js +63 -0
- package/dist/compile/source.d.ts +11 -0
- package/dist/compile/source.d.ts.map +1 -0
- package/dist/compile/source.js +51 -0
- package/dist/compile/types.d.ts +52 -0
- package/dist/compile/types.d.ts.map +1 -0
- package/dist/compile/types.js +5 -0
- package/dist/decoder/index.d.ts +106 -0
- package/dist/decoder/index.d.ts.map +1 -0
- package/dist/decoder/index.js +262 -0
- package/dist/evaluate/check-composite.d.ts +39 -0
- package/dist/evaluate/check-composite.d.ts.map +1 -0
- package/dist/evaluate/check-composite.js +184 -0
- package/dist/evaluate/check-scalar.d.ts +20 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -0
- package/dist/evaluate/check-scalar.js +81 -0
- package/dist/evaluate/check.d.ts +11 -0
- package/dist/evaluate/check.d.ts.map +1 -0
- package/dist/evaluate/check.js +126 -0
- package/dist/evaluate/index.d.ts +7 -0
- package/dist/evaluate/index.d.ts.map +1 -0
- package/dist/evaluate/index.js +6 -0
- package/dist/evaluate/issue.d.ts +10 -0
- package/dist/evaluate/issue.d.ts.map +1 -0
- package/dist/evaluate/issue.js +11 -0
- package/dist/evaluate/predicate.d.ts +26 -0
- package/dist/evaluate/predicate.d.ts.map +1 -0
- package/dist/evaluate/predicate.js +37 -0
- package/dist/evaluate/shared.d.ts +59 -0
- package/dist/evaluate/shared.d.ts.map +1 -0
- package/dist/evaluate/shared.js +96 -0
- package/dist/evaluate/state.d.ts +65 -0
- package/dist/evaluate/state.d.ts.map +1 -0
- package/dist/evaluate/state.js +66 -0
- package/dist/guard/base.d.ts +72 -0
- package/dist/guard/base.d.ts.map +1 -0
- package/dist/guard/base.js +136 -0
- package/dist/guard/error.d.ts +19 -0
- package/dist/guard/error.d.ts.map +1 -0
- package/dist/guard/error.js +22 -0
- package/dist/guard/index.d.ts +10 -0
- package/dist/guard/index.d.ts.map +1 -0
- package/dist/guard/index.js +8 -0
- package/dist/guard/number.d.ts +32 -0
- package/dist/guard/number.d.ts.map +1 -0
- package/dist/guard/number.js +71 -0
- package/dist/guard/props.d.ts +18 -0
- package/dist/guard/props.d.ts.map +1 -0
- package/dist/guard/props.js +35 -0
- package/dist/guard/read.d.ts +42 -0
- package/dist/guard/read.d.ts.map +1 -0
- package/dist/guard/read.js +114 -0
- package/dist/guard/registry.d.ts +15 -0
- package/dist/guard/registry.d.ts.map +1 -0
- package/dist/guard/registry.js +21 -0
- package/dist/guard/string.d.ts +36 -0
- package/dist/guard/string.d.ts.map +1 -0
- package/dist/guard/string.js +95 -0
- package/dist/guard/types.d.ts +103 -0
- package/dist/guard/types.d.ts.map +1 -0
- package/dist/guard/types.js +5 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/internal/index.d.ts +34 -0
- package/dist/internal/index.d.ts.map +1 -0
- package/dist/internal/index.js +56 -0
- package/dist/ir/builder.d.ts +173 -0
- package/dist/ir/builder.d.ts.map +1 -0
- package/dist/ir/builder.js +481 -0
- package/dist/ir/freeze.d.ts +10 -0
- package/dist/ir/freeze.d.ts.map +1 -0
- package/dist/ir/freeze.js +102 -0
- package/dist/ir/index.d.ts +9 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +7 -0
- package/dist/ir/regexp.d.ts +6 -0
- package/dist/ir/regexp.d.ts.map +1 -0
- package/dist/ir/regexp.js +12 -0
- package/dist/ir/types.d.ts +215 -0
- package/dist/ir/types.d.ts.map +1 -0
- package/dist/ir/types.js +5 -0
- package/dist/ir/validate.d.ts +10 -0
- package/dist/ir/validate.d.ts.map +1 -0
- package/dist/ir/validate.js +271 -0
- package/dist/issue/index.d.ts +44 -0
- package/dist/issue/index.d.ts.map +1 -0
- package/dist/issue/index.js +152 -0
- package/dist/json-schema/emit-combinator.d.ts +28 -0
- package/dist/json-schema/emit-combinator.d.ts.map +1 -0
- package/dist/json-schema/emit-combinator.js +96 -0
- package/dist/json-schema/emit-composite.d.ts +28 -0
- package/dist/json-schema/emit-composite.d.ts.map +1 -0
- package/dist/json-schema/emit-composite.js +127 -0
- package/dist/json-schema/emit-scalar.d.ts +25 -0
- package/dist/json-schema/emit-scalar.d.ts.map +1 -0
- package/dist/json-schema/emit-scalar.js +104 -0
- package/dist/json-schema/emit-types.d.ts +12 -0
- package/dist/json-schema/emit-types.d.ts.map +1 -0
- package/dist/json-schema/emit-types.js +5 -0
- package/dist/json-schema/emit.d.ts +12 -0
- package/dist/json-schema/emit.d.ts.map +1 -0
- package/dist/json-schema/emit.js +62 -0
- package/dist/json-schema/freeze.d.ts +14 -0
- package/dist/json-schema/freeze.d.ts.map +1 -0
- package/dist/json-schema/freeze.js +114 -0
- package/dist/json-schema/index.d.ts +20 -0
- package/dist/json-schema/index.d.ts.map +1 -0
- package/dist/json-schema/index.js +76 -0
- package/dist/json-schema/issue.d.ts +11 -0
- package/dist/json-schema/issue.d.ts.map +1 -0
- package/dist/json-schema/issue.js +14 -0
- package/dist/json-schema/read.d.ts +29 -0
- package/dist/json-schema/read.d.ts.map +1 -0
- package/dist/json-schema/read.js +87 -0
- package/dist/json-schema/types.d.ts +106 -0
- package/dist/json-schema/types.d.ts.map +1 -0
- package/dist/json-schema/types.js +5 -0
- package/dist/kind/index.d.ts +119 -0
- package/dist/kind/index.d.ts.map +1 -0
- package/dist/kind/index.js +94 -0
- package/dist/lower/index.d.ts +7 -0
- package/dist/lower/index.d.ts.map +1 -0
- package/dist/lower/index.js +199 -0
- package/dist/message/index.d.ts +51 -0
- package/dist/message/index.d.ts.map +1 -0
- package/dist/message/index.js +269 -0
- package/dist/optimize/compact.d.ts +10 -0
- package/dist/optimize/compact.d.ts.map +1 -0
- package/dist/optimize/compact.js +60 -0
- package/dist/optimize/fold-boolean.d.ts +15 -0
- package/dist/optimize/fold-boolean.d.ts.map +1 -0
- package/dist/optimize/fold-boolean.js +75 -0
- package/dist/optimize/fold-common.d.ts +45 -0
- package/dist/optimize/fold-common.d.ts.map +1 -0
- package/dist/optimize/fold-common.js +71 -0
- package/dist/optimize/fold-scalar.d.ts +59 -0
- package/dist/optimize/fold-scalar.d.ts.map +1 -0
- package/dist/optimize/fold-scalar.js +174 -0
- package/dist/optimize/fold.d.ts +10 -0
- package/dist/optimize/fold.d.ts.map +1 -0
- package/dist/optimize/fold.js +103 -0
- package/dist/optimize/index.d.ts +10 -0
- package/dist/optimize/index.d.ts.map +1 -0
- package/dist/optimize/index.js +23 -0
- package/dist/optimize/map-node.d.ts +21 -0
- package/dist/optimize/map-node.d.ts.map +1 -0
- package/dist/optimize/map-node.js +222 -0
- package/dist/optimize/remap.d.ts +30 -0
- package/dist/optimize/remap.d.ts.map +1 -0
- package/dist/optimize/remap.js +46 -0
- package/dist/optimize/rewrite.d.ts +22 -0
- package/dist/optimize/rewrite.d.ts.map +1 -0
- package/dist/optimize/rewrite.js +34 -0
- package/dist/plan/cache.d.ts +20 -0
- package/dist/plan/cache.d.ts.map +1 -0
- package/dist/plan/cache.js +122 -0
- package/dist/plan/index.d.ts +8 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +6 -0
- package/dist/plan/predicate.d.ts +27 -0
- package/dist/plan/predicate.d.ts.map +1 -0
- package/dist/plan/predicate.js +415 -0
- package/dist/plan/schema-predicate.d.ts +15 -0
- package/dist/plan/schema-predicate.d.ts.map +1 -0
- package/dist/plan/schema-predicate.js +277 -0
- package/dist/plan/types.d.ts +18 -0
- package/dist/plan/types.d.ts.map +1 -0
- package/dist/plan/types.js +5 -0
- package/dist/result/index.d.ts +27 -0
- package/dist/result/index.d.ts.map +1 -0
- package/dist/result/index.js +20 -0
- package/dist/schema/common.d.ts +30 -0
- package/dist/schema/common.d.ts.map +1 -0
- package/dist/schema/common.js +102 -0
- package/dist/schema/freeze.d.ts +10 -0
- package/dist/schema/freeze.d.ts.map +1 -0
- package/dist/schema/freeze.js +163 -0
- package/dist/schema/index.d.ts +11 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +9 -0
- package/dist/schema/lazy.d.ts +10 -0
- package/dist/schema/lazy.d.ts.map +1 -0
- package/dist/schema/lazy.js +25 -0
- package/dist/schema/literal.d.ts +10 -0
- package/dist/schema/literal.d.ts.map +1 -0
- package/dist/schema/literal.js +17 -0
- package/dist/schema/types.d.ts +243 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +9 -0
- package/dist/schema/validate.d.ts +10 -0
- package/dist/schema/validate.d.ts.map +1 -0
- package/dist/schema/validate.js +268 -0
- package/docs/api.md +301 -0
- package/docs/engine-notes.md +153 -0
- package/docs/index.html +1242 -0
- package/package.json +68 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file graph-predicate.ts
|
|
3
|
+
* @brief Predicate source emitter backed by optimized Sea-of-Nodes graphs.
|
|
4
|
+
*/
|
|
5
|
+
import { NodeTag } from "../kind/index.js";
|
|
6
|
+
import { makeValidationPlan } from "../plan/index.js";
|
|
7
|
+
import { pushKeyset, pushLiteral, pushRegex, pushSchema, stringRef } from "./context.js";
|
|
8
|
+
/**
|
|
9
|
+
* @brief emit graph function.
|
|
10
|
+
* @details Emits one predicate function from the optimized graph owned by a schema plan.
|
|
11
|
+
* @returns Generated function name.
|
|
12
|
+
*/
|
|
13
|
+
export function emitGraphFunction(schema, context) {
|
|
14
|
+
const cached = context.functionNames.get(schema);
|
|
15
|
+
if (cached !== undefined) {
|
|
16
|
+
return cached;
|
|
17
|
+
}
|
|
18
|
+
const name = `p${String(context.functions.length)}`;
|
|
19
|
+
const source = {
|
|
20
|
+
name,
|
|
21
|
+
body: ""
|
|
22
|
+
};
|
|
23
|
+
context.functionNames.set(schema, name);
|
|
24
|
+
context.functions.push(source);
|
|
25
|
+
const plan = makeValidationPlan(schema);
|
|
26
|
+
source.body = emitGraphBody(plan.graph, plan.graph.result, "v", context);
|
|
27
|
+
return name;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @brief emit graph functions.
|
|
31
|
+
* @details Serializes every graph predicate function accumulated in the context.
|
|
32
|
+
* @returns JavaScript source for the predicate function table.
|
|
33
|
+
*/
|
|
34
|
+
export function emitGraphFunctions(context) {
|
|
35
|
+
const chunks = new Array(context.functions.length);
|
|
36
|
+
for (let index = 0; index < context.functions.length; index += 1) {
|
|
37
|
+
const source = context.functions[index];
|
|
38
|
+
if (source !== undefined) {
|
|
39
|
+
chunks[index] = `function ${source.name}(v){${source.body}}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return chunks.join("");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* @brief emit graph body.
|
|
46
|
+
*/
|
|
47
|
+
function emitGraphBody(graph, id, value, context) {
|
|
48
|
+
const state = {
|
|
49
|
+
chunks: [],
|
|
50
|
+
dataSlots: new Map(),
|
|
51
|
+
dataGuards: new Set(),
|
|
52
|
+
temp: 0
|
|
53
|
+
};
|
|
54
|
+
emitGraphReturn(graph, id, value, context, state);
|
|
55
|
+
return state.chunks.join("");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @brief emit graph return.
|
|
59
|
+
*/
|
|
60
|
+
function emitGraphReturn(graph, id, value, context, state) {
|
|
61
|
+
const node = graph.nodes[id];
|
|
62
|
+
if (node === undefined) {
|
|
63
|
+
state.chunks.push("return false;");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
switch (node.tag) {
|
|
67
|
+
case NodeTag.Return:
|
|
68
|
+
emitGraphReturn(graph, node.value, value, context, state);
|
|
69
|
+
return;
|
|
70
|
+
case NodeTag.And:
|
|
71
|
+
emitAndReturn(graph, node.values, value, context, state);
|
|
72
|
+
return;
|
|
73
|
+
case NodeTag.Or:
|
|
74
|
+
emitOrReturn(graph, node.values, value, context, state);
|
|
75
|
+
return;
|
|
76
|
+
case NodeTag.DiscriminantDispatch:
|
|
77
|
+
emitDiscriminantDispatchReturn(graph, node.value, value, node.key, node.literals, node.schemas, context, state);
|
|
78
|
+
return;
|
|
79
|
+
default:
|
|
80
|
+
state.chunks.push(`return ${emitGraphExpression(graph, id, value, context, state)};`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* @brief emit and return.
|
|
85
|
+
*/
|
|
86
|
+
function emitAndReturn(graph, ids, value, context, state) {
|
|
87
|
+
for (let index = 0; index < ids.length; index += 1) {
|
|
88
|
+
const id = ids[index];
|
|
89
|
+
if (id !== undefined) {
|
|
90
|
+
emitFalseCheck(graph, id, value, context, state);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
state.chunks.push("return true;");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @brief emit false check.
|
|
97
|
+
*/
|
|
98
|
+
function emitFalseCheck(graph, id, value, context, state) {
|
|
99
|
+
const node = graph.nodes[id];
|
|
100
|
+
if (node?.tag === NodeTag.And) {
|
|
101
|
+
for (let index = 0; index < node.values.length; index += 1) {
|
|
102
|
+
const child = node.values[index];
|
|
103
|
+
if (child !== undefined) {
|
|
104
|
+
emitFalseCheck(graph, child, value, context, state);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (node?.tag === NodeTag.ArrayEvery) {
|
|
110
|
+
emitArrayEveryCheck(graph, node.value, node.item, value, context, state);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (node?.tag === NodeTag.RecordEvery) {
|
|
114
|
+
emitRecordEveryCheck(graph, node.value, node.item, value, context, state);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (node?.tag === NodeTag.HasOwnData) {
|
|
118
|
+
emitHasDataCheck(graph, node.object, node.key, value, context, state);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (node?.tag === NodeTag.StrictKeys) {
|
|
122
|
+
emitStrictKeysCheck(graph, node.object, node.keys, value, context, state);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
state.chunks.push(`if(!${emitGraphExpression(graph, id, value, context, state)})return false;`);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* @brief emit array every check.
|
|
129
|
+
*/
|
|
130
|
+
function emitArrayEveryCheck(graph, valueId, item, value, context, state) {
|
|
131
|
+
const arrayExpression = emitGraphExpression(graph, valueId, value, context, state);
|
|
132
|
+
const index = `i${String(state.temp)}`;
|
|
133
|
+
state.temp += 1;
|
|
134
|
+
const descriptor = `d${String(state.temp)}`;
|
|
135
|
+
state.temp += 1;
|
|
136
|
+
const itemValue = `v${String(state.temp)}`;
|
|
137
|
+
state.temp += 1;
|
|
138
|
+
state.chunks.push(`for(let ${index}=0;${index}<${arrayExpression}.length;${index}+=1){`, `const ${descriptor}=gp(${arrayExpression},${index});`, `if(${descriptor}!==undefined&&!h.call(${descriptor},"value"))return false;`, `const ${itemValue}=${descriptor}===undefined?undefined:${descriptor}.value;`, `if(!${emitInlineSchemaExpression(item, itemValue, context)})return false;`, "}");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* @brief emit record every check.
|
|
142
|
+
*/
|
|
143
|
+
function emitRecordEveryCheck(graph, valueId, item, value, context, state) {
|
|
144
|
+
const recordExpression = emitGraphExpression(graph, valueId, value, context, state);
|
|
145
|
+
const keys = `ks${String(state.temp)}`;
|
|
146
|
+
state.temp += 1;
|
|
147
|
+
const index = `i${String(state.temp)}`;
|
|
148
|
+
state.temp += 1;
|
|
149
|
+
const key = `key${String(state.temp)}`;
|
|
150
|
+
state.temp += 1;
|
|
151
|
+
const descriptor = `d${String(state.temp)}`;
|
|
152
|
+
state.temp += 1;
|
|
153
|
+
const itemValue = `v${String(state.temp)}`;
|
|
154
|
+
state.temp += 1;
|
|
155
|
+
state.chunks.push(`const ${keys}=Object.keys(${recordExpression});`, `for(let ${index}=0;${index}<${keys}.length;${index}+=1){`, `const ${key}=${keys}[${index}];`, `if(${key}===undefined)return false;`, `const ${descriptor}=gp(${recordExpression},${key});`, `if(${descriptor}===undefined||!h.call(${descriptor},"value"))return false;`, `const ${itemValue}=${descriptor}.value;`, `if(!${emitInlineSchemaExpression(item, itemValue, context)})return false;`, "}");
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @brief emit strict keys check.
|
|
159
|
+
*/
|
|
160
|
+
function emitStrictKeysCheck(graph, object, keys, value, context, state) {
|
|
161
|
+
const objectExpression = emitGraphExpression(graph, object, value, context, state);
|
|
162
|
+
if (hasAllRequiredKeys(object, keys, state)) {
|
|
163
|
+
state.chunks.push(`if(Object.getOwnPropertyNames(${objectExpression}).length!==${String(keys.length)}||Object.getOwnPropertySymbols(${objectExpression}).length!==0)return false;`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const present = `xs${String(state.temp)}`;
|
|
167
|
+
state.temp += 1;
|
|
168
|
+
const index = `i${String(state.temp)}`;
|
|
169
|
+
state.temp += 1;
|
|
170
|
+
const key = `key${String(state.temp)}`;
|
|
171
|
+
state.temp += 1;
|
|
172
|
+
state.chunks.push(`const ${present}=Reflect.ownKeys(${objectExpression});`, `for(let ${index}=0;${index}<${present}.length;${index}+=1){`, `const ${key}=${present}[${index}];`, `if(typeof ${key}!=="string"||!${keyMembershipExpression(key, keys, context)})return false;`, "}");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* @brief emit or return.
|
|
176
|
+
*/
|
|
177
|
+
function emitOrReturn(graph, ids, value, context, state) {
|
|
178
|
+
for (let index = 0; index < ids.length; index += 1) {
|
|
179
|
+
const id = ids[index];
|
|
180
|
+
if (id !== undefined) {
|
|
181
|
+
state.chunks.push(`if(${emitGraphExpression(graph, id, value, context, state)})return true;`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
state.chunks.push("return false;");
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* @brief emit discriminant dispatch return.
|
|
188
|
+
*/
|
|
189
|
+
function emitDiscriminantDispatchReturn(graph, object, value, key, literals, schemas, context, state) {
|
|
190
|
+
const objectExpression = emitGraphExpression(graph, object, value, context, state);
|
|
191
|
+
const descriptor = `d${String(state.temp)}`;
|
|
192
|
+
state.temp += 1;
|
|
193
|
+
state.chunks.push(`if(!o(${objectExpression}))return false;`, `const ${descriptor}=g(${objectExpression},${stringRef(context, key)});`, `if(${descriptor}===undefined||typeof ${descriptor}.value!=="string")return false;`, `switch(${descriptor}.value){`);
|
|
194
|
+
for (let index = 0; index < schemas.length; index += 1) {
|
|
195
|
+
const schema = schemas[index];
|
|
196
|
+
const literal = literals[index];
|
|
197
|
+
if (schema !== undefined && literal !== undefined) {
|
|
198
|
+
state.chunks.push(`case ${stringRef(context, literal)}:return ${emitGraphFunction(schema, context)}(${objectExpression});`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
state.chunks.push("default:return false;}");
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* @brief emit graph expression.
|
|
205
|
+
*/
|
|
206
|
+
function emitGraphExpression(graph, id, value, context, state) {
|
|
207
|
+
const node = graph.nodes[id];
|
|
208
|
+
if (node === undefined) {
|
|
209
|
+
return "undefined";
|
|
210
|
+
}
|
|
211
|
+
switch (node.tag) {
|
|
212
|
+
case NodeTag.Start:
|
|
213
|
+
return "true";
|
|
214
|
+
case NodeTag.Param:
|
|
215
|
+
return value;
|
|
216
|
+
case NodeTag.Const:
|
|
217
|
+
return literalExpression(node.value, context);
|
|
218
|
+
case NodeTag.GetProp:
|
|
219
|
+
return state === undefined
|
|
220
|
+
? `gv(${emitGraphExpression(graph, node.object, value, context, state)},${stringRef(context, node.key)})`
|
|
221
|
+
: emitDataValueSlot(graph, node.object, node.key, value, context, state);
|
|
222
|
+
case NodeTag.IsString:
|
|
223
|
+
return `(typeof ${emitGraphExpression(graph, node.value, value, context, state)}==="string")`;
|
|
224
|
+
case NodeTag.IsNumber:
|
|
225
|
+
return finiteNumberExpression(emitGraphExpression(graph, node.value, value, context, state));
|
|
226
|
+
case NodeTag.IsBoolean:
|
|
227
|
+
return `(typeof ${emitGraphExpression(graph, node.value, value, context, state)}==="boolean")`;
|
|
228
|
+
case NodeTag.IsBigInt:
|
|
229
|
+
return `(typeof ${emitGraphExpression(graph, node.value, value, context, state)}==="bigint")`;
|
|
230
|
+
case NodeTag.IsSymbol:
|
|
231
|
+
return `(typeof ${emitGraphExpression(graph, node.value, value, context, state)}==="symbol")`;
|
|
232
|
+
case NodeTag.IsObject:
|
|
233
|
+
return `o(${emitGraphExpression(graph, node.value, value, context, state)})`;
|
|
234
|
+
case NodeTag.IsArray:
|
|
235
|
+
return `Array.isArray(${emitGraphExpression(graph, node.value, value, context, state)})`;
|
|
236
|
+
case NodeTag.IsUndefined:
|
|
237
|
+
return `(${emitGraphExpression(graph, node.value, value, context, state)}===undefined)`;
|
|
238
|
+
case NodeTag.IsNull:
|
|
239
|
+
return `(${emitGraphExpression(graph, node.value, value, context, state)}===null)`;
|
|
240
|
+
case NodeTag.IsInteger:
|
|
241
|
+
return `Number.isInteger(${emitGraphExpression(graph, node.value, value, context, state)})`;
|
|
242
|
+
case NodeTag.Not:
|
|
243
|
+
return `(${emitGraphExpression(graph, node.value, value, context, state)}!==true)`;
|
|
244
|
+
case NodeTag.Equals:
|
|
245
|
+
return `Object.is(${emitGraphExpression(graph, node.left, value, context, state)},${emitGraphExpression(graph, node.right, value, context, state)})`;
|
|
246
|
+
case NodeTag.Gte:
|
|
247
|
+
return `(${emitGraphExpression(graph, node.left, value, context, state)}>=${emitGraphExpression(graph, node.right, value, context, state)})`;
|
|
248
|
+
case NodeTag.Lte:
|
|
249
|
+
return `(${emitGraphExpression(graph, node.left, value, context, state)}<=${emitGraphExpression(graph, node.right, value, context, state)})`;
|
|
250
|
+
case NodeTag.StringMin:
|
|
251
|
+
return `(${emitGraphExpression(graph, node.value, value, context, state)}.length>=${String(node.bound)})`;
|
|
252
|
+
case NodeTag.StringMax:
|
|
253
|
+
return `(${emitGraphExpression(graph, node.value, value, context, state)}.length<=${String(node.bound)})`;
|
|
254
|
+
case NodeTag.Regex:
|
|
255
|
+
return regexExpression(emitGraphExpression(graph, node.value, value, context, state), node.regex, context);
|
|
256
|
+
case NodeTag.HasOwn:
|
|
257
|
+
return `ho(${emitGraphExpression(graph, node.object, value, context, state)},${stringRef(context, node.key)})`;
|
|
258
|
+
case NodeTag.HasOwnData:
|
|
259
|
+
return state === undefined
|
|
260
|
+
? `hd(${emitGraphExpression(graph, node.object, value, context, state)},${stringRef(context, node.key)})`
|
|
261
|
+
: hasDataExpression(graph, node.object, node.key, value, context, state);
|
|
262
|
+
case NodeTag.StrictKeys:
|
|
263
|
+
return `sk(${emitGraphExpression(graph, node.object, value, context, state)},k[${String(pushKeyset(context, node.keys))}])`;
|
|
264
|
+
case NodeTag.ArrayEvery:
|
|
265
|
+
return `ea(${emitGraphExpression(graph, node.value, value, context, state)},${emitGraphFunction(node.item, context)})`;
|
|
266
|
+
case NodeTag.TupleItems:
|
|
267
|
+
return emitTupleItemsExpression(emitGraphExpression(graph, node.value, value, context, state), node.items, context);
|
|
268
|
+
case NodeTag.RecordEvery:
|
|
269
|
+
return `er(${emitGraphExpression(graph, node.value, value, context, state)},${emitGraphFunction(node.item, context)})`;
|
|
270
|
+
case NodeTag.DiscriminantDispatch:
|
|
271
|
+
return emitDiscriminantDispatchExpression(emitGraphExpression(graph, node.value, value, context, state), node.key, node.literals, node.schemas, context);
|
|
272
|
+
case NodeTag.SchemaCheck:
|
|
273
|
+
return `d(${String(pushSchema(context, node.schema))},${emitGraphExpression(graph, node.value, value, context, state)})`;
|
|
274
|
+
case NodeTag.And:
|
|
275
|
+
return emitBooleanFoldExpression(graph, node.values, value, context, state, true);
|
|
276
|
+
case NodeTag.Or:
|
|
277
|
+
return emitBooleanFoldExpression(graph, node.values, value, context, state, false);
|
|
278
|
+
case NodeTag.Return:
|
|
279
|
+
return emitGraphExpression(graph, node.value, value, context, state);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* @brief emit boolean fold expression.
|
|
284
|
+
*/
|
|
285
|
+
function emitBooleanFoldExpression(graph, ids, value, context, state, and) {
|
|
286
|
+
const fallback = and ? "true" : "false";
|
|
287
|
+
const operator = and ? "&&" : "||";
|
|
288
|
+
const parts = [];
|
|
289
|
+
for (let index = 0; index < ids.length; index += 1) {
|
|
290
|
+
const id = ids[index];
|
|
291
|
+
if (id !== undefined) {
|
|
292
|
+
parts.push(emitGraphExpression(graph, id, value, context, undefined));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (parts.length === 0) {
|
|
296
|
+
return fallback;
|
|
297
|
+
}
|
|
298
|
+
return `(${parts.join(operator)})`;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* @brief emit data slot.
|
|
302
|
+
*/
|
|
303
|
+
function emitDataSlot(graph, object, key, value, context, state) {
|
|
304
|
+
const cacheKey = dataSlotKey(object, key);
|
|
305
|
+
const cached = state.dataSlots.get(cacheKey);
|
|
306
|
+
if (cached !== undefined) {
|
|
307
|
+
return cached;
|
|
308
|
+
}
|
|
309
|
+
const objectExpression = emitGraphExpression(graph, object, value, context, state);
|
|
310
|
+
const descriptor = `d${String(state.temp)}`;
|
|
311
|
+
state.temp += 1;
|
|
312
|
+
const keyRef = stringRef(context, key);
|
|
313
|
+
state.chunks.push(`const ${descriptor}=gp(${objectExpression},${keyRef});`);
|
|
314
|
+
const slot = {
|
|
315
|
+
descriptor,
|
|
316
|
+
value: undefined
|
|
317
|
+
};
|
|
318
|
+
state.dataSlots.set(cacheKey, slot);
|
|
319
|
+
return slot;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* @brief emit data value slot.
|
|
323
|
+
*/
|
|
324
|
+
function emitDataValueSlot(graph, object, key, value, context, state) {
|
|
325
|
+
const cacheKey = dataSlotKey(object, key);
|
|
326
|
+
const slot = emitDataSlot(graph, object, key, value, context, state);
|
|
327
|
+
if (slot.value !== undefined) {
|
|
328
|
+
return slot.value;
|
|
329
|
+
}
|
|
330
|
+
const localValue = `v${String(state.temp)}`;
|
|
331
|
+
state.temp += 1;
|
|
332
|
+
const source = state.dataGuards.has(cacheKey)
|
|
333
|
+
? `${slot.descriptor}.value`
|
|
334
|
+
: `${slot.descriptor}===undefined?undefined:${slot.descriptor}.value`;
|
|
335
|
+
state.chunks.push(`const ${localValue}=${source};`);
|
|
336
|
+
slot.value = localValue;
|
|
337
|
+
return localValue;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* @brief emit has data check.
|
|
341
|
+
*/
|
|
342
|
+
function emitHasDataCheck(graph, object, key, value, context, state) {
|
|
343
|
+
const cacheKey = dataSlotKey(object, key);
|
|
344
|
+
const slot = emitDataSlot(graph, object, key, value, context, state);
|
|
345
|
+
state.chunks.push(`if(${slot.descriptor}===undefined||!h.call(${slot.descriptor},"value"))return false;`);
|
|
346
|
+
state.dataGuards.add(cacheKey);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* @brief has data expression.
|
|
350
|
+
*/
|
|
351
|
+
function hasDataExpression(graph, object, key, value, context, state) {
|
|
352
|
+
const slot = emitDataSlot(graph, object, key, value, context, state);
|
|
353
|
+
return `(${slot.descriptor}!==undefined&&h.call(${slot.descriptor},"value"))`;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* @brief data slot key.
|
|
357
|
+
*/
|
|
358
|
+
function dataSlotKey(object, key) {
|
|
359
|
+
return `${String(object)}:${key}`;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* @brief has all required keys.
|
|
363
|
+
*/
|
|
364
|
+
function hasAllRequiredKeys(object, keys, state) {
|
|
365
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
366
|
+
const key = keys[index];
|
|
367
|
+
if (key === undefined || !state.dataGuards.has(dataSlotKey(object, key))) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* @brief key membership expression.
|
|
375
|
+
*/
|
|
376
|
+
function keyMembershipExpression(key, keys, context) {
|
|
377
|
+
if (keys.length === 0) {
|
|
378
|
+
return "false";
|
|
379
|
+
}
|
|
380
|
+
const parts = new Array(keys.length);
|
|
381
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
382
|
+
const value = keys[index];
|
|
383
|
+
parts[index] = value === undefined
|
|
384
|
+
? "false"
|
|
385
|
+
: `${key}===${stringRef(context, value)}`;
|
|
386
|
+
}
|
|
387
|
+
return `(${parts.join("||")})`;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* @brief emit inline schema expression.
|
|
391
|
+
*/
|
|
392
|
+
function emitInlineSchemaExpression(schema, value, context) {
|
|
393
|
+
const plan = makeValidationPlan(schema);
|
|
394
|
+
return emitGraphExpression(plan.graph, plan.graph.result, value, context, undefined);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* @brief finite number expression.
|
|
398
|
+
*/
|
|
399
|
+
function finiteNumberExpression(value) {
|
|
400
|
+
return `(typeof ${value}==="number"&&Number.isFinite(${value}))`;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* @brief regex expression.
|
|
404
|
+
*/
|
|
405
|
+
function regexExpression(value, regex, context) {
|
|
406
|
+
const index = pushRegex(context, regex);
|
|
407
|
+
const ref = `r[${String(index)}]`;
|
|
408
|
+
return `((${ref}.lastIndex=0),${ref}.test(${value}))`;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* @brief emit tuple items expression.
|
|
412
|
+
*/
|
|
413
|
+
function emitTupleItemsExpression(value, items, context) {
|
|
414
|
+
const parts = [
|
|
415
|
+
`Array.isArray(${value})`,
|
|
416
|
+
`${value}.length===${String(items.length)}`
|
|
417
|
+
];
|
|
418
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
419
|
+
const item = items[index];
|
|
420
|
+
if (item !== undefined) {
|
|
421
|
+
parts.push(`ev(${value},${String(index)},${emitGraphFunction(item, context)})`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return `(${parts.join("&&")})`;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* @brief emit discriminant dispatch expression.
|
|
428
|
+
*/
|
|
429
|
+
function emitDiscriminantDispatchExpression(value, key, literals, schemas, context) {
|
|
430
|
+
const functions = [];
|
|
431
|
+
for (let index = 0; index < schemas.length; index += 1) {
|
|
432
|
+
const schema = schemas[index];
|
|
433
|
+
if (schema !== undefined) {
|
|
434
|
+
functions.push(emitGraphFunction(schema, context));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const keyset = `k[${String(pushKeyset(context, literals))}]`;
|
|
438
|
+
if (functions.length === 0) {
|
|
439
|
+
return `dj(${value},${stringRef(context, key)},${keyset})`;
|
|
440
|
+
}
|
|
441
|
+
return `dj(${value},${stringRef(context, key)},${keyset},${functions.join(",")})`;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* @brief literal expression.
|
|
445
|
+
*/
|
|
446
|
+
function literalExpression(value, context) {
|
|
447
|
+
if (value === true) {
|
|
448
|
+
return "true";
|
|
449
|
+
}
|
|
450
|
+
if (value === false) {
|
|
451
|
+
return "false";
|
|
452
|
+
}
|
|
453
|
+
if (value === null) {
|
|
454
|
+
return "null";
|
|
455
|
+
}
|
|
456
|
+
if (value === undefined) {
|
|
457
|
+
return "undefined";
|
|
458
|
+
}
|
|
459
|
+
return `l[${String(pushLiteral(context, value))}]`;
|
|
460
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file compile/guard.ts
|
|
3
|
+
* @brief Compiled guard construction and receiver validation.
|
|
4
|
+
*/
|
|
5
|
+
import { BaseGuard, type Guard, type Presence, type RuntimeValue } from "../guard/index.js";
|
|
6
|
+
import type { CheckResult } from "../issue/index.js";
|
|
7
|
+
import { type Schema } from "../schema/index.js";
|
|
8
|
+
import { type BooleanPredicate, type IssueCollectorRoot } from "./runtime.js";
|
|
9
|
+
import type { CompileOptions, CompiledGuard } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* @brief compiled base guard.
|
|
12
|
+
* @details Owns its state directly; methods expose receiver checks and explicit result flow.
|
|
13
|
+
* @invariant Construction leaves the instance in a fully usable state before it escapes.
|
|
14
|
+
*/
|
|
15
|
+
export declare class CompiledBaseGuard<TValue, TPresence extends Presence = "required"> extends BaseGuard<TValue, TPresence> implements CompiledGuard<TValue, TPresence> {
|
|
16
|
+
readonly source: string;
|
|
17
|
+
private readonly test;
|
|
18
|
+
private readonly collect;
|
|
19
|
+
/**
|
|
20
|
+
* @brief constructor.
|
|
21
|
+
* @post The receiver is initialized according to the class invariant before it can be observed.
|
|
22
|
+
*/
|
|
23
|
+
constructor(schema: Schema, test: BooleanPredicate, collect: IssueCollectorRoot, source: string);
|
|
24
|
+
/**
|
|
25
|
+
* @brief is.
|
|
26
|
+
*/
|
|
27
|
+
is(this: unknown, value: unknown): value is RuntimeValue<TValue, TPresence>;
|
|
28
|
+
/**
|
|
29
|
+
* @brief check.
|
|
30
|
+
*/
|
|
31
|
+
check(this: unknown, value: unknown): CheckResult<RuntimeValue<TValue, TPresence>>;
|
|
32
|
+
/**
|
|
33
|
+
* @brief assert.
|
|
34
|
+
*/
|
|
35
|
+
assert(this: unknown, value: unknown): asserts value is RuntimeValue<TValue, TPresence>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @brief compile.
|
|
39
|
+
*/
|
|
40
|
+
export declare function compile<TValue, TPresence extends Presence>(guard: Guard<TValue, TPresence>, options?: Partial<CompileOptions>): CompiledBaseGuard<TValue, TPresence>;
|
|
41
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/compile/guard.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,SAAS,EAET,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAGL,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,gBAAgB,EAErB,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAOpB;;;;GAIG;AACH,qBAAa,iBAAiB,CAC5B,MAAM,EACN,SAAS,SAAS,QAAQ,GAAG,UAAU,CACvC,SAAQ,SAAS,CAAC,MAAM,EAAE,SAAS,CAAE,YAAW,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC;IAChF,SAAwB,MAAM,EAAE,MAAM,CAAC;IACvC,iBAAyB,IAAI,CAAmB;IAChD,iBAAyB,OAAO,CAAqB;IAErD;;;OAGG;gBAED,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM;IAmBhB;;eAEW;IACK,EAAE,CAChB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC;IAI3C;;eAEW;IACK,KAAK,CACnB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,OAAO,GACb,WAAW,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAI/C;;eAEW;IACK,MAAM,CACpB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC;CAMpD;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS,QAAQ,EACxD,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAChC,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAgCtC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file compile/guard.ts
|
|
3
|
+
* @brief Compiled guard construction and receiver validation.
|
|
4
|
+
*/
|
|
5
|
+
import { BaseGuard, TypeSeaAssertionError } from "../guard/index.js";
|
|
6
|
+
import { finalizeIssueArray } from "../issue/index.js";
|
|
7
|
+
import { err, ok } from "../result/index.js";
|
|
8
|
+
import { freezeSchema, isSchemaValue } from "../schema/index.js";
|
|
9
|
+
import { makeDynamicCheck, makeDynamicIssueCheck, strictKeys } from "./runtime.js";
|
|
10
|
+
import { emitCompiledSourceBundle } from "./source.js";
|
|
11
|
+
/**
|
|
12
|
+
* @brief constructed compiled guards.
|
|
13
|
+
*/
|
|
14
|
+
const constructedCompiledGuards = new WeakSet();
|
|
15
|
+
/**
|
|
16
|
+
* @brief compiled base guard.
|
|
17
|
+
* @details Owns its state directly; methods expose receiver checks and explicit result flow.
|
|
18
|
+
* @invariant Construction leaves the instance in a fully usable state before it escapes.
|
|
19
|
+
*/
|
|
20
|
+
export class CompiledBaseGuard extends BaseGuard {
|
|
21
|
+
/**
|
|
22
|
+
* @brief constructor.
|
|
23
|
+
* @post The receiver is initialized according to the class invariant before it can be observed.
|
|
24
|
+
*/
|
|
25
|
+
constructor(schema, test, collect, source) {
|
|
26
|
+
if (typeof test !== "function") {
|
|
27
|
+
throw new TypeError("compiled guard test must be a function");
|
|
28
|
+
}
|
|
29
|
+
if (typeof collect !== "function") {
|
|
30
|
+
throw new TypeError("compiled guard collector must be a function");
|
|
31
|
+
}
|
|
32
|
+
if (typeof source !== "string") {
|
|
33
|
+
throw new TypeError("compiled guard source must be a string");
|
|
34
|
+
}
|
|
35
|
+
super(schema);
|
|
36
|
+
defineReadonlyProperty(this, "test", test, false);
|
|
37
|
+
defineReadonlyProperty(this, "collect", collect, false);
|
|
38
|
+
defineReadonlyProperty(this, "source", source, true);
|
|
39
|
+
constructedCompiledGuards.add(this);
|
|
40
|
+
Object.freeze(this);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @brief is.
|
|
44
|
+
*/
|
|
45
|
+
is(value) {
|
|
46
|
+
return isStrictTrue(readCompiledTest(this)(value));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* @brief check.
|
|
50
|
+
*/
|
|
51
|
+
check(value) {
|
|
52
|
+
return runCompiledCheck(this, value);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @brief assert.
|
|
56
|
+
*/
|
|
57
|
+
assert(value) {
|
|
58
|
+
const result = runCompiledCheck(this, value);
|
|
59
|
+
if (!result.ok) {
|
|
60
|
+
throw new TypeSeaAssertionError(result.error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @brief compile.
|
|
66
|
+
*/
|
|
67
|
+
export function compile(guard, options) {
|
|
68
|
+
const schema = readCompileSchema(guard);
|
|
69
|
+
const name = readCompileName(options);
|
|
70
|
+
const bundle = emitCompiledSourceBundle(schema, name);
|
|
71
|
+
// compile() intentionally emits source so V8 can optimize the validator body.
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
73
|
+
const factory = new Function("l", "r", "k", "u", "d", "m", "sk", bundle.source);
|
|
74
|
+
const dynamicCheck = makeDynamicCheck(bundle.dynamicSchemas);
|
|
75
|
+
const runtime = factory(bundle.literals, bundle.regexps, bundle.keysets, bundle.strings, dynamicCheck, makeDynamicIssueCheck(bundle.dynamicSchemas), strictKeys);
|
|
76
|
+
return new CompiledBaseGuard(schema, runtime.is, runtime.check, bundle.source);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @brief read compile schema.
|
|
80
|
+
*/
|
|
81
|
+
function readCompileSchema(guard) {
|
|
82
|
+
if (!isRecord(guard)) {
|
|
83
|
+
throw new TypeError("compile guard must be a TypeSea guard");
|
|
84
|
+
}
|
|
85
|
+
const schema = guard["schema"];
|
|
86
|
+
if (!isSchemaValue(schema)) {
|
|
87
|
+
throw new TypeError("compile guard must contain a valid TypeSea schema");
|
|
88
|
+
}
|
|
89
|
+
return freezeSchema(schema);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* @brief is strict true.
|
|
93
|
+
*/
|
|
94
|
+
function isStrictTrue(value) {
|
|
95
|
+
return value === true;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @brief run compiled check.
|
|
99
|
+
*/
|
|
100
|
+
function runCompiledCheck(guard, value) {
|
|
101
|
+
const issues = finalizeIssueArray(readCompiledCollect(guard)(value));
|
|
102
|
+
if (issues.length === 0) {
|
|
103
|
+
return ok(value);
|
|
104
|
+
}
|
|
105
|
+
return err(issues);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* @brief read compiled test.
|
|
109
|
+
*/
|
|
110
|
+
function readCompiledTest(guard) {
|
|
111
|
+
if (isConstructedCompiledGuard(guard)) {
|
|
112
|
+
return guard["test"];
|
|
113
|
+
}
|
|
114
|
+
if (!isRecord(guard)) {
|
|
115
|
+
throw new TypeError("compiled guard receiver must be a TypeSea guard");
|
|
116
|
+
}
|
|
117
|
+
const test = guard["test"];
|
|
118
|
+
if (typeof test !== "function") {
|
|
119
|
+
throw new TypeError("compiled guard receiver must contain a test function");
|
|
120
|
+
}
|
|
121
|
+
return test;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* @brief read compiled collect.
|
|
125
|
+
*/
|
|
126
|
+
function readCompiledCollect(guard) {
|
|
127
|
+
if (isConstructedCompiledGuard(guard)) {
|
|
128
|
+
return guard["collect"];
|
|
129
|
+
}
|
|
130
|
+
if (!isRecord(guard)) {
|
|
131
|
+
throw new TypeError("compiled guard receiver must be a TypeSea guard");
|
|
132
|
+
}
|
|
133
|
+
const collect = guard["collect"];
|
|
134
|
+
if (typeof collect !== "function") {
|
|
135
|
+
throw new TypeError("compiled guard receiver must contain a collector function");
|
|
136
|
+
}
|
|
137
|
+
return collect;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* @brief define readonly property.
|
|
141
|
+
*/
|
|
142
|
+
function defineReadonlyProperty(target, key, value, enumerable) {
|
|
143
|
+
Object.defineProperty(target, key, {
|
|
144
|
+
configurable: false,
|
|
145
|
+
enumerable,
|
|
146
|
+
value,
|
|
147
|
+
writable: false
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* @brief read compile name.
|
|
152
|
+
*/
|
|
153
|
+
function readCompileName(options) {
|
|
154
|
+
if (options === undefined) {
|
|
155
|
+
return "typesea_is";
|
|
156
|
+
}
|
|
157
|
+
if (!isRecord(options)) {
|
|
158
|
+
throw new TypeError("compile options must be an object");
|
|
159
|
+
}
|
|
160
|
+
const name = options["name"];
|
|
161
|
+
if (name === undefined) {
|
|
162
|
+
return "typesea_is";
|
|
163
|
+
}
|
|
164
|
+
if (typeof name !== "string") {
|
|
165
|
+
throw new TypeError("compile name must be a string");
|
|
166
|
+
}
|
|
167
|
+
return name;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* @brief is record.
|
|
171
|
+
*/
|
|
172
|
+
function isRecord(value) {
|
|
173
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* @brief is constructed compiled guard.
|
|
177
|
+
*/
|
|
178
|
+
function isConstructedCompiledGuard(value) {
|
|
179
|
+
return isRecord(value) && constructedCompiledGuards.has(value);
|
|
180
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file compile/index.ts
|
|
3
|
+
* @brief Public compile module barrel.
|
|
4
|
+
*/
|
|
5
|
+
export { CompiledBaseGuard, compile } from "./guard.js";
|
|
6
|
+
export { emitCompiledSourceBundle } from "./source.js";
|
|
7
|
+
export type { CompileOptions, CompiledGuard, CompiledSourceBundle } from "./types.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|