schemair 0.1.0 → 0.3.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/README.md +542 -32
- package/dist/authoring/index.cjs +13 -350
- package/dist/authoring/index.d.cts +2 -90
- package/dist/authoring/index.d.ts +2 -90
- package/dist/authoring/index.js +2 -304
- package/dist/authoring-Dnrg5TXm.cjs +389 -0
- package/dist/authoring-DyJNYs5o.js +362 -0
- package/dist/chunk-bFfwrPtJ.js +18 -0
- package/dist/compatibility/index.cjs +43 -0
- package/dist/compatibility/index.d.cts +2 -0
- package/dist/compatibility/index.d.ts +2 -0
- package/dist/compatibility/index.js +42 -0
- package/dist/definition/index.cjs +10 -2
- package/dist/definition/index.d.cts +3 -21
- package/dist/definition/index.d.ts +3 -21
- package/dist/definition/index.js +2 -2
- package/dist/definition-BH_LzXGc.js +1115 -0
- package/dist/definition-BLLBpLKv.cjs +1187 -0
- package/dist/index-1sDuqu05.d.ts +373 -0
- package/dist/index-BFSMT_2d.d.ts +53 -0
- package/dist/index-BGz7L_Fq.d.cts +73 -0
- package/dist/index-BTtdqi_M.d.ts +418 -0
- package/dist/index-BfbClf6R.d.cts +20 -0
- package/dist/index-CK7Is7vy.d.cts +420 -0
- package/dist/index-CUGhtuwA.d.cts +53 -0
- package/dist/index-CV8EZQy8.d.ts +92 -0
- package/dist/index-CzNxjqVg.d.cts +47 -0
- package/dist/index-DGHMUZ5m.d.cts +92 -0
- package/dist/{index-eK2Xgrwp.d.ts → index-DxvfPmw6.d.ts} +13 -9
- package/dist/index-T6nFhvGQ.d.ts +20 -0
- package/dist/{index-TACcK_mi.d.cts → index-ba_52Yu9.d.cts} +13 -9
- package/dist/index-hrcM9oJe.d.ts +47 -0
- package/dist/index-i7Au-FQ6.d.cts +373 -0
- package/dist/index-mu1znI1F.d.ts +73 -0
- package/dist/index.cjs +70 -58
- package/dist/index.d.cts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +10 -6
- package/dist/integrations/json-schema/index.cjs +328 -0
- package/dist/integrations/json-schema/index.d.cts +53 -0
- package/dist/integrations/json-schema/index.d.ts +53 -0
- package/dist/integrations/json-schema/index.js +324 -0
- package/dist/integrations/standard-schema/index.cjs +32 -0
- package/dist/integrations/standard-schema/index.d.cts +22 -0
- package/dist/integrations/standard-schema/index.d.ts +22 -0
- package/dist/integrations/standard-schema/index.js +32 -0
- package/dist/payload/index.cjs +45 -82
- package/dist/payload/index.d.cts +2 -56
- package/dist/payload/index.d.ts +2 -56
- package/dist/payload/index.js +45 -81
- package/dist/relations/index.cjs +3 -4
- package/dist/relations/index.d.cts +2 -2
- package/dist/relations/index.d.ts +2 -2
- package/dist/relations/index.js +2 -2
- package/dist/{relations-CMz_0nf4.cjs → relations-NUVJkAG8.cjs} +143 -211
- package/dist/{relations-By0bK3UK.js → relations-QtnCRW9x.js} +140 -202
- package/dist/resolve/index.cjs +308 -0
- package/dist/resolve/index.d.cts +2 -0
- package/dist/resolve/index.d.ts +2 -0
- package/dist/resolve/index.js +305 -0
- package/dist/schema-ref-key-BHVFVfj1.cjs +26 -0
- package/dist/schema-ref-key-DR__tPr-.js +14 -0
- package/dist/spec/index.cjs +9 -0
- package/dist/spec/index.d.cts +2 -2
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +3 -1
- package/dist/standard/index.cjs +810 -0
- package/dist/standard/index.d.cts +3 -0
- package/dist/standard/index.d.ts +3 -0
- package/dist/standard/index.js +777 -0
- package/dist/standard-BGMgbbEQ.js +471 -0
- package/dist/standard-etPFZDJI.cjs +513 -0
- package/dist/type-interpreter/index.cjs +3 -7
- package/dist/type-interpreter/index.d.cts +2 -99
- package/dist/type-interpreter/index.d.ts +2 -99
- package/dist/type-interpreter/index.js +2 -2
- package/dist/{type-interpreter-Ck0VDhzn.js → type-interpreter-BA8gcLUU.js} +58 -560
- package/dist/{type-interpreter-DAIBUqKf.cjs → type-interpreter-D8xETgq1.cjs} +63 -589
- package/package.json +60 -5
- package/dist/definition-BXj3T94L.js +0 -467
- package/dist/definition-DSZZTz4e.cjs +0 -473
- package/dist/index-CEzHfht2.d.ts +0 -269
- package/dist/index-rzkFjgrt.d.cts +0 -269
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
const require_definition = require('../definition-BLLBpLKv.cjs');
|
|
2
|
+
const require_schema_ref_key = require('../schema-ref-key-BHVFVfj1.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/resolve/schema-closure.ts
|
|
5
|
+
var AsyncResolverError = class extends Error {};
|
|
6
|
+
function isObject(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function refNode(value) {
|
|
10
|
+
if (!isObject(value) || value.kind !== "ref" || !Array.isArray(value.refPath) || value.refPath.some((part) => typeof part !== "string")) return void 0;
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
function issue(status, code, path, message) {
|
|
14
|
+
return {
|
|
15
|
+
code: `closure.${status}.${code}`,
|
|
16
|
+
path,
|
|
17
|
+
message
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function children(value, basePath) {
|
|
21
|
+
if (Array.isArray(value)) return value.map((child, index) => ({
|
|
22
|
+
value: child,
|
|
23
|
+
path: basePath.length === 0 && index === 0 ? [] : [index]
|
|
24
|
+
}));
|
|
25
|
+
if (!isObject(value)) return [];
|
|
26
|
+
if (value.kind === "record" && Array.isArray(value.fields)) {
|
|
27
|
+
const fields = value.fields.flatMap((field) => {
|
|
28
|
+
if (!isObject(field) || typeof field.key !== "string" || !("schema" in field)) return [];
|
|
29
|
+
return [{
|
|
30
|
+
value: field.schema,
|
|
31
|
+
path: ["fields", field.key]
|
|
32
|
+
}];
|
|
33
|
+
});
|
|
34
|
+
if (value.additionalFields !== void 0 && value.additionalFields !== true) fields.push({
|
|
35
|
+
value: value.additionalFields,
|
|
36
|
+
path: ["additionalFields"]
|
|
37
|
+
});
|
|
38
|
+
return fields;
|
|
39
|
+
}
|
|
40
|
+
if (value.kind === "recordOf" && Array.isArray(value.fields)) {
|
|
41
|
+
const fields = value.fields.flatMap((field) => {
|
|
42
|
+
if (!isObject(field) || typeof field.key !== "string" || !("value" in field)) return [];
|
|
43
|
+
return [{
|
|
44
|
+
value: field.value,
|
|
45
|
+
path: ["fields", field.key]
|
|
46
|
+
}];
|
|
47
|
+
});
|
|
48
|
+
if (value.additionalFields !== void 0 && value.additionalFields !== true) fields.push({
|
|
49
|
+
value: value.additionalFields,
|
|
50
|
+
path: ["additionalFields"]
|
|
51
|
+
});
|
|
52
|
+
return fields;
|
|
53
|
+
}
|
|
54
|
+
if ((value.kind === "taggedUnion" || value.kind === "taggedUnionOf") && Array.isArray(value.variants)) {
|
|
55
|
+
const member = value.kind === "taggedUnion" ? "schema" : "value";
|
|
56
|
+
return value.variants.flatMap((variant) => {
|
|
57
|
+
if (!isObject(variant) || typeof variant.key !== "string" || !(member in variant)) return [];
|
|
58
|
+
return [{
|
|
59
|
+
value: variant[member],
|
|
60
|
+
path: ["variants", variant.key]
|
|
61
|
+
}];
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const members = {
|
|
65
|
+
array: ["elementSchema"],
|
|
66
|
+
tuple: ["elementSchemas"],
|
|
67
|
+
nullable: ["value"],
|
|
68
|
+
arrayOf: ["element"],
|
|
69
|
+
tupleOf: ["elements"],
|
|
70
|
+
nullableOf: ["value"],
|
|
71
|
+
maybeAbsent: ["value"],
|
|
72
|
+
typeVar: ["extends"],
|
|
73
|
+
mergeRecords: ["sources"],
|
|
74
|
+
intersect: ["sources"],
|
|
75
|
+
elementOf: ["source"],
|
|
76
|
+
valueOf: ["source"],
|
|
77
|
+
elementAt: ["source"],
|
|
78
|
+
fieldOf: ["source"],
|
|
79
|
+
keyOf: ["source"],
|
|
80
|
+
fieldsOf: ["source"],
|
|
81
|
+
pickFields: ["source"],
|
|
82
|
+
omitFields: ["source"],
|
|
83
|
+
partialFields: ["source"],
|
|
84
|
+
requiredFields: ["source"],
|
|
85
|
+
excludeVariants: ["source"],
|
|
86
|
+
extractVariants: ["source"],
|
|
87
|
+
structured: ["schema"]
|
|
88
|
+
};
|
|
89
|
+
if (typeof value.kind === "string") {
|
|
90
|
+
const edges$1 = (Object.hasOwn(members, value.kind) ? members[value.kind] : []).filter((key) => key in value).map((key) => ({
|
|
91
|
+
value: value[key],
|
|
92
|
+
path: [key]
|
|
93
|
+
}));
|
|
94
|
+
if (value.kind === "refine") {
|
|
95
|
+
edges$1.push({
|
|
96
|
+
value: value.source,
|
|
97
|
+
path: ["source"]
|
|
98
|
+
});
|
|
99
|
+
if (Array.isArray(value.fields)) value.fields.forEach((field, index) => {
|
|
100
|
+
if (isObject(field) && "intersectWith" in field) edges$1.push({
|
|
101
|
+
value: field.intersectWith,
|
|
102
|
+
path: [
|
|
103
|
+
"fields",
|
|
104
|
+
index,
|
|
105
|
+
"intersectWith"
|
|
106
|
+
]
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return edges$1;
|
|
111
|
+
}
|
|
112
|
+
const edges = [];
|
|
113
|
+
for (const key of [
|
|
114
|
+
"input",
|
|
115
|
+
"output",
|
|
116
|
+
"data"
|
|
117
|
+
]) if (key in value) edges.push({
|
|
118
|
+
value: value[key],
|
|
119
|
+
path: [key]
|
|
120
|
+
});
|
|
121
|
+
for (const key of [
|
|
122
|
+
"errors",
|
|
123
|
+
"emits",
|
|
124
|
+
"operations",
|
|
125
|
+
"containers"
|
|
126
|
+
]) if (isObject(value[key])) for (const [name, child] of Object.entries(value[key])) edges.push({
|
|
127
|
+
value: child,
|
|
128
|
+
path: [key, name]
|
|
129
|
+
});
|
|
130
|
+
return edges;
|
|
131
|
+
}
|
|
132
|
+
/** Recursively load all external schema references reachable from an entry,
|
|
133
|
+
* preserving reference paths and recording cycles rather than inlining refs.
|
|
134
|
+
* Yielding host requests lets both execution modes use identical traversal state. */
|
|
135
|
+
function* loadReferences(entry, context) {
|
|
136
|
+
const refs = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const ref of context.refs ?? []) refs.set(require_schema_ref_key.schemaRefKey(ref.refPath), {
|
|
138
|
+
refPath: [...ref.refPath],
|
|
139
|
+
schema: ref.schema
|
|
140
|
+
});
|
|
141
|
+
const active = /* @__PURE__ */ new Set();
|
|
142
|
+
const visited = /* @__PURE__ */ new Set();
|
|
143
|
+
const objects = /* @__PURE__ */ new Set();
|
|
144
|
+
const cycles = /* @__PURE__ */ new Map();
|
|
145
|
+
const issues = [];
|
|
146
|
+
let steps = 0;
|
|
147
|
+
let nodes = 0;
|
|
148
|
+
let rejected = false;
|
|
149
|
+
let incomplete = false;
|
|
150
|
+
function* walk(value, path, depth) {
|
|
151
|
+
steps += 1;
|
|
152
|
+
if (steps > (context.maxSteps ?? 1e4) || depth > (context.maxDepth ?? 64)) {
|
|
153
|
+
incomplete = true;
|
|
154
|
+
issues.push(issue("incomplete", "budget", path, "schema closure work budget exceeded"));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (isObject(value) && value.kind === "ref" && !require_definition.validateSchemaNodeDefinition(value).ok) {
|
|
158
|
+
rejected = true;
|
|
159
|
+
issues.push(issue("rejected", "schema", path, "reference must be a valid SchemaNode"));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const ref = refNode(value);
|
|
163
|
+
if (ref) {
|
|
164
|
+
const key = require_schema_ref_key.schemaRefKey(ref.refPath);
|
|
165
|
+
if (active.has(key)) {
|
|
166
|
+
cycles.set(key, [...ref.refPath]);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (visited.has(key)) return;
|
|
170
|
+
active.add(key);
|
|
171
|
+
try {
|
|
172
|
+
const preloaded = refs.get(key);
|
|
173
|
+
if (preloaded !== void 0) {
|
|
174
|
+
if (!require_definition.validateSchemaNodeDefinition(preloaded.schema).ok) {
|
|
175
|
+
rejected = true;
|
|
176
|
+
issues.push(issue("rejected", "schema", path, "preloaded ref did not contain a valid SchemaNode"));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
visited.add(key);
|
|
180
|
+
yield* walk(preloaded.schema, path, depth + 1);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (nodes >= (context.maxNodes ?? 1e4)) {
|
|
184
|
+
incomplete = true;
|
|
185
|
+
issues.push(issue("incomplete", "nodes", path, "schema closure node budget exceeded"));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
let resolution;
|
|
189
|
+
if (!context.resolveRef) {
|
|
190
|
+
incomplete = true;
|
|
191
|
+
issues.push(issue("incomplete", "unresolved", path, "refPath is not present in the resolved environment"));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
resolution = yield {
|
|
196
|
+
refPath: ref.refPath,
|
|
197
|
+
context: {
|
|
198
|
+
path,
|
|
199
|
+
refPath: ref.refPath,
|
|
200
|
+
ref,
|
|
201
|
+
depth
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
} catch (error) {
|
|
205
|
+
incomplete = true;
|
|
206
|
+
issues.push(issue("incomplete", error instanceof AsyncResolverError ? "resolver.async" : "resolver", path, `refPath resolver failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (!resolution) {
|
|
210
|
+
incomplete = true;
|
|
211
|
+
issues.push(issue("incomplete", "unresolved", path, "refPath resolver returned no schema"));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (typeof resolution === "object" && "status" in resolution && resolution.status !== "resolved") {
|
|
215
|
+
incomplete = true;
|
|
216
|
+
issues.push(issue("incomplete", `ref.${resolution.status}`, path, resolution.message ?? "refPath resolver could not determine this path"));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const definition = require_definition.validateSchemaNodeDefinition(typeof resolution === "object" && "status" in resolution ? resolution.schema : resolution);
|
|
220
|
+
if (!definition.ok) {
|
|
221
|
+
rejected = true;
|
|
222
|
+
issues.push(issue("rejected", "schema", path, "resolved ref did not contain a valid SchemaNode"));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
refs.set(key, {
|
|
226
|
+
refPath: [...ref.refPath],
|
|
227
|
+
schema: definition.node
|
|
228
|
+
});
|
|
229
|
+
nodes += 1;
|
|
230
|
+
visited.add(key);
|
|
231
|
+
yield* walk(definition.node, path, depth + 1);
|
|
232
|
+
} finally {
|
|
233
|
+
active.delete(key);
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!isObject(value) && !Array.isArray(value)) return;
|
|
238
|
+
if (objects.has(value)) {
|
|
239
|
+
incomplete = true;
|
|
240
|
+
issues.push(issue("incomplete", "cycle.data", path, "input contains an object cycle"));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
objects.add(value);
|
|
244
|
+
try {
|
|
245
|
+
for (const child of children(value, path)) yield* walk(child.value, [...path, ...child.path], depth + 1);
|
|
246
|
+
} finally {
|
|
247
|
+
objects.delete(value);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
yield* walk(entry, [], 0);
|
|
251
|
+
return {
|
|
252
|
+
status: rejected ? "rejected" : incomplete ? "incomplete" : "resolved",
|
|
253
|
+
graph: {
|
|
254
|
+
refs: [...refs.values()],
|
|
255
|
+
cycles: [...cycles.values()].sort((left, right) => require_schema_ref_key.schemaRefKey(left).localeCompare(require_schema_ref_key.schemaRefKey(right)))
|
|
256
|
+
},
|
|
257
|
+
issues
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/** Load references using a synchronous host resolver. */
|
|
261
|
+
function resolveSchemaReferences(entry, context = {}) {
|
|
262
|
+
const traversal = loadReferences(entry, context);
|
|
263
|
+
let step = traversal.next();
|
|
264
|
+
while (!step.done) {
|
|
265
|
+
let resolution;
|
|
266
|
+
try {
|
|
267
|
+
resolution = context.resolveRef(step.value.refPath, step.value.context);
|
|
268
|
+
if (resolution && typeof resolution === "object" && "then" in resolution && typeof resolution.then === "function") {
|
|
269
|
+
if (resolution instanceof Promise) resolution.catch(() => {});
|
|
270
|
+
throw new AsyncResolverError("reference loading requires a synchronous resolver; use resolveSchemaReferencesAsync");
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
step = traversal.throw(error);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
step = traversal.next(resolution);
|
|
277
|
+
}
|
|
278
|
+
return step.value;
|
|
279
|
+
}
|
|
280
|
+
/** Load references using a synchronous or asynchronous host resolver. */
|
|
281
|
+
async function resolveSchemaReferencesAsync(entry, context = {}) {
|
|
282
|
+
const traversal = loadReferences(entry, context);
|
|
283
|
+
let step = traversal.next();
|
|
284
|
+
while (!step.done) {
|
|
285
|
+
let resolution;
|
|
286
|
+
try {
|
|
287
|
+
resolution = await context.resolveRef(step.value.refPath, step.value.context);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
step = traversal.throw(error);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
step = traversal.next(resolution);
|
|
293
|
+
}
|
|
294
|
+
return step.value;
|
|
295
|
+
}
|
|
296
|
+
/** Resolve all external schema refs reachable from an operation declaration. */
|
|
297
|
+
function resolveOperationClosure(entry, context = {}) {
|
|
298
|
+
return resolveSchemaReferences(entry, context);
|
|
299
|
+
}
|
|
300
|
+
async function resolveOperationClosureAsync(entry, context = {}) {
|
|
301
|
+
return resolveSchemaReferencesAsync(entry, context);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
//#endregion
|
|
305
|
+
exports.resolveOperationClosure = resolveOperationClosure;
|
|
306
|
+
exports.resolveOperationClosureAsync = resolveOperationClosureAsync;
|
|
307
|
+
exports.resolveSchemaReferences = resolveSchemaReferences;
|
|
308
|
+
exports.resolveSchemaReferencesAsync = resolveSchemaReferencesAsync;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as SchemaClosureResolutionContext, c as SchemaRefResolution, d as resolveSchemaReferences, f as resolveSchemaReferencesAsync, i as SchemaClosureDiagnostic, l as resolveOperationClosure, n as ResolvedSchemaGraph, o as SchemaClosureResult, r as SchemaClosureContext, s as SchemaClosureStatus, t as AsyncSchemaClosureContext, u as resolveOperationClosureAsync } from "../index-CUGhtuwA.cjs";
|
|
2
|
+
export { AsyncSchemaClosureContext, ResolvedSchemaGraph, SchemaClosureContext, SchemaClosureDiagnostic, SchemaClosureResolutionContext, SchemaClosureResult, SchemaClosureStatus, SchemaRefResolution, resolveOperationClosure, resolveOperationClosureAsync, resolveSchemaReferences, resolveSchemaReferencesAsync };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as SchemaClosureResolutionContext, c as SchemaRefResolution, d as resolveSchemaReferences, f as resolveSchemaReferencesAsync, i as SchemaClosureDiagnostic, l as resolveOperationClosure, n as ResolvedSchemaGraph, o as SchemaClosureResult, r as SchemaClosureContext, s as SchemaClosureStatus, t as AsyncSchemaClosureContext, u as resolveOperationClosureAsync } from "../index-BFSMT_2d.js";
|
|
2
|
+
export { AsyncSchemaClosureContext, ResolvedSchemaGraph, SchemaClosureContext, SchemaClosureDiagnostic, SchemaClosureResolutionContext, SchemaClosureResult, SchemaClosureStatus, SchemaRefResolution, resolveOperationClosure, resolveOperationClosureAsync, resolveSchemaReferences, resolveSchemaReferencesAsync };
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { f as validateSchemaNodeDefinition } from "../definition-BH_LzXGc.js";
|
|
2
|
+
import { n as schemaRefKey } from "../schema-ref-key-DR__tPr-.js";
|
|
3
|
+
|
|
4
|
+
//#region src/resolve/schema-closure.ts
|
|
5
|
+
var AsyncResolverError = class extends Error {};
|
|
6
|
+
function isObject(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function refNode(value) {
|
|
10
|
+
if (!isObject(value) || value.kind !== "ref" || !Array.isArray(value.refPath) || value.refPath.some((part) => typeof part !== "string")) return void 0;
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
function issue(status, code, path, message) {
|
|
14
|
+
return {
|
|
15
|
+
code: `closure.${status}.${code}`,
|
|
16
|
+
path,
|
|
17
|
+
message
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function children(value, basePath) {
|
|
21
|
+
if (Array.isArray(value)) return value.map((child, index) => ({
|
|
22
|
+
value: child,
|
|
23
|
+
path: basePath.length === 0 && index === 0 ? [] : [index]
|
|
24
|
+
}));
|
|
25
|
+
if (!isObject(value)) return [];
|
|
26
|
+
if (value.kind === "record" && Array.isArray(value.fields)) {
|
|
27
|
+
const fields = value.fields.flatMap((field) => {
|
|
28
|
+
if (!isObject(field) || typeof field.key !== "string" || !("schema" in field)) return [];
|
|
29
|
+
return [{
|
|
30
|
+
value: field.schema,
|
|
31
|
+
path: ["fields", field.key]
|
|
32
|
+
}];
|
|
33
|
+
});
|
|
34
|
+
if (value.additionalFields !== void 0 && value.additionalFields !== true) fields.push({
|
|
35
|
+
value: value.additionalFields,
|
|
36
|
+
path: ["additionalFields"]
|
|
37
|
+
});
|
|
38
|
+
return fields;
|
|
39
|
+
}
|
|
40
|
+
if (value.kind === "recordOf" && Array.isArray(value.fields)) {
|
|
41
|
+
const fields = value.fields.flatMap((field) => {
|
|
42
|
+
if (!isObject(field) || typeof field.key !== "string" || !("value" in field)) return [];
|
|
43
|
+
return [{
|
|
44
|
+
value: field.value,
|
|
45
|
+
path: ["fields", field.key]
|
|
46
|
+
}];
|
|
47
|
+
});
|
|
48
|
+
if (value.additionalFields !== void 0 && value.additionalFields !== true) fields.push({
|
|
49
|
+
value: value.additionalFields,
|
|
50
|
+
path: ["additionalFields"]
|
|
51
|
+
});
|
|
52
|
+
return fields;
|
|
53
|
+
}
|
|
54
|
+
if ((value.kind === "taggedUnion" || value.kind === "taggedUnionOf") && Array.isArray(value.variants)) {
|
|
55
|
+
const member = value.kind === "taggedUnion" ? "schema" : "value";
|
|
56
|
+
return value.variants.flatMap((variant) => {
|
|
57
|
+
if (!isObject(variant) || typeof variant.key !== "string" || !(member in variant)) return [];
|
|
58
|
+
return [{
|
|
59
|
+
value: variant[member],
|
|
60
|
+
path: ["variants", variant.key]
|
|
61
|
+
}];
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const members = {
|
|
65
|
+
array: ["elementSchema"],
|
|
66
|
+
tuple: ["elementSchemas"],
|
|
67
|
+
nullable: ["value"],
|
|
68
|
+
arrayOf: ["element"],
|
|
69
|
+
tupleOf: ["elements"],
|
|
70
|
+
nullableOf: ["value"],
|
|
71
|
+
maybeAbsent: ["value"],
|
|
72
|
+
typeVar: ["extends"],
|
|
73
|
+
mergeRecords: ["sources"],
|
|
74
|
+
intersect: ["sources"],
|
|
75
|
+
elementOf: ["source"],
|
|
76
|
+
valueOf: ["source"],
|
|
77
|
+
elementAt: ["source"],
|
|
78
|
+
fieldOf: ["source"],
|
|
79
|
+
keyOf: ["source"],
|
|
80
|
+
fieldsOf: ["source"],
|
|
81
|
+
pickFields: ["source"],
|
|
82
|
+
omitFields: ["source"],
|
|
83
|
+
partialFields: ["source"],
|
|
84
|
+
requiredFields: ["source"],
|
|
85
|
+
excludeVariants: ["source"],
|
|
86
|
+
extractVariants: ["source"],
|
|
87
|
+
structured: ["schema"]
|
|
88
|
+
};
|
|
89
|
+
if (typeof value.kind === "string") {
|
|
90
|
+
const edges$1 = (Object.hasOwn(members, value.kind) ? members[value.kind] : []).filter((key) => key in value).map((key) => ({
|
|
91
|
+
value: value[key],
|
|
92
|
+
path: [key]
|
|
93
|
+
}));
|
|
94
|
+
if (value.kind === "refine") {
|
|
95
|
+
edges$1.push({
|
|
96
|
+
value: value.source,
|
|
97
|
+
path: ["source"]
|
|
98
|
+
});
|
|
99
|
+
if (Array.isArray(value.fields)) value.fields.forEach((field, index) => {
|
|
100
|
+
if (isObject(field) && "intersectWith" in field) edges$1.push({
|
|
101
|
+
value: field.intersectWith,
|
|
102
|
+
path: [
|
|
103
|
+
"fields",
|
|
104
|
+
index,
|
|
105
|
+
"intersectWith"
|
|
106
|
+
]
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return edges$1;
|
|
111
|
+
}
|
|
112
|
+
const edges = [];
|
|
113
|
+
for (const key of [
|
|
114
|
+
"input",
|
|
115
|
+
"output",
|
|
116
|
+
"data"
|
|
117
|
+
]) if (key in value) edges.push({
|
|
118
|
+
value: value[key],
|
|
119
|
+
path: [key]
|
|
120
|
+
});
|
|
121
|
+
for (const key of [
|
|
122
|
+
"errors",
|
|
123
|
+
"emits",
|
|
124
|
+
"operations",
|
|
125
|
+
"containers"
|
|
126
|
+
]) if (isObject(value[key])) for (const [name, child] of Object.entries(value[key])) edges.push({
|
|
127
|
+
value: child,
|
|
128
|
+
path: [key, name]
|
|
129
|
+
});
|
|
130
|
+
return edges;
|
|
131
|
+
}
|
|
132
|
+
/** Recursively load all external schema references reachable from an entry,
|
|
133
|
+
* preserving reference paths and recording cycles rather than inlining refs.
|
|
134
|
+
* Yielding host requests lets both execution modes use identical traversal state. */
|
|
135
|
+
function* loadReferences(entry, context) {
|
|
136
|
+
const refs = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const ref of context.refs ?? []) refs.set(schemaRefKey(ref.refPath), {
|
|
138
|
+
refPath: [...ref.refPath],
|
|
139
|
+
schema: ref.schema
|
|
140
|
+
});
|
|
141
|
+
const active = /* @__PURE__ */ new Set();
|
|
142
|
+
const visited = /* @__PURE__ */ new Set();
|
|
143
|
+
const objects = /* @__PURE__ */ new Set();
|
|
144
|
+
const cycles = /* @__PURE__ */ new Map();
|
|
145
|
+
const issues = [];
|
|
146
|
+
let steps = 0;
|
|
147
|
+
let nodes = 0;
|
|
148
|
+
let rejected = false;
|
|
149
|
+
let incomplete = false;
|
|
150
|
+
function* walk(value, path, depth) {
|
|
151
|
+
steps += 1;
|
|
152
|
+
if (steps > (context.maxSteps ?? 1e4) || depth > (context.maxDepth ?? 64)) {
|
|
153
|
+
incomplete = true;
|
|
154
|
+
issues.push(issue("incomplete", "budget", path, "schema closure work budget exceeded"));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (isObject(value) && value.kind === "ref" && !validateSchemaNodeDefinition(value).ok) {
|
|
158
|
+
rejected = true;
|
|
159
|
+
issues.push(issue("rejected", "schema", path, "reference must be a valid SchemaNode"));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const ref = refNode(value);
|
|
163
|
+
if (ref) {
|
|
164
|
+
const key = schemaRefKey(ref.refPath);
|
|
165
|
+
if (active.has(key)) {
|
|
166
|
+
cycles.set(key, [...ref.refPath]);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (visited.has(key)) return;
|
|
170
|
+
active.add(key);
|
|
171
|
+
try {
|
|
172
|
+
const preloaded = refs.get(key);
|
|
173
|
+
if (preloaded !== void 0) {
|
|
174
|
+
if (!validateSchemaNodeDefinition(preloaded.schema).ok) {
|
|
175
|
+
rejected = true;
|
|
176
|
+
issues.push(issue("rejected", "schema", path, "preloaded ref did not contain a valid SchemaNode"));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
visited.add(key);
|
|
180
|
+
yield* walk(preloaded.schema, path, depth + 1);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (nodes >= (context.maxNodes ?? 1e4)) {
|
|
184
|
+
incomplete = true;
|
|
185
|
+
issues.push(issue("incomplete", "nodes", path, "schema closure node budget exceeded"));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
let resolution;
|
|
189
|
+
if (!context.resolveRef) {
|
|
190
|
+
incomplete = true;
|
|
191
|
+
issues.push(issue("incomplete", "unresolved", path, "refPath is not present in the resolved environment"));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
resolution = yield {
|
|
196
|
+
refPath: ref.refPath,
|
|
197
|
+
context: {
|
|
198
|
+
path,
|
|
199
|
+
refPath: ref.refPath,
|
|
200
|
+
ref,
|
|
201
|
+
depth
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
} catch (error) {
|
|
205
|
+
incomplete = true;
|
|
206
|
+
issues.push(issue("incomplete", error instanceof AsyncResolverError ? "resolver.async" : "resolver", path, `refPath resolver failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (!resolution) {
|
|
210
|
+
incomplete = true;
|
|
211
|
+
issues.push(issue("incomplete", "unresolved", path, "refPath resolver returned no schema"));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (typeof resolution === "object" && "status" in resolution && resolution.status !== "resolved") {
|
|
215
|
+
incomplete = true;
|
|
216
|
+
issues.push(issue("incomplete", `ref.${resolution.status}`, path, resolution.message ?? "refPath resolver could not determine this path"));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const definition = validateSchemaNodeDefinition(typeof resolution === "object" && "status" in resolution ? resolution.schema : resolution);
|
|
220
|
+
if (!definition.ok) {
|
|
221
|
+
rejected = true;
|
|
222
|
+
issues.push(issue("rejected", "schema", path, "resolved ref did not contain a valid SchemaNode"));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
refs.set(key, {
|
|
226
|
+
refPath: [...ref.refPath],
|
|
227
|
+
schema: definition.node
|
|
228
|
+
});
|
|
229
|
+
nodes += 1;
|
|
230
|
+
visited.add(key);
|
|
231
|
+
yield* walk(definition.node, path, depth + 1);
|
|
232
|
+
} finally {
|
|
233
|
+
active.delete(key);
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!isObject(value) && !Array.isArray(value)) return;
|
|
238
|
+
if (objects.has(value)) {
|
|
239
|
+
incomplete = true;
|
|
240
|
+
issues.push(issue("incomplete", "cycle.data", path, "input contains an object cycle"));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
objects.add(value);
|
|
244
|
+
try {
|
|
245
|
+
for (const child of children(value, path)) yield* walk(child.value, [...path, ...child.path], depth + 1);
|
|
246
|
+
} finally {
|
|
247
|
+
objects.delete(value);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
yield* walk(entry, [], 0);
|
|
251
|
+
return {
|
|
252
|
+
status: rejected ? "rejected" : incomplete ? "incomplete" : "resolved",
|
|
253
|
+
graph: {
|
|
254
|
+
refs: [...refs.values()],
|
|
255
|
+
cycles: [...cycles.values()].sort((left, right) => schemaRefKey(left).localeCompare(schemaRefKey(right)))
|
|
256
|
+
},
|
|
257
|
+
issues
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/** Load references using a synchronous host resolver. */
|
|
261
|
+
function resolveSchemaReferences(entry, context = {}) {
|
|
262
|
+
const traversal = loadReferences(entry, context);
|
|
263
|
+
let step = traversal.next();
|
|
264
|
+
while (!step.done) {
|
|
265
|
+
let resolution;
|
|
266
|
+
try {
|
|
267
|
+
resolution = context.resolveRef(step.value.refPath, step.value.context);
|
|
268
|
+
if (resolution && typeof resolution === "object" && "then" in resolution && typeof resolution.then === "function") {
|
|
269
|
+
if (resolution instanceof Promise) resolution.catch(() => {});
|
|
270
|
+
throw new AsyncResolverError("reference loading requires a synchronous resolver; use resolveSchemaReferencesAsync");
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
step = traversal.throw(error);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
step = traversal.next(resolution);
|
|
277
|
+
}
|
|
278
|
+
return step.value;
|
|
279
|
+
}
|
|
280
|
+
/** Load references using a synchronous or asynchronous host resolver. */
|
|
281
|
+
async function resolveSchemaReferencesAsync(entry, context = {}) {
|
|
282
|
+
const traversal = loadReferences(entry, context);
|
|
283
|
+
let step = traversal.next();
|
|
284
|
+
while (!step.done) {
|
|
285
|
+
let resolution;
|
|
286
|
+
try {
|
|
287
|
+
resolution = await context.resolveRef(step.value.refPath, step.value.context);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
step = traversal.throw(error);
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
step = traversal.next(resolution);
|
|
293
|
+
}
|
|
294
|
+
return step.value;
|
|
295
|
+
}
|
|
296
|
+
/** Resolve all external schema refs reachable from an operation declaration. */
|
|
297
|
+
function resolveOperationClosure(entry, context = {}) {
|
|
298
|
+
return resolveSchemaReferences(entry, context);
|
|
299
|
+
}
|
|
300
|
+
async function resolveOperationClosureAsync(entry, context = {}) {
|
|
301
|
+
return resolveSchemaReferencesAsync(entry, context);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
//#endregion
|
|
305
|
+
export { resolveOperationClosure, resolveOperationClosureAsync, resolveSchemaReferences, resolveSchemaReferencesAsync };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/internal/schema-ref-key.ts
|
|
3
|
+
/** Encode ref path segments without allowing a segment separator collision. */
|
|
4
|
+
function schemaRefKey(path) {
|
|
5
|
+
return JSON.stringify(path);
|
|
6
|
+
}
|
|
7
|
+
/** Build the private lookup index used by synchronous host boundaries. */
|
|
8
|
+
function indexSchemaRefs(entries) {
|
|
9
|
+
const index = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const entry of entries ?? []) index.set(schemaRefKey(entry.refPath), entry.schema);
|
|
11
|
+
return index;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
Object.defineProperty(exports, 'indexSchemaRefs', {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () {
|
|
18
|
+
return indexSchemaRefs;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(exports, 'schemaRefKey', {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return schemaRefKey;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/internal/schema-ref-key.ts
|
|
2
|
+
/** Encode ref path segments without allowing a segment separator collision. */
|
|
3
|
+
function schemaRefKey(path) {
|
|
4
|
+
return JSON.stringify(path);
|
|
5
|
+
}
|
|
6
|
+
/** Build the private lookup index used by synchronous host boundaries. */
|
|
7
|
+
function indexSchemaRefs(entries) {
|
|
8
|
+
const index = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const entry of entries ?? []) index.set(schemaRefKey(entry.refPath), entry.schema);
|
|
10
|
+
return index;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { schemaRefKey as n, indexSchemaRefs as t };
|
package/dist/spec/index.cjs
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const require_standard = require('../standard-etPFZDJI.cjs');
|
|
2
|
+
|
|
3
|
+
exports.STANDARD_CONSTRAINT_DEFINITIONS = require_standard.STANDARD_CONSTRAINT_DEFINITIONS;
|
|
4
|
+
exports.STANDARD_CONSTRAINT_PATHS = require_standard.STANDARD_CONSTRAINT_PATHS;
|
|
5
|
+
exports.STANDARD_CONSTRAINT_PATH_LIST = require_standard.STANDARD_CONSTRAINT_PATH_LIST;
|
|
6
|
+
exports.STANDARD_SEMANTIC_DEFINITIONS = require_standard.STANDARD_SEMANTIC_DEFINITIONS;
|
|
7
|
+
exports.STANDARD_SEMANTIC_PATHS = require_standard.STANDARD_SEMANTIC_PATHS;
|
|
8
|
+
exports.STANDARD_SEMANTIC_PATH_LIST = require_standard.STANDARD_SEMANTIC_PATH_LIST;
|
|
9
|
+
exports.STANDARD_SEMANTIC_RELATIONS = require_standard.STANDARD_SEMANTIC_RELATIONS;
|