@oh-my-pi/omptype 18.16.0 → 18.18.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 +18 -0
- package/README.md +33 -0
- package/dist/js/compile.js +25 -3
- package/dist/js/from-json-schema.js +61 -216
- package/dist/js/interp.js +2 -0
- package/dist/js/jsonschema/codegen.js +514 -0
- package/dist/js/jsonschema/interpret.js +729 -0
- package/dist/js/jsonschema/pattern.js +221 -0
- package/dist/js/jsonschema/plan.js +448 -0
- package/dist/js/jsonschema/resolve.js +321 -0
- package/dist/js/jsonschema/runtime.js +129 -0
- package/dist/js/jsonschema/validator.js +106 -0
- package/dist/js/typebox.js +5 -5
- package/dist/types/from-json-schema.d.ts +8 -3
- package/dist/types/ir.d.ts +2 -0
- package/dist/types/jsonschema/codegen.d.ts +6 -0
- package/dist/types/jsonschema/interpret.d.ts +48 -0
- package/dist/types/jsonschema/pattern.d.ts +17 -0
- package/dist/types/jsonschema/plan.d.ts +128 -0
- package/dist/types/jsonschema/resolve.d.ts +43 -0
- package/dist/types/jsonschema/runtime.d.ts +30 -0
- package/dist/types/jsonschema/validator.d.ts +33 -0
- package/package.json +2 -5
- package/src/compile.ts +24 -3
- package/src/from-json-schema.ts +64 -213
- package/src/interp.ts +1 -0
- package/src/ir.ts +2 -0
- package/src/jsonschema/codegen.ts +495 -0
- package/src/jsonschema/interpret.ts +724 -0
- package/src/jsonschema/pattern.ts +202 -0
- package/src/jsonschema/plan.ts +538 -0
- package/src/jsonschema/resolve.ts +333 -0
- package/src/jsonschema/runtime.ts +117 -0
- package/src/jsonschema/validator.ts +113 -0
- package/src/typebox.ts +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.17.0] - 2026-11-06
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- `fromJsonSchema` returns an opaque whole-document validator (no `.pick()`/`.props`); `format` is annotation-only unless checked via `formats`; bad `$ref` throws `invalid $ref`/`unresolved $ref`.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added `fromJsonSchema(schema, { draft, schemas, formats })`, validating JSON Schema draft 2020-12 and draft 7, including dynamic/remote refs and unevaluated keywords.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Faster `fromJsonSchema` validation, including `$ref`-heavy schemas.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- `fromJsonSchema` falls back to interpreted validation instead of throwing `EvalError` where generated code is forbidden.
|
|
22
|
+
|
|
5
23
|
## [18.13.3] - 2026-10-28
|
|
6
24
|
|
|
7
25
|
### Changed
|
package/README.md
CHANGED
|
@@ -87,6 +87,39 @@ const user = ZodUser.parse({ name: "Ada" });
|
|
|
87
87
|
`@oh-my-pi/omptype/ark` provides the repository's ArkType compatibility facade
|
|
88
88
|
and re-exports the same `type` and `scope` implementations.
|
|
89
89
|
|
|
90
|
+
## JSON Schema import
|
|
91
|
+
|
|
92
|
+
`fromJsonSchema` turns any JSON Schema document into an omptype schema that
|
|
93
|
+
validates exactly as drafts 2020-12 and 7 specify, including `$dynamicRef`,
|
|
94
|
+
`unevaluatedProperties`/`unevaluatedItems`, `$id`/`$anchor` resolution, and
|
|
95
|
+
meta-schema vocabularies:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { fromJsonSchema } from "@oh-my-pi/omptype";
|
|
99
|
+
|
|
100
|
+
const read = fromJsonSchema(mcpTool.inputSchema, {
|
|
101
|
+
draft: "2020-12", // semantics where a resource declares no `$schema` ("7" for draft 7)
|
|
102
|
+
schemas: { "https://example.com/defs.json": defs }, // documents `$ref`s may name
|
|
103
|
+
formats: { email: value => value.includes("@") }, // `format` only asserts with a check
|
|
104
|
+
});
|
|
105
|
+
read.allows(args); // boolean
|
|
106
|
+
read(args); // args with absent `default`s filled in, or OmpErrors with paths
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The first calls are interpreted from a compiled plan; hot schemas switch to
|
|
110
|
+
generated code (tagged unions become a `switch`, simple patterns char-code
|
|
111
|
+
checks). It passes all 1,298 draft 2020-12 and 925 draft 7 core tests of the
|
|
112
|
+
JSON-Schema-Test-Suite. Hot checks from the
|
|
113
|
+
[pi-schema benchmark](https://github.com/earendil-works/pi/tree/main/packages/schema)
|
|
114
|
+
(Node 26, Apple M4 Max, ns per valid check):
|
|
115
|
+
|
|
116
|
+
| Case | omptype | ata | Ajv | TypeBox | pi-schema |
|
|
117
|
+
| -------------------------------- | ------: | --: | --: | ------: | --------: |
|
|
118
|
+
| nested object with tagged unions | **85** | 131 | 337 | 341 | 305 |
|
|
119
|
+
| union of 5 messages | **11** | 24 | 48 | 75 | 60 |
|
|
120
|
+
| MCP tool schema with `$ref` | **35** | 40 | 85 | 66 | 113 |
|
|
121
|
+
| recursive `$ref` schema | **158** | 196 | 246 | 776 | 570 |
|
|
122
|
+
|
|
90
123
|
## Performance
|
|
91
124
|
|
|
92
125
|
Run the benchmark from the repository root:
|
package/dist/js/compile.js
CHANGED
|
@@ -240,6 +240,10 @@ class Builder {
|
|
|
240
240
|
}
|
|
241
241
|
case "sub":
|
|
242
242
|
return `!(${this.ref(node.schema.run)}(${v}) instanceof AE)`;
|
|
243
|
+
case "refine":
|
|
244
|
+
if (node.check !== undefined)
|
|
245
|
+
return `(${this.predicate(node.base, v)})&&${this.ref(node.check)}(${v})`;
|
|
246
|
+
return `!(${this.ref(boundWalk(node))}(${v}) instanceof AE)`;
|
|
243
247
|
default:
|
|
244
248
|
return `!(${this.ref(boundWalk(node))}(${v}) instanceof AE)`;
|
|
245
249
|
}
|
|
@@ -895,6 +899,22 @@ function boundWalk(node) {
|
|
|
895
899
|
function resolvedRoot(ir) {
|
|
896
900
|
return ir.k === "alias" ? ir.resolve() : ir;
|
|
897
901
|
}
|
|
902
|
+
/** Set once the runtime refuses code generation from strings (strict CSP); the interpreter serves from then on. */
|
|
903
|
+
let jitBlocked = false;
|
|
904
|
+
/** Build with `build`, or `undefined` when code generation from strings is forbidden. */
|
|
905
|
+
function tryBuild(build) {
|
|
906
|
+
if (jitBlocked)
|
|
907
|
+
return undefined;
|
|
908
|
+
try {
|
|
909
|
+
return build();
|
|
910
|
+
}
|
|
911
|
+
catch (error) {
|
|
912
|
+
if (!(error instanceof EvalError))
|
|
913
|
+
throw error;
|
|
914
|
+
jitBlocked = true;
|
|
915
|
+
return undefined;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
898
918
|
const compiledCache = new WeakMap();
|
|
899
919
|
const allowsCache = new WeakMap();
|
|
900
920
|
/** Compile `ir` into a specialized validator. */
|
|
@@ -908,8 +928,9 @@ export function compile(ir) {
|
|
|
908
928
|
// fresh one forever. The wrapper resolves to the built validator by call
|
|
909
929
|
// time; the interpreter is a safety net that never triggers post-build.
|
|
910
930
|
const built = {};
|
|
911
|
-
|
|
912
|
-
|
|
931
|
+
const deferred = (value) => (built.value === undefined ? walk(root, value) : built.value(value));
|
|
932
|
+
compiledCache.set(root, deferred);
|
|
933
|
+
const compiled = tryBuild(() => new Builder().build(root)) ?? ((value) => walk(root, value));
|
|
913
934
|
built.value = compiled;
|
|
914
935
|
compiledCache.set(root, compiled);
|
|
915
936
|
return compiled;
|
|
@@ -923,7 +944,8 @@ export function compileAllows(ir) {
|
|
|
923
944
|
if (validator === undefined) {
|
|
924
945
|
const built = {};
|
|
925
946
|
allowsCache.set(root, ((value) => built.value === undefined ? !(walk(root, value) instanceof OmpErrors) : built.value(value)));
|
|
926
|
-
const compiled = new Builder().buildAllows(root)
|
|
947
|
+
const compiled = tryBuild(() => new Builder().buildAllows(root)) ??
|
|
948
|
+
((value) => !(walk(root, value) instanceof OmpErrors));
|
|
927
949
|
built.value = compiled;
|
|
928
950
|
allowsCache.set(root, compiled);
|
|
929
951
|
return compiled;
|
|
@@ -1,235 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSON Schema → omptype importer.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Validates exactly as JSON Schema drafts 2020-12 and 7 specify: every
|
|
5
|
+
* keyword including `$dynamicRef`, `unevaluatedProperties`/`unevaluatedItems`,
|
|
6
|
+
* `$id`/`$anchor` resolution, remote references, and vocabularies declared by
|
|
7
|
+
* meta-schemas. Validation runs on an eval-free closure engine and moves to
|
|
8
|
+
* generated code once a schema is hot (see `jsonschema/`).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The result is a regular omptype schema: callable, composable, emitting the
|
|
11
|
+
* source document from `toJsonSchema()`, and filling absent properties from
|
|
12
|
+
* their `default` when called (never in `allows`).
|
|
13
|
+
*
|
|
14
|
+
* # Example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const read = fromJsonSchema({
|
|
17
|
+
* type: "object",
|
|
18
|
+
* properties: { path: { type: "string" }, offset: { type: "integer", minimum: 0 } },
|
|
19
|
+
* required: ["path"],
|
|
20
|
+
* });
|
|
21
|
+
* read.allows({ path: "a.ts" }); // true
|
|
22
|
+
* read({ offset: -1 }); // OmpErrors: path missing, offset below 0
|
|
23
|
+
* ```
|
|
13
24
|
*/
|
|
14
|
-
import {
|
|
15
|
-
import { parseLocalRefPointer } from "./local-ref.js";
|
|
25
|
+
import { OmpErrors } from "./errors.js";
|
|
16
26
|
import { IR_BRAND } from "./ir.js";
|
|
17
|
-
import {
|
|
27
|
+
import { Validator } from "./jsonschema/validator.js";
|
|
18
28
|
import { type } from "./type.js";
|
|
19
|
-
/** `format` values lowered to built-in keyword validators. */
|
|
20
|
-
const FORMAT_KEYWORDS = {
|
|
21
|
-
email: "string.email",
|
|
22
|
-
uuid: "string.uuid",
|
|
23
|
-
"date-time": "string.date.iso",
|
|
24
|
-
date: "string.date.iso",
|
|
25
|
-
ipv4: "string.ip.v4",
|
|
26
|
-
ipv6: "string.ip.v6",
|
|
27
|
-
regex: "string.regex",
|
|
28
|
-
};
|
|
29
|
-
class Importer {
|
|
30
|
-
#root;
|
|
31
|
-
#aliases = new Map();
|
|
32
|
-
constructor(root) {
|
|
33
|
-
this.#root = root;
|
|
34
|
-
}
|
|
35
|
-
resolveRef(ref) {
|
|
36
|
-
const cached = this.#aliases.get(ref);
|
|
37
|
-
if (cached !== undefined)
|
|
38
|
-
return cached;
|
|
39
|
-
let target;
|
|
40
|
-
if (ref === "#") {
|
|
41
|
-
target = this.#root;
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
const pointer = parseLocalRefPointer(ref);
|
|
45
|
-
if (pointer === undefined || pointer.length !== 2 || (pointer[0] !== "$defs" && pointer[0] !== "definitions"))
|
|
46
|
-
throw new OmpTypeError(`unsupported $ref: ${ref}`);
|
|
47
|
-
const defs = this.#root[pointer[0]];
|
|
48
|
-
target = typeof defs === "object" && defs !== null ? defs[pointer[1]] : undefined;
|
|
49
|
-
if (target === undefined)
|
|
50
|
-
throw new OmpTypeError(`unresolved $ref: ${ref}`);
|
|
51
|
-
}
|
|
52
|
-
// Register the alias before lowering so recursive references resolve
|
|
53
|
-
// to the same node instead of recursing forever.
|
|
54
|
-
let lowered;
|
|
55
|
-
const alias = {
|
|
56
|
-
k: "alias",
|
|
57
|
-
name: ref,
|
|
58
|
-
resolve: () => {
|
|
59
|
-
lowered ??= this.lower(target);
|
|
60
|
-
return lowered;
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
this.#aliases.set(ref, alias);
|
|
64
|
-
return alias;
|
|
65
|
-
}
|
|
66
|
-
lower(schema) {
|
|
67
|
-
if (schema === true)
|
|
68
|
-
return { k: "unknown" };
|
|
69
|
-
if (schema === false)
|
|
70
|
-
return { k: "never" };
|
|
71
|
-
if (typeof schema !== "object" || schema === null) {
|
|
72
|
-
throw new OmpTypeError("JSON Schema nodes must be booleans or objects");
|
|
73
|
-
}
|
|
74
|
-
const node = schema;
|
|
75
|
-
const desc = typeof node.description === "string" ? node.description : undefined;
|
|
76
|
-
const ir = this.#lowerNode(node);
|
|
77
|
-
return desc === undefined ? ir : { ...ir, desc };
|
|
78
|
-
}
|
|
79
|
-
#lowerNode(node) {
|
|
80
|
-
if (typeof node.$ref === "string")
|
|
81
|
-
return this.resolveRef(node.$ref);
|
|
82
|
-
if (Array.isArray(node.enum)) {
|
|
83
|
-
const members = node.enum.map((v) => ({ k: "lit", v }));
|
|
84
|
-
return members.length === 1 ? members[0] : { k: "union", members };
|
|
85
|
-
}
|
|
86
|
-
if ("const" in node)
|
|
87
|
-
return { k: "lit", v: node.const };
|
|
88
|
-
const branches = node.anyOf ?? node.oneOf;
|
|
89
|
-
if (Array.isArray(branches)) {
|
|
90
|
-
return { k: "union", members: branches.map(branch => this.lower(branch)) };
|
|
91
|
-
}
|
|
92
|
-
if (Array.isArray(node.allOf)) {
|
|
93
|
-
const members = node.allOf.map(branch => this.lower(branch));
|
|
94
|
-
return members.length === 1 ? members[0] : { k: "intersection", members };
|
|
95
|
-
}
|
|
96
|
-
if (typeof node.not === "object" && node.not !== null && Object.keys(node.not).length === 0) {
|
|
97
|
-
return { k: "never" };
|
|
98
|
-
}
|
|
99
|
-
if (Array.isArray(node.type)) {
|
|
100
|
-
const members = node.type.map(t => this.#lowerTyped(node, String(t)));
|
|
101
|
-
return members.length === 1 ? members[0] : { k: "union", members };
|
|
102
|
-
}
|
|
103
|
-
if (typeof node.type === "string")
|
|
104
|
-
return this.#lowerTyped(node, node.type);
|
|
105
|
-
// No explicit type: infer from structural keywords, else accept anything.
|
|
106
|
-
if (node.properties !== undefined || node.required !== undefined)
|
|
107
|
-
return this.#lowerObject(node);
|
|
108
|
-
if (node.items !== undefined || node.prefixItems !== undefined)
|
|
109
|
-
return this.#lowerArray(node);
|
|
110
|
-
return { k: "unknown" };
|
|
111
|
-
}
|
|
112
|
-
#lowerTyped(node, kind) {
|
|
113
|
-
switch (kind) {
|
|
114
|
-
case "null":
|
|
115
|
-
return { k: "null" };
|
|
116
|
-
case "boolean":
|
|
117
|
-
return { k: "boolean" };
|
|
118
|
-
case "string":
|
|
119
|
-
return this.#lowerString(node);
|
|
120
|
-
case "number":
|
|
121
|
-
case "integer": {
|
|
122
|
-
const ir = { k: "number" };
|
|
123
|
-
if (kind === "integer")
|
|
124
|
-
ir.int = true;
|
|
125
|
-
if (typeof node.minimum === "number")
|
|
126
|
-
ir.min = node.minimum;
|
|
127
|
-
if (typeof node.maximum === "number")
|
|
128
|
-
ir.max = node.maximum;
|
|
129
|
-
if (typeof node.exclusiveMinimum === "number") {
|
|
130
|
-
ir.min = node.exclusiveMinimum;
|
|
131
|
-
ir.xmin = true;
|
|
132
|
-
}
|
|
133
|
-
if (typeof node.exclusiveMaximum === "number") {
|
|
134
|
-
ir.max = node.exclusiveMaximum;
|
|
135
|
-
ir.xmax = true;
|
|
136
|
-
}
|
|
137
|
-
if (typeof node.multipleOf === "number")
|
|
138
|
-
ir.divisor = node.multipleOf;
|
|
139
|
-
return ir;
|
|
140
|
-
}
|
|
141
|
-
case "object":
|
|
142
|
-
return this.#lowerObject(node);
|
|
143
|
-
case "array":
|
|
144
|
-
return this.#lowerArray(node);
|
|
145
|
-
default:
|
|
146
|
-
throw new OmpTypeError(`unsupported JSON Schema type: ${kind}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
#lowerString(node) {
|
|
150
|
-
const base = { k: "string" };
|
|
151
|
-
if (typeof node.minLength === "number")
|
|
152
|
-
base.min = node.minLength;
|
|
153
|
-
if (typeof node.maxLength === "number")
|
|
154
|
-
base.max = node.maxLength;
|
|
155
|
-
if (node.format === "uri" || node.format === "url")
|
|
156
|
-
base.url = true;
|
|
157
|
-
const members = [];
|
|
158
|
-
if (typeof node.format === "string") {
|
|
159
|
-
const keyword = FORMAT_KEYWORDS[node.format];
|
|
160
|
-
if (keyword !== undefined) {
|
|
161
|
-
const formatIR = keywordIR(keyword);
|
|
162
|
-
if (formatIR !== undefined)
|
|
163
|
-
members.push(formatIR);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (typeof node.pattern === "string")
|
|
167
|
-
members.push(patternIR(new RegExp(node.pattern)));
|
|
168
|
-
if (members.length === 0)
|
|
169
|
-
return base;
|
|
170
|
-
if (base.min !== undefined || base.max !== undefined || base.url)
|
|
171
|
-
members.unshift(base);
|
|
172
|
-
return members.length === 1 ? members[0] : { k: "intersection", members };
|
|
173
|
-
}
|
|
174
|
-
#lowerObject(node) {
|
|
175
|
-
const required = new Set(Array.isArray(node.required) ? node.required.map(String) : []);
|
|
176
|
-
const props = [];
|
|
177
|
-
if (typeof node.properties === "object" && node.properties !== null) {
|
|
178
|
-
for (const [key, value] of Object.entries(node.properties)) {
|
|
179
|
-
const prop = { key, opt: !required.has(key), val: this.lower(value) };
|
|
180
|
-
if (typeof value === "object" && value !== null && "default" in value) {
|
|
181
|
-
prop.hasDefault = true;
|
|
182
|
-
prop.def = value.default;
|
|
183
|
-
prop.opt = true;
|
|
184
|
-
}
|
|
185
|
-
props.push(prop);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
const extra = node.additionalProperties;
|
|
189
|
-
return {
|
|
190
|
-
k: "object",
|
|
191
|
-
props,
|
|
192
|
-
extras: extra === false ? "reject" : "keep",
|
|
193
|
-
...(typeof extra === "object" && extra !== null ? { index: this.lower(extra) } : {}),
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
#lowerArray(node) {
|
|
197
|
-
if (Array.isArray(node.prefixItems)) {
|
|
198
|
-
const minItems = typeof node.minItems === "number" ? node.minItems : node.prefixItems.length;
|
|
199
|
-
const prefix = node.prefixItems.map((item, index) => ({
|
|
200
|
-
val: this.lower(item),
|
|
201
|
-
opt: index >= minItems,
|
|
202
|
-
}));
|
|
203
|
-
return {
|
|
204
|
-
k: "tuple",
|
|
205
|
-
prefix,
|
|
206
|
-
postfix: [],
|
|
207
|
-
...(node.items !== undefined && node.items !== false ? { variadic: this.lower(node.items) } : {}),
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
const ir = { k: "array", el: node.items === undefined ? { k: "unknown" } : this.lower(node.items) };
|
|
211
|
-
if (typeof node.minItems === "number")
|
|
212
|
-
ir.min = node.minItems;
|
|
213
|
-
if (typeof node.maxItems === "number")
|
|
214
|
-
ir.max = node.maxItems;
|
|
215
|
-
return ir;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
29
|
/**
|
|
219
30
|
* Build a callable omptype schema from a JSON Schema document.
|
|
220
31
|
*
|
|
221
32
|
* # Errors
|
|
222
|
-
* Throws
|
|
223
|
-
*
|
|
33
|
+
* Throws `OmpTypeError` when a `$ref` is malformed or names a document or
|
|
34
|
+
* location that neither `schema` nor `options.schemas` contains, when a
|
|
35
|
+
* `pattern` is not a regular expression, or when a schema node is neither a
|
|
36
|
+
* boolean nor an object.
|
|
224
37
|
*/
|
|
225
|
-
export function fromJsonSchema(schema) {
|
|
226
|
-
|
|
38
|
+
export function fromJsonSchema(schema, options) {
|
|
39
|
+
// Runs after 64 checks, long after `imported` below exists.
|
|
40
|
+
const validator = new Validator(schema, options, compiled => {
|
|
41
|
+
imported.allows = compiled;
|
|
42
|
+
});
|
|
43
|
+
const check = validator.check;
|
|
44
|
+
const node = typeof schema === "object" && schema !== null ? schema : undefined;
|
|
45
|
+
const refine = {
|
|
46
|
+
k: "refine",
|
|
47
|
+
base: { k: "unknown" },
|
|
48
|
+
check,
|
|
49
|
+
pred: value => check(value) || toErrors(validator.explain(value), value),
|
|
50
|
+
expected: "a value matching the JSON Schema",
|
|
51
|
+
json: node ?? (schema === false ? { not: {} } : {}),
|
|
52
|
+
};
|
|
53
|
+
if (typeof node?.description === "string")
|
|
54
|
+
refine.desc = node.description;
|
|
55
|
+
const ir = validator.hasDefaults
|
|
56
|
+
? { k: "morph", input: refine, fn: value => validator.fillDefaults(value) }
|
|
57
|
+
: refine;
|
|
227
58
|
const embedded = {
|
|
228
59
|
[IR_BRAND]: true,
|
|
229
|
-
ir
|
|
60
|
+
ir,
|
|
230
61
|
hasSteps: false,
|
|
231
62
|
hasDefault: false,
|
|
232
63
|
run: value => value,
|
|
233
64
|
};
|
|
234
|
-
|
|
65
|
+
const imported = type.raw(embedded);
|
|
66
|
+
// The engine's check is the whole boolean path; skip the generic dispatcher.
|
|
67
|
+
// Once generated code exists, `onCompile` above rebinds `allows` to it.
|
|
68
|
+
Object.defineProperty(imported, "allows", { value: check, writable: true, configurable: true });
|
|
69
|
+
return imported;
|
|
70
|
+
}
|
|
71
|
+
function toErrors(issues, value) {
|
|
72
|
+
if (issues.length === 0)
|
|
73
|
+
return new OmpErrors([], "a value matching the JSON Schema", value);
|
|
74
|
+
const errors = new OmpErrors(issues[0].path, issues[0].expected, issues[0].data);
|
|
75
|
+
for (let index = 1; index < issues.length; index++) {
|
|
76
|
+
const issue = issues[index];
|
|
77
|
+
errors.append(new OmpErrors(issue.path, issue.expected, issue.data));
|
|
78
|
+
}
|
|
79
|
+
return errors;
|
|
235
80
|
}
|