@jxsuite/schema 0.28.5 → 0.30.1
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/defs/children-value.schema.ts +10 -2
- package/package.json +3 -3
- package/schema.json +4 -1
- package/src/guards.ts +12 -0
- package/src/schema.ts +47 -7
- package/types.ts +13 -0
|
@@ -15,11 +15,19 @@ export const arrayNamespaceSchema = {
|
|
|
15
15
|
} as const;
|
|
16
16
|
|
|
17
17
|
export const childrenValueSchema = {
|
|
18
|
-
description:
|
|
18
|
+
description:
|
|
19
|
+
"Array of child definitions — elements, text, or Array namespaces (dynamic lists) mixed " +
|
|
20
|
+
"freely. A bare Array namespace (the whole children slot is one dynamic list) is also " +
|
|
21
|
+
"accepted for backward compatibility.",
|
|
19
22
|
oneOf: [
|
|
20
23
|
{
|
|
21
24
|
items: {
|
|
22
|
-
oneOf: [
|
|
25
|
+
oneOf: [
|
|
26
|
+
{ $ref: "#/$defs/ElementDef" },
|
|
27
|
+
{ $ref: "#/$defs/ArrayNamespace" },
|
|
28
|
+
{ type: "string" },
|
|
29
|
+
{ type: "number" },
|
|
30
|
+
],
|
|
23
31
|
},
|
|
24
32
|
type: "array",
|
|
25
33
|
},
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@webref/css": "^8.
|
|
3
|
+
"@webref/css": "^8.6.0",
|
|
4
4
|
"@webref/elements": "^2.7.1",
|
|
5
|
-
"@webref/idl": "^3.81.
|
|
5
|
+
"@webref/idl": "^3.81.1"
|
|
6
6
|
},
|
|
7
7
|
"description": "JSON Schema 2020-12 meta-schema generator for Jx documents",
|
|
8
8
|
"exports": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"upgrade": "bunx npm-check-updates -u && bun install"
|
|
40
40
|
},
|
|
41
41
|
"type": "module",
|
|
42
|
-
"version": "0.
|
|
42
|
+
"version": "0.30.1",
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"json-schema-to-ts": "^3.1.1"
|
|
45
45
|
}
|
package/schema.json
CHANGED
|
@@ -4665,7 +4665,7 @@
|
|
|
4665
4665
|
"type": "object"
|
|
4666
4666
|
},
|
|
4667
4667
|
"ChildrenValue": {
|
|
4668
|
-
"description": "
|
|
4668
|
+
"description": "Array of child definitions — elements, text, or Array namespaces (dynamic lists) mixed freely. A bare Array namespace (the whole children slot is one dynamic list) is also accepted for backward compatibility.",
|
|
4669
4669
|
"oneOf": [
|
|
4670
4670
|
{
|
|
4671
4671
|
"items": {
|
|
@@ -4673,6 +4673,9 @@
|
|
|
4673
4673
|
{
|
|
4674
4674
|
"$ref": "#/$defs/ElementDef"
|
|
4675
4675
|
},
|
|
4676
|
+
{
|
|
4677
|
+
"$ref": "#/$defs/ArrayNamespace"
|
|
4678
|
+
},
|
|
4676
4679
|
{
|
|
4677
4680
|
"type": "string"
|
|
4678
4681
|
},
|
package/src/guards.ts
CHANGED
|
@@ -126,6 +126,18 @@ export function isMappedArray(value: unknown): value is JxMappedArray {
|
|
|
126
126
|
return isJsonObject(value) && value.$prototype === "Array";
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Whether a node's `children` holds at least one mapped array — either as the bare whole-children
|
|
131
|
+
* slot (legacy) or as a member of the children array. Used by renderers and the compiler to decide
|
|
132
|
+
* if a children list needs inline repeater expansion.
|
|
133
|
+
*/
|
|
134
|
+
export function childrenContainArray(children?: unknown): boolean {
|
|
135
|
+
if (isMappedArray(children)) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return Array.isArray(children) && children.some((c) => isMappedArray(c));
|
|
139
|
+
}
|
|
140
|
+
|
|
129
141
|
/** A .class.json schema-defined class document — `{ $prototype: "Class" }`. */
|
|
130
142
|
export function isClassDef(value: unknown): value is JxClassDef {
|
|
131
143
|
return isJsonObject(value) && value.$prototype === "Class";
|
package/src/schema.ts
CHANGED
|
@@ -96,7 +96,24 @@ import { projectConfigSchema } from "../defs/project-config.schema";
|
|
|
96
96
|
|
|
97
97
|
// ─── Web standards data loader ────────────────────────────────────────────────
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
let webDataCache: Promise<{
|
|
100
|
+
cssProps: string[];
|
|
101
|
+
eventHandlers: string[];
|
|
102
|
+
tagExamples: string[];
|
|
103
|
+
}> | null = null;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Web-standards parsing (WebIDL / CSS / HTML elements) is expensive and the data is static for the
|
|
107
|
+
* Process, so memoize it. generateSchema runs several times across a build or test run, and
|
|
108
|
+
* Re-parsing on each call made the validateDocument / CLI tests load-sensitive (occasionally past
|
|
109
|
+
* The 5s test timeout under full-suite CPU contention).
|
|
110
|
+
*/
|
|
111
|
+
function loadWebData() {
|
|
112
|
+
webDataCache ??= computeWebData();
|
|
113
|
+
return webDataCache;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function computeWebData() {
|
|
100
117
|
const [elementsData, cssData, idlData] = await Promise.all([
|
|
101
118
|
listElements(),
|
|
102
119
|
css.listAll(),
|
|
@@ -487,13 +504,30 @@ export async function generateSchemaString() {
|
|
|
487
504
|
return JSON.stringify(await generateSchema(), null, 2);
|
|
488
505
|
}
|
|
489
506
|
|
|
507
|
+
// Minimal structural types for the optional `ajv` / `ajv-formats` peer deps
|
|
508
|
+
// (no direct dependency, and shipping no types usable from here).
|
|
509
|
+
interface AjvValidateFn {
|
|
510
|
+
(doc: unknown): boolean;
|
|
511
|
+
errors?: unknown[] | null;
|
|
512
|
+
}
|
|
513
|
+
interface AjvInstance {
|
|
514
|
+
compile: (schema: unknown) => AjvValidateFn;
|
|
515
|
+
}
|
|
516
|
+
type AjvCtor = new (opts: {
|
|
517
|
+
allErrors: boolean;
|
|
518
|
+
ownProperties: boolean;
|
|
519
|
+
strict: boolean;
|
|
520
|
+
}) => AjvInstance;
|
|
521
|
+
type AddFormatsFn = (ajv: AjvInstance) => void;
|
|
522
|
+
|
|
490
523
|
export async function validateDocument(doc: Record<string, unknown>) {
|
|
491
|
-
let Ajv, addFormats;
|
|
524
|
+
let Ajv: AjvCtor, addFormats: AddFormatsFn;
|
|
492
525
|
try {
|
|
526
|
+
// The generated schema is JSON Schema 2020-12, so use the matching Ajv build
|
|
527
|
+
// (the default `ajv` export is draft-07 and can't compile a 2020-12 schema).
|
|
528
|
+
({ default: Ajv } = (await import("ajv/dist/2020")) as { default: AjvCtor });
|
|
493
529
|
// @ts-expect-error — optional peer dependency
|
|
494
|
-
({ default:
|
|
495
|
-
// @ts-expect-error — optional peer dependency
|
|
496
|
-
({ default: addFormats } = await import("ajv-formats"));
|
|
530
|
+
({ default: addFormats } = (await import("ajv-formats")) as { default: AddFormatsFn });
|
|
497
531
|
} catch {
|
|
498
532
|
throw new Error("Schema validation requires ajv and ajv-formats: bun add ajv ajv-formats");
|
|
499
533
|
}
|
|
@@ -510,11 +544,11 @@ export async function validateDocument(doc: Record<string, unknown>) {
|
|
|
510
544
|
|
|
511
545
|
// ─── CLI ──────────────────────────────────────────────────────────────────────
|
|
512
546
|
|
|
513
|
-
|
|
547
|
+
async function runSchemaCli() {
|
|
514
548
|
const { writeFileSync } = await import("node:fs");
|
|
515
549
|
const { resolve, dirname } = await import("node:path");
|
|
516
550
|
|
|
517
|
-
const schemaDir = dirname(resolve(process.argv[1], ".."));
|
|
551
|
+
const schemaDir = dirname(resolve(process.argv[1] as string, ".."));
|
|
518
552
|
|
|
519
553
|
const componentSchema = await generateSchema();
|
|
520
554
|
const projectSchema = generateProjectSchema();
|
|
@@ -539,3 +573,9 @@ if (process.argv[1] && process.argv[1].endsWith("schema.ts")) {
|
|
|
539
573
|
console.error(" class-schema.json");
|
|
540
574
|
}
|
|
541
575
|
}
|
|
576
|
+
|
|
577
|
+
// Runs when invoked as a script or driven by a test that stages argv[1]. The build lives in an async
|
|
578
|
+
// Function rather than a top-level await: Bun's test runtime drops a dynamically-imported module's
|
|
579
|
+
// Top-level-await continuation on Windows. `ready` lets tests await the same sequence.
|
|
580
|
+
// oxlint-disable-next-line unicorn/prefer-top-level-await
|
|
581
|
+
export const ready = process.argv[1]?.endsWith("schema.ts") ? runSchemaCli() : undefined;
|
package/types.ts
CHANGED
|
@@ -198,6 +198,13 @@ export interface JxElement {
|
|
|
198
198
|
tagName?: string;
|
|
199
199
|
textContent?: string | null | JxRef;
|
|
200
200
|
innerHTML?: string;
|
|
201
|
+
/**
|
|
202
|
+
* Child nodes. A repeater (`{ $prototype: "Array", … }`) may appear as a member of the array —
|
|
203
|
+
* nestled among siblings or as the sole child — and is structurally a `JxElement` (its
|
|
204
|
+
* `items`/`map`/`filter`/`sort` are absorbed by the open index signature; narrow with
|
|
205
|
+
* `isMappedArray`). The bare `| JxMappedArray` form (whole children slot is one repeater) is
|
|
206
|
+
* retained for backward compatibility with legacy docs.
|
|
207
|
+
*/
|
|
201
208
|
children?: (JxElement | string)[] | JxMappedArray;
|
|
202
209
|
style?: JxStyle;
|
|
203
210
|
attributes?: Record<string, JxAttributeValue>;
|
|
@@ -471,6 +478,12 @@ export interface JxMutableNode {
|
|
|
471
478
|
tagName?: string;
|
|
472
479
|
textContent?: string | null | JxRef;
|
|
473
480
|
innerHTML?: string;
|
|
481
|
+
/**
|
|
482
|
+
* Child nodes. The editor models a mapped-array (repeater) member as a `JxMutableNode` carrying
|
|
483
|
+
* `$prototype: "Array"` (plus `items`/`map`/`filter`/`sort` below), so members stay assignable
|
|
484
|
+
* here. The bare `| JxMappedArray` form (whole children slot is one repeater) is retained for
|
|
485
|
+
* backward compatibility.
|
|
486
|
+
*/
|
|
474
487
|
children?: (JxMutableNode | string)[] | JxMappedArray;
|
|
475
488
|
style?: JxStyle;
|
|
476
489
|
attributes?: Record<string, JxAttributeValue>;
|