@flighthq/scene-document 0.5.1-next.658.9cb44d7 → 0.5.1-next.685.f72fc7f
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 +2 -2
- package/dist/contract.d.ts +1 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -0
- package/dist/contract.js.map +1 -1
- package/dist/flightDocumentResourceDependencies.d.ts +3 -0
- package/dist/flightDocumentResourceDependencies.d.ts.map +1 -0
- package/dist/flightDocumentResourceDependencies.js +12 -0
- package/dist/flightDocumentResourceDependencies.js.map +1 -0
- package/dist/flightDocumentText.d.ts.map +1 -1
- package/dist/flightDocumentText.js +370 -10
- package/dist/flightDocumentText.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/sceneDocumentInteractiveStateBindings.d.ts +11 -0
- package/dist/sceneDocumentInteractiveStateBindings.d.ts.map +1 -0
- package/dist/sceneDocumentInteractiveStateBindings.js +108 -0
- package/dist/sceneDocumentInteractiveStateBindings.js.map +1 -0
- package/dist/sceneDocumentLayoutBindings.d.ts +5 -0
- package/dist/sceneDocumentLayoutBindings.d.ts.map +1 -0
- package/dist/sceneDocumentLayoutBindings.js +207 -0
- package/dist/sceneDocumentLayoutBindings.js.map +1 -0
- package/dist/sceneDocumentRefusal.d.ts +4 -1
- package/dist/sceneDocumentRefusal.d.ts.map +1 -1
- package/dist/sceneDocumentRefusal.js +140 -0
- package/dist/sceneDocumentRefusal.js.map +1 -1
- package/dist/sceneDocumentScene2DMaterialization.d.ts +2 -2
- package/dist/sceneDocumentScene2DMaterialization.d.ts.map +1 -1
- package/dist/sceneDocumentScene2DMaterialization.js +73 -10
- package/dist/sceneDocumentScene2DMaterialization.js.map +1 -1
- package/dist/sceneDocumentScene3DMaterialization.d.ts +2 -2
- package/dist/sceneDocumentScene3DMaterialization.d.ts.map +1 -1
- package/dist/sceneDocumentScene3DMaterialization.js +71 -10
- package/dist/sceneDocumentScene3DMaterialization.js.map +1 -1
- package/package.json +10 -10
- package/src/flightDocumentResourceDependencies.test.ts +83 -0
- package/src/flightDocumentText.test.ts +271 -0
- package/src/sceneDocumentInteractiveStateBindings.test.ts +129 -0
- package/src/sceneDocumentLayoutBindings.test.ts +141 -0
- package/src/sceneDocumentMaterializationSelection.test.ts +4 -0
- package/src/sceneDocumentMultiSceneMaterialization.test.ts +6 -0
- package/src/sceneDocumentRefusal.test.ts +84 -0
- package/src/sceneDocumentScene2DMaterialization.test.ts +353 -1
- package/src/sceneDocumentScene3DMaterialization.test.ts +147 -4
package/README.md
CHANGED
|
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/scene-document`. The
|
|
|
13
13
|
This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
|
|
14
14
|
|
|
15
15
|
- [Flight project](https://github.com/flighthq/flight)
|
|
16
|
-
- [Source for @flighthq/scene-document@0.5.1-next.
|
|
17
|
-
- [License](https://github.com/flighthq/flight/blob/
|
|
16
|
+
- [Source for @flighthq/scene-document@0.5.1-next.685.f72fc7f](https://github.com/flighthq/flight/tree/f72fc7feaa9653d950f39c7d2fe6365f48e82e51/packages/scene-document)
|
|
17
|
+
- [License](https://github.com/flighthq/flight/blob/f72fc7feaa9653d950f39c7d2fe6365f48e82e51/LICENSE.md)
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { explainFlightDocumentText, formatFlightDocumentText, parseFlightDocumentText } from './flightDocumentText';
|
|
2
|
+
export { getFlightDocumentResourceDependencies } from './flightDocumentResourceDependencies';
|
|
2
3
|
export { createFlightDocumentFromScene2D, createFlightDocumentScene2DMaterialization, createFlightDocumentScene2DMaterializationFromText, explainFlightDocumentRefusal, explainFlightDocumentRefusalFromText, } from './sceneDocumentScene2DMaterialization';
|
|
3
4
|
export { createFlightDocumentFromScene3D, createFlightDocumentScene3DMaterialization, createFlightDocumentScene3DMaterializationFromText, explainFlightDocumentScene3DRefusal, explainFlightDocumentScene3DRefusalFromText, } from './sceneDocumentScene3DMaterialization';
|
|
4
5
|
//# sourceMappingURL=contract.d.ts.map
|
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,mCAAmC,EACnC,2CAA2C,GAC5C,MAAM,uCAAuC,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EAAE,qCAAqC,EAAE,MAAM,sCAAsC,CAAC;AAC7F,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,mCAAmC,EACnC,2CAA2C,GAC5C,MAAM,uCAAuC,CAAC"}
|
package/dist/contract.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { explainFlightDocumentText, formatFlightDocumentText, parseFlightDocumentText } from './flightDocumentText';
|
|
2
|
+
export { getFlightDocumentResourceDependencies } from './flightDocumentResourceDependencies';
|
|
2
3
|
export { createFlightDocumentFromScene2D, createFlightDocumentScene2DMaterialization, createFlightDocumentScene2DMaterializationFromText, explainFlightDocumentRefusal, explainFlightDocumentRefusalFromText, } from './sceneDocumentScene2DMaterialization';
|
|
3
4
|
export { createFlightDocumentFromScene3D, createFlightDocumentScene3DMaterialization, createFlightDocumentScene3DMaterializationFromText, explainFlightDocumentScene3DRefusal, explainFlightDocumentScene3DRefusalFromText, } from './sceneDocumentScene3DMaterialization';
|
|
4
5
|
//# sourceMappingURL=contract.js.map
|
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,mCAAmC,EACnC,2CAA2C,GAC5C,MAAM,uCAAuC,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EAAE,qCAAqC,EAAE,MAAM,sCAAsC,CAAC;AAC7F,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,+BAA+B,EAC/B,0CAA0C,EAC1C,kDAAkD,EAClD,mCAAmC,EACnC,2CAA2C,GAC5C,MAAM,uCAAuC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { FlightDocument, FlightDocumentResourceDescriptor, FlightDocumentSchemaRegistry } from '@flighthq/types/contract';
|
|
2
|
+
export declare function getFlightDocumentResourceDependencies(document: Readonly<FlightDocument>, schemas: Readonly<FlightDocumentSchemaRegistry>): readonly Readonly<FlightDocumentResourceDescriptor>[] | null;
|
|
3
|
+
//# sourceMappingURL=flightDocumentResourceDependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flightDocumentResourceDependencies.d.ts","sourceRoot":"","sources":["../src/flightDocumentResourceDependencies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,gCAAgC,EAChC,4BAA4B,EAC7B,MAAM,0BAA0B,CAAC;AAKlC,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,EAClC,OAAO,EAAE,QAAQ,CAAC,4BAA4B,CAAC,GAC9C,SAAS,QAAQ,CAAC,gCAAgC,CAAC,EAAE,GAAG,IAAI,CAK9D"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getRegistryTableEntry } from '@flighthq/registry/contract';
|
|
2
|
+
// The resource table is the document's direct dependency list. This query verifies that every declared
|
|
3
|
+
// kind has an authored schema, but deliberately does not interpret fields as graph edges or resolve any
|
|
4
|
+
// live resource: traversal and loading policy belong to their callers.
|
|
5
|
+
export function getFlightDocumentResourceDependencies(document, schemas) {
|
|
6
|
+
for (const descriptor of document.resources) {
|
|
7
|
+
if (getRegistryTableEntry(schemas.resourceSchemas, descriptor.kind) === null)
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return document.resources;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=flightDocumentResourceDependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flightDocumentResourceDependencies.js","sourceRoot":"","sources":["../src/flightDocumentResourceDependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAOpE,uGAAuG;AACvG,wGAAwG;AACxG,uEAAuE;AACvE,MAAM,UAAU,qCAAqC,CACnD,QAAkC,EAClC,OAA+C;IAE/C,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC5C,IAAI,qBAAqB,CAAC,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;IAC5F,CAAC;IACD,OAAO,QAAQ,CAAC,SAAS,CAAC;AAC5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flightDocumentText.d.ts","sourceRoot":"","sources":["../src/flightDocumentText.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,
|
|
1
|
+
{"version":3,"file":"flightDocumentText.d.ts","sourceRoot":"","sources":["../src/flightDocumentText.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EASd,gCAAgC,EAOhC,kBAAkB,EAOnB,MAAM,0BAA0B,CAAC;AAMlC,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,kBAAkB,GAAG,gCAAgC,GAAG,IAAI,CAE3G;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAsB/F;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG,cAAc,GAAG,IAAI,CAEvF"}
|
|
@@ -88,6 +88,7 @@ function appendNode(lines, node, indent) {
|
|
|
88
88
|
const prefix = ' '.repeat(indent);
|
|
89
89
|
lines.push(prefix + 'kind: ' + formatString(node.kind));
|
|
90
90
|
appendFields(lines, node.fields, indent, NODE_RESERVED_FIELDS);
|
|
91
|
+
appendNodeInteractiveMetadata(lines, node, indent);
|
|
91
92
|
if (node.children.length > 0) {
|
|
92
93
|
lines.push(prefix + 'children:');
|
|
93
94
|
for (const child of node.children)
|
|
@@ -98,12 +99,67 @@ function appendNodeSequenceItem(lines, node, indent) {
|
|
|
98
99
|
const prefix = ' '.repeat(indent);
|
|
99
100
|
lines.push(prefix + '- kind: ' + formatString(node.kind));
|
|
100
101
|
appendFields(lines, node.fields, indent + 2, NODE_RESERVED_FIELDS);
|
|
102
|
+
appendNodeInteractiveMetadata(lines, node, indent + 2);
|
|
101
103
|
if (node.children.length > 0) {
|
|
102
104
|
lines.push(prefix + ' children:');
|
|
103
105
|
for (const child of node.children)
|
|
104
106
|
appendNodeSequenceItem(lines, child, indent + 4);
|
|
105
107
|
}
|
|
106
108
|
}
|
|
109
|
+
function appendInteractiveState(lines, state, indent) {
|
|
110
|
+
const entries = getInteractiveStateEntries(state);
|
|
111
|
+
if (entries.length === 0 && state.extensions.length === 0) {
|
|
112
|
+
throw new TypeError('FlightDocument interactive state must not be empty');
|
|
113
|
+
}
|
|
114
|
+
for (const [property, value] of entries)
|
|
115
|
+
appendMappingEntry(lines, property, value, indent);
|
|
116
|
+
if (state.extensions.length === 0)
|
|
117
|
+
return;
|
|
118
|
+
lines.push(' '.repeat(indent) + 'extensions:');
|
|
119
|
+
for (const extension of state.extensions) {
|
|
120
|
+
lines.push(' '.repeat(indent + 2) + '- kind: ' + formatString(extension.kind));
|
|
121
|
+
appendFields(lines, extension.fields, indent + 4, DESCRIPTOR_RESERVED_FIELDS);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function appendNodeInteractiveMetadata(lines, node, indent) {
|
|
125
|
+
const prefix = ' '.repeat(indent);
|
|
126
|
+
if (node.interactiveStates == null) {
|
|
127
|
+
if (node.transition != null)
|
|
128
|
+
throw new TypeError('FlightDocument transition requires interactiveStates');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const phases = getInteractiveStatePhases(node.interactiveStates);
|
|
132
|
+
if (phases.length === 0)
|
|
133
|
+
throw new TypeError('FlightDocument interactiveStates must not be empty');
|
|
134
|
+
lines.push(prefix + 'interactiveStates:');
|
|
135
|
+
for (const [phase, state] of phases) {
|
|
136
|
+
lines.push(prefix + ' ' + phase + ':');
|
|
137
|
+
appendInteractiveState(lines, state, indent + 4);
|
|
138
|
+
}
|
|
139
|
+
if (node.transition != null) {
|
|
140
|
+
lines.push(prefix + 'transition:');
|
|
141
|
+
lines.push(prefix + ' kind: ' + formatString(node.transition.kind));
|
|
142
|
+
appendFields(lines, node.transition.fields, indent + 2, DESCRIPTOR_RESERVED_FIELDS);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function getInteractiveStateEntries(state) {
|
|
146
|
+
const out = [];
|
|
147
|
+
for (const property of INTERACTIVE_STATE_PROPERTIES) {
|
|
148
|
+
const value = state[property];
|
|
149
|
+
if (value !== undefined)
|
|
150
|
+
out.push([property, value]);
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
function getInteractiveStatePhases(states) {
|
|
155
|
+
const out = [];
|
|
156
|
+
for (const phase of INTERACTIVE_STATE_PHASES) {
|
|
157
|
+
const state = states[phase];
|
|
158
|
+
if (state !== null)
|
|
159
|
+
out.push([phase, state]);
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
107
163
|
function appendObjectEntries(lines, value, indent, reserved) {
|
|
108
164
|
for (const [key, entry] of Object.entries(value).sort(([left], [right]) => left.localeCompare(right))) {
|
|
109
165
|
if (reserved.includes(key))
|
|
@@ -153,6 +209,60 @@ function appendScene(lines, scene) {
|
|
|
153
209
|
}
|
|
154
210
|
lines.push(' scene:');
|
|
155
211
|
appendNode(lines, scene.scene, 6);
|
|
212
|
+
appendLayouts(lines, scene.layouts);
|
|
213
|
+
appendTokens(lines, scene.tokens);
|
|
214
|
+
}
|
|
215
|
+
function appendLayouts(lines, layouts) {
|
|
216
|
+
if (layouts.length === 0)
|
|
217
|
+
return;
|
|
218
|
+
const seenTargets = new Set();
|
|
219
|
+
lines.push(' layouts:');
|
|
220
|
+
for (const layout of layouts) {
|
|
221
|
+
const nodes = layout.tree.nodes;
|
|
222
|
+
if (nodes.length === 0)
|
|
223
|
+
throw new RangeError('FlightDocument layout tree must not be empty');
|
|
224
|
+
if (layout.targets.length !== nodes.length) {
|
|
225
|
+
throw new RangeError('FlightDocument layout targets must match its tree nodes index-for-index');
|
|
226
|
+
}
|
|
227
|
+
lines.push(' - targets:');
|
|
228
|
+
for (const target of layout.targets) {
|
|
229
|
+
if (target.length === 0)
|
|
230
|
+
throw new RangeError('FlightDocument layout target names must not be empty');
|
|
231
|
+
if (seenTargets.has(target))
|
|
232
|
+
throw new RangeError('FlightDocument layout targets must be unique per scene');
|
|
233
|
+
seenTargets.add(target);
|
|
234
|
+
lines.push(' - ' + formatString(target));
|
|
235
|
+
}
|
|
236
|
+
lines.push(' tree:');
|
|
237
|
+
lines.push(' nodes:');
|
|
238
|
+
for (let index = 0; index < nodes.length; index++)
|
|
239
|
+
appendLayoutNode(lines, nodes[index], index);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function appendLayoutNode(lines, node, index) {
|
|
243
|
+
if (node.kind.length === 0)
|
|
244
|
+
throw new RangeError('FlightDocument layout node kinds must not be empty');
|
|
245
|
+
if (!Number.isInteger(node.parentIndex) || node.parentIndex < -1 || node.parentIndex >= index) {
|
|
246
|
+
throw new RangeError('FlightDocument layout parentIndex must be -1 or precede its node');
|
|
247
|
+
}
|
|
248
|
+
lines.push(' - kind: ' + formatString(node.kind));
|
|
249
|
+
lines.push(' parentIndex: ' + String(node.parentIndex));
|
|
250
|
+
if (node.containerStyle !== null)
|
|
251
|
+
appendMappingEntry(lines, 'containerStyle', node.containerStyle, 14);
|
|
252
|
+
if (node.itemStyle !== null)
|
|
253
|
+
appendMappingEntry(lines, 'itemStyle', node.itemStyle, 14);
|
|
254
|
+
}
|
|
255
|
+
function appendTokens(lines, tokens) {
|
|
256
|
+
if (tokens.length === 0)
|
|
257
|
+
return;
|
|
258
|
+
lines.push(' tokens:');
|
|
259
|
+
for (const token of tokens) {
|
|
260
|
+
lines.push(' - kind: ' + formatString(token.kind));
|
|
261
|
+
lines.push(' key: ' + formatString(token.key));
|
|
262
|
+
// Mode names are sorted so a formatted document is stable, while the token ROWS keep the order
|
|
263
|
+
// they were authored in: row order is the author's, mode order is not meaningful.
|
|
264
|
+
appendFields(lines, token.values, 8, TOKEN_RESERVED_FIELDS);
|
|
265
|
+
}
|
|
156
266
|
}
|
|
157
267
|
function appendSequence(lines, values, indent) {
|
|
158
268
|
const prefix = ' '.repeat(indent);
|
|
@@ -306,10 +416,12 @@ function readFlightDocumentText(text) {
|
|
|
306
416
|
kind: null,
|
|
307
417
|
limit: parsed.limit,
|
|
308
418
|
line: parsed.line,
|
|
419
|
+
mode: null,
|
|
309
420
|
offset: parsed.offset,
|
|
310
421
|
path: '',
|
|
311
422
|
reason: parsed.kind,
|
|
312
423
|
resourceKey: null,
|
|
424
|
+
tokenKey: null,
|
|
313
425
|
version: null,
|
|
314
426
|
},
|
|
315
427
|
};
|
|
@@ -409,7 +521,83 @@ function readLight(value, path, context) {
|
|
|
409
521
|
light.node = node;
|
|
410
522
|
return light;
|
|
411
523
|
}
|
|
412
|
-
function
|
|
524
|
+
function readInteractiveState(value, path, dimension, context) {
|
|
525
|
+
if (!isMapping(value) || !hasOnlyKeys(value, INTERACTIVE_STATE_KEYS))
|
|
526
|
+
return refuse(context, path);
|
|
527
|
+
const state = { extensions: [] };
|
|
528
|
+
for (const property of INTERACTIVE_STATE_PROPERTIES) {
|
|
529
|
+
const propertyValue = value[property];
|
|
530
|
+
if (propertyValue === undefined)
|
|
531
|
+
continue;
|
|
532
|
+
if (property === 'visible') {
|
|
533
|
+
if (typeof propertyValue !== 'boolean')
|
|
534
|
+
return refuse(context, appendPath(path, property));
|
|
535
|
+
}
|
|
536
|
+
else if (typeof propertyValue !== 'number' || !Number.isFinite(propertyValue)) {
|
|
537
|
+
return refuse(context, appendPath(path, property));
|
|
538
|
+
}
|
|
539
|
+
if (dimension === 'Scene3D' && INTERACTIVE_STATE_2D_PROPERTIES.includes(property)) {
|
|
540
|
+
return refuse(context, appendPath(path, property));
|
|
541
|
+
}
|
|
542
|
+
Object.assign(state, { [property]: propertyValue });
|
|
543
|
+
}
|
|
544
|
+
const extensionsRaw = value['extensions'];
|
|
545
|
+
if (extensionsRaw !== undefined) {
|
|
546
|
+
if (!Array.isArray(extensionsRaw))
|
|
547
|
+
return refuse(context, appendPath(path, 'extensions'));
|
|
548
|
+
const kinds = new Set();
|
|
549
|
+
for (let i = 0; i < extensionsRaw.length; i++) {
|
|
550
|
+
const extensionPath = `${path}.extensions[${i}]`;
|
|
551
|
+
const extension = readInteractiveStateExtension(extensionsRaw[i], extensionPath, context);
|
|
552
|
+
if (extension === null)
|
|
553
|
+
return null;
|
|
554
|
+
if (kinds.has(extension.kind)) {
|
|
555
|
+
return refuseWithReason(context, FlightDocumentRefusalReason.InteractiveStateExtensionKindDuplicate, extensionPath, extension.kind);
|
|
556
|
+
}
|
|
557
|
+
kinds.add(extension.kind);
|
|
558
|
+
state.extensions.push(extension);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (getInteractiveStateEntries(state).length === 0 && state.extensions.length === 0)
|
|
562
|
+
return refuse(context, path);
|
|
563
|
+
return state;
|
|
564
|
+
}
|
|
565
|
+
function readInteractiveStateExtension(value, path, context) {
|
|
566
|
+
if (!isMapping(value))
|
|
567
|
+
return refuse(context, path);
|
|
568
|
+
const kind = value['kind'];
|
|
569
|
+
if (typeof kind !== 'string')
|
|
570
|
+
return refuse(context, appendPath(path, 'kind'));
|
|
571
|
+
const fields = copyFlightDocumentFields(value, DESCRIPTOR_RESERVED_FIELDS, path, context);
|
|
572
|
+
return fields === null ? null : { fields, kind };
|
|
573
|
+
}
|
|
574
|
+
function readInteractiveStates(value, path, dimension, context) {
|
|
575
|
+
if (!isMapping(value) || !hasOnlyKeys(value, INTERACTIVE_STATE_PHASES))
|
|
576
|
+
return refuse(context, path);
|
|
577
|
+
const states = { disabled: null, hover: null, pressed: null };
|
|
578
|
+
let count = 0;
|
|
579
|
+
for (const phase of INTERACTIVE_STATE_PHASES) {
|
|
580
|
+
const stateRaw = value[phase];
|
|
581
|
+
if (stateRaw === undefined)
|
|
582
|
+
continue;
|
|
583
|
+
const state = readInteractiveState(stateRaw, appendPath(path, phase), dimension, context);
|
|
584
|
+
if (state === null)
|
|
585
|
+
return null;
|
|
586
|
+
states[phase] = state;
|
|
587
|
+
count++;
|
|
588
|
+
}
|
|
589
|
+
return count === 0 ? refuse(context, path) : states;
|
|
590
|
+
}
|
|
591
|
+
function readInteractiveStateTransition(value, path, context) {
|
|
592
|
+
if (!isMapping(value))
|
|
593
|
+
return refuse(context, path);
|
|
594
|
+
const kind = value['kind'];
|
|
595
|
+
if (typeof kind !== 'string')
|
|
596
|
+
return refuse(context, appendPath(path, 'kind'));
|
|
597
|
+
const fields = copyFlightDocumentFields(value, DESCRIPTOR_RESERVED_FIELDS, path, context);
|
|
598
|
+
return fields === null ? null : { fields, kind };
|
|
599
|
+
}
|
|
600
|
+
function readNode(value, path, dimension, context) {
|
|
413
601
|
if (!isMapping(value))
|
|
414
602
|
return refuse(context, path);
|
|
415
603
|
const kind = value['kind'];
|
|
@@ -421,14 +609,30 @@ function readNode(value, path, context) {
|
|
|
421
609
|
if (!Array.isArray(childrenRaw))
|
|
422
610
|
return refuse(context, appendPath(path, 'children'));
|
|
423
611
|
for (let index = 0; index < childrenRaw.length; index++) {
|
|
424
|
-
const child = readNode(childrenRaw[index], `${path}.children[${index}]`, context);
|
|
612
|
+
const child = readNode(childrenRaw[index], `${path}.children[${index}]`, dimension, context);
|
|
425
613
|
if (child === null)
|
|
426
614
|
return null;
|
|
427
615
|
children.push(child);
|
|
428
616
|
}
|
|
429
617
|
}
|
|
618
|
+
const interactiveStatesRaw = value['interactiveStates'];
|
|
619
|
+
let interactiveStates = null;
|
|
620
|
+
if (interactiveStatesRaw !== undefined) {
|
|
621
|
+
interactiveStates = readInteractiveStates(interactiveStatesRaw, appendPath(path, 'interactiveStates'), dimension, context);
|
|
622
|
+
if (interactiveStates === null)
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
const transitionRaw = value['transition'];
|
|
626
|
+
if (transitionRaw !== undefined && interactiveStates === null)
|
|
627
|
+
return refuse(context, appendPath(path, 'transition'));
|
|
628
|
+
let transition = null;
|
|
629
|
+
if (transitionRaw !== undefined) {
|
|
630
|
+
transition = readInteractiveStateTransition(transitionRaw, appendPath(path, 'transition'), context);
|
|
631
|
+
if (transition === null)
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
430
634
|
const fields = copyFlightDocumentFields(value, NODE_RESERVED_FIELDS, path, context);
|
|
431
|
-
return fields === null ? null : { children, fields, kind };
|
|
635
|
+
return fields === null ? null : { children, fields, interactiveStates, kind, transition };
|
|
432
636
|
}
|
|
433
637
|
function readOptionalIndex(value, path, context) {
|
|
434
638
|
if (value === undefined)
|
|
@@ -519,10 +723,16 @@ function readScene2D(mapping, path, context) {
|
|
|
519
723
|
if (backgroundColor !== undefined && backgroundColor !== null && typeof backgroundColor !== 'number') {
|
|
520
724
|
return refuse(context, appendPath(path, 'backgroundColor'));
|
|
521
725
|
}
|
|
522
|
-
const scene = readNode(mapping['scene'], appendPath(path, 'scene'), context);
|
|
726
|
+
const scene = readNode(mapping['scene'], appendPath(path, 'scene'), 'Scene2D', context);
|
|
523
727
|
if (scene === null)
|
|
524
728
|
return null;
|
|
525
|
-
|
|
729
|
+
const layouts = readLayouts(mapping['layouts'], path, context);
|
|
730
|
+
if (layouts === null)
|
|
731
|
+
return null;
|
|
732
|
+
const tokens = readTokens(mapping['tokens'], path, context);
|
|
733
|
+
if (tokens === null)
|
|
734
|
+
return null;
|
|
735
|
+
return { backgroundColor: backgroundColor ?? null, kind: 'Scene2D', layouts, scene, tokens };
|
|
526
736
|
}
|
|
527
737
|
function readScene3D(mapping, path, context) {
|
|
528
738
|
if (!hasOnlyKeys(mapping, SCENE_3D_KEYS))
|
|
@@ -551,10 +761,134 @@ function readScene3D(mapping, path, context) {
|
|
|
551
761
|
lights.push(light);
|
|
552
762
|
}
|
|
553
763
|
}
|
|
554
|
-
const scene = readNode(mapping['scene'], appendPath(path, 'scene'), context);
|
|
764
|
+
const scene = readNode(mapping['scene'], appendPath(path, 'scene'), 'Scene3D', context);
|
|
555
765
|
if (scene === null)
|
|
556
766
|
return null;
|
|
557
|
-
|
|
767
|
+
const layouts = readLayouts(mapping['layouts'], path, context);
|
|
768
|
+
if (layouts === null)
|
|
769
|
+
return null;
|
|
770
|
+
const tokens = readTokens(mapping['tokens'], path, context);
|
|
771
|
+
if (tokens === null)
|
|
772
|
+
return null;
|
|
773
|
+
return { cameras, kind: 'Scene3D', layouts, lights, scene, tokens };
|
|
774
|
+
}
|
|
775
|
+
function readLayouts(value, scenePath, context) {
|
|
776
|
+
if (value === undefined)
|
|
777
|
+
return [];
|
|
778
|
+
const layoutsPath = appendPath(scenePath, 'layouts');
|
|
779
|
+
if (!Array.isArray(value))
|
|
780
|
+
return refuse(context, layoutsPath);
|
|
781
|
+
const layouts = [];
|
|
782
|
+
const seenTargets = new Set();
|
|
783
|
+
for (let layoutIndex = 0; layoutIndex < value.length; layoutIndex++) {
|
|
784
|
+
const layoutPath = `${layoutsPath}[${layoutIndex}]`;
|
|
785
|
+
const raw = value[layoutIndex];
|
|
786
|
+
if (!isMapping(raw) || !hasOnlyKeys(raw, LAYOUT_KEYS))
|
|
787
|
+
return refuse(context, layoutPath);
|
|
788
|
+
const targetsPath = appendPath(layoutPath, 'targets');
|
|
789
|
+
const targetsRaw = raw['targets'];
|
|
790
|
+
if (!Array.isArray(targetsRaw) || targetsRaw.length === 0)
|
|
791
|
+
return refuse(context, targetsPath);
|
|
792
|
+
const targets = [];
|
|
793
|
+
for (let targetIndex = 0; targetIndex < targetsRaw.length; targetIndex++) {
|
|
794
|
+
const targetPath = `${targetsPath}[${targetIndex}]`;
|
|
795
|
+
const target = targetsRaw[targetIndex];
|
|
796
|
+
if (typeof target !== 'string' || target.length === 0 || seenTargets.has(target)) {
|
|
797
|
+
return refuse(context, targetPath);
|
|
798
|
+
}
|
|
799
|
+
seenTargets.add(target);
|
|
800
|
+
targets.push(target);
|
|
801
|
+
}
|
|
802
|
+
const treePath = appendPath(layoutPath, 'tree');
|
|
803
|
+
const treeRaw = raw['tree'];
|
|
804
|
+
if (!isMapping(treeRaw) || !hasOnlyKeys(treeRaw, LAYOUT_TREE_KEYS))
|
|
805
|
+
return refuse(context, treePath);
|
|
806
|
+
const nodesPath = appendPath(treePath, 'nodes');
|
|
807
|
+
const nodesRaw = treeRaw['nodes'];
|
|
808
|
+
if (!Array.isArray(nodesRaw) || nodesRaw.length === 0)
|
|
809
|
+
return refuse(context, nodesPath);
|
|
810
|
+
const nodes = [];
|
|
811
|
+
for (let nodeIndex = 0; nodeIndex < nodesRaw.length; nodeIndex++) {
|
|
812
|
+
const node = readLayoutNode(nodesRaw[nodeIndex], nodeIndex, `${nodesPath}[${nodeIndex}]`, context);
|
|
813
|
+
if (node === null)
|
|
814
|
+
return null;
|
|
815
|
+
nodes.push(node);
|
|
816
|
+
}
|
|
817
|
+
if (targets.length !== nodes.length)
|
|
818
|
+
return refuse(context, targetsPath);
|
|
819
|
+
layouts.push({ targets, tree: { nodes } });
|
|
820
|
+
}
|
|
821
|
+
return layouts;
|
|
822
|
+
}
|
|
823
|
+
function readLayoutNode(value, index, path, context) {
|
|
824
|
+
if (!isMapping(value) || !hasOnlyKeys(value, LAYOUT_NODE_KEYS))
|
|
825
|
+
return refuse(context, path);
|
|
826
|
+
const kind = value['kind'];
|
|
827
|
+
if (typeof kind !== 'string' || kind.length === 0)
|
|
828
|
+
return refuse(context, appendPath(path, 'kind'));
|
|
829
|
+
const parentIndex = value['parentIndex'];
|
|
830
|
+
if (!Number.isInteger(parentIndex) || parentIndex < -1 || parentIndex >= index) {
|
|
831
|
+
return refuse(context, appendPath(path, 'parentIndex'));
|
|
832
|
+
}
|
|
833
|
+
const containerStyle = readLayoutStyle(value['containerStyle'], appendPath(path, 'containerStyle'), context);
|
|
834
|
+
if (containerStyle === INVALID_LAYOUT_STYLE)
|
|
835
|
+
return null;
|
|
836
|
+
const itemStyle = readLayoutStyle(value['itemStyle'], appendPath(path, 'itemStyle'), context);
|
|
837
|
+
if (itemStyle === INVALID_LAYOUT_STYLE)
|
|
838
|
+
return null;
|
|
839
|
+
return { containerStyle, itemStyle, kind, parentIndex: parentIndex };
|
|
840
|
+
}
|
|
841
|
+
function readLayoutStyle(value, path, context) {
|
|
842
|
+
if (value === undefined || value === null)
|
|
843
|
+
return null;
|
|
844
|
+
if (!isMapping(value)) {
|
|
845
|
+
refuse(context, path);
|
|
846
|
+
return INVALID_LAYOUT_STYLE;
|
|
847
|
+
}
|
|
848
|
+
const fields = copyFlightDocumentFields(value, [], path, context);
|
|
849
|
+
return fields ?? INVALID_LAYOUT_STYLE;
|
|
850
|
+
}
|
|
851
|
+
function readTokens(value, path, context) {
|
|
852
|
+
if (value === undefined)
|
|
853
|
+
return [];
|
|
854
|
+
if (!Array.isArray(value))
|
|
855
|
+
return refuse(context, appendPath(path, 'tokens'));
|
|
856
|
+
const tokens = [];
|
|
857
|
+
const seen = new Set();
|
|
858
|
+
for (let index = 0; index < value.length; index++) {
|
|
859
|
+
const rowPath = `${path}.tokens[${index}]`;
|
|
860
|
+
const raw = value[index];
|
|
861
|
+
if (!isMapping(raw))
|
|
862
|
+
return refuse(context, rowPath);
|
|
863
|
+
const kind = raw['kind'];
|
|
864
|
+
const key = raw['key'];
|
|
865
|
+
if (typeof kind !== 'string')
|
|
866
|
+
return refuse(context, appendPath(rowPath, 'kind'));
|
|
867
|
+
if (typeof key !== 'string')
|
|
868
|
+
return refuse(context, appendPath(rowPath, 'key'));
|
|
869
|
+
if (!SAFE_PLAIN_SCALAR_PATTERN.test(key)) {
|
|
870
|
+
return refuseToken(context, FlightDocumentRefusalReason.TokenKeyInvalid, appendPath(rowPath, 'key'), key, null);
|
|
871
|
+
}
|
|
872
|
+
if (seen.has(key)) {
|
|
873
|
+
return refuseToken(context, FlightDocumentRefusalReason.TokenKeyDuplicate, appendPath(rowPath, 'key'), key, null);
|
|
874
|
+
}
|
|
875
|
+
seen.add(key);
|
|
876
|
+
const values = {};
|
|
877
|
+
for (const mode of Object.keys(raw)) {
|
|
878
|
+
if (TOKEN_RESERVED_FIELDS.includes(mode))
|
|
879
|
+
continue;
|
|
880
|
+
const modePath = appendPath(rowPath, mode);
|
|
881
|
+
if (!SAFE_PLAIN_SCALAR_PATTERN.test(mode)) {
|
|
882
|
+
return refuseToken(context, FlightDocumentRefusalReason.TokenModeInvalid, modePath, key, mode);
|
|
883
|
+
}
|
|
884
|
+
const modeValue = copyFlightDocumentValue(raw[mode], modePath, context);
|
|
885
|
+
if (modeValue === INVALID_FLIGHT_DOCUMENT_VALUE)
|
|
886
|
+
return null;
|
|
887
|
+
values[mode] = modeValue;
|
|
888
|
+
}
|
|
889
|
+
tokens.push({ key, kind, values });
|
|
890
|
+
}
|
|
891
|
+
return tokens;
|
|
558
892
|
}
|
|
559
893
|
function readTransform3D(value, path, context) {
|
|
560
894
|
if (!isMapping(value) || !hasOnlyKeys(value, TRANSFORM_3D_KEYS))
|
|
@@ -592,6 +926,20 @@ function refuse(context, path) {
|
|
|
592
926
|
context.refusal ??= createDocumentRefusal(FlightDocumentRefusalReason.StructureInvalid, path);
|
|
593
927
|
return null;
|
|
594
928
|
}
|
|
929
|
+
function refuseWithReason(context, reason, path, kind) {
|
|
930
|
+
if (context.refusal === null) {
|
|
931
|
+
context.refusal = createDocumentRefusal(reason, path);
|
|
932
|
+
context.refusal.kind = kind;
|
|
933
|
+
}
|
|
934
|
+
return null;
|
|
935
|
+
}
|
|
936
|
+
function refuseToken(context, reason, path, tokenKey, mode) {
|
|
937
|
+
const refusal = createDocumentRefusal(reason, path);
|
|
938
|
+
refusal.mode = mode;
|
|
939
|
+
refusal.tokenKey = tokenKey;
|
|
940
|
+
context.refusal ??= refusal;
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
595
943
|
function refuseValue(context, reason, path) {
|
|
596
944
|
context.refusal ??= createDocumentRefusal(reason, path);
|
|
597
945
|
return INVALID_FLIGHT_DOCUMENT_VALUE;
|
|
@@ -600,18 +948,30 @@ function appendPath(path, key) {
|
|
|
600
948
|
return path === '' ? key : path + '.' + key;
|
|
601
949
|
}
|
|
602
950
|
const INVALID_FLIGHT_DOCUMENT_VALUE = Symbol('invalid-flight-document-value');
|
|
951
|
+
const INVALID_LAYOUT_STYLE = Symbol('invalid-layout-style');
|
|
603
952
|
const INVALID_OPTIONAL_INDEX = Symbol('invalid-flight-document-optional-index');
|
|
604
953
|
const CAMERA_KEYS = ['far', 'name', 'near', 'node', 'projection', 'transform'];
|
|
954
|
+
const DESCRIPTOR_RESERVED_FIELDS = ['kind'];
|
|
605
955
|
const DOCUMENT_KEYS = ['defaultScene', 'flight', 'resources', 'scenes'];
|
|
956
|
+
const INTERACTIVE_STATE_2D_PROPERTIES = ['scaleX', 'scaleY', 'x', 'y'];
|
|
957
|
+
const INTERACTIVE_STATE_KEYS = ['alpha', 'extensions', 'scaleX', 'scaleY', 'visible', 'x', 'y'];
|
|
958
|
+
const INTERACTIVE_STATE_PHASES = ['disabled', 'hover', 'pressed'];
|
|
959
|
+
const INTERACTIVE_STATE_PROPERTIES = ['alpha', 'scaleX', 'scaleY', 'visible', 'x', 'y'];
|
|
606
960
|
const LIGHT_KEYS = ['descriptor', 'name', 'node', 'transform'];
|
|
607
|
-
const
|
|
961
|
+
const LAYOUT_KEYS = ['targets', 'tree'];
|
|
962
|
+
const LAYOUT_NODE_KEYS = ['containerStyle', 'itemStyle', 'kind', 'parentIndex'];
|
|
963
|
+
const LAYOUT_TREE_KEYS = ['nodes'];
|
|
964
|
+
const NODE_RESERVED_FIELDS = ['children', 'interactiveStates', 'kind', 'transition'];
|
|
608
965
|
const ORTHOGRAPHIC_PROJECTION_KEYS = ['halfHeight', 'halfWidth', 'kind'];
|
|
609
966
|
const PERSPECTIVE_PROJECTION_KEYS = ['aspect', 'fovY', 'kind'];
|
|
610
967
|
const QUATERNION_KEYS = ['w', 'x', 'y', 'z'];
|
|
611
968
|
const RESOURCE_RESERVED_FIELDS = ['key', 'kind'];
|
|
612
969
|
const SAFE_PLAIN_SCALAR_PATTERN = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
|
|
613
|
-
const SCENE_2D_KEYS = ['backgroundColor', 'kind', 'scene'];
|
|
614
|
-
const SCENE_3D_KEYS = ['cameras', 'kind', 'lights', 'scene'];
|
|
970
|
+
const SCENE_2D_KEYS = ['backgroundColor', 'kind', 'layouts', 'scene', 'tokens'];
|
|
971
|
+
const SCENE_3D_KEYS = ['cameras', 'kind', 'layouts', 'lights', 'scene', 'tokens'];
|
|
972
|
+
// A token row flattens its mode variants beside kind and key, exactly as a resource row flattens
|
|
973
|
+
// its fields, so these two names are structural and can never be authored as mode names.
|
|
974
|
+
const TOKEN_RESERVED_FIELDS = ['key', 'kind'];
|
|
615
975
|
const TRANSFORM_3D_KEYS = ['position', 'rotation', 'scale'];
|
|
616
976
|
const VECTOR_3_KEYS = ['x', 'y', 'z'];
|
|
617
977
|
//# sourceMappingURL=flightDocumentText.js.map
|