@ai-matrx/content-ir 0.3.0 → 0.6.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 +72 -0
- package/dist/index.cjs +186 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -13
- package/dist/index.d.ts +60 -13
- package/dist/index.js +186 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 — 2026-08-29
|
|
4
|
+
|
|
5
|
+
- **`$ref` / `$defs` resolution — a kind's child kinds are no longer invisible
|
|
6
|
+
to JSON Schema → KindSchema.** `convertAiSchemaToBlockFields` resolves `#`,
|
|
7
|
+
`#/$defs/<name>` and `#/definitions/<name>` in field position, in array
|
|
8
|
+
`items`, and inside `anyOf`/`oneOf` (including `items: {anyOf: [$ref, …]}`,
|
|
9
|
+
the multi-kind array). Referenced defs are registered as their own drafts,
|
|
10
|
+
with a cycle brake so a self-referencing kind terminates. An unresolvable
|
|
11
|
+
ref is a loud error, never a guess.
|
|
12
|
+
|
|
13
|
+
WHY: `kindSchemaToJsonSchema` externalizes every child kind as a `$def`, and
|
|
14
|
+
the reverse direction rejected `$ref` outright — so every
|
|
15
|
+
`{type:"object", kind}` and `{type:"array", itemKinds}` field came back
|
|
16
|
+
EMPTY. Measured over the 62 live kinds carrying both a stored field list and
|
|
17
|
+
a schema, 36 lost fields this way (sections, slides, nodes, edges, criteria,
|
|
18
|
+
questions, segments, …).
|
|
19
|
+
|
|
20
|
+
- **A `__kind`-carrying record reads back as a record.** An object whose only
|
|
21
|
+
declared property is `__kind`, with typed `additionalProperties`, is the
|
|
22
|
+
forward converter's emission for `{type:"record", values}` — it was widening
|
|
23
|
+
to an open `inline_object` and losing the value type.
|
|
24
|
+
|
|
25
|
+
- Live-corpus result: schema-derived KindSchemas now match the stored field
|
|
26
|
+
list byte-for-byte for 48 of 62 kinds, with 1 strictly richer. The remaining
|
|
27
|
+
13 are DIVERGENCE BETWEEN THE TWO STORED COPIES, not conversion gaps — 4
|
|
28
|
+
stored lists carry `__kind` as a data field (it is the discriminator, never
|
|
29
|
+
a field), and 9 disagree on enums, bounds, required flags or descriptions
|
|
30
|
+
the schema states and the copy does not. That is the evidence for retiring
|
|
31
|
+
the stored copy.
|
|
32
|
+
|
|
33
|
+
## 0.5.0 — 2026-08-29
|
|
34
|
+
|
|
35
|
+
- **A multi-type union is no longer silently narrowed to its first member.**
|
|
36
|
+
`resolvePrimaryType` now reports every non-null member, and
|
|
37
|
+
`convertAiSchemaToBlockFields` branches on them: a union spanning
|
|
38
|
+
objects/arrays becomes `json`, a scalar-only union becomes
|
|
39
|
+
`{type:"union", scalars}`, and anything unnameable stays `json` with a
|
|
40
|
+
warning. Single-typed fields are untouched.
|
|
41
|
+
|
|
42
|
+
WHY: `type: ["string","number","boolean","object","array","null"]` —
|
|
43
|
+
pydantic's `Any`, and the commonest construct in user-authored kinds —
|
|
44
|
+
converted to plain `string`. The loss was invisible and it inverted the
|
|
45
|
+
field's meaning: an `estimated_count` of `1` then FAILED validation, so a
|
|
46
|
+
correct payload read as a broken instance. Widening is safe; silently
|
|
47
|
+
narrowing is not.
|
|
48
|
+
|
|
49
|
+
- New `__tests__/json-schema-to-kind.test.ts` pins JSON Schema → KindSchema
|
|
50
|
+
over the constructs a stored field list historically could not hold —
|
|
51
|
+
pydantic-Any unions, `items: {}` arrays, arrays of `__kind` children,
|
|
52
|
+
nested `__kind` objects, and markerless inline objects. All convert with
|
|
53
|
+
zero errors, which is the evidence that `emitted_json_schema` is sufficient
|
|
54
|
+
on its own and a second stored copy of a kind's fields is unnecessary.
|
|
55
|
+
|
|
56
|
+
## 0.4.0 — 2026-08-29
|
|
57
|
+
|
|
58
|
+
- **`unverified` — "we never checked it" is no longer "we checked it and it
|
|
59
|
+
failed."** `IrKindState` gains `unverified`, and `raw_object` events carry a
|
|
60
|
+
`cause` (`"unverified" | "invalid"`, absent reads as `"invalid"`). The four
|
|
61
|
+
no-schema-registered degrades — the two pending-schema resolutions, plus the
|
|
62
|
+
typed and speculated finalizers — now report `unverified`; every validation
|
|
63
|
+
failure, array-item mismatch, duplicate key, bad placement, and contradicted
|
|
64
|
+
speculation still reports `invalid`. `IrTree` carries the cause onto
|
|
65
|
+
`root.kindState` and into `nodeIndex`.
|
|
66
|
+
|
|
67
|
+
WHY THIS EXISTS: `raw` meant both things, and on 2026-08-28 the render route
|
|
68
|
+
began reading `raw` as "broken instance" and diverting it away from the
|
|
69
|
+
kind's component. Every kind whose schema cannot be reconstructed — nested
|
|
70
|
+
objects, arrays of child kinds, loose fields — degrades on the no-schema
|
|
71
|
+
path, so ~221 live kinds with purpose-built components silently started
|
|
72
|
+
rendering as key/value dumps. Consumers MUST NOT treat `unverified` as a
|
|
73
|
+
failure: the value is intact and was never examined.
|
|
74
|
+
|
|
3
75
|
## 0.3.0 — 2026-08-29
|
|
4
76
|
|
|
5
77
|
- **KIND PRESERVATION now covers STRUCTURAL raws.** A node that degrades to
|
package/dist/index.cjs
CHANGED
|
@@ -111,11 +111,20 @@ var IrTree = class {
|
|
|
111
111
|
*/
|
|
112
112
|
earlyFields = /* @__PURE__ */ new Map();
|
|
113
113
|
/**
|
|
114
|
-
* pathKey → identified kind preserved through a
|
|
115
|
-
*
|
|
116
|
-
*
|
|
114
|
+
* pathKey → identified kind preserved through a raw fallback (parser stamped
|
|
115
|
+
* `kind` on the raw_object event) — schema-availability degrades and, since
|
|
116
|
+
* 2026-08-29, structural ones too. Only a node nothing ever identified (no
|
|
117
|
+
* `__kind` at all) is absent here.
|
|
117
118
|
*/
|
|
118
119
|
rawKinds = /* @__PURE__ */ new Map();
|
|
120
|
+
/**
|
|
121
|
+
* pathKey → WHY the node degraded. `"unverified"` means no schema was
|
|
122
|
+
* available and nothing was ever checked; `"invalid"` means a check ran and
|
|
123
|
+
* failed. THE RENDER ROUTE BRANCHES ON THIS — see `IrKindState`. Absent =
|
|
124
|
+
* `"invalid"`, so a parser that predates the `cause` field (or any consumer
|
|
125
|
+
* hand-building events) keeps the strict, safe reading.
|
|
126
|
+
*/
|
|
127
|
+
rawCauses = /* @__PURE__ */ new Map();
|
|
119
128
|
regionStatus = "streaming";
|
|
120
129
|
errorReason = null;
|
|
121
130
|
rootRawValue = null;
|
|
@@ -168,6 +177,7 @@ var IrTree = class {
|
|
|
168
177
|
this.pendingSchemaPaths.delete(pathKey);
|
|
169
178
|
this.earlyFields.delete(pathKey);
|
|
170
179
|
if (event.kind) this.rawKinds.set(pathKey, event.kind);
|
|
180
|
+
this.rawCauses.set(pathKey, event.cause ?? "invalid");
|
|
171
181
|
this.markRaw(event.path, event.reason, event.value);
|
|
172
182
|
return;
|
|
173
183
|
}
|
|
@@ -366,10 +376,11 @@ var IrTree = class {
|
|
|
366
376
|
const isRaw = rootRawReason !== null;
|
|
367
377
|
const identifiedKind = this.identifiedKinds.get("") ?? "";
|
|
368
378
|
const rootKind = isRaw ? this.rawKinds.get("") ?? "" : rootNode?.kind ?? (this.completedKind || identifiedKind);
|
|
379
|
+
const rootRawState = this.rawCauses.get("") === "unverified" ? "unverified" : "raw";
|
|
369
380
|
const root = {
|
|
370
381
|
role: "structured",
|
|
371
382
|
kind: rootKind,
|
|
372
|
-
kindState: isRaw ?
|
|
383
|
+
kindState: isRaw ? rootRawState : rootNode ? rootNode.kindState : this.pendingSchemaPaths.has("") ? "pending_schema" : this.regionStatus === "streaming" ? identifiedKind ? "pending_schema" : "pending_kind" : "raw",
|
|
373
384
|
discriminator: JSON_DISCRIMINATOR,
|
|
374
385
|
path: [],
|
|
375
386
|
status: this.regionStatus,
|
|
@@ -392,7 +403,7 @@ var IrTree = class {
|
|
|
392
403
|
if (pathKey === "") continue;
|
|
393
404
|
nodeIndex[pathKey] = {
|
|
394
405
|
kind: this.rawKinds.get(pathKey) ?? "",
|
|
395
|
-
kindState: "raw",
|
|
406
|
+
kindState: this.rawCauses.get(pathKey) === "unverified" ? "unverified" : "raw",
|
|
396
407
|
status: "complete"
|
|
397
408
|
};
|
|
398
409
|
}
|
|
@@ -732,7 +743,8 @@ var KindStreamParser = class {
|
|
|
732
743
|
safeCopy(value),
|
|
733
744
|
`No block schema registered for "${kind}".`,
|
|
734
745
|
at,
|
|
735
|
-
kind
|
|
746
|
+
kind,
|
|
747
|
+
"unverified"
|
|
736
748
|
);
|
|
737
749
|
}
|
|
738
750
|
}
|
|
@@ -766,7 +778,8 @@ var KindStreamParser = class {
|
|
|
766
778
|
safeCopy(value ?? {}),
|
|
767
779
|
`No block schema registered for "${kind}".`,
|
|
768
780
|
at,
|
|
769
|
-
kind
|
|
781
|
+
kind,
|
|
782
|
+
"unverified"
|
|
770
783
|
);
|
|
771
784
|
this.closedPendingPaths.delete(pathKey);
|
|
772
785
|
continue;
|
|
@@ -1312,7 +1325,8 @@ var KindStreamParser = class {
|
|
|
1312
1325
|
objectValue,
|
|
1313
1326
|
`No block schema registered for "${kind}".`,
|
|
1314
1327
|
at,
|
|
1315
|
-
kind
|
|
1328
|
+
kind,
|
|
1329
|
+
"unverified"
|
|
1316
1330
|
);
|
|
1317
1331
|
return;
|
|
1318
1332
|
}
|
|
@@ -1346,7 +1360,8 @@ var KindStreamParser = class {
|
|
|
1346
1360
|
objectValue,
|
|
1347
1361
|
`No block schema registered for "${kind}".`,
|
|
1348
1362
|
at,
|
|
1349
|
-
kind
|
|
1363
|
+
kind,
|
|
1364
|
+
"unverified"
|
|
1350
1365
|
);
|
|
1351
1366
|
return;
|
|
1352
1367
|
}
|
|
@@ -1419,7 +1434,15 @@ var KindStreamParser = class {
|
|
|
1419
1434
|
this.speculativeKinds.delete(pathKey);
|
|
1420
1435
|
this.emitRawObject(path, safeCopy(liveValue), reason, at, identifiedKind);
|
|
1421
1436
|
}
|
|
1422
|
-
|
|
1437
|
+
/**
|
|
1438
|
+
* Degrade ONE node off the resolved path.
|
|
1439
|
+
*
|
|
1440
|
+
* `cause` defaults to `"invalid"` deliberately: every call site that omits
|
|
1441
|
+
* it is a real failure (validation, duplicate key, placement, contradicted
|
|
1442
|
+
* speculation). ONLY the "no schema registered" sites pass `"unverified"`,
|
|
1443
|
+
* and they are the reason the parameter exists — see `IrKindState`.
|
|
1444
|
+
*/
|
|
1445
|
+
emitRawObject(path, value, reason, at, identifiedKind, cause = "invalid") {
|
|
1423
1446
|
const pathKey = this.pathKey(path);
|
|
1424
1447
|
if (this.rawObjectPaths.has(pathKey)) return;
|
|
1425
1448
|
this.rawObjectPaths.add(pathKey);
|
|
@@ -1430,6 +1453,7 @@ var KindStreamParser = class {
|
|
|
1430
1453
|
value,
|
|
1431
1454
|
reason,
|
|
1432
1455
|
...identifiedKind !== void 0 && { kind: identifiedKind },
|
|
1456
|
+
cause,
|
|
1433
1457
|
at
|
|
1434
1458
|
});
|
|
1435
1459
|
}
|
|
@@ -2999,21 +3023,26 @@ function fieldSchemaSummary(field) {
|
|
|
2999
3023
|
function resolvePrimaryType(node) {
|
|
3000
3024
|
const raw = node.type;
|
|
3001
3025
|
if (typeof raw === "string") {
|
|
3002
|
-
|
|
3026
|
+
const t = raw === "integer" ? "number" : raw;
|
|
3027
|
+
return { type: t, nullable: false, members: [t] };
|
|
3003
3028
|
}
|
|
3004
3029
|
if (Array.isArray(raw)) {
|
|
3005
3030
|
const types = raw.filter((t) => typeof t === "string");
|
|
3006
3031
|
const nullable = types.includes("null");
|
|
3007
|
-
const
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
if (node.
|
|
3016
|
-
|
|
3032
|
+
const members = [
|
|
3033
|
+
...new Set(
|
|
3034
|
+
types.filter((t) => t !== "null").map((t) => t === "integer" ? "number" : t)
|
|
3035
|
+
)
|
|
3036
|
+
];
|
|
3037
|
+
const primary = members[0] ?? (nullable && types.length === 1 ? "null" : null);
|
|
3038
|
+
return { type: primary ?? null, nullable, members };
|
|
3039
|
+
}
|
|
3040
|
+
if (node.enum) return { type: "string", nullable: false, members: ["string"] };
|
|
3041
|
+
if (node.properties)
|
|
3042
|
+
return { type: "object", nullable: false, members: ["object"] };
|
|
3043
|
+
if (node.items)
|
|
3044
|
+
return { type: "array", nullable: false, members: ["array"] };
|
|
3045
|
+
return { type: null, nullable: false, members: [] };
|
|
3017
3046
|
}
|
|
3018
3047
|
function carriedMetadataKeys(field) {
|
|
3019
3048
|
if (field === null) return /* @__PURE__ */ new Set();
|
|
@@ -3148,6 +3177,29 @@ function buildAgentSchemaWithRenderBlockSupport(input, rootKindSlug, arrayBindin
|
|
|
3148
3177
|
}
|
|
3149
3178
|
return updatedRoot;
|
|
3150
3179
|
}
|
|
3180
|
+
function resolveRef(ref, ctx) {
|
|
3181
|
+
if (ref === "#" || ref === "#/") {
|
|
3182
|
+
return { slug: ctx.schemaName, node: ctx.rootSchema };
|
|
3183
|
+
}
|
|
3184
|
+
const match = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
|
|
3185
|
+
if (!match) return null;
|
|
3186
|
+
const name = decodeURIComponent(
|
|
3187
|
+
(match[1] ?? "").replace(/~1/g, "/").replace(/~0/g, "~")
|
|
3188
|
+
);
|
|
3189
|
+
const node = ctx.defs[name];
|
|
3190
|
+
if (!isRecord4(node)) return null;
|
|
3191
|
+
const declared = isRecord4(node.properties) ? readBlockKindFromProperties(node.properties) : null;
|
|
3192
|
+
return { slug: declared ?? name, node };
|
|
3193
|
+
}
|
|
3194
|
+
function refToObjectField(resolved, path, ctx) {
|
|
3195
|
+
if (ctx.refsInProgress.has(resolved.slug)) return;
|
|
3196
|
+
ctx.refsInProgress.add(resolved.slug);
|
|
3197
|
+
try {
|
|
3198
|
+
registerDeclaredKindDraft(resolved.slug, resolved.node, path, ctx);
|
|
3199
|
+
} finally {
|
|
3200
|
+
ctx.refsInProgress.delete(resolved.slug);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3151
3203
|
function isAnyValueSchema(node) {
|
|
3152
3204
|
return node.type === void 0 && node.enum === void 0 && node.const === void 0 && node.properties === void 0 && node.items === void 0 && node.additionalProperties === void 0 && node.anyOf === void 0 && node.oneOf === void 0 && node.allOf === void 0 && node.$ref === void 0;
|
|
3153
3205
|
}
|
|
@@ -3184,12 +3236,21 @@ function convertProperty(fieldName, node, required, path, ctx) {
|
|
|
3184
3236
|
}
|
|
3185
3237
|
function convertPropertyCore(fieldName, node, required, path, ctx) {
|
|
3186
3238
|
if (typeof node.$ref === "string") {
|
|
3187
|
-
ctx
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3239
|
+
const resolved = resolveRef(node.$ref, ctx);
|
|
3240
|
+
if (!resolved) {
|
|
3241
|
+
ctx.problems.push({
|
|
3242
|
+
severity: "error",
|
|
3243
|
+
path,
|
|
3244
|
+
message: `Unresolvable $ref ("${node.$ref}") \u2014 only "#", "#/$defs/<name>" and "#/definitions/<name>" are supported.`
|
|
3245
|
+
});
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
refToObjectField(resolved, path, ctx);
|
|
3249
|
+
return {
|
|
3250
|
+
...requiredNullableFlags(required),
|
|
3251
|
+
type: "object",
|
|
3252
|
+
kind: resolved.slug
|
|
3253
|
+
};
|
|
3193
3254
|
}
|
|
3194
3255
|
if (Array.isArray(node.anyOf) || Array.isArray(node.oneOf)) {
|
|
3195
3256
|
const variants = node.anyOf ?? node.oneOf;
|
|
@@ -3205,12 +3266,18 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
|
|
|
3205
3266
|
continue;
|
|
3206
3267
|
}
|
|
3207
3268
|
if (typeof variant.$ref === "string") {
|
|
3208
|
-
ctx
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3269
|
+
const resolvedVariant = resolveRef(variant.$ref, ctx);
|
|
3270
|
+
if (!resolvedVariant) {
|
|
3271
|
+
ctx.problems.push({
|
|
3272
|
+
severity: "error",
|
|
3273
|
+
path,
|
|
3274
|
+
message: `Unresolvable $ref inside anyOf/oneOf ("${variant.$ref}").`
|
|
3275
|
+
});
|
|
3276
|
+
unsupported = true;
|
|
3277
|
+
continue;
|
|
3278
|
+
}
|
|
3279
|
+
refToObjectField(resolvedVariant, path, ctx);
|
|
3280
|
+
memberKinds.push(resolvedVariant.slug);
|
|
3214
3281
|
continue;
|
|
3215
3282
|
}
|
|
3216
3283
|
const { type: type2, nullable: nullable2 } = resolvePrimaryType(variant);
|
|
@@ -3331,7 +3398,34 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
|
|
|
3331
3398
|
});
|
|
3332
3399
|
return { ...requiredNullableFlags(required), type: "json" };
|
|
3333
3400
|
}
|
|
3334
|
-
const { type, nullable } = resolvePrimaryType(node);
|
|
3401
|
+
const { type, nullable, members } = resolvePrimaryType(node);
|
|
3402
|
+
if (members.length > 1) {
|
|
3403
|
+
const objectish = members.some((m) => m === "object" || m === "array");
|
|
3404
|
+
if (objectish) {
|
|
3405
|
+
ctx.problems.push({
|
|
3406
|
+
severity: "info",
|
|
3407
|
+
path,
|
|
3408
|
+
message: `Union of [${members.join(", ")}] at "${path || "(root)"}" spans objects/arrays \u2014 carried as any JSON value (json).`
|
|
3409
|
+
});
|
|
3410
|
+
return { ...requiredNullableFlags(required), type: "json" };
|
|
3411
|
+
}
|
|
3412
|
+
const scalars = members.filter(
|
|
3413
|
+
(m) => m === "string" || m === "number" || m === "boolean"
|
|
3414
|
+
);
|
|
3415
|
+
if (scalars.length === members.length && scalars.length > 1) {
|
|
3416
|
+
return {
|
|
3417
|
+
...requiredNullableFlags(required, nullable),
|
|
3418
|
+
type: "union",
|
|
3419
|
+
scalars
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
ctx.problems.push({
|
|
3423
|
+
severity: "warning",
|
|
3424
|
+
path,
|
|
3425
|
+
message: `Union of [${members.join(", ")}] at "${path || "(root)"}" has no exact field type \u2014 carried as any JSON value (json) rather than narrowed to "${type}".`
|
|
3426
|
+
});
|
|
3427
|
+
return { ...requiredNullableFlags(required), type: "json" };
|
|
3428
|
+
}
|
|
3335
3429
|
if (type === "string") {
|
|
3336
3430
|
if (Array.isArray(node.enum)) {
|
|
3337
3431
|
const values = node.enum.filter(
|
|
@@ -3386,6 +3480,27 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
|
|
|
3386
3480
|
});
|
|
3387
3481
|
return null;
|
|
3388
3482
|
}
|
|
3483
|
+
if (typeof itemNode.$ref === "string") {
|
|
3484
|
+
const resolvedItem = resolveRef(itemNode.$ref, ctx);
|
|
3485
|
+
if (!resolvedItem) {
|
|
3486
|
+
ctx.problems.push({
|
|
3487
|
+
severity: "error",
|
|
3488
|
+
path: `${path}[]`,
|
|
3489
|
+
message: `Unresolvable $ref in array items ("${itemNode.$ref}").`
|
|
3490
|
+
});
|
|
3491
|
+
return null;
|
|
3492
|
+
}
|
|
3493
|
+
refToObjectField(resolvedItem, `${path}[]`, ctx);
|
|
3494
|
+
ctx.arrayBindings.push({
|
|
3495
|
+
arrayField: fieldName,
|
|
3496
|
+
itemKindSlug: resolvedItem.slug
|
|
3497
|
+
});
|
|
3498
|
+
return {
|
|
3499
|
+
...requiredNullableFlags(required, nullable),
|
|
3500
|
+
type: "array",
|
|
3501
|
+
itemKinds: [resolvedItem.slug]
|
|
3502
|
+
};
|
|
3503
|
+
}
|
|
3389
3504
|
if (isAnyValueSchema(itemNode)) {
|
|
3390
3505
|
return {
|
|
3391
3506
|
...requiredNullableFlags(required, nullable),
|
|
@@ -3420,11 +3535,29 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
|
|
|
3420
3535
|
}
|
|
3421
3536
|
const itemKinds = [];
|
|
3422
3537
|
for (const variant of itemVariants) {
|
|
3538
|
+
if (isRecord4(variant) && typeof variant.$ref === "string") {
|
|
3539
|
+
const resolvedVariant = resolveRef(variant.$ref, ctx);
|
|
3540
|
+
if (!resolvedVariant) {
|
|
3541
|
+
ctx.problems.push({
|
|
3542
|
+
severity: "error",
|
|
3543
|
+
path: `${path}[]`,
|
|
3544
|
+
message: `Unresolvable $ref in array items anyOf ("${variant.$ref}").`
|
|
3545
|
+
});
|
|
3546
|
+
return null;
|
|
3547
|
+
}
|
|
3548
|
+
itemKinds.push(resolvedVariant.slug);
|
|
3549
|
+
refToObjectField(resolvedVariant, `${path}[]<${resolvedVariant.slug}>`, ctx);
|
|
3550
|
+
ctx.arrayBindings.push({
|
|
3551
|
+
arrayField: fieldName,
|
|
3552
|
+
itemKindSlug: resolvedVariant.slug
|
|
3553
|
+
});
|
|
3554
|
+
continue;
|
|
3555
|
+
}
|
|
3423
3556
|
if (!isRecord4(variant) || !isRecord4(variant.properties)) {
|
|
3424
3557
|
ctx.problems.push({
|
|
3425
3558
|
severity: "error",
|
|
3426
3559
|
path: `${path}[]`,
|
|
3427
|
-
message: "Array items anyOf/oneOf variants must be inline objects declaring __kind."
|
|
3560
|
+
message: "Array items anyOf/oneOf variants must be inline objects declaring __kind, or $refs to defs."
|
|
3428
3561
|
});
|
|
3429
3562
|
return null;
|
|
3430
3563
|
}
|
|
@@ -3558,6 +3691,14 @@ function convertPropertyCore(fieldName, node, required, path, ctx) {
|
|
|
3558
3691
|
kind: referencedKind
|
|
3559
3692
|
};
|
|
3560
3693
|
}
|
|
3694
|
+
if (Object.keys(nestedFields).length === 0 && !apIsOpen && isRecord4(ap) && KIND_KEY in node.properties) {
|
|
3695
|
+
const apType = resolvePrimaryType(ap).type;
|
|
3696
|
+
return {
|
|
3697
|
+
...requiredNullableFlags(required, nullable),
|
|
3698
|
+
type: "record",
|
|
3699
|
+
values: apType === "string" || apType === "number" || apType === "boolean" ? apType : "json"
|
|
3700
|
+
};
|
|
3701
|
+
}
|
|
3561
3702
|
let open = apIsOpen;
|
|
3562
3703
|
if (!apIsOpen && isRecord4(ap)) {
|
|
3563
3704
|
ctx.problems.push({
|
|
@@ -3674,12 +3815,21 @@ function normalizeAiSchemaInput(input) {
|
|
|
3674
3815
|
return { name: null, strict: null, rootSchema: null, parseErrors };
|
|
3675
3816
|
}
|
|
3676
3817
|
function convertAiSchemaToBlockFields(schemaName, rootSchema, strict) {
|
|
3818
|
+
const rawDefs = isRecord4(rootSchema.$defs) ? rootSchema.$defs : isRecord4(rootSchema.definitions) ? rootSchema.definitions : {};
|
|
3819
|
+
const defs = {};
|
|
3820
|
+
for (const [name, node] of Object.entries(rawDefs)) {
|
|
3821
|
+
if (isRecord4(node)) defs[name] = node;
|
|
3822
|
+
}
|
|
3677
3823
|
const ctx = {
|
|
3678
3824
|
schemaName,
|
|
3825
|
+
strict,
|
|
3679
3826
|
problems: [],
|
|
3680
3827
|
droppedMetadata: [],
|
|
3681
3828
|
blockSchemas: [],
|
|
3682
|
-
arrayBindings: []
|
|
3829
|
+
arrayBindings: [],
|
|
3830
|
+
defs,
|
|
3831
|
+
rootSchema,
|
|
3832
|
+
refsInProgress: /* @__PURE__ */ new Set()
|
|
3683
3833
|
};
|
|
3684
3834
|
ctx.droppedMetadata.push(...collectDropped(rootSchema, ""));
|
|
3685
3835
|
const rootAp = rootSchema.additionalProperties;
|