@jxsuite/schema 2.1.0 → 2.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 +7 -0
- package/defs/children-value.schema.ts +13 -0
- package/defs/element-def.schema.ts +7 -4
- package/defs/statement.schema.ts +29 -2
- package/defs/style-object.schema.ts +52 -3
- package/package.json +9 -4
- package/project-schema.json +24 -3
- package/schema.json +5065 -13
- package/schemas/project.core.schema.json +24 -3
- package/src/a11y.ts +760 -0
- package/src/dialogs.ts +428 -0
- package/src/doc-ops.ts +348 -0
- package/src/guards.ts +43 -5
- package/src/json-layout.ts +474 -0
- package/src/overlays.ts +825 -0
- package/src/schema.ts +28 -4
- package/types.ts +26 -2
package/README.md
CHANGED
|
@@ -42,6 +42,13 @@ const schema = await generateSchema(); // component meta-schema object
|
|
|
42
42
|
const valid = await validateDocument(doc); // validate a Jx document
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
## Documents as data
|
|
46
|
+
|
|
47
|
+
Two subpaths let any host edit and write a Jx document the way Studio does, with no DOM, no reactive store and no yjs:
|
|
48
|
+
|
|
49
|
+
- **`@jxsuite/schema/doc-ops`** is the document-op vocabulary. A `JxDocOp` (`set-key`, `insert-child`, `remove-child`, `set-child`, `move-child`) is a value-carrying mutation addressed by `JxPath`. `applyDocOpToDoc(doc, op)` applies one to a plain tree; `inverseOf(doc, op)` computes the op that undoes it, against the document as it stands before the op, in the coordinates of the document after it; `applyDocOpsWithInverse(doc, ops)` applies a sequence and answers each forward/inverse pair. Studio's history, the canvas iframe's shadow document and the collab bridge all replay through this one implementation, and `@jxsuite/collab/ops` re-exports it. Undoing an insert or move into a node that had no `children` leaves `children: []` behind, as Studio's history always has.
|
|
50
|
+
- **`@jxsuite/schema/json-layout`** is the layout-preserving JSON serializer behind every save. `parseJsonDocument(text)` answers the document and the facts about its text the formatter keeps; `serializeJson(document, layout)` writes it back with those honoured, so a one-value edit is a one-line diff.
|
|
51
|
+
|
|
45
52
|
## Component schema coverage
|
|
46
53
|
|
|
47
54
|
- **`tagName`**: all standard HTML element names from `@webref/elements`
|
|
@@ -7,6 +7,19 @@ export const arrayNamespaceSchema = {
|
|
|
7
7
|
items: {
|
|
8
8
|
oneOf: [{ $ref: "#/$defs/RefObject" }, { type: "array" }],
|
|
9
9
|
},
|
|
10
|
+
key: {
|
|
11
|
+
additionalProperties: false,
|
|
12
|
+
description:
|
|
13
|
+
"The identity of each rendered row: a $map/item pointer read per item. A row whose key " +
|
|
14
|
+
"survives a change keeps its DOM node and its effects across reorders, insertions and " +
|
|
15
|
+
"removals; without a key, rows are keyed by index. $map/index is not a key — an index " +
|
|
16
|
+
"names a position, not a row.",
|
|
17
|
+
properties: {
|
|
18
|
+
$ref: { pattern: "^\\$map/item(/.+)?$", type: "string" },
|
|
19
|
+
},
|
|
20
|
+
required: ["$ref"],
|
|
21
|
+
type: "object",
|
|
22
|
+
},
|
|
10
23
|
map: { $ref: "#/$defs/ElementDef" },
|
|
11
24
|
sort: { $ref: "#/$defs/RefObject" },
|
|
12
25
|
},
|
|
@@ -40,10 +40,13 @@ export const elementPropertyValueSchema = {
|
|
|
40
40
|
|
|
41
41
|
export const switchDefSchema = {
|
|
42
42
|
additionalProperties: false,
|
|
43
|
-
description:
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
|
|
43
|
+
description:
|
|
44
|
+
"Reactive $ref that drives which case to render: a state entry, or inside a mapped array's template the row's $map/item or $map/index (spec §14.1).",
|
|
45
|
+
// The discriminant is a reactive state path (e.g. "#/state/currentRoute") or a row pointer
|
|
46
|
+
// ("$map/item/dividerAbove") resolved by ResolveRef at render time — not a #/$defs/ type pointer.
|
|
47
|
+
properties: {
|
|
48
|
+
$ref: { oneOf: [{ $ref: "#/$defs/StateRef" }, { $ref: "#/$defs/MapRef" }], type: "string" },
|
|
49
|
+
},
|
|
47
50
|
required: ["$ref"],
|
|
48
51
|
type: "object",
|
|
49
52
|
} as const;
|
package/defs/statement.schema.ts
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
* string: explicit structured function declaration, mirroring ESTree's `BlockStatement.body =
|
|
7
7
|
* Statement[]`. Every statement kind reuses a web-platform name: bare expression nodes (§19), the
|
|
8
8
|
* JSON Schema 2020-12 `if`/`then`/`else` keyword triple, the element-level `$switch`/`cases`
|
|
9
|
-
* convention in statement position, and WHATWG's `dispatchEvent` with `CustomEventInit` members
|
|
9
|
+
* convention in statement position, and WHATWG's `dispatchEvent` with `CustomEventInit` members,
|
|
10
|
+
* `stopPropagation` and `preventDefault`.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
export const statementSchema = {
|
|
13
14
|
description:
|
|
14
|
-
"One statement of a structured function body. Either a bare expression node in statement position (a mutation like =/push, or a call — its result discarded unless captured by an assignment), an if/then/else branch (JSON Schema conditional keywords; if holds a pure expression, then/else hold statement lists), a $switch multiway branch (discriminant matched by string form against cases keys, like element-level $switch),
|
|
15
|
+
"One statement of a structured function body. Either a bare expression node in statement position (a mutation like =/push, or a call — its result discarded unless captured by an assignment), an if/then/else branch (JSON Schema conditional keywords; if holds a pure expression, then/else hold statement lists), a $switch multiway branch (discriminant matched by string form against cases keys, like element-level $switch), a dispatchEvent statement (WHATWG DOM: dispatches a CustomEvent from the handler's current target, with CustomEventInit members detail/bubbles/composed), or the two WHATWG event verbs stopPropagation and preventDefault, each spelled as the member set to true.",
|
|
15
16
|
oneOf: [
|
|
16
17
|
{ $ref: "#/$defs/ExpressionNode" },
|
|
17
18
|
{
|
|
@@ -54,6 +55,32 @@ export const statementSchema = {
|
|
|
54
55
|
title: "dispatchEvent — emit a CustomEvent (WHATWG naming, CustomEventInit members)",
|
|
55
56
|
type: "object",
|
|
56
57
|
},
|
|
58
|
+
{
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
properties: {
|
|
61
|
+
stopPropagation: {
|
|
62
|
+
const: true,
|
|
63
|
+
description:
|
|
64
|
+
"Stop the handler's event at the current target (WHATWG DOM stopPropagation), so an ancestor's handler for the same event does not run. A body run without an event has nothing to stop.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ["stopPropagation"],
|
|
68
|
+
title: "stopPropagation — stop the event here (WHATWG DOM)",
|
|
69
|
+
type: "object",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
additionalProperties: false,
|
|
73
|
+
properties: {
|
|
74
|
+
preventDefault: {
|
|
75
|
+
const: true,
|
|
76
|
+
description:
|
|
77
|
+
"Cancel the handler's event's default action (WHATWG DOM preventDefault): a link's navigation, a form's submission, a key's scroll.",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
required: ["preventDefault"],
|
|
81
|
+
title: "preventDefault — cancel the event's default action (WHATWG DOM)",
|
|
82
|
+
type: "object",
|
|
83
|
+
},
|
|
57
84
|
],
|
|
58
85
|
} as const;
|
|
59
86
|
|
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
export const styleObjectSchema = {
|
|
2
|
+
/* AnyOf, not oneOf, for the reason `propsObjectSchema` gives: a `{ $ref }` legitimately matches
|
|
3
|
+
both branches. It is a reactive VALUE, and it is also — vacuously — a nested block holding one
|
|
4
|
+
declaration named `$ref`, because a block admits a string under any key. Exclusive matching
|
|
5
|
+
rejects it as ambiguous, which is what `oneOf` did the moment RefObject was added here. The
|
|
6
|
+
ambiguity is harmless: the runtime reads an object carrying `$ref` as a value, and nothing
|
|
7
|
+
else can. */
|
|
2
8
|
additionalProperties: {
|
|
3
|
-
|
|
9
|
+
anyOf: [
|
|
10
|
+
{ type: "string" },
|
|
11
|
+
{ type: "number" },
|
|
12
|
+
{ $ref: "#/$defs/RefObject" },
|
|
13
|
+
{ $ref: "#/$defs/StyleObject" },
|
|
14
|
+
],
|
|
4
15
|
},
|
|
5
16
|
description:
|
|
6
17
|
"CSS style definition. camelCase property names follow CSSOM convention. " +
|
|
7
18
|
"Keys starting with :, ., &, or [ are treated as nested CSS selectors. " +
|
|
8
19
|
"Keys matching $media breakpoint names (or other @-prefixed at-rules) group nested rules. " +
|
|
9
20
|
"Nesting is recursive: selector and at-rule groups may nest to arbitrary depth " +
|
|
10
|
-
"(e.g. breakpoint → selector → pseudo-class), mirroring the compiler's recursive emission."
|
|
11
|
-
|
|
21
|
+
"(e.g. breakpoint → selector → pseudo-class), mirroring the compiler's recursive emission. " +
|
|
22
|
+
"An object carrying $ref is a reactive VALUE, and the runtime reads it as one. It also " +
|
|
23
|
+
"matches the nested-block branch vacuously, since a block admits a string under any key, " +
|
|
24
|
+
"which is why these branches are anyOf rather than oneOf. " +
|
|
25
|
+
"A DECLARATION at-rule (@font-face, @property, @position-try, @counter-style) may hold an " +
|
|
26
|
+
"ARRAY of blocks, which is that key written more than once, in order: an object's keys are " +
|
|
27
|
+
"unique, so @font-face — the at-rule whose identity is not in its key — could not otherwise " +
|
|
28
|
+
"state a family's second weight at all.",
|
|
29
|
+
patternProperties: {
|
|
30
|
+
/*
|
|
31
|
+
* A DECLARATION at-rule, and only one of those four, may hold several blocks.
|
|
32
|
+
*
|
|
33
|
+
* `additionalProperties` below admits no array, so this is the whole of it. The builder scopes
|
|
34
|
+
* the form the same way (`blocksOf` in `packages/runtime/src/css.ts`), and the two must agree:
|
|
35
|
+
* a schema that admitted an array under a selector would validate a document the builder
|
|
36
|
+
* silently drops, which is the same trap `staticStyleObjectSchema` exists to avoid one level up.
|
|
37
|
+
*/
|
|
38
|
+
"^@(font-face|property|position-try|counter-style)": {
|
|
39
|
+
anyOf: [
|
|
40
|
+
{ $ref: "#/$defs/StyleObject" },
|
|
41
|
+
{ items: { $ref: "#/$defs/StyleObject" }, minItems: 1, type: "array" },
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
properties: {
|
|
46
|
+
/*
|
|
47
|
+
* Prose, not a declaration: why the rule exists, in the author's words.
|
|
48
|
+
*
|
|
49
|
+
* A style block had nowhere to say that, and writing it anyway emitted
|
|
50
|
+
* `$description: why this exists;` — an invalid declaration the parser drops in silence, with
|
|
51
|
+
* the prose inside the text the runtime interns rules by. Every `$`-prefixed key is metadata
|
|
52
|
+
* here for the same reason it is everywhere else in a document, and no CSS property begins with
|
|
53
|
+
* `$`. A static emitter renders it as a comment; the runtime ignores it.
|
|
54
|
+
*/
|
|
55
|
+
$description: {
|
|
56
|
+
description:
|
|
57
|
+
"Why this rule exists. Emitted as a comment by static builds, ignored at runtime.",
|
|
58
|
+
type: "string",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
12
61
|
type: "object",
|
|
13
62
|
} as const;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@webref/css": "^8.7.
|
|
4
|
-
"@webref/elements": "^2.
|
|
5
|
-
"@webref/idl": "^3.
|
|
3
|
+
"@webref/css": "^8.7.5",
|
|
4
|
+
"@webref/elements": "^2.9.0",
|
|
5
|
+
"@webref/idl": "^3.84.0",
|
|
6
6
|
"ajv": "^8.20.0",
|
|
7
7
|
"ajv-formats": "^3.0.1"
|
|
8
8
|
},
|
|
@@ -20,8 +20,13 @@
|
|
|
20
20
|
"./locale": "./src/locale.ts",
|
|
21
21
|
"./intl": "./src/intl.ts",
|
|
22
22
|
"./media-type": "./src/media-type.ts",
|
|
23
|
+
"./overlays": "./src/overlays.ts",
|
|
24
|
+
"./dialogs": "./src/dialogs.ts",
|
|
25
|
+
"./a11y": "./src/a11y.ts",
|
|
23
26
|
"./ijson": "./src/ijson.ts",
|
|
24
27
|
"./parse": "./src/parse.ts",
|
|
28
|
+
"./doc-ops": "./src/doc-ops.ts",
|
|
29
|
+
"./json-layout": "./src/json-layout.ts",
|
|
25
30
|
"./defs": "./defs/index.ts",
|
|
26
31
|
"./schema.json": "./schema.json",
|
|
27
32
|
"./project-schema.json": "./project-schema.json",
|
|
@@ -55,7 +60,7 @@
|
|
|
55
60
|
"upgrade": "bun update --latest && bun install"
|
|
56
61
|
},
|
|
57
62
|
"type": "module",
|
|
58
|
-
"version": "2.
|
|
63
|
+
"version": "2.3.0",
|
|
59
64
|
"devDependencies": {
|
|
60
65
|
"json-schema-to-ts": "^3.1.1"
|
|
61
66
|
}
|
package/project-schema.json
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"StyleObject": {
|
|
67
67
|
"additionalProperties": {
|
|
68
|
-
"
|
|
68
|
+
"anyOf": [
|
|
69
69
|
{
|
|
70
70
|
"type": "string"
|
|
71
71
|
},
|
|
@@ -77,8 +77,29 @@
|
|
|
77
77
|
}
|
|
78
78
|
]
|
|
79
79
|
},
|
|
80
|
-
"description": "CSS style definition. camelCase property names follow CSSOM convention. Keys starting with :, ., &, or [ are treated as nested CSS selectors. Keys matching $media breakpoint names (or other @-prefixed at-rules) group nested rules. Nesting is recursive: selector and at-rule groups may nest to arbitrary depth (e.g. breakpoint → selector → pseudo-class), mirroring the compiler's recursive emission.",
|
|
81
|
-
"
|
|
80
|
+
"description": "CSS style definition. camelCase property names follow CSSOM convention. Keys starting with :, ., &, or [ are treated as nested CSS selectors. Keys matching $media breakpoint names (or other @-prefixed at-rules) group nested rules. Nesting is recursive: selector and at-rule groups may nest to arbitrary depth (e.g. breakpoint → selector → pseudo-class), mirroring the compiler's recursive emission. An object carrying $ref is a reactive VALUE, and the runtime reads it as one. It also matches the nested-block branch vacuously, since a block admits a string under any key, which is why these branches are anyOf rather than oneOf. A DECLARATION at-rule (@font-face, @property, @position-try, @counter-style) may hold an ARRAY of blocks, which is that key written more than once, in order: an object's keys are unique, so @font-face — the at-rule whose identity is not in its key — could not otherwise state a family's second weight at all.",
|
|
81
|
+
"patternProperties": {
|
|
82
|
+
"^@(font-face|property|position-try|counter-style)": {
|
|
83
|
+
"anyOf": [
|
|
84
|
+
{
|
|
85
|
+
"$ref": "#/$defs/StyleObject"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"items": {
|
|
89
|
+
"$ref": "#/$defs/StyleObject"
|
|
90
|
+
},
|
|
91
|
+
"minItems": 1,
|
|
92
|
+
"type": "array"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"properties": {
|
|
98
|
+
"$description": {
|
|
99
|
+
"description": "Why this rule exists. Emitted as a comment by static builds, ignored at runtime.",
|
|
100
|
+
"type": "string"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
82
103
|
"type": "object"
|
|
83
104
|
}
|
|
84
105
|
},
|