@jxsuite/schema 1.0.0 → 1.2.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/defs/expression-node.schema.ts +118 -9
- package/defs/function-def.schema.ts +7 -2
- package/defs/index.ts +5 -0
- package/defs/project-config.schema.ts +9 -2
- package/defs/statement.schema.ts +65 -0
- package/package.json +3 -2
- package/project-schema.json +3 -2
- package/schema.json +324 -13
- package/schemas/document.paths.schema.json +1 -1
- package/schemas/project.core.schema.json +21 -78
- package/schemas/project.fields.schema.json +1 -1
- package/src/asset-paths.ts +42 -0
- package/src/extension-registry.ts +5 -0
- package/src/format-registry.ts +5 -2
- package/src/guards.ts +21 -0
- package/src/schema.ts +39 -1
- package/types.ts +53 -3
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export const expressionPointerSchema = {
|
|
2
2
|
additionalProperties: false,
|
|
3
|
-
description:
|
|
3
|
+
description:
|
|
4
|
+
"A JSON Pointer $ref operand within an expression node. $args/<name> resolves a named formula's parameter (callable entries only).",
|
|
4
5
|
properties: {
|
|
5
6
|
$ref: {
|
|
6
|
-
pattern: "^(\\$map/|\\$reduce/|event#/|#/|parent#/|window#/|document#/)",
|
|
7
|
+
pattern: "^(\\$map/|\\$reduce/|\\$args/|event#/|#/|parent#/|window#/|document#/)",
|
|
7
8
|
type: "string",
|
|
8
9
|
},
|
|
9
10
|
},
|
|
@@ -18,8 +19,14 @@ export const expressionLiteralSchema = {
|
|
|
18
19
|
{ type: "boolean" },
|
|
19
20
|
{ type: "null" },
|
|
20
21
|
{ items: { $ref: "#/$defs/ExpressionOperand" }, type: "array" },
|
|
22
|
+
{
|
|
23
|
+
description:
|
|
24
|
+
"Plain-object literal (e.g. an Intl options bag). Objects carrying $ref or operator keys are pointers/nodes, never literals.",
|
|
25
|
+
not: { anyOf: [{ required: ["$ref"] }, { required: ["operator"] }] },
|
|
26
|
+
type: "object",
|
|
27
|
+
},
|
|
21
28
|
],
|
|
22
|
-
description: "A non-reactive operand: scalar or array of operands.",
|
|
29
|
+
description: "A non-reactive operand: scalar, plain-object literal, or array of operands.",
|
|
23
30
|
} as const;
|
|
24
31
|
|
|
25
32
|
export const expressionOperandSchema = {
|
|
@@ -34,7 +41,47 @@ export const expressionOperandSchema = {
|
|
|
34
41
|
|
|
35
42
|
export const unaryOperatorSchema = { enum: ["!", "-"] } as const;
|
|
36
43
|
export const binaryOperatorSchema = {
|
|
37
|
-
enum: ["+", "-", "*", "/", "%", "===", "!==", "<", "<=", ">", ">=", "&&", "||"],
|
|
44
|
+
enum: ["+", "-", "*", "/", "%", "===", "!==", "<", "<=", ">", ">=", "&&", "||", "??"],
|
|
45
|
+
} as const;
|
|
46
|
+
export const conditionalOperatorSchema = { const: "?:" } as const;
|
|
47
|
+
export const switchOperatorSchema = { const: "switch" } as const;
|
|
48
|
+
export const callOperatorSchema = { const: "call" } as const;
|
|
49
|
+
export const pureMethodSchema = {
|
|
50
|
+
description:
|
|
51
|
+
"A genuine pure String.prototype / Array.prototype / Number.prototype method (spec §19.4d). The ES2023 change-by-copy family (toSorted, toReversed, toSpliced, with) stands in where mutation would otherwise occur. Receiver in target; value carries the argument (bare scalar) or argument list (array).",
|
|
52
|
+
enum: [
|
|
53
|
+
"includes",
|
|
54
|
+
"indexOf",
|
|
55
|
+
"lastIndexOf",
|
|
56
|
+
"join",
|
|
57
|
+
"slice",
|
|
58
|
+
"concat",
|
|
59
|
+
"at",
|
|
60
|
+
"flat",
|
|
61
|
+
"toSorted",
|
|
62
|
+
"toReversed",
|
|
63
|
+
"toSpliced",
|
|
64
|
+
"with",
|
|
65
|
+
"toUpperCase",
|
|
66
|
+
"toLowerCase",
|
|
67
|
+
"trim",
|
|
68
|
+
"trimStart",
|
|
69
|
+
"trimEnd",
|
|
70
|
+
"split",
|
|
71
|
+
"startsWith",
|
|
72
|
+
"endsWith",
|
|
73
|
+
"padStart",
|
|
74
|
+
"padEnd",
|
|
75
|
+
"replaceAll",
|
|
76
|
+
"repeat",
|
|
77
|
+
"charAt",
|
|
78
|
+
"normalize",
|
|
79
|
+
"toLocaleUpperCase",
|
|
80
|
+
"toLocaleLowerCase",
|
|
81
|
+
"toFixed",
|
|
82
|
+
"toPrecision",
|
|
83
|
+
"toLocaleString",
|
|
84
|
+
],
|
|
38
85
|
} as const;
|
|
39
86
|
export const assignmentOperatorSchema = { enum: ["=", "+=", "-=", "*=", "/="] } as const;
|
|
40
87
|
export const noArgMethodSchema = { enum: ["pop", "shift"] } as const;
|
|
@@ -99,24 +146,80 @@ export const expressionNodeSchema = {
|
|
|
99
146
|
{
|
|
100
147
|
properties: {
|
|
101
148
|
operator: { $ref: "#/$defs/ReduceMethod" },
|
|
102
|
-
target: {
|
|
149
|
+
target: {
|
|
150
|
+
anyOf: [{ $ref: "#/$defs/ExpressionPointer" }, { $ref: "#/$defs/ExpressionNode" }],
|
|
151
|
+
},
|
|
103
152
|
value: { $ref: "#/$defs/ExpressionNode" },
|
|
104
153
|
},
|
|
105
154
|
required: ["operator", "value", "initial"],
|
|
106
|
-
title: "reduce — pure fold
|
|
155
|
+
title: "reduce — pure fold over a pointer or derived array; seed in initial",
|
|
107
156
|
},
|
|
108
157
|
{
|
|
109
158
|
not: { required: ["initial"] },
|
|
110
159
|
properties: {
|
|
111
160
|
operator: { $ref: "#/$defs/MapFilterMethod" },
|
|
112
|
-
target: {
|
|
161
|
+
target: {
|
|
162
|
+
anyOf: [{ $ref: "#/$defs/ExpressionPointer" }, { $ref: "#/$defs/ExpressionNode" }],
|
|
163
|
+
},
|
|
113
164
|
value: { $ref: "#/$defs/ExpressionNode" },
|
|
114
165
|
},
|
|
115
166
|
required: ["operator", "value"],
|
|
116
|
-
title: "map / filter — pure; per-item expression in value
|
|
167
|
+
title: "map / filter — pure over a pointer or derived array; per-item expression in value",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
description:
|
|
171
|
+
"The ECMAScript conditional (ternary) operator, pure: target is the test, value the consequent, initial the alternate (the reduce precedent for repurposing initial). Chain else-if by nesting another ?: node in initial.",
|
|
172
|
+
properties: { operator: { $ref: "#/$defs/ConditionalOperator" } },
|
|
173
|
+
required: ["operator", "value", "initial"],
|
|
174
|
+
title: "?: — pure conditional; test in target, consequent in value, alternate in initial",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
description:
|
|
178
|
+
"Value-keyed multiway selection, pure: target is the discriminant (matched against case keys by its string form, like element-level $switch), cases maps matched values to result operands, default is the operand when no case matches (result is undefined without it). Condition-chain branching composes from nested ?: nodes instead.",
|
|
179
|
+
not: { anyOf: [{ required: ["value"] }, { required: ["initial"] }] },
|
|
180
|
+
properties: {
|
|
181
|
+
cases: {
|
|
182
|
+
additionalProperties: { $ref: "#/$defs/ExpressionOperand" },
|
|
183
|
+
type: "object",
|
|
184
|
+
},
|
|
185
|
+
default: { $ref: "#/$defs/ExpressionOperand" },
|
|
186
|
+
operator: { $ref: "#/$defs/SwitchOperator" },
|
|
187
|
+
},
|
|
188
|
+
required: ["operator", "cases"],
|
|
189
|
+
title:
|
|
190
|
+
"switch — pure value-keyed selection; discriminant in target, results in cases/default",
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
description:
|
|
194
|
+
"A pure standard-library method call: target is the receiver (any operand — never mutated; change-by-copy names replace the mutating originals), value the optional argument (bare scalar) or argument list (array). A missing receiver or method yields undefined, matching null-safe path reads.",
|
|
195
|
+
not: { required: ["initial"] },
|
|
196
|
+
properties: { operator: { $ref: "#/$defs/PureMethod" } },
|
|
197
|
+
required: ["operator"],
|
|
198
|
+
title: "Pure method — genuine prototype methods; receiver in target, args in value",
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
description:
|
|
202
|
+
"Invoke a callable, pure in formula position: target is the callee pointer — a named formula entry (#/state/…) or a blessed pure global via window#/ (Math.*, JSON.*, Object.keys/values/entries, and the Intl helpers Intl/formatNumber, Intl/formatDate, Intl/formatRelativeTime) — and value is the positional argument list (the splice args-in-value precedent). Argument order follows the callee's declared parameters.",
|
|
203
|
+
not: { required: ["initial"] },
|
|
204
|
+
properties: {
|
|
205
|
+
operator: { $ref: "#/$defs/CallOperator" },
|
|
206
|
+
target: { $ref: "#/$defs/ExpressionPointer" },
|
|
207
|
+
value: { items: { $ref: "#/$defs/ExpressionOperand" }, type: "array" },
|
|
208
|
+
},
|
|
209
|
+
required: ["operator"],
|
|
210
|
+
title: "call — invoke a named formula or blessed global; callee in target, args in value",
|
|
117
211
|
},
|
|
118
212
|
],
|
|
119
213
|
properties: {
|
|
214
|
+
cases: {
|
|
215
|
+
additionalProperties: { $ref: "#/$defs/ExpressionOperand" },
|
|
216
|
+
description: "switch only: matched discriminant value (string form) → result operand.",
|
|
217
|
+
type: "object",
|
|
218
|
+
},
|
|
219
|
+
default: {
|
|
220
|
+
$ref: "#/$defs/ExpressionOperand",
|
|
221
|
+
description: "switch only: result operand when no case key matches.",
|
|
222
|
+
},
|
|
120
223
|
initial: { $ref: "#/$defs/ExpressionOperand" },
|
|
121
224
|
operator: { type: "string" },
|
|
122
225
|
target: { $ref: "#/$defs/ExpressionOperand" },
|
|
@@ -129,11 +232,17 @@ export const expressionNodeSchema = {
|
|
|
129
232
|
export const expressionEntrySchema = {
|
|
130
233
|
additionalProperties: false,
|
|
131
234
|
description:
|
|
132
|
-
"A declarative expression entry (Shape 5). Used as a state entry or inline event handler.",
|
|
235
|
+
"A declarative expression entry (Shape 5). Used as a state entry or inline event handler. With parameters it is a named formula: a pure, reusable computation invoked via the call operator, its parameters resolved through $args/<name> refs in the body.",
|
|
133
236
|
properties: {
|
|
134
237
|
$description: { type: "string" },
|
|
135
238
|
$expression: { $ref: "#/$defs/ExpressionNode" },
|
|
136
239
|
$title: { type: "string" },
|
|
240
|
+
parameters: {
|
|
241
|
+
description:
|
|
242
|
+
"Named-formula parameters (CEM convention, as on Function entries): bare names or CEM parameter objects. Present ⇒ the entry is callable, not a computed value.",
|
|
243
|
+
items: { anyOf: [{ type: "string" }, { $ref: "#/$defs/CemParameter" }] },
|
|
244
|
+
type: "array",
|
|
245
|
+
},
|
|
137
246
|
},
|
|
138
247
|
required: ["$expression"],
|
|
139
248
|
type: "object",
|
|
@@ -16,13 +16,18 @@ export const functionDefSchema = {
|
|
|
16
16
|
type: "string",
|
|
17
17
|
},
|
|
18
18
|
body: {
|
|
19
|
-
description:
|
|
19
|
+
description:
|
|
20
|
+
"Inline function body: an opaque JS source string (first implicit parameter is state), or a structured statement array (spec §20) — explicit structured function declaration, analyzable by tooling and editable visually. The escalation ladder within the shape is structured statements → JS string.",
|
|
20
21
|
examples: [
|
|
21
22
|
"state.count++",
|
|
22
23
|
'state.items.push({ id: Date.now(), text: "", done: false })',
|
|
23
24
|
'return state.score >= 90 ? "gold" : "silver"',
|
|
25
|
+
[
|
|
26
|
+
{ operator: "push", target: { $ref: "#/state/cart" }, value: 1 },
|
|
27
|
+
{ dispatchEvent: "cart-changed", detail: { $ref: "#/state/cart" } },
|
|
28
|
+
],
|
|
24
29
|
],
|
|
25
|
-
type: "string",
|
|
30
|
+
oneOf: [{ type: "string" }, { $ref: "#/$defs/StatementList" }],
|
|
26
31
|
},
|
|
27
32
|
description: { type: "string" },
|
|
28
33
|
emits: {
|
package/defs/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ export {
|
|
|
34
34
|
// State shapes
|
|
35
35
|
export { typedStateDefSchema } from "./typed-state-def.schema";
|
|
36
36
|
export { functionDefSchema } from "./function-def.schema";
|
|
37
|
+
export { statementSchema, statementListSchema } from "./statement.schema";
|
|
37
38
|
export { externalClassDefSchema, BUILT_IN_PROTOTYPES } from "./external-class-def.schema";
|
|
38
39
|
export { pureTypeDefSchema } from "./pure-type-def.schema";
|
|
39
40
|
|
|
@@ -46,6 +47,10 @@ export {
|
|
|
46
47
|
expressionEntrySchema,
|
|
47
48
|
unaryOperatorSchema,
|
|
48
49
|
binaryOperatorSchema,
|
|
50
|
+
conditionalOperatorSchema,
|
|
51
|
+
switchOperatorSchema,
|
|
52
|
+
callOperatorSchema,
|
|
53
|
+
pureMethodSchema,
|
|
49
54
|
assignmentOperatorSchema,
|
|
50
55
|
noArgMethodSchema,
|
|
51
56
|
oneArgMethodSchema,
|
|
@@ -54,9 +54,15 @@ export const projectConfigSchema = {
|
|
|
54
54
|
additionalProperties: { type: "string" },
|
|
55
55
|
description:
|
|
56
56
|
"Named media breakpoints following CSS @custom-media convention. " +
|
|
57
|
-
"Available in all component style objects."
|
|
57
|
+
"Available in all component style objects. Declaring a pure color-scheme " +
|
|
58
|
+
'query (e.g. "--dark": "(prefers-color-scheme: dark)") additionally opts the ' +
|
|
59
|
+
"site into the forced-scheme contract: @--dark style blocks are dual-emitted " +
|
|
60
|
+
"so a data-color-scheme attribute on <html> overrides the OS preference, " +
|
|
61
|
+
"color-scheme is declared on :root, and a pre-paint script restores the " +
|
|
62
|
+
"visitor's persisted choice (spec §9.5).",
|
|
58
63
|
examples: [
|
|
59
64
|
{
|
|
65
|
+
"--dark": "(prefers-color-scheme: dark)",
|
|
60
66
|
"--lg": "(min-width: 1024px)",
|
|
61
67
|
"--md": "(min-width: 768px)",
|
|
62
68
|
"--sm": "(min-width: 640px)",
|
|
@@ -110,7 +116,8 @@ export const projectConfigSchema = {
|
|
|
110
116
|
},
|
|
111
117
|
format: {
|
|
112
118
|
default: "directory",
|
|
113
|
-
description:
|
|
119
|
+
description:
|
|
120
|
+
"Reserved; currently unused. Accepted for forward compatibility with single-file output (desktop single-file mode) — the build emits per-route directories regardless.",
|
|
114
121
|
enum: ["directory", "single"],
|
|
115
122
|
type: "string",
|
|
116
123
|
},
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// oxlint-disable unicorn/no-thenable -- `then` is the JSON Schema conditional keyword (spec §20), not a promise
|
|
2
|
+
/**
|
|
3
|
+
* Statement schema (spec §20) — structured function bodies.
|
|
4
|
+
*
|
|
5
|
+
* A Function entry's `body` may be a JSON array of statements instead of an opaque JS source
|
|
6
|
+
* string: explicit structured function declaration, mirroring ESTree's `BlockStatement.body =
|
|
7
|
+
* Statement[]`. Every statement kind reuses a web-platform name: bare expression nodes (§19), the
|
|
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.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const statementSchema = {
|
|
13
|
+
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), or a dispatchEvent statement (WHATWG DOM: dispatches a CustomEvent from the handler's current target, with CustomEventInit members detail/bubbles/composed).",
|
|
15
|
+
oneOf: [
|
|
16
|
+
{ $ref: "#/$defs/ExpressionNode" },
|
|
17
|
+
{
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
properties: {
|
|
20
|
+
else: { items: { $ref: "#/$defs/Statement" }, type: "array" },
|
|
21
|
+
if: { $ref: "#/$defs/ExpressionOperand" },
|
|
22
|
+
then: { items: { $ref: "#/$defs/Statement" }, type: "array" },
|
|
23
|
+
},
|
|
24
|
+
required: ["if", "then"],
|
|
25
|
+
title: "if / then / else — conditional branch (JSON Schema keyword triple)",
|
|
26
|
+
type: "object",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
properties: {
|
|
31
|
+
$switch: { $ref: "#/$defs/ExpressionOperand" },
|
|
32
|
+
cases: {
|
|
33
|
+
additionalProperties: { items: { $ref: "#/$defs/Statement" }, type: "array" },
|
|
34
|
+
type: "object",
|
|
35
|
+
},
|
|
36
|
+
default: { items: { $ref: "#/$defs/Statement" }, type: "array" },
|
|
37
|
+
},
|
|
38
|
+
required: ["$switch", "cases"],
|
|
39
|
+
title: "$switch / cases — multiway branch (element-level convention, ECMA switch semantics)",
|
|
40
|
+
type: "object",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
additionalProperties: false,
|
|
44
|
+
properties: {
|
|
45
|
+
bubbles: { type: "boolean" },
|
|
46
|
+
composed: { type: "boolean" },
|
|
47
|
+
detail: { $ref: "#/$defs/ExpressionOperand" },
|
|
48
|
+
dispatchEvent: {
|
|
49
|
+
description: "The CustomEvent type to dispatch (WHATWG DOM dispatchEvent).",
|
|
50
|
+
type: "string",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
required: ["dispatchEvent"],
|
|
54
|
+
title: "dispatchEvent — emit a CustomEvent (WHATWG naming, CustomEventInit members)",
|
|
55
|
+
type: "object",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
export const statementListSchema = {
|
|
61
|
+
description:
|
|
62
|
+
"A structured function body: statements executed sequentially (one yielding a promise is awaited before the next, per ECMA async/await semantics).",
|
|
63
|
+
items: { $ref: "#/$defs/Statement" },
|
|
64
|
+
type: "array",
|
|
65
|
+
} as const;
|
package/package.json
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"@webref/css": "^8.7.0",
|
|
4
4
|
"@webref/elements": "^2.7.1",
|
|
5
|
-
"@webref/idl": "^3.
|
|
5
|
+
"@webref/idl": "^3.82.0",
|
|
6
6
|
"ajv": "^8.20.0",
|
|
7
7
|
"ajv-formats": "^3.0.1"
|
|
8
8
|
},
|
|
9
9
|
"description": "JSON Schema 2020-12 meta-schema generator for Jx documents",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./src/schema.ts",
|
|
12
|
+
"./asset-paths": "./src/asset-paths.ts",
|
|
12
13
|
"./extension-registry": "./src/extension-registry.ts",
|
|
13
14
|
"./format-registry": "./src/format-registry.ts",
|
|
14
15
|
"./project-schemas": "./src/project-schemas.ts",
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
"upgrade": "bunx npm-check-updates -u && bun install"
|
|
50
51
|
},
|
|
51
52
|
"type": "module",
|
|
52
|
-
"version": "1.
|
|
53
|
+
"version": "1.2.0",
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"json-schema-to-ts": "^3.1.1"
|
|
55
56
|
}
|
package/project-schema.json
CHANGED
|
@@ -131,9 +131,10 @@
|
|
|
131
131
|
"additionalProperties": {
|
|
132
132
|
"type": "string"
|
|
133
133
|
},
|
|
134
|
-
"description": "Named media breakpoints following CSS @custom-media convention. Available in all component style objects.",
|
|
134
|
+
"description": "Named media breakpoints following CSS @custom-media convention. Available in all component style objects. Declaring a pure color-scheme query (e.g. \"--dark\": \"(prefers-color-scheme: dark)\") additionally opts the site into the forced-scheme contract: @--dark style blocks are dual-emitted so a data-color-scheme attribute on <html> overrides the OS preference, color-scheme is declared on :root, and a pre-paint script restores the visitor's persisted choice (spec §9.5).",
|
|
135
135
|
"examples": [
|
|
136
136
|
{
|
|
137
|
+
"--dark": "(prefers-color-scheme: dark)",
|
|
137
138
|
"--lg": "(min-width: 1024px)",
|
|
138
139
|
"--md": "(min-width: 768px)",
|
|
139
140
|
"--sm": "(min-width: 640px)"
|
|
@@ -193,7 +194,7 @@
|
|
|
193
194
|
},
|
|
194
195
|
"format": {
|
|
195
196
|
"default": "directory",
|
|
196
|
-
"description": "
|
|
197
|
+
"description": "Reserved; currently unused. Accepted for forward compatibility with single-file output (desktop single-file mode) — the build emits per-route directories regardless.",
|
|
197
198
|
"enum": [
|
|
198
199
|
"directory",
|
|
199
200
|
"single"
|
package/schema.json
CHANGED
|
@@ -224,13 +224,35 @@
|
|
|
224
224
|
"type": "string"
|
|
225
225
|
},
|
|
226
226
|
"body": {
|
|
227
|
-
"description": "Inline function body string
|
|
227
|
+
"description": "Inline function body: an opaque JS source string (first implicit parameter is state), or a structured statement array (spec §20) — explicit structured function declaration, analyzable by tooling and editable visually. The escalation ladder within the shape is structured statements → JS string.",
|
|
228
228
|
"examples": [
|
|
229
229
|
"state.count++",
|
|
230
230
|
"state.items.push({ id: Date.now(), text: \"\", done: false })",
|
|
231
|
-
"return state.score >= 90 ? \"gold\" : \"silver\""
|
|
231
|
+
"return state.score >= 90 ? \"gold\" : \"silver\"",
|
|
232
|
+
[
|
|
233
|
+
{
|
|
234
|
+
"operator": "push",
|
|
235
|
+
"target": {
|
|
236
|
+
"$ref": "#/state/cart"
|
|
237
|
+
},
|
|
238
|
+
"value": 1
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"dispatchEvent": "cart-changed",
|
|
242
|
+
"detail": {
|
|
243
|
+
"$ref": "#/state/cart"
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
]
|
|
232
247
|
],
|
|
233
|
-
"
|
|
248
|
+
"oneOf": [
|
|
249
|
+
{
|
|
250
|
+
"type": "string"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"$ref": "#/$defs/StatementList"
|
|
254
|
+
}
|
|
255
|
+
]
|
|
234
256
|
},
|
|
235
257
|
"description": {
|
|
236
258
|
"type": "string"
|
|
@@ -951,10 +973,10 @@
|
|
|
951
973
|
},
|
|
952
974
|
"ExpressionPointer": {
|
|
953
975
|
"additionalProperties": false,
|
|
954
|
-
"description": "A JSON Pointer $ref operand within an expression node.",
|
|
976
|
+
"description": "A JSON Pointer $ref operand within an expression node. $args/<name> resolves a named formula's parameter (callable entries only).",
|
|
955
977
|
"properties": {
|
|
956
978
|
"$ref": {
|
|
957
|
-
"pattern": "^(\\$map/|\\$reduce/|event#/|#/|parent#/|window#/|document#/)",
|
|
979
|
+
"pattern": "^(\\$map/|\\$reduce/|\\$args/|event#/|#/|parent#/|window#/|document#/)",
|
|
958
980
|
"type": "string"
|
|
959
981
|
}
|
|
960
982
|
},
|
|
@@ -985,9 +1007,27 @@
|
|
|
985
1007
|
"$ref": "#/$defs/ExpressionOperand"
|
|
986
1008
|
},
|
|
987
1009
|
"type": "array"
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
"description": "Plain-object literal (e.g. an Intl options bag). Objects carrying $ref or operator keys are pointers/nodes, never literals.",
|
|
1013
|
+
"not": {
|
|
1014
|
+
"anyOf": [
|
|
1015
|
+
{
|
|
1016
|
+
"required": [
|
|
1017
|
+
"$ref"
|
|
1018
|
+
]
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
"required": [
|
|
1022
|
+
"operator"
|
|
1023
|
+
]
|
|
1024
|
+
}
|
|
1025
|
+
]
|
|
1026
|
+
},
|
|
1027
|
+
"type": "object"
|
|
988
1028
|
}
|
|
989
1029
|
],
|
|
990
|
-
"description": "A non-reactive operand: scalar or array of operands."
|
|
1030
|
+
"description": "A non-reactive operand: scalar, plain-object literal, or array of operands."
|
|
991
1031
|
},
|
|
992
1032
|
"ExpressionOperand": {
|
|
993
1033
|
"anyOf": [
|
|
@@ -1023,7 +1063,53 @@
|
|
|
1023
1063
|
">",
|
|
1024
1064
|
">=",
|
|
1025
1065
|
"&&",
|
|
1026
|
-
"||"
|
|
1066
|
+
"||",
|
|
1067
|
+
"??"
|
|
1068
|
+
]
|
|
1069
|
+
},
|
|
1070
|
+
"ConditionalOperator": {
|
|
1071
|
+
"const": "?:"
|
|
1072
|
+
},
|
|
1073
|
+
"SwitchOperator": {
|
|
1074
|
+
"const": "switch"
|
|
1075
|
+
},
|
|
1076
|
+
"CallOperator": {
|
|
1077
|
+
"const": "call"
|
|
1078
|
+
},
|
|
1079
|
+
"PureMethod": {
|
|
1080
|
+
"description": "A genuine pure String.prototype / Array.prototype / Number.prototype method (spec §19.4d). The ES2023 change-by-copy family (toSorted, toReversed, toSpliced, with) stands in where mutation would otherwise occur. Receiver in target; value carries the argument (bare scalar) or argument list (array).",
|
|
1081
|
+
"enum": [
|
|
1082
|
+
"includes",
|
|
1083
|
+
"indexOf",
|
|
1084
|
+
"lastIndexOf",
|
|
1085
|
+
"join",
|
|
1086
|
+
"slice",
|
|
1087
|
+
"concat",
|
|
1088
|
+
"at",
|
|
1089
|
+
"flat",
|
|
1090
|
+
"toSorted",
|
|
1091
|
+
"toReversed",
|
|
1092
|
+
"toSpliced",
|
|
1093
|
+
"with",
|
|
1094
|
+
"toUpperCase",
|
|
1095
|
+
"toLowerCase",
|
|
1096
|
+
"trim",
|
|
1097
|
+
"trimStart",
|
|
1098
|
+
"trimEnd",
|
|
1099
|
+
"split",
|
|
1100
|
+
"startsWith",
|
|
1101
|
+
"endsWith",
|
|
1102
|
+
"padStart",
|
|
1103
|
+
"padEnd",
|
|
1104
|
+
"replaceAll",
|
|
1105
|
+
"repeat",
|
|
1106
|
+
"charAt",
|
|
1107
|
+
"normalize",
|
|
1108
|
+
"toLocaleUpperCase",
|
|
1109
|
+
"toLocaleLowerCase",
|
|
1110
|
+
"toFixed",
|
|
1111
|
+
"toPrecision",
|
|
1112
|
+
"toLocaleString"
|
|
1027
1113
|
]
|
|
1028
1114
|
},
|
|
1029
1115
|
"AssignmentOperator": {
|
|
@@ -1206,7 +1292,14 @@
|
|
|
1206
1292
|
"$ref": "#/$defs/ReduceMethod"
|
|
1207
1293
|
},
|
|
1208
1294
|
"target": {
|
|
1209
|
-
"
|
|
1295
|
+
"anyOf": [
|
|
1296
|
+
{
|
|
1297
|
+
"$ref": "#/$defs/ExpressionPointer"
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
"$ref": "#/$defs/ExpressionNode"
|
|
1301
|
+
}
|
|
1302
|
+
]
|
|
1210
1303
|
},
|
|
1211
1304
|
"value": {
|
|
1212
1305
|
"$ref": "#/$defs/ExpressionNode"
|
|
@@ -1217,7 +1310,7 @@
|
|
|
1217
1310
|
"value",
|
|
1218
1311
|
"initial"
|
|
1219
1312
|
],
|
|
1220
|
-
"title": "reduce — pure fold
|
|
1313
|
+
"title": "reduce — pure fold over a pointer or derived array; seed in initial"
|
|
1221
1314
|
},
|
|
1222
1315
|
{
|
|
1223
1316
|
"not": {
|
|
@@ -1230,7 +1323,14 @@
|
|
|
1230
1323
|
"$ref": "#/$defs/MapFilterMethod"
|
|
1231
1324
|
},
|
|
1232
1325
|
"target": {
|
|
1233
|
-
"
|
|
1326
|
+
"anyOf": [
|
|
1327
|
+
{
|
|
1328
|
+
"$ref": "#/$defs/ExpressionPointer"
|
|
1329
|
+
},
|
|
1330
|
+
{
|
|
1331
|
+
"$ref": "#/$defs/ExpressionNode"
|
|
1332
|
+
}
|
|
1333
|
+
]
|
|
1234
1334
|
},
|
|
1235
1335
|
"value": {
|
|
1236
1336
|
"$ref": "#/$defs/ExpressionNode"
|
|
@@ -1240,10 +1340,114 @@
|
|
|
1240
1340
|
"operator",
|
|
1241
1341
|
"value"
|
|
1242
1342
|
],
|
|
1243
|
-
"title": "map / filter — pure; per-item expression in value
|
|
1343
|
+
"title": "map / filter — pure over a pointer or derived array; per-item expression in value"
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
"description": "The ECMAScript conditional (ternary) operator, pure: target is the test, value the consequent, initial the alternate (the reduce precedent for repurposing initial). Chain else-if by nesting another ?: node in initial.",
|
|
1347
|
+
"properties": {
|
|
1348
|
+
"operator": {
|
|
1349
|
+
"$ref": "#/$defs/ConditionalOperator"
|
|
1350
|
+
}
|
|
1351
|
+
},
|
|
1352
|
+
"required": [
|
|
1353
|
+
"operator",
|
|
1354
|
+
"value",
|
|
1355
|
+
"initial"
|
|
1356
|
+
],
|
|
1357
|
+
"title": "?: — pure conditional; test in target, consequent in value, alternate in initial"
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
"description": "Value-keyed multiway selection, pure: target is the discriminant (matched against case keys by its string form, like element-level $switch), cases maps matched values to result operands, default is the operand when no case matches (result is undefined without it). Condition-chain branching composes from nested ?: nodes instead.",
|
|
1361
|
+
"not": {
|
|
1362
|
+
"anyOf": [
|
|
1363
|
+
{
|
|
1364
|
+
"required": [
|
|
1365
|
+
"value"
|
|
1366
|
+
]
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
"required": [
|
|
1370
|
+
"initial"
|
|
1371
|
+
]
|
|
1372
|
+
}
|
|
1373
|
+
]
|
|
1374
|
+
},
|
|
1375
|
+
"properties": {
|
|
1376
|
+
"cases": {
|
|
1377
|
+
"additionalProperties": {
|
|
1378
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1379
|
+
},
|
|
1380
|
+
"type": "object"
|
|
1381
|
+
},
|
|
1382
|
+
"default": {
|
|
1383
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1384
|
+
},
|
|
1385
|
+
"operator": {
|
|
1386
|
+
"$ref": "#/$defs/SwitchOperator"
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
"required": [
|
|
1390
|
+
"operator",
|
|
1391
|
+
"cases"
|
|
1392
|
+
],
|
|
1393
|
+
"title": "switch — pure value-keyed selection; discriminant in target, results in cases/default"
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
"description": "A pure standard-library method call: target is the receiver (any operand — never mutated; change-by-copy names replace the mutating originals), value the optional argument (bare scalar) or argument list (array). A missing receiver or method yields undefined, matching null-safe path reads.",
|
|
1397
|
+
"not": {
|
|
1398
|
+
"required": [
|
|
1399
|
+
"initial"
|
|
1400
|
+
]
|
|
1401
|
+
},
|
|
1402
|
+
"properties": {
|
|
1403
|
+
"operator": {
|
|
1404
|
+
"$ref": "#/$defs/PureMethod"
|
|
1405
|
+
}
|
|
1406
|
+
},
|
|
1407
|
+
"required": [
|
|
1408
|
+
"operator"
|
|
1409
|
+
],
|
|
1410
|
+
"title": "Pure method — genuine prototype methods; receiver in target, args in value"
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
"description": "Invoke a callable, pure in formula position: target is the callee pointer — a named formula entry (#/state/…) or a blessed pure global via window#/ (Math.*, JSON.*, Object.keys/values/entries, and the Intl helpers Intl/formatNumber, Intl/formatDate, Intl/formatRelativeTime) — and value is the positional argument list (the splice args-in-value precedent). Argument order follows the callee's declared parameters.",
|
|
1414
|
+
"not": {
|
|
1415
|
+
"required": [
|
|
1416
|
+
"initial"
|
|
1417
|
+
]
|
|
1418
|
+
},
|
|
1419
|
+
"properties": {
|
|
1420
|
+
"operator": {
|
|
1421
|
+
"$ref": "#/$defs/CallOperator"
|
|
1422
|
+
},
|
|
1423
|
+
"target": {
|
|
1424
|
+
"$ref": "#/$defs/ExpressionPointer"
|
|
1425
|
+
},
|
|
1426
|
+
"value": {
|
|
1427
|
+
"items": {
|
|
1428
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1429
|
+
},
|
|
1430
|
+
"type": "array"
|
|
1431
|
+
}
|
|
1432
|
+
},
|
|
1433
|
+
"required": [
|
|
1434
|
+
"operator"
|
|
1435
|
+
],
|
|
1436
|
+
"title": "call — invoke a named formula or blessed global; callee in target, args in value"
|
|
1244
1437
|
}
|
|
1245
1438
|
],
|
|
1246
1439
|
"properties": {
|
|
1440
|
+
"cases": {
|
|
1441
|
+
"additionalProperties": {
|
|
1442
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1443
|
+
},
|
|
1444
|
+
"description": "switch only: matched discriminant value (string form) → result operand.",
|
|
1445
|
+
"type": "object"
|
|
1446
|
+
},
|
|
1447
|
+
"default": {
|
|
1448
|
+
"$ref": "#/$defs/ExpressionOperand",
|
|
1449
|
+
"description": "switch only: result operand when no case key matches."
|
|
1450
|
+
},
|
|
1247
1451
|
"initial": {
|
|
1248
1452
|
"$ref": "#/$defs/ExpressionOperand"
|
|
1249
1453
|
},
|
|
@@ -1265,7 +1469,7 @@
|
|
|
1265
1469
|
},
|
|
1266
1470
|
"ExpressionEntry": {
|
|
1267
1471
|
"additionalProperties": false,
|
|
1268
|
-
"description": "A declarative expression entry (Shape 5). Used as a state entry or inline event handler.",
|
|
1472
|
+
"description": "A declarative expression entry (Shape 5). Used as a state entry or inline event handler. With parameters it is a named formula: a pure, reusable computation invoked via the call operator, its parameters resolved through $args/<name> refs in the body.",
|
|
1269
1473
|
"properties": {
|
|
1270
1474
|
"$description": {
|
|
1271
1475
|
"type": "string"
|
|
@@ -1275,6 +1479,20 @@
|
|
|
1275
1479
|
},
|
|
1276
1480
|
"$title": {
|
|
1277
1481
|
"type": "string"
|
|
1482
|
+
},
|
|
1483
|
+
"parameters": {
|
|
1484
|
+
"description": "Named-formula parameters (CEM convention, as on Function entries): bare names or CEM parameter objects. Present ⇒ the entry is callable, not a computed value.",
|
|
1485
|
+
"items": {
|
|
1486
|
+
"anyOf": [
|
|
1487
|
+
{
|
|
1488
|
+
"type": "string"
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
"$ref": "#/$defs/CemParameter"
|
|
1492
|
+
}
|
|
1493
|
+
]
|
|
1494
|
+
},
|
|
1495
|
+
"type": "array"
|
|
1278
1496
|
}
|
|
1279
1497
|
},
|
|
1280
1498
|
"required": [
|
|
@@ -1282,6 +1500,99 @@
|
|
|
1282
1500
|
],
|
|
1283
1501
|
"type": "object"
|
|
1284
1502
|
},
|
|
1503
|
+
"Statement": {
|
|
1504
|
+
"description": "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), or a dispatchEvent statement (WHATWG DOM: dispatches a CustomEvent from the handler's current target, with CustomEventInit members detail/bubbles/composed).",
|
|
1505
|
+
"oneOf": [
|
|
1506
|
+
{
|
|
1507
|
+
"$ref": "#/$defs/ExpressionNode"
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
"additionalProperties": false,
|
|
1511
|
+
"properties": {
|
|
1512
|
+
"else": {
|
|
1513
|
+
"items": {
|
|
1514
|
+
"$ref": "#/$defs/Statement"
|
|
1515
|
+
},
|
|
1516
|
+
"type": "array"
|
|
1517
|
+
},
|
|
1518
|
+
"if": {
|
|
1519
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1520
|
+
},
|
|
1521
|
+
"then": {
|
|
1522
|
+
"items": {
|
|
1523
|
+
"$ref": "#/$defs/Statement"
|
|
1524
|
+
},
|
|
1525
|
+
"type": "array"
|
|
1526
|
+
}
|
|
1527
|
+
},
|
|
1528
|
+
"required": [
|
|
1529
|
+
"if",
|
|
1530
|
+
"then"
|
|
1531
|
+
],
|
|
1532
|
+
"title": "if / then / else — conditional branch (JSON Schema keyword triple)",
|
|
1533
|
+
"type": "object"
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
"additionalProperties": false,
|
|
1537
|
+
"properties": {
|
|
1538
|
+
"$switch": {
|
|
1539
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1540
|
+
},
|
|
1541
|
+
"cases": {
|
|
1542
|
+
"additionalProperties": {
|
|
1543
|
+
"items": {
|
|
1544
|
+
"$ref": "#/$defs/Statement"
|
|
1545
|
+
},
|
|
1546
|
+
"type": "array"
|
|
1547
|
+
},
|
|
1548
|
+
"type": "object"
|
|
1549
|
+
},
|
|
1550
|
+
"default": {
|
|
1551
|
+
"items": {
|
|
1552
|
+
"$ref": "#/$defs/Statement"
|
|
1553
|
+
},
|
|
1554
|
+
"type": "array"
|
|
1555
|
+
}
|
|
1556
|
+
},
|
|
1557
|
+
"required": [
|
|
1558
|
+
"$switch",
|
|
1559
|
+
"cases"
|
|
1560
|
+
],
|
|
1561
|
+
"title": "$switch / cases — multiway branch (element-level convention, ECMA switch semantics)",
|
|
1562
|
+
"type": "object"
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
"additionalProperties": false,
|
|
1566
|
+
"properties": {
|
|
1567
|
+
"bubbles": {
|
|
1568
|
+
"type": "boolean"
|
|
1569
|
+
},
|
|
1570
|
+
"composed": {
|
|
1571
|
+
"type": "boolean"
|
|
1572
|
+
},
|
|
1573
|
+
"detail": {
|
|
1574
|
+
"$ref": "#/$defs/ExpressionOperand"
|
|
1575
|
+
},
|
|
1576
|
+
"dispatchEvent": {
|
|
1577
|
+
"description": "The CustomEvent type to dispatch (WHATWG DOM dispatchEvent).",
|
|
1578
|
+
"type": "string"
|
|
1579
|
+
}
|
|
1580
|
+
},
|
|
1581
|
+
"required": [
|
|
1582
|
+
"dispatchEvent"
|
|
1583
|
+
],
|
|
1584
|
+
"title": "dispatchEvent — emit a CustomEvent (WHATWG naming, CustomEventInit members)",
|
|
1585
|
+
"type": "object"
|
|
1586
|
+
}
|
|
1587
|
+
]
|
|
1588
|
+
},
|
|
1589
|
+
"StatementList": {
|
|
1590
|
+
"description": "A structured function body: statements executed sequentially (one yielding a promise is awaited before the next, per ECMA async/await semantics).",
|
|
1591
|
+
"items": {
|
|
1592
|
+
"$ref": "#/$defs/Statement"
|
|
1593
|
+
},
|
|
1594
|
+
"type": "array"
|
|
1595
|
+
},
|
|
1285
1596
|
"ElementDef": {
|
|
1286
1597
|
"additionalProperties": {
|
|
1287
1598
|
"$ref": "#/$defs/ElementPropertyValue"
|
|
@@ -21723,7 +22034,7 @@
|
|
|
21723
22034
|
"additionalProperties": {
|
|
21724
22035
|
"type": "string"
|
|
21725
22036
|
},
|
|
21726
|
-
"description": "Named media breakpoints following CSS @custom-media convention. Keys use the CSS custom property -- prefix.",
|
|
22037
|
+
"description": "Named media breakpoints following CSS @custom-media convention. Keys use the CSS custom property -- prefix. Pure color-scheme queries (e.g. \"--dark\": \"(prefers-color-scheme: dark)\") are dual-emitted so a data-color-scheme attribute on the root element forces the scheme regardless of the OS preference (spec §9.5).",
|
|
21727
22038
|
"examples": [
|
|
21728
22039
|
{
|
|
21729
22040
|
"--dark": "(prefers-color-scheme: dark)",
|
|
@@ -41,10 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"service": {
|
|
43
43
|
"description": "How images are optimized: \"build\" runs Sharp at build time; \"cloudflare\" emits /cdn-cgi/image transform URLs served by Cloudflare Image Transformations (requires the feature to be enabled on the serving zone).",
|
|
44
|
-
"enum": [
|
|
45
|
-
"build",
|
|
46
|
-
"cloudflare"
|
|
47
|
-
],
|
|
44
|
+
"enum": ["build", "cloudflare"],
|
|
48
45
|
"type": "string"
|
|
49
46
|
},
|
|
50
47
|
"sizes": {
|
|
@@ -88,20 +85,11 @@
|
|
|
88
85
|
"type": "array"
|
|
89
86
|
},
|
|
90
87
|
"type": {
|
|
91
|
-
"enum": [
|
|
92
|
-
"string",
|
|
93
|
-
"number",
|
|
94
|
-
"integer",
|
|
95
|
-
"boolean",
|
|
96
|
-
"array",
|
|
97
|
-
"object"
|
|
98
|
-
],
|
|
88
|
+
"enum": ["string", "number", "integer", "boolean", "array", "object"],
|
|
99
89
|
"type": "string"
|
|
100
90
|
}
|
|
101
91
|
},
|
|
102
|
-
"required": [
|
|
103
|
-
"type"
|
|
104
|
-
],
|
|
92
|
+
"required": ["type"],
|
|
105
93
|
"type": "object"
|
|
106
94
|
},
|
|
107
95
|
"RelationshipRef": {
|
|
@@ -115,9 +103,7 @@
|
|
|
115
103
|
"type": "string"
|
|
116
104
|
}
|
|
117
105
|
},
|
|
118
|
-
"required": [
|
|
119
|
-
"$ref"
|
|
120
|
-
],
|
|
106
|
+
"required": ["$ref"],
|
|
121
107
|
"type": "object"
|
|
122
108
|
}
|
|
123
109
|
},
|
|
@@ -140,9 +126,7 @@
|
|
|
140
126
|
"type": "string"
|
|
141
127
|
}
|
|
142
128
|
},
|
|
143
|
-
"required": [
|
|
144
|
-
"$ref"
|
|
145
|
-
],
|
|
129
|
+
"required": ["$ref"],
|
|
146
130
|
"type": "object"
|
|
147
131
|
},
|
|
148
132
|
{
|
|
@@ -192,9 +176,10 @@
|
|
|
192
176
|
"additionalProperties": {
|
|
193
177
|
"type": "string"
|
|
194
178
|
},
|
|
195
|
-
"description": "Named media breakpoints following CSS @custom-media convention. Available in all component style objects.",
|
|
179
|
+
"description": "Named media breakpoints following CSS @custom-media convention. Available in all component style objects. Declaring a pure color-scheme query (e.g. \"--dark\": \"(prefers-color-scheme: dark)\") additionally opts the site into the forced-scheme contract: @--dark style blocks are dual-emitted so a data-color-scheme attribute on <html> overrides the OS preference, color-scheme is declared on :root, and a pre-paint script restores the visitor's persisted choice (spec §9.5).",
|
|
196
180
|
"examples": [
|
|
197
181
|
{
|
|
182
|
+
"--dark": "(prefers-color-scheme: dark)",
|
|
198
183
|
"--lg": "(min-width: 1024px)",
|
|
199
184
|
"--md": "(min-width: 768px)",
|
|
200
185
|
"--sm": "(min-width: 640px)"
|
|
@@ -211,13 +196,7 @@
|
|
|
211
196
|
"properties": {
|
|
212
197
|
"adapter": {
|
|
213
198
|
"description": "Platform adapter for deployment-specific output.",
|
|
214
|
-
"enum": [
|
|
215
|
-
"static",
|
|
216
|
-
"cloudflare-pages",
|
|
217
|
-
"cloudflare-workers",
|
|
218
|
-
"node",
|
|
219
|
-
"bun"
|
|
220
|
-
],
|
|
199
|
+
"enum": ["static", "cloudflare-pages", "cloudflare-workers", "node", "bun"],
|
|
221
200
|
"type": "string"
|
|
222
201
|
},
|
|
223
202
|
"deploy": {
|
|
@@ -239,26 +218,17 @@
|
|
|
239
218
|
},
|
|
240
219
|
"provider": {
|
|
241
220
|
"description": "Hosting provider the project is connected to.",
|
|
242
|
-
"enum": [
|
|
243
|
-
"cloudflare-pages"
|
|
244
|
-
],
|
|
221
|
+
"enum": ["cloudflare-pages"],
|
|
245
222
|
"type": "string"
|
|
246
223
|
}
|
|
247
224
|
},
|
|
248
|
-
"required": [
|
|
249
|
-
"provider",
|
|
250
|
-
"accountId",
|
|
251
|
-
"projectName"
|
|
252
|
-
],
|
|
225
|
+
"required": ["provider", "accountId", "projectName"],
|
|
253
226
|
"type": "object"
|
|
254
227
|
},
|
|
255
228
|
"format": {
|
|
256
229
|
"default": "directory",
|
|
257
|
-
"description": "
|
|
258
|
-
"enum": [
|
|
259
|
-
"directory",
|
|
260
|
-
"single"
|
|
261
|
-
],
|
|
230
|
+
"description": "Reserved; currently unused. Accepted for forward compatibility with single-file output (desktop single-file mode) — the build emits per-route directories regardless.",
|
|
231
|
+
"enum": ["directory", "single"],
|
|
262
232
|
"type": "string"
|
|
263
233
|
},
|
|
264
234
|
"outDir": {
|
|
@@ -274,11 +244,7 @@
|
|
|
274
244
|
"trailingSlash": {
|
|
275
245
|
"default": "always",
|
|
276
246
|
"description": "Trailing slash behavior for generated URLs.",
|
|
277
|
-
"enum": [
|
|
278
|
-
"always",
|
|
279
|
-
"never",
|
|
280
|
-
"ignore"
|
|
281
|
-
],
|
|
247
|
+
"enum": ["always", "never", "ignore"],
|
|
282
248
|
"type": "string"
|
|
283
249
|
}
|
|
284
250
|
},
|
|
@@ -307,9 +273,7 @@
|
|
|
307
273
|
"layout": {
|
|
308
274
|
"default": null,
|
|
309
275
|
"description": "Default layout file path applied to all pages. Set to null to render pages without a layout.",
|
|
310
|
-
"examples": [
|
|
311
|
-
"./layouts/base.json"
|
|
312
|
-
],
|
|
276
|
+
"examples": ["./layouts/base.json"],
|
|
313
277
|
"oneOf": [
|
|
314
278
|
{
|
|
315
279
|
"type": "string"
|
|
@@ -324,11 +288,7 @@
|
|
|
324
288
|
},
|
|
325
289
|
"extensions": {
|
|
326
290
|
"description": "Extension packages: bare package names (resolved project-first through the package exports map) or relative paths. Each must export jx-extension.json.",
|
|
327
|
-
"examples": [
|
|
328
|
-
[
|
|
329
|
-
"@jxsuite/parser"
|
|
330
|
-
]
|
|
331
|
-
],
|
|
291
|
+
"examples": [["@jxsuite/parser"]],
|
|
332
292
|
"items": {
|
|
333
293
|
"type": "string"
|
|
334
294
|
},
|
|
@@ -339,20 +299,12 @@
|
|
|
339
299
|
"properties": {
|
|
340
300
|
"defaultLocale": {
|
|
341
301
|
"description": "Default locale code.",
|
|
342
|
-
"examples": [
|
|
343
|
-
"en"
|
|
344
|
-
],
|
|
302
|
+
"examples": ["en"],
|
|
345
303
|
"type": "string"
|
|
346
304
|
},
|
|
347
305
|
"locales": {
|
|
348
306
|
"description": "Available locale codes.",
|
|
349
|
-
"examples": [
|
|
350
|
-
[
|
|
351
|
-
"en",
|
|
352
|
-
"fr",
|
|
353
|
-
"de"
|
|
354
|
-
]
|
|
355
|
-
],
|
|
307
|
+
"examples": [["en", "fr", "de"]],
|
|
356
308
|
"items": {
|
|
357
309
|
"type": "string"
|
|
358
310
|
},
|
|
@@ -360,10 +312,7 @@
|
|
|
360
312
|
},
|
|
361
313
|
"routing": {
|
|
362
314
|
"description": "Locale routing strategy.",
|
|
363
|
-
"enum": [
|
|
364
|
-
"prefix-except-default",
|
|
365
|
-
"prefix-always"
|
|
366
|
-
],
|
|
315
|
+
"enum": ["prefix-except-default", "prefix-always"],
|
|
367
316
|
"type": "string"
|
|
368
317
|
}
|
|
369
318
|
},
|
|
@@ -388,10 +337,7 @@
|
|
|
388
337
|
"name": {
|
|
389
338
|
"default": "Jx Site",
|
|
390
339
|
"description": "Human-readable project name.",
|
|
391
|
-
"examples": [
|
|
392
|
-
"My Portfolio",
|
|
393
|
-
"Jx Example Site"
|
|
394
|
-
],
|
|
340
|
+
"examples": ["My Portfolio", "Jx Example Site"],
|
|
395
341
|
"type": "string"
|
|
396
342
|
},
|
|
397
343
|
"redirects": {
|
|
@@ -429,13 +375,10 @@
|
|
|
429
375
|
},
|
|
430
376
|
"url": {
|
|
431
377
|
"description": "Production URL of the deployed site.",
|
|
432
|
-
"examples": [
|
|
433
|
-
"https://example.com",
|
|
434
|
-
"https://jxsuite.com"
|
|
435
|
-
],
|
|
378
|
+
"examples": ["https://example.com", "https://jxsuite.com"],
|
|
436
379
|
"type": "string"
|
|
437
380
|
}
|
|
438
381
|
},
|
|
439
382
|
"title": "Jx Project Core",
|
|
440
383
|
"type": "object"
|
|
441
|
-
}
|
|
384
|
+
}
|
|
@@ -11,4 +11,4 @@
|
|
|
11
11
|
],
|
|
12
12
|
"description": "Default field-schema union for section entry schemas: the core field shape plus relationship references. Per-project entry documents override this resource with the effective union. See specs/extensions.md §5.3.",
|
|
13
13
|
"title": "Jx Project Field Union"
|
|
14
|
-
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic mapping from Function-def `$src` module specifiers to bundled asset URLs. Shared
|
|
3
|
+
* between the compiler's sidecar bundler (which writes the bundle) and extension `lower()`
|
|
4
|
+
* implementations (which emit the URL into client code) so neither needs to depend on the other.
|
|
5
|
+
*
|
|
6
|
+
* The mapping is intentionally hash-free: the same specifier always yields the same URL, letting
|
|
7
|
+
* lowered defs reference bundles the compiler produces later in the build. Distinct specifiers that
|
|
8
|
+
* collide on a slug are rejected by the bundler at build time.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Prefix for npm package specifiers in `$src` (spec §12): `npm:<pkg>[/subpath]`. */
|
|
12
|
+
export const NPM_SPECIFIER_PREFIX = "npm:";
|
|
13
|
+
|
|
14
|
+
/** URL directory (under the site root) where bundled sidecars are written. */
|
|
15
|
+
export const SIDECAR_ASSET_DIR = "/assets/";
|
|
16
|
+
|
|
17
|
+
/** True when a `$src` specifier names an npm package rather than a project file. */
|
|
18
|
+
export function isNpmSpecifier(specifier: string): boolean {
|
|
19
|
+
return specifier.startsWith(NPM_SPECIFIER_PREFIX);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Map a Function-def `$src` specifier to its bundled asset URL.
|
|
24
|
+
*
|
|
25
|
+
* `npm:@jxsuite/search/client` → `/assets/jxsuite-search-client.js` `./lib/search-helpers.ts` →
|
|
26
|
+
* `/assets/lib-search-helpers.js`
|
|
27
|
+
*/
|
|
28
|
+
export function sidecarAssetPath(specifier: string): string {
|
|
29
|
+
let base = specifier;
|
|
30
|
+
if (isNpmSpecifier(base)) {
|
|
31
|
+
base = base.slice(NPM_SPECIFIER_PREFIX.length);
|
|
32
|
+
}
|
|
33
|
+
base = base
|
|
34
|
+
.replace(/^\.\//, "")
|
|
35
|
+
.replace(/\.(js|ts|mjs|mts)$/, "")
|
|
36
|
+
.replaceAll("@", "")
|
|
37
|
+
.replaceAll(/[/\\]+/g, "-")
|
|
38
|
+
.replaceAll(/[^\w.-]/g, "-")
|
|
39
|
+
.replaceAll(/-+/g, "-")
|
|
40
|
+
.replaceAll(/^-|-$/g, "");
|
|
41
|
+
return `${SIDECAR_ASSET_DIR}${base}.js`;
|
|
42
|
+
}
|
|
@@ -151,6 +151,11 @@ export class ExtensionRegistry {
|
|
|
151
151
|
return this.#classes.find((e) => e.capabilities.resolvePaths?.discriminator === key);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/** Classes declaring an `emit` capability (build-time asset emission), in declaration order. */
|
|
155
|
+
emitters(): FormatEntry[] {
|
|
156
|
+
return this.#classes.filter((e) => e.capabilities.emit !== undefined);
|
|
157
|
+
}
|
|
158
|
+
|
|
154
159
|
/** Server-mount classes, sorted by `server.order` (ascending; default 100), then name. */
|
|
155
160
|
serverMounts(): FormatEntry[] {
|
|
156
161
|
return this.#classes
|
package/src/format-registry.ts
CHANGED
|
@@ -21,14 +21,16 @@ export const FORMAT_CAPABILITIES: readonly FormatCapability[] = [
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* All well-known static capability roles across admission blocks (specs/extensions.md §8): format
|
|
24
|
-
* roles plus project-section (`projectData`, `resolvePaths`), compile-away (`lower`),
|
|
25
|
-
* (`mount`), and connector (`dialect`, `deploySchema`,
|
|
24
|
+
* roles plus project-section (`projectData`, `resolvePaths`), compile-away (`lower`), build-time
|
|
25
|
+
* asset emission (`emit`), server-mount (`mount`), and connector (`dialect`, `deploySchema`,
|
|
26
|
+
* `bindings`, `testConnection`) roles.
|
|
26
27
|
*/
|
|
27
28
|
export type ExtensionCapability =
|
|
28
29
|
| FormatCapability
|
|
29
30
|
| "projectData"
|
|
30
31
|
| "resolvePaths"
|
|
31
32
|
| "lower"
|
|
33
|
+
| "emit"
|
|
32
34
|
| "mount"
|
|
33
35
|
| "dialect"
|
|
34
36
|
| "deploySchema"
|
|
@@ -40,6 +42,7 @@ export const EXTENSION_CAPABILITIES: readonly ExtensionCapability[] = [
|
|
|
40
42
|
"projectData",
|
|
41
43
|
"resolvePaths",
|
|
42
44
|
"lower",
|
|
45
|
+
"emit",
|
|
43
46
|
"mount",
|
|
44
47
|
"dialect",
|
|
45
48
|
"deploySchema",
|
package/src/guards.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
JxPrototypeDef,
|
|
20
20
|
JxRef,
|
|
21
21
|
JxServerFnDef,
|
|
22
|
+
JxStatement,
|
|
22
23
|
JxStateObject,
|
|
23
24
|
JxStyle,
|
|
24
25
|
} from "../types";
|
|
@@ -49,6 +50,26 @@ export function isExpressionDef(value: unknown): value is JxExpressionDef {
|
|
|
49
50
|
return isJsonObject(value) && isJsonObject(value.$expression);
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Shape 5 with `parameters`: a named formula — a pure, reusable computation invoked via the `call`
|
|
55
|
+
* operator rather than lowered to a computed value.
|
|
56
|
+
*/
|
|
57
|
+
export function isNamedFormulaDef(
|
|
58
|
+
value: unknown,
|
|
59
|
+
): value is JxExpressionDef & { parameters: unknown[] } {
|
|
60
|
+
return isExpressionDef(value) && Array.isArray(value.parameters) && value.parameters.length > 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Shape 4 with a structured body: a Function entry whose `body` is a statement array (spec §20)
|
|
65
|
+
* rather than opaque JS source.
|
|
66
|
+
*/
|
|
67
|
+
export function hasStructuredBody(
|
|
68
|
+
value: unknown,
|
|
69
|
+
): value is JxFunctionDef & { body: JxStatement[] } {
|
|
70
|
+
return isFunctionDef(value) && Array.isArray(value.body);
|
|
71
|
+
}
|
|
72
|
+
|
|
52
73
|
/** A non-Function `$prototype` instance (Request, Storage, ContentCollection, classes, …). */
|
|
53
74
|
export function isPrototypeDef(value: unknown): value is JxPrototypeDef {
|
|
54
75
|
return (
|
package/src/schema.ts
CHANGED
|
@@ -58,11 +58,14 @@ import {
|
|
|
58
58
|
} from "../defs/element-def.schema";
|
|
59
59
|
import { typedStateDefSchema } from "../defs/typed-state-def.schema";
|
|
60
60
|
import { functionDefSchema } from "../defs/function-def.schema";
|
|
61
|
+
import { statementListSchema, statementSchema } from "../defs/statement.schema";
|
|
61
62
|
import { externalClassDefSchema } from "../defs/external-class-def.schema";
|
|
62
63
|
import { pureTypeDefSchema } from "../defs/pure-type-def.schema";
|
|
63
64
|
import {
|
|
64
65
|
assignmentOperatorSchema,
|
|
65
66
|
binaryOperatorSchema,
|
|
67
|
+
callOperatorSchema,
|
|
68
|
+
conditionalOperatorSchema,
|
|
66
69
|
expressionEntrySchema,
|
|
67
70
|
expressionLiteralSchema,
|
|
68
71
|
expressionNodeSchema,
|
|
@@ -71,8 +74,10 @@ import {
|
|
|
71
74
|
mapFilterMethodSchema,
|
|
72
75
|
noArgMethodSchema,
|
|
73
76
|
oneArgMethodSchema,
|
|
77
|
+
pureMethodSchema,
|
|
74
78
|
reduceMethodSchema,
|
|
75
79
|
spliceMethodSchema,
|
|
80
|
+
switchOperatorSchema,
|
|
76
81
|
unaryOperatorSchema,
|
|
77
82
|
} from "../defs/expression-node.schema";
|
|
78
83
|
import {
|
|
@@ -218,6 +223,10 @@ export async function generateSchema() {
|
|
|
218
223
|
ExpressionOperand: expressionOperandSchema,
|
|
219
224
|
UnaryOperator: unaryOperatorSchema,
|
|
220
225
|
BinaryOperator: binaryOperatorSchema,
|
|
226
|
+
ConditionalOperator: conditionalOperatorSchema,
|
|
227
|
+
SwitchOperator: switchOperatorSchema,
|
|
228
|
+
CallOperator: callOperatorSchema,
|
|
229
|
+
PureMethod: pureMethodSchema,
|
|
221
230
|
AssignmentOperator: assignmentOperatorSchema,
|
|
222
231
|
NoArgMethod: noArgMethodSchema,
|
|
223
232
|
OneArgMethod: oneArgMethodSchema,
|
|
@@ -226,6 +235,8 @@ export async function generateSchema() {
|
|
|
226
235
|
MapFilterMethod: mapFilterMethodSchema,
|
|
227
236
|
ExpressionNode: expressionNodeSchema,
|
|
228
237
|
ExpressionEntry: expressionEntrySchema,
|
|
238
|
+
Statement: statementSchema,
|
|
239
|
+
StatementList: statementListSchema,
|
|
229
240
|
|
|
230
241
|
// Element defs — with webref data injected
|
|
231
242
|
ElementDef: {
|
|
@@ -327,7 +338,10 @@ export async function generateSchema() {
|
|
|
327
338
|
additionalProperties: { type: "string" },
|
|
328
339
|
description:
|
|
329
340
|
"Named media breakpoints following CSS @custom-media convention. " +
|
|
330
|
-
"Keys use the CSS custom property -- prefix."
|
|
341
|
+
"Keys use the CSS custom property -- prefix. Pure color-scheme queries " +
|
|
342
|
+
'(e.g. "--dark": "(prefers-color-scheme: dark)") are dual-emitted so a ' +
|
|
343
|
+
"data-color-scheme attribute on the root element forces the scheme " +
|
|
344
|
+
"regardless of the OS preference (spec §9.5).",
|
|
331
345
|
examples: [
|
|
332
346
|
{
|
|
333
347
|
"--dark": "(prefers-color-scheme: dark)",
|
|
@@ -663,6 +677,30 @@ async function runSchemaCli() {
|
|
|
663
677
|
writeFileSync(resolve(schemaDir, "schemas", "project.fields.schema.json"), fieldsStr, "utf8");
|
|
664
678
|
writeFileSync(resolve(schemaDir, "schemas", "document.paths.schema.json"), pathsStr, "utf8");
|
|
665
679
|
writeFileSync(resolve(schemaDir, "extension-manifest.schema.json"), manifestStr, "utf8");
|
|
680
|
+
// The schemas/ fragments are oxfmt-managed (unlike packages/schema/*.json, which .oxfmtrc
|
|
681
|
+
// Ignores), so emit them formatted — otherwise every `bun run generate:schema` reintroduces
|
|
682
|
+
// Raw-stringify formatting and dirties the tree. This is a dev-hygiene step only: the JSON
|
|
683
|
+
// Above is already written and valid, and oxfmt just prettifies it (e.g. collapsing short enum
|
|
684
|
+
// Arrays onto one line). Inside a sandboxed/offline build (e.g. `nix build`) oxfmt exits
|
|
685
|
+
// Non-zero with no diagnostic output, so treat a failure as non-fatal and keep the valid JSON
|
|
686
|
+
// Rather than aborting the build over cosmetic formatting.
|
|
687
|
+
const fmt = Bun.spawnSync(
|
|
688
|
+
[
|
|
689
|
+
"bunx",
|
|
690
|
+
"oxfmt",
|
|
691
|
+
resolve(schemaDir, "schemas", "project.core.schema.json"),
|
|
692
|
+
resolve(schemaDir, "schemas", "project.fields.schema.json"),
|
|
693
|
+
resolve(schemaDir, "schemas", "document.paths.schema.json"),
|
|
694
|
+
],
|
|
695
|
+
{ cwd: schemaDir },
|
|
696
|
+
);
|
|
697
|
+
if (fmt.exitCode !== 0) {
|
|
698
|
+
const detail =
|
|
699
|
+
fmt.stderr.toString() ||
|
|
700
|
+
fmt.stdout.toString() ||
|
|
701
|
+
`exit ${fmt.exitCode ?? "null"}${fmt.signalCode ? `, signal ${fmt.signalCode}` : ""}`;
|
|
702
|
+
console.error(`Warning: skipped oxfmt reformat of generated schemas (${detail})`);
|
|
703
|
+
}
|
|
666
704
|
console.error("Generated:");
|
|
667
705
|
console.error(" schema.json (component)");
|
|
668
706
|
console.error(" project-schema.json");
|
package/types.ts
CHANGED
|
@@ -88,18 +88,29 @@ export type JxExpressionOperand =
|
|
|
88
88
|
| number
|
|
89
89
|
| boolean
|
|
90
90
|
| null
|
|
91
|
-
| JxExpressionOperand[]
|
|
91
|
+
| JxExpressionOperand[]
|
|
92
|
+
// Plain-object literal (e.g. an Intl options bag); $ref/operator shapes are the members above.
|
|
93
|
+
| Record<string, JsonValue>;
|
|
92
94
|
|
|
93
95
|
export interface JxExpressionNode {
|
|
94
96
|
operator: string;
|
|
95
97
|
target: JxExpressionOperand;
|
|
96
98
|
value?: JxExpressionOperand;
|
|
97
99
|
initial?: JxExpressionOperand;
|
|
100
|
+
/** `switch` only: matched discriminant value (string form) → result operand. */
|
|
101
|
+
cases?: Record<string, JxExpressionOperand>;
|
|
102
|
+
/** `switch` only: result operand when no case key matches. */
|
|
103
|
+
default?: JxExpressionOperand;
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
/** A state entry (or event binding) whose value is computed from a declarative expression. */
|
|
101
107
|
export interface JxExpressionDef {
|
|
102
108
|
$expression: JxExpressionNode;
|
|
109
|
+
/**
|
|
110
|
+
* Named-formula parameters (CEM convention, as on Function entries). Present ⇒ the entry is a
|
|
111
|
+
* callable formula invoked via the `call` operator, with `$args/<name>` refs in its body.
|
|
112
|
+
*/
|
|
113
|
+
parameters?: (string | CemParameter)[];
|
|
103
114
|
[key: string]: unknown;
|
|
104
115
|
}
|
|
105
116
|
|
|
@@ -108,11 +119,50 @@ export interface JxExpressionDef {
|
|
|
108
119
|
// Detection algorithm in buildScope(). Use the guards in `@jxsuite/schema/guards`
|
|
109
120
|
// To discriminate.
|
|
110
121
|
|
|
122
|
+
// ─── Statement Model (spec §20) ─────────────────────────────────────────────────
|
|
123
|
+
// Structured function bodies: `body` as a statement array instead of opaque JS source,
|
|
124
|
+
// Mirroring ESTree's BlockStatement.body = Statement[].
|
|
125
|
+
|
|
126
|
+
/** An `{ if, then, else }` branch — the JSON Schema 2020-12 conditional keyword triple. */
|
|
127
|
+
export interface JxIfStatement {
|
|
128
|
+
if: JxExpressionOperand;
|
|
129
|
+
then: JxStatement[];
|
|
130
|
+
else?: JxStatement[];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** A `{ $switch, cases }` multiway branch in statement position (element-level convention). */
|
|
134
|
+
export interface JxSwitchStatement {
|
|
135
|
+
$switch: JxExpressionOperand;
|
|
136
|
+
cases: Record<string, JxStatement[]>;
|
|
137
|
+
default?: JxStatement[];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** A WHATWG `dispatchEvent` statement: emits a CustomEvent with CustomEventInit members. */
|
|
141
|
+
export interface JxDispatchStatement {
|
|
142
|
+
dispatchEvent: string;
|
|
143
|
+
detail?: JxExpressionOperand;
|
|
144
|
+
bubbles?: boolean;
|
|
145
|
+
composed?: boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* One statement of a structured function body: a bare expression node in statement position
|
|
150
|
+
* (mutation or `call`), a branch, a multiway branch, or an event dispatch.
|
|
151
|
+
*/
|
|
152
|
+
export type JxStatement =
|
|
153
|
+
| JxExpressionNode
|
|
154
|
+
| JxIfStatement
|
|
155
|
+
| JxSwitchStatement
|
|
156
|
+
| JxDispatchStatement;
|
|
157
|
+
|
|
111
158
|
/** A function declaration: inline `body` or external `$src`/`$export`. */
|
|
112
159
|
export interface JxFunctionDef {
|
|
113
160
|
$prototype: "Function";
|
|
114
|
-
/**
|
|
115
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Inline function body: opaque JS source (the reactive scope is the implicit first parameter) or
|
|
163
|
+
* a structured statement array (spec §20).
|
|
164
|
+
*/
|
|
165
|
+
body?: string | JxStatement[];
|
|
116
166
|
/** Parameters after the implicit scope parameter: bare names or CEM parameter objects. */
|
|
117
167
|
parameters?: (string | CemParameter)[];
|
|
118
168
|
/** Explicit function name; defaults to the state key. */
|