@pixi-ui-editor/schema 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test-fixtures.js","sourceRoot":"","sources":["../src/index.test-fixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n BUTTON_STATE_KEYS,\r\n createDefaultLocalization,\r\n CURRENT_SCHEMA_VERSION,\r\n validateProjectDocument,\r\n type ProjectDocument,\r\n type UINode,\r\n type ValidationResult,\r\n} from \"./index.js\";\r\n\r\nexport type ButtonNode = Extract<UINode, { type: \"button\" }>;\r\n\r\n/** Appends a button whose four states each reference their own image asset, wired into the fixture's scene root. */\r\nexport function addButtonNode(document: ProjectDocument): ButtonNode {\r\n const scene = document.scenes[0]!;\r\n const root = scene.nodes[0]!;\r\n const assetIds = BUTTON_STATE_KEYS.map((state, index) => {\r\n const id = stableId(10 + index);\r\n document.assets.push({ id, name: `Button ${state}`, type: \"image\", source: { uri: `assets/button-${state}.png`, mediaType: \"image/png\" } });\r\n return id;\r\n });\r\n\r\n const button: ButtonNode = {\r\n id: stableId(20),\r\n name: \"Play\",\r\n type: \"button\",\r\n parentId: root.id,\r\n children: [],\r\n visible: true,\r\n enabled: true,\r\n states: { normalAssetId: assetIds[0]!, hoverAssetId: assetIds[1]!, pressedAssetId: assetIds[2]!, disabledAssetId: assetIds[3]! },\r\n transform: { x: 0, y: 0, width: 120, height: 40, scaleX: 1, scaleY: 1, rotation: 0 },\r\n };\r\n root.children.push(button.id);\r\n scene.nodes.push(button);\r\n return button;\r\n}\r\n\r\nexport type CheckboxNode = Extract<UINode, { type: \"checkbox\" }>;\r\n\r\n/** Appends a checkbox whose required unchecked/checked states each reference their own image asset. */\r\nexport function addCheckboxNode(document: ProjectDocument): CheckboxNode {\r\n const scene = document.scenes[0]!;\r\n const root = scene.nodes[0]!;\r\n const uncheckedAssetId = stableId(70);\r\n const checkedAssetId = stableId(71);\r\n document.assets.push({ id: uncheckedAssetId, name: \"Checkbox unchecked\", type: \"image\", source: { uri: \"assets/checkbox-unchecked.png\", mediaType: \"image/png\" } });\r\n document.assets.push({ id: checkedAssetId, name: \"Checkbox checked\", type: \"image\", source: { uri: \"assets/checkbox-checked.png\", mediaType: \"image/png\" } });\r\n\r\n const checkbox: CheckboxNode = {\r\n id: stableId(72),\r\n name: \"Agree\",\r\n type: \"checkbox\",\r\n parentId: root.id,\r\n children: [],\r\n visible: true,\r\n enabled: true,\r\n defaultChecked: false,\r\n states: { uncheckedAssetId, checkedAssetId },\r\n transform: { x: 0, y: 0, width: 32, height: 32, scaleX: 1, scaleY: 1, rotation: 0 },\r\n };\r\n root.children.push(checkbox.id);\r\n scene.nodes.push(checkbox);\r\n return checkbox;\r\n}\r\n\r\nexport const stableId = (value: number): string =>\r\n `00000000-0000-4000-8000-${String(value).padStart(12, \"0\")}`;\r\n\r\n/** Appends an atlas asset with one named frame and points an existing image node at that frame id. */\r\nexport function addAtlasAssetWithFrame(document: ProjectDocument): { atlasId: string; frameId: string } {\r\n const atlasId = stableId(40);\r\n const frameId = stableId(41);\r\n document.assets.push({\r\n id: atlasId,\r\n name: \"Atlas\",\r\n type: \"atlas\",\r\n files: {\r\n json: { name: \"atlas.json\", uri: \"assets/atlas.json\", mediaType: \"application/json\" },\r\n texture: { name: \"atlas.png\", uri: \"assets/atlas.png\", mediaType: \"image/png\" },\r\n },\r\n frames: { \"icon.png\": frameId },\r\n });\r\n (document.scenes[0]!.nodes[1] as { assetId: string }).assetId = frameId;\r\n return { atlasId, frameId };\r\n}\r\n\r\nexport function createProjectDocumentFixture(): ProjectDocument {\r\n const project = stableId(1);\r\n const scene = stableId(2);\r\n const root = stableId(3);\r\n const image = stableId(4);\r\n const asset = stableId(5);\r\n const prefab = stableId(6);\r\n\r\n return {\r\n schemaVersion: CURRENT_SCHEMA_VERSION,\r\n project: { id: project, name: \"Project\" },\r\n settings: {\r\n layoutProfileSelection: { mode: \"aspect-ratio\", mobileMaxAspectRatio: 1 },\r\n },\r\n localization: createDefaultLocalization(),\r\n assets: [\r\n {\r\n id: asset,\r\n name: \"Logo\",\r\n type: \"image\",\r\n source: { uri: \"assets/logo.png\", mediaType: \"image/png\" },\r\n },\r\n ],\r\n effects: [],\r\n prefabs: [\r\n {\r\n id: prefab,\r\n name: \"Badge\",\r\n rootNodeIds: [],\r\n nodes: [],\r\n exposedProperties: [],\r\n },\r\n ],\r\n scenes: [\r\n {\r\n id: scene,\r\n name: \"Main\",\r\n rootNodeIds: [root],\r\n layout: {\r\n referenceViewports: {\r\n desktop: { width: 1920, height: 1080 },\r\n mobile: { width: 390, height: 844 },\r\n },\r\n preferredViewports: {\r\n desktop: { width: 1920, height: 1080 },\r\n mobile: { width: 390, height: 844 },\r\n },\r\n },\r\n nodes: [\r\n {\r\n id: root,\r\n name: \"Root\",\r\n type: \"container\",\r\n parentId: null,\r\n children: [image],\r\n visible: true,\r\n transform: {\r\n x: 0,\r\n y: 0,\r\n width: 100,\r\n height: 100,\r\n scaleX: 1,\r\n scaleY: 1,\r\n rotation: 0,\r\n },\r\n },\r\n {\r\n id: image,\r\n name: \"Logo\",\r\n type: \"image\",\r\n assetId: asset,\r\n parentId: root,\r\n children: [],\r\n visible: true,\r\n transform: {\r\n x: 0,\r\n y: 0,\r\n width: 10,\r\n height: 10,\r\n scaleX: 1,\r\n scaleY: 1,\r\n rotation: 0,\r\n },\r\n },\r\n ],\r\n },\r\n ],\r\n };\r\n}\r\n\r\nexport function validateFixtureMutation(mutate: (document: ProjectDocument) => void): ValidationResult {\r\n const document = createProjectDocumentFixture();\r\n mutate(document);\r\n return validateProjectDocument(document);\r\n}\r\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -1,458 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { CURRENT_SCHEMA_VERSION, createStableId, migrateProjectDocument, serializeProjectDocument, validateProjectDocument, } from "./index.js";
3
- import { addAtlasAssetWithFrame, addButtonNode, addCheckboxNode, createProjectDocumentFixture, stableId, validateFixtureMutation, } from "./index.test-fixtures.js";
4
- describe("schema v1", () => {
5
- it("generates independent UUID stable IDs", () => {
6
- const first = createStableId();
7
- const second = createStableId();
8
- expect(first).toMatch(/^[0-9a-f]{8}-/i);
9
- expect(first).not.toBe(second);
10
- });
11
- it("accepts a minimal valid document", () => {
12
- expect(validateProjectDocument(createProjectDocumentFixture())).toEqual({ valid: true, issues: [] });
13
- });
14
- it("accepts a rectangular mask node and migrates v20 without rewriting its graph", () => {
15
- const document = createProjectDocumentFixture();
16
- const scene = document.scenes[0];
17
- const root = scene.nodes[0];
18
- const mask = {
19
- id: stableId(90),
20
- name: "Viewport mask",
21
- type: "mask",
22
- parentId: root.id,
23
- children: [],
24
- visible: true,
25
- transform: { x: 0, y: 0, width: 320, height: 180, scaleX: 1, scaleY: 1, rotation: 0 },
26
- };
27
- root.children.push(mask.id);
28
- scene.nodes.push(mask);
29
- expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });
30
- document.schemaVersion = 20;
31
- const before = structuredClone({ scenes: document.scenes, prefabs: document.prefabs });
32
- const migrated = migrateProjectDocument(document);
33
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
34
- expect({ scenes: migrated.scenes, prefabs: migrated.prefabs }).toEqual(before);
35
- });
36
- it("accepts prefab property overrides and local children while rejecting structural inherited edits", () => {
37
- const document = createProjectDocumentFixture();
38
- const prefab = document.prefabs[0];
39
- const definitionNode = structuredClone(document.scenes[0].nodes[1]);
40
- definitionNode.id = stableId(60);
41
- definitionNode.parentId = null;
42
- prefab.rootNodeIds = [definitionNode.id];
43
- prefab.nodes = [definitionNode];
44
- const root = document.scenes[0].nodes[0];
45
- const instanceId = stableId(61);
46
- root.children.push(instanceId);
47
- document.scenes[0].nodes.push({
48
- id: instanceId,
49
- name: "Badge",
50
- type: "prefab-instance",
51
- prefabId: prefab.id,
52
- parentId: root.id,
53
- children: [],
54
- visible: true,
55
- transform: { x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1, rotation: 0 },
56
- propertyOverrides: [{ nodeId: definitionNode.id, patch: { name: "Configured badge" } }],
57
- locallyAddedNodes: [{
58
- id: stableId(62), name: "Caption", type: "text", text: "Local", parentId: definitionNode.id, children: [], visible: true,
59
- transform: { x: 0, y: 0, width: 80, height: 20, scaleX: 1, scaleY: 1, rotation: 0 },
60
- }],
61
- });
62
- expect(validateProjectDocument(document).valid).toBe(true);
63
- const instance = document.scenes[0].nodes.at(-1);
64
- if (instance.type !== "prefab-instance")
65
- throw new Error("Expected prefab instance.");
66
- instance.propertyOverrides[0].patch.children = [];
67
- expect(validateProjectDocument(document).issues.some((issue) => issue.code === "STRUCTURAL_PREFAB_OVERRIDE")).toBe(true);
68
- });
69
- it("accepts normalized anchors and rejects values outside the parent rectangle", () => {
70
- const document = createProjectDocumentFixture();
71
- document.scenes[0].nodes[1].transform.anchorMinX = 0.5;
72
- document.scenes[0].nodes[1].transform.anchorMinY = 1;
73
- expect(validateProjectDocument(document).valid).toBe(true);
74
- document.scenes[0].nodes[1].transform.anchorMinX = 1.1;
75
- expect(validateProjectDocument(document).issues[0].code).toBe("STRUCTURAL_SCHEMA");
76
- });
77
- it("requires positive sizeDelta on a point-anchor axis", () => {
78
- const document = createProjectDocumentFixture();
79
- const transform = document.scenes[0].nodes[1].transform;
80
- transform.width = -20;
81
- expect(validateProjectDocument(document).issues[0].code).toBe("NON_POSITIVE_SIZE");
82
- });
83
- it("migrates v1 point anchors to v2 anchorMin/anchorMax pairs", () => {
84
- const document = createProjectDocumentFixture();
85
- document.schemaVersion = 1;
86
- const v1Document = document;
87
- const transform = v1Document.scenes[0].nodes[1].transform;
88
- transform.anchorX = 0.5;
89
- transform.anchorY = 1;
90
- v1Document.scenes[0].nodes[1].layoutOverrides = { mobile: { transform: { anchorX: 0.25 } } };
91
- const migrated = migrateProjectDocument(document);
92
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
93
- expect(migrated.scenes[0].nodes[1].transform).toMatchObject({ anchorMinX: 0.5, anchorMaxX: 0.5, anchorMinY: 1, anchorMaxY: 1 });
94
- expect(migrated.scenes[0].nodes[1].transform).not.toHaveProperty("anchorX");
95
- expect(migrated.scenes[0].nodes[1].layoutOverrides?.mobile?.transform).toEqual({ anchorMinX: 0.25, anchorMaxX: 0.25 });
96
- });
97
- it("accepts a button whose four states reference image assets", () => {
98
- const document = createProjectDocumentFixture();
99
- addButtonNode(document);
100
- expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });
101
- });
102
- it("reports the offending state field when a button state references a non-image asset", () => {
103
- const document = createProjectDocumentFixture();
104
- const button = addButtonNode(document);
105
- const spineAsset = stableId(30);
106
- document.assets.push({
107
- id: spineAsset,
108
- name: "Hero",
109
- type: "spine",
110
- files: {
111
- skeleton: { name: "hero.json", uri: "assets/hero.json", mediaType: "application/json" },
112
- atlas: { name: "hero.atlas", uri: "assets/hero.atlas", mediaType: "text/plain" },
113
- textures: [{ name: "hero.png", uri: "assets/hero.png", mediaType: "image/png" }],
114
- },
115
- });
116
- button.states.pressedAssetId = spineAsset;
117
- const result = validateProjectDocument(document);
118
- expect(result.issues).toMatchObject([{ code: "INCOMPATIBLE_ASSET_REFERENCE", path: "/scenes/0/nodes/2/states/pressedAssetId" }]);
119
- });
120
- it("accepts a checkbox without hover states, and accepts one with valid hover states", () => {
121
- const document = createProjectDocumentFixture();
122
- const checkbox = addCheckboxNode(document);
123
- expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });
124
- checkbox.states.uncheckedHoverAssetId = checkbox.states.uncheckedAssetId;
125
- checkbox.states.checkedHoverAssetId = checkbox.states.checkedAssetId;
126
- expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });
127
- });
128
- it("reports the offending state field when a checkbox hover state references a non-image asset", () => {
129
- const document = createProjectDocumentFixture();
130
- const checkbox = addCheckboxNode(document);
131
- const spineAsset = stableId(31);
132
- document.assets.push({
133
- id: spineAsset,
134
- name: "Hero",
135
- type: "spine",
136
- files: {
137
- skeleton: { name: "hero.json", uri: "assets/hero.json", mediaType: "application/json" },
138
- atlas: { name: "hero.atlas", uri: "assets/hero.atlas", mediaType: "text/plain" },
139
- textures: [{ name: "hero.png", uri: "assets/hero.png", mediaType: "image/png" }],
140
- },
141
- });
142
- checkbox.states.checkedHoverAssetId = spineAsset;
143
- const result = validateProjectDocument(document);
144
- expect(result.issues).toMatchObject([{ code: "INCOMPATIBLE_ASSET_REFERENCE", path: "/scenes/0/nodes/2/states/checkedHoverAssetId" }]);
145
- });
146
- it("migrates a v2 document to v3 without changing its existing nodes", () => {
147
- const document = createProjectDocumentFixture();
148
- const v2Nodes = structuredClone(document.scenes[0].nodes);
149
- document.schemaVersion = 2;
150
- const migrated = migrateProjectDocument(document);
151
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
152
- expect(migrated.scenes[0].nodes).toEqual(v2Nodes);
153
- });
154
- it("migrates a v3 document to v4 without changing its existing assets or nodes", () => {
155
- const document = createProjectDocumentFixture();
156
- const v3Assets = structuredClone(document.assets);
157
- const v3Nodes = structuredClone(document.scenes[0].nodes);
158
- document.schemaVersion = 3;
159
- const migrated = migrateProjectDocument(document);
160
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
161
- expect(migrated.assets).toEqual(v3Assets);
162
- expect(migrated.scenes[0].nodes).toEqual(v3Nodes);
163
- });
164
- it("migrates a v4 document to v5 without changing its existing assets or nodes", () => {
165
- const document = createProjectDocumentFixture();
166
- const v4Assets = structuredClone(document.assets);
167
- const v4Nodes = structuredClone(document.scenes[0].nodes);
168
- document.schemaVersion = 4;
169
- const migrated = migrateProjectDocument(document);
170
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
171
- expect(migrated.assets).toEqual(v4Assets);
172
- expect(migrated.scenes[0].nodes).toEqual(v4Nodes);
173
- });
174
- it("rejects a sound asset with an empty source uri", () => {
175
- const result = validateFixtureMutation((document) => {
176
- document.assets.push({
177
- id: stableId(45),
178
- name: "Click",
179
- type: "sound",
180
- source: { uri: "", mediaType: "audio/wav" },
181
- });
182
- });
183
- expect(result.issues.some((issue) => issue.code === "STRUCTURAL_SCHEMA")).toBe(true);
184
- });
185
- it("allows zero or negative sizeDelta on a stretched axis", () => {
186
- const document = createProjectDocumentFixture();
187
- const transform = document.scenes[0].nodes[1].transform;
188
- transform.anchorMinY = 0;
189
- transform.anchorMaxY = 1;
190
- transform.height = 0;
191
- expect(validateProjectDocument(document).valid).toBe(true);
192
- transform.height = -100;
193
- expect(validateProjectDocument(document).valid).toBe(true);
194
- });
195
- it("migrates v7 reference viewports through the v11 Unity sizeDelta contract", () => {
196
- const document = createProjectDocumentFixture();
197
- const referenceViewports = structuredClone(document.scenes[0].layout.referenceViewports);
198
- const transform = document.scenes[0].nodes[1].transform;
199
- transform.anchorMinX = 0;
200
- transform.anchorMaxX = 1;
201
- transform.width = 50 - referenceViewports.desktop.width;
202
- document.schemaVersion = 7;
203
- delete document.scenes[0].layout.preferredViewports;
204
- const migrated = migrateProjectDocument(document);
205
- expect(migrated.scenes[0].layout.preferredViewports).toEqual(referenceViewports);
206
- expect(migrated.scenes[0].nodes[1].transform.width).toBe(50 - referenceViewports.desktop.width);
207
- });
208
- it("removes the v8 responsive toggle while preserving its preferred-space rect", () => {
209
- const document = createProjectDocumentFixture();
210
- document.schemaVersion = 8;
211
- const typed = document;
212
- const transform = typed.scenes[0].nodes[1].transform;
213
- transform.anchorMinY = 0;
214
- transform.anchorMaxY = 1;
215
- transform.y = 515;
216
- transform.width = 50;
217
- transform.height = 50;
218
- transform.responsiveSize = {
219
- mode: "scale-stretched-axes",
220
- referenceParentWidth: 1920,
221
- referenceParentHeight: 1080,
222
- };
223
- const migrated = migrateProjectDocument(document);
224
- const migratedTransform = migrated.scenes[0].nodes[1].transform;
225
- expect(migratedTransform).not.toHaveProperty("responsiveSize");
226
- expect(migratedTransform).toMatchObject({ y: 515, width: 50, height: 50 - 1080 });
227
- });
228
- it("migrates v9 point-anchor rects into the preferred coordinate space", () => {
229
- const document = createProjectDocumentFixture();
230
- document.schemaVersion = 9;
231
- document.scenes[0].layout.referenceViewports.desktop = { width: 3840, height: 2160 };
232
- document.scenes[0].layout.preferredViewports.desktop = { width: 1920, height: 1080 };
233
- const transform = document.scenes[0].nodes[1].transform;
234
- transform.x = 100;
235
- transform.y = 200;
236
- transform.width = 50;
237
- transform.height = 80;
238
- const migrated = migrateProjectDocument(document);
239
- expect(migrated.scenes[0].nodes[1].transform).toMatchObject({
240
- x: 50,
241
- y: 100,
242
- width: 25,
243
- height: 40,
244
- });
245
- });
246
- it("migrates a v10 absolute stretch rect to anchoredPosition and sizeDelta", () => {
247
- const document = createProjectDocumentFixture();
248
- document.schemaVersion = 10;
249
- const transform = document.scenes[0].nodes[1].transform;
250
- transform.anchorMinX = 0;
251
- transform.anchorMaxX = 1;
252
- transform.pivotX = 0.5;
253
- transform.x = 25;
254
- transform.width = 50;
255
- const migrated = migrateProjectDocument(document);
256
- expect(migrated.scenes[0].nodes[1].transform).toMatchObject({
257
- x: 25 - 1920 * 0.5,
258
- width: 50 - 1920,
259
- });
260
- });
261
- it("migrates v11 documents with editor-only disabled by default", () => {
262
- const document = createProjectDocumentFixture();
263
- document.schemaVersion = 11;
264
- const migrated = migrateProjectDocument(document);
265
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
266
- expect(migrated.scenes[0].nodes[0].editorOnly).toBeUndefined();
267
- expect(validateProjectDocument(migrated).valid).toBe(true);
268
- });
269
- it("migrates v18 base presentation values without changing scene, prefab, or local nodes", () => {
270
- const document = createProjectDocumentFixture();
271
- const prefab = document.prefabs[0];
272
- const definitionId = stableId(70);
273
- prefab.rootNodeIds = [definitionId];
274
- prefab.nodes = [{
275
- id: definitionId, name: "Definition label", type: "text", text: "Definition", parentId: null, children: [], visible: true,
276
- style: { fontFamily: "Arial", fontSize: 20, fontWeight: "normal", fontStyle: "normal", fill: "#FFFFFF", align: "left", verticalAlign: "top", wordWrap: false, breakWords: false, letterSpacing: 0 },
277
- transform: { x: 0, y: 0, width: 100, height: 30, scaleX: 1, scaleY: 1, rotation: 0 },
278
- }];
279
- const root = document.scenes[0].nodes[0];
280
- const instanceId = stableId(71);
281
- root.children.push(instanceId);
282
- document.scenes[0].nodes.push({
283
- id: instanceId, name: "Instance", type: "prefab-instance", prefabId: prefab.id, parentId: root.id, children: [], visible: true,
284
- transform: { x: 0, y: 0, width: 100, height: 30, scaleX: 1, scaleY: 1, rotation: 0 },
285
- locallyAddedNodes: [{
286
- id: stableId(72), name: "Local label", type: "text", text: "Local", parentId: definitionId, children: [], visible: true,
287
- style: { fontFamily: "Arial", fontSize: 18, fontWeight: "bold", fontStyle: "normal", fill: "#FFFFFF", align: "center", verticalAlign: "middle", wordWrap: false, breakWords: false, letterSpacing: 1 },
288
- transform: { x: 0, y: 0, width: 80, height: 20, scaleX: 1, scaleY: 1, rotation: 0 },
289
- }],
290
- });
291
- const previousOwners = structuredClone({ scenes: document.scenes, prefabs: document.prefabs });
292
- document.schemaVersion = 18;
293
- const migrated = migrateProjectDocument(document);
294
- expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
295
- expect({ scenes: migrated.scenes, prefabs: migrated.prefabs }).toEqual(previousOwners);
296
- expect(validateProjectDocument(migrated)).toEqual({ valid: true, issues: [] });
297
- });
298
- it("validates sparse text and Spine presentation overrides", () => {
299
- const document = createProjectDocumentFixture();
300
- const root = document.scenes[0].nodes[0];
301
- const textId = stableId(73);
302
- root.children.push(textId);
303
- document.scenes[0].nodes.push({
304
- id: textId, name: "Responsive label", type: "text", text: "Label", parentId: root.id, children: [], visible: true,
305
- style: { fontFamily: "Arial", fontSize: 24, fontWeight: "normal", fontStyle: "normal", fill: "#FFFFFF", align: "left", verticalAlign: "top", wordWrap: false, breakWords: false, letterSpacing: 0 },
306
- textStyleOverrides: { mobile: { fontSize: 36, align: "center" } },
307
- transform: { x: 0, y: 0, width: 200, height: 60, scaleX: 1, scaleY: 1, rotation: 0 },
308
- });
309
- const spineAssetId = stableId(74);
310
- document.assets.push({ id: spineAssetId, name: "Hero", type: "spine", files: { skeleton: { name: "hero.json", uri: "assets/hero.json", mediaType: "application/json" }, atlas: { name: "hero.atlas", uri: "assets/hero.atlas", mediaType: "text/plain" }, textures: [{ name: "hero.png", uri: "assets/hero.png", mediaType: "image/png" }] } });
311
- const spineId = stableId(75);
312
- root.children.push(spineId);
313
- document.scenes[0].nodes.push({
314
- id: spineId, name: "Hero", type: "spine", assetId: spineAssetId, animation: "idle", autoplay: true, loop: true, animationSpeed: 1,
315
- spineOverrides: { mobile: { animation: "portrait-idle", loop: false, animationSpeed: 0.8 } },
316
- parentId: root.id, children: [], visible: true, transform: { x: 0, y: 0, width: 200, height: 200, scaleX: 1, scaleY: 1, rotation: 0 },
317
- });
318
- expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });
319
- });
320
- it("accepts persistent editor lock metadata without changing runtime node fields", () => {
321
- const document = createProjectDocumentFixture();
322
- document.scenes[0].nodes[0].locked = true;
323
- expect(validateProjectDocument(document).valid).toBe(true);
324
- expect(migrateProjectDocument(document).scenes[0].nodes[0].locked).toBe(true);
325
- });
326
- it("rejects a button press sound that references an image asset", () => {
327
- const document = createProjectDocumentFixture();
328
- const button = addButtonNode(document);
329
- button.sounds = { pressAssetId: button.states.normalAssetId };
330
- const result = validateProjectDocument(document);
331
- expect(result.issues).toMatchObject([{ code: "INCOMPATIBLE_ASSET_REFERENCE", path: "/scenes/0/nodes/2/sounds/pressAssetId" }]);
332
- });
333
- it("accepts an image node whose assetId is an atlas frame id", () => {
334
- const document = createProjectDocumentFixture();
335
- addAtlasAssetWithFrame(document);
336
- expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });
337
- });
338
- it("rejects an atlas asset with an incomplete files object", () => {
339
- const result = validateFixtureMutation((document) => {
340
- document.assets.push({
341
- id: stableId(42),
342
- name: "Broken atlas",
343
- type: "atlas",
344
- files: { json: { name: "atlas.json", uri: "assets/atlas.json", mediaType: "application/json" } },
345
- frames: { "icon.png": stableId(43) },
346
- });
347
- });
348
- expect(result.issues.some((issue) => issue.code === "STRUCTURAL_SCHEMA")).toBe(true);
349
- });
350
- it("rejects an atlas asset without a frames map", () => {
351
- const result = validateFixtureMutation((document) => {
352
- document.assets.push({
353
- id: stableId(44),
354
- name: "Broken atlas",
355
- type: "atlas",
356
- files: {
357
- json: { name: "atlas.json", uri: "assets/atlas.json", mediaType: "application/json" },
358
- texture: { name: "atlas.png", uri: "assets/atlas.png", mediaType: "image/png" },
359
- },
360
- });
361
- });
362
- expect(result.issues.some((issue) => issue.code === "STRUCTURAL_SCHEMA")).toBe(true);
363
- });
364
- it.each(["desktop", "mobile"])("rejects missing %s viewport", (profile) => {
365
- const result = validateFixtureMutation((document) => {
366
- delete document.scenes[0].layout.referenceViewports[profile];
367
- });
368
- expect(result.issues[0].code).toBe("STRUCTURAL_SCHEMA");
369
- });
370
- it("reports duplicate IDs", () => {
371
- const result = validateFixtureMutation((document) => {
372
- document.scenes[0].nodes[1].id = document.scenes[0].nodes[0].id;
373
- });
374
- expect(result.issues.some((issue) => issue.code === "DUPLICATE_ID")).toBe(true);
375
- });
376
- it("reports missing child and asset references", () => {
377
- const result = validateFixtureMutation((document) => {
378
- document.scenes[0].nodes[0].children = [stableId(99)];
379
- document.scenes[0].nodes[1].assetId = stableId(98);
380
- });
381
- expect(result.issues.map((issue) => issue.code)).toEqual(expect.arrayContaining(["MISSING_CHILD_REFERENCE", "MISSING_ASSET_REFERENCE"]));
382
- });
383
- it("reports missing prefab references", () => {
384
- const result = validateFixtureMutation((document) => {
385
- document.scenes[0].nodes[1] = {
386
- ...document.scenes[0].nodes[1],
387
- type: "prefab-instance",
388
- prefabId: stableId(99),
389
- };
390
- });
391
- expect(result.issues.some((issue) => issue.code === "MISSING_PREFAB_REFERENCE")).toBe(true);
392
- });
393
- it("reports inconsistent parent and children", () => {
394
- const result = validateFixtureMutation((document) => {
395
- document.scenes[0].nodes[1].parentId = null;
396
- });
397
- expect(result.issues.some((issue) => issue.code === "HIERARCHY_PARENT_MISMATCH")).toBe(true);
398
- });
399
- it("reports cycles", () => {
400
- const result = validateFixtureMutation((document) => {
401
- const nodes = document.scenes[0].nodes;
402
- nodes[0].parentId = nodes[1].id;
403
- nodes[1].children = [nodes[0].id];
404
- });
405
- expect(result.issues.some((issue) => issue.code === "HIERARCHY_CYCLE")).toBe(true);
406
- });
407
- it("reports duplicate binding keys", () => {
408
- const result = validateFixtureMutation((document) => {
409
- document.scenes[0].nodes[0].bindingKey = "target";
410
- document.scenes[0].nodes[1].bindingKey = "target";
411
- });
412
- expect(result.issues.some((issue) => issue.code === "DUPLICATE_BINDING_KEY")).toBe(true);
413
- });
414
- it("rejects an incomplete spine asset", () => {
415
- const result = validateFixtureMutation((document) => {
416
- document.assets[0] = {
417
- id: stableId(5),
418
- name: "Hero",
419
- type: "spine",
420
- files: {
421
- skeleton: { name: "hero.json", uri: "hero.json", mediaType: "application/json" },
422
- textures: [{ name: "hero.png", uri: "hero.png", mediaType: "image/png" }],
423
- },
424
- };
425
- });
426
- expect(result.issues.some((issue) => issue.code === "STRUCTURAL_SCHEMA")).toBe(true);
427
- });
428
- it("rejects unknown profile keys and schema versions", () => {
429
- const result = validateFixtureMutation((document) => {
430
- document.scenes[0].nodes[0].layoutOverrides = { tablet: {} };
431
- document.schemaVersion = 0;
432
- });
433
- expect(result.issues.some((issue) => issue.code === "STRUCTURAL_SCHEMA")).toBe(true);
434
- });
435
- it("clones and validates the current version without mutating input", () => {
436
- const input = createProjectDocumentFixture();
437
- const output = migrateProjectDocument(input);
438
- expect(output).toEqual(input);
439
- expect(output).not.toBe(input);
440
- output.project.name = "Changed";
441
- expect(input.project.name).toBe("Project");
442
- });
443
- it("rejects non-finite numbers", () => {
444
- const result = validateFixtureMutation((document) => {
445
- document.scenes[0].nodes[0].transform.x = Number.NaN;
446
- });
447
- expect(result.issues.some((issue) => issue.code === "NON_FINITE_NUMBER")).toBe(true);
448
- });
449
- it("serializes deterministically without mutating the document", () => {
450
- const input = createProjectDocumentFixture();
451
- const before = structuredClone(input);
452
- const reordered = Object.fromEntries(Object.entries(input).reverse());
453
- expect(serializeProjectDocument(input)).toBe(serializeProjectDocument(reordered));
454
- expect(serializeProjectDocument(input).endsWith("\n")).toBe(true);
455
- expect(input).toEqual(before);
456
- });
457
- });
458
- //# sourceMappingURL=index.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,GAExB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,4BAA4B,EAC5B,QAAQ,EACR,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAElC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,uBAAuB,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACvG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAC7B,MAAM,IAAI,GAAG;YACX,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC;YAChB,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,MAAe;YACrB,QAAQ,EAAE,IAAI,CAAC,EAAE;YACjB,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;SACtF,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAE9E,QAAsC,CAAC,aAAa,GAAG,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iGAAiG,EAAE,GAAG,EAAE;QACzG,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QACpC,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QACtE,cAAc,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QACjC,cAAc,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC/B,MAAM,CAAC,WAAW,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,GAAG,CAAC,cAAc,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,IAAI,CAAC;YAC7B,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,iBAAiB;YACvB,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,QAAQ,EAAE,IAAI,CAAC,EAAE;YACjB,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;YACrF,iBAAiB,EAAE,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,EAAE,CAAC;YACvF,iBAAiB,EAAE,CAAC;oBAClB,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI;oBACxH,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;iBACpF,CAAC;SACH,CAAC,CAAC;QACH,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE3D,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC;QACnD,IAAI,QAAQ,CAAC,IAAI,KAAK,iBAAiB;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QACtF,QAAQ,CAAC,iBAAkB,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC;QACpD,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3H,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,UAAU,GAAG,GAAG,CAAC;QACzD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACvD,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE3D,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,UAAU,GAAG,GAAG,CAAC;QACzD,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC;QAC1D,SAAS,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAEtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,QAAQ,GAAG,4BAA4B,EAAwC,CAAC;QACtF,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC;QAC3B,MAAM,UAAU,GAAG,QAAsC,CAAC;QAC1D,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAoC,CAAC;QACvF,SAAS,CAAC,OAAO,GAAG,GAAG,CAAC;QACxB,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC;QACtB,UAAU,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,eAAe,GAAG,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAW,EAAE,EAAE,CAAC;QAExG,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QAClI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC9E,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3H,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,aAAa,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,GAAG,EAAE;QAC5F,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;YACnB,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,EAAE,SAAS,EAAE,kBAAkB,EAAE;gBACvF,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,mBAAmB,EAAE,SAAS,EAAE,YAAY,EAAE;gBAChF,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;aACjF;SACF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,cAAc,GAAG,UAAU,CAAC;QAE1C,MAAM,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,IAAI,EAAE,yCAAyC,EAAE,CAAC,CAAC,CAAC;IACnI,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kFAAkF,EAAE,GAAG,EAAE;QAC1F,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAE/E,QAAQ,CAAC,MAAM,CAAC,qBAAqB,GAAG,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC;QACzE,QAAQ,CAAC,MAAM,CAAC,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC;QACrE,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4FAA4F,EAAE,GAAG,EAAE;QACpG,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;YACnB,EAAE,EAAE,UAAU;YACd,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,EAAE,SAAS,EAAE,kBAAkB,EAAE;gBACvF,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,mBAAmB,EAAE,SAAS,EAAE,YAAY,EAAE;gBAChF,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;aACjF;SACF,CAAC,CAAC;QACH,QAAQ,CAAC,MAAM,CAAC,mBAAmB,GAAG,UAAU,CAAC;QAEjD,MAAM,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,IAAI,EAAE,8CAA8C,EAAE,CAAC,CAAC,CAAC;IACxI,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC;QAC1D,QAAsC,CAAC,aAAa,GAAG,CAAC,CAAC;QAE1D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC;QAC1D,QAAsC,CAAC,aAAa,GAAG,CAAC,CAAC;QAE1D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC;QAC1D,QAAsC,CAAC,aAAa,GAAG,CAAC,CAAC;QAE1D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;gBACnB,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAChB,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,OAAO;gBACb,MAAM,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;aAC5C,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC;QAC1D,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QACrB,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC;QACxB,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,kBAAkB,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC1F,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC;QAC1D,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,KAAK,GAAG,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC;QACvD,QAAsC,CAAC,aAAa,GAAG,CAAC,CAAC;QAC1D,OAAQ,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,MAAuD,CAAC,kBAAkB,CAAC;QAEvG,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAElD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAClF,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,QAAQ,GAAG,4BAA4B,EAAwC,CAAC;QACtF,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,QAAsC,CAAC;QACrD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAA+C,CAAC;QAC7F,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC;QAClB,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;QACrB,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC;QACtB,SAAS,CAAC,cAAc,GAAG;YACzB,IAAI,EAAE,sBAAsB;YAC5B,oBAAoB,EAAE,IAAI;YAC1B,qBAAqB,EAAE,IAAI;SAC5B,CAAC;QAEF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAA+C,CAAC;QAExG,MAAM,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;QAC/D,MAAM,CAAC,iBAAiB,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAC/C,QAAsC,CAAC,aAAa,GAAG,CAAC,CAAC;QAC1D,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACtF,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACtF,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC;QAC1D,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC;QAClB,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC;QAClB,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;QACrB,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC;QAEtB,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAElD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC;YAC5D,CAAC,EAAE,EAAE;YACL,CAAC,EAAE,GAAG;YACN,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,EAAE;SACX,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAC/C,QAAsC,CAAC,aAAa,GAAG,EAAE,CAAC;QAC3D,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC;QAC1D,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC;QACvB,SAAS,CAAC,CAAC,GAAG,EAAE,CAAC;QACjB,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;QAErB,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAElD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC;YAC5D,CAAC,EAAE,EAAE,GAAG,IAAI,GAAG,GAAG;YAClB,KAAK,EAAE,EAAE,GAAG,IAAI;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAC/C,QAAsC,CAAC,aAAa,GAAG,EAAE,CAAC;QAE3D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAElD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC,CAAC,aAAa,EAAE,CAAC;QACjE,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,GAAG,EAAE;QAC9F,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QACpC,MAAM,YAAY,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,WAAW,GAAG,CAAC,YAAY,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,GAAG,CAAC;gBACd,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI;gBACzH,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;gBACnM,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;aACrF,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/B,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,IAAI,CAAC;YAC7B,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI;YAC9H,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;YACpF,iBAAiB,EAAE,CAAC;oBAClB,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI;oBACvH,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;oBACtM,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;iBACpF,CAAC;SACH,CAAC,CAAC;QACH,MAAM,cAAc,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9F,QAAsC,CAAC,aAAa,GAAG,EAAE,CAAC;QAE3D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAElD,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACvF,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,IAAI,CAAC;YAC7B,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI;YACjH,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;YACnM,kBAAkB,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YACjE,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;SACrF,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,mBAAmB,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChV,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,IAAI,CAAC;YAC7B,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;YACjI,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,EAAE;YAC5F,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;SACtI,CAAC,CAAC;QAEH,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,GAAG,IAAI,CAAC;QAE5C,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAE9D,MAAM,MAAM,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,IAAI,EAAE,uCAAuC,EAAE,CAAC,CAAC,CAAC;IACjI,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;QAChD,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;gBACnB,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAChB,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,mBAAmB,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE;gBAChG,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;aAC5B,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;gBACnB,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAChB,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE;oBACL,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,mBAAmB,EAAE,SAAS,EAAE,kBAAkB,EAAE;oBACrF,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE;iBAChF;aACO,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,6BAA6B,EAAE,CAAC,OAAO,EAAE,EAAE;QACxE,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,OAAQ,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,kBAA8C,CAAC,OAAO,CAAC,CAAC;QAC7F,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;QACtE,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,QAAQ,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YACvD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAyB,CAAC,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CACtD,MAAM,CAAC,eAAe,CAAC,CAAC,yBAAyB,EAAE,yBAAyB,CAAC,CAAC,CAC/E,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG;gBAC7B,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE;gBAChC,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;aACvB,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC;YACxC,KAAK,CAAC,CAAC,CAAE,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,CAAC,CAAE,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,GAAG,QAAQ,CAAC;YACpD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,GAAG,QAAQ,CAAC;QACtD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG;gBACnB,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;gBACf,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE;oBACL,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,kBAAkB,EAAE;oBAChF,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;iBAC1E;aACO,CAAC;QACb,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,eAAe,GAAG,EAAE,MAAM,EAAE,EAAE,EAAW,CAAC;YACvE,QAAsC,CAAC,aAAa,GAAG,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,KAAK,GAAG,4BAA4B,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;QACzD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,KAAK,GAAG,4BAA4B,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAoB,CAAC;QAEzF,MAAM,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\r\nimport {\r\n CURRENT_SCHEMA_VERSION,\r\n createStableId,\r\n migrateProjectDocument,\r\n serializeProjectDocument,\r\n validateProjectDocument,\r\n type ProjectDocument,\r\n} from \"./index.js\";\r\nimport {\r\n addAtlasAssetWithFrame,\r\n addButtonNode,\r\n addCheckboxNode,\r\n createProjectDocumentFixture,\r\n stableId,\r\n validateFixtureMutation,\r\n} from \"./index.test-fixtures.js\";\r\n\r\ndescribe(\"schema v1\", () => {\r\n it(\"generates independent UUID stable IDs\", () => {\r\n const first = createStableId();\r\n const second = createStableId();\r\n expect(first).toMatch(/^[0-9a-f]{8}-/i);\r\n expect(first).not.toBe(second);\r\n });\r\n\r\n it(\"accepts a minimal valid document\", () => {\r\n expect(validateProjectDocument(createProjectDocumentFixture())).toEqual({ valid: true, issues: [] });\r\n });\r\n\r\n it(\"accepts a rectangular mask node and migrates v20 without rewriting its graph\", () => {\r\n const document = createProjectDocumentFixture();\r\n const scene = document.scenes[0]!;\r\n const root = scene.nodes[0]!;\r\n const mask = {\r\n id: stableId(90),\r\n name: \"Viewport mask\",\r\n type: \"mask\" as const,\r\n parentId: root.id,\r\n children: [],\r\n visible: true,\r\n transform: { x: 0, y: 0, width: 320, height: 180, scaleX: 1, scaleY: 1, rotation: 0 },\r\n };\r\n root.children.push(mask.id);\r\n scene.nodes.push(mask);\r\n expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });\r\n\r\n (document as { schemaVersion: number }).schemaVersion = 20;\r\n const before = structuredClone({ scenes: document.scenes, prefabs: document.prefabs });\r\n const migrated = migrateProjectDocument(document);\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect({ scenes: migrated.scenes, prefabs: migrated.prefabs }).toEqual(before);\r\n });\r\n\r\n it(\"accepts prefab property overrides and local children while rejecting structural inherited edits\", () => {\r\n const document = createProjectDocumentFixture();\r\n const prefab = document.prefabs[0]!;\r\n const definitionNode = structuredClone(document.scenes[0]!.nodes[1]!);\r\n definitionNode.id = stableId(60);\r\n definitionNode.parentId = null;\r\n prefab.rootNodeIds = [definitionNode.id];\r\n prefab.nodes = [definitionNode];\r\n const root = document.scenes[0]!.nodes[0]!;\r\n const instanceId = stableId(61);\r\n root.children.push(instanceId);\r\n document.scenes[0]!.nodes.push({\r\n id: instanceId,\r\n name: \"Badge\",\r\n type: \"prefab-instance\",\r\n prefabId: prefab.id,\r\n parentId: root.id,\r\n children: [],\r\n visible: true,\r\n transform: { x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1, rotation: 0 },\r\n propertyOverrides: [{ nodeId: definitionNode.id, patch: { name: \"Configured badge\" } }],\r\n locallyAddedNodes: [{\r\n id: stableId(62), name: \"Caption\", type: \"text\", text: \"Local\", parentId: definitionNode.id, children: [], visible: true,\r\n transform: { x: 0, y: 0, width: 80, height: 20, scaleX: 1, scaleY: 1, rotation: 0 },\r\n }],\r\n });\r\n expect(validateProjectDocument(document).valid).toBe(true);\r\n\r\n const instance = document.scenes[0]!.nodes.at(-1)!;\r\n if (instance.type !== \"prefab-instance\") throw new Error(\"Expected prefab instance.\");\r\n instance.propertyOverrides![0]!.patch.children = [];\r\n expect(validateProjectDocument(document).issues.some((issue) => issue.code === \"STRUCTURAL_PREFAB_OVERRIDE\")).toBe(true);\r\n });\r\n\r\n it(\"accepts normalized anchors and rejects values outside the parent rectangle\", () => {\r\n const document = createProjectDocumentFixture();\r\n document.scenes[0]!.nodes[1]!.transform.anchorMinX = 0.5;\r\n document.scenes[0]!.nodes[1]!.transform.anchorMinY = 1;\r\n expect(validateProjectDocument(document).valid).toBe(true);\r\n\r\n document.scenes[0]!.nodes[1]!.transform.anchorMinX = 1.1;\r\n expect(validateProjectDocument(document).issues[0]!.code).toBe(\"STRUCTURAL_SCHEMA\");\r\n });\r\n\r\n it(\"requires positive sizeDelta on a point-anchor axis\", () => {\r\n const document = createProjectDocumentFixture();\r\n const transform = document.scenes[0]!.nodes[1]!.transform;\r\n transform.width = -20;\r\n expect(validateProjectDocument(document).issues[0]!.code).toBe(\"NON_POSITIVE_SIZE\");\r\n\r\n });\r\n\r\n it(\"migrates v1 point anchors to v2 anchorMin/anchorMax pairs\", () => {\r\n const document = createProjectDocumentFixture() as unknown as Record<string, unknown>;\r\n document.schemaVersion = 1;\r\n const v1Document = document as unknown as ProjectDocument;\r\n const transform = v1Document.scenes[0]!.nodes[1]!.transform as Record<string, unknown>;\r\n transform.anchorX = 0.5;\r\n transform.anchorY = 1;\r\n v1Document.scenes[0]!.nodes[1]!.layoutOverrides = { mobile: { transform: { anchorX: 0.25 } as never } };\r\n\r\n const migrated = migrateProjectDocument(document);\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect(migrated.scenes[0]!.nodes[1]!.transform).toMatchObject({ anchorMinX: 0.5, anchorMaxX: 0.5, anchorMinY: 1, anchorMaxY: 1 });\r\n expect(migrated.scenes[0]!.nodes[1]!.transform).not.toHaveProperty(\"anchorX\");\r\n expect(migrated.scenes[0]!.nodes[1]!.layoutOverrides?.mobile?.transform).toEqual({ anchorMinX: 0.25, anchorMaxX: 0.25 });\r\n });\r\n\r\n it(\"accepts a button whose four states reference image assets\", () => {\r\n const document = createProjectDocumentFixture();\r\n addButtonNode(document);\r\n expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });\r\n });\r\n\r\n it(\"reports the offending state field when a button state references a non-image asset\", () => {\r\n const document = createProjectDocumentFixture();\r\n const button = addButtonNode(document);\r\n const spineAsset = stableId(30);\r\n document.assets.push({\r\n id: spineAsset,\r\n name: \"Hero\",\r\n type: \"spine\",\r\n files: {\r\n skeleton: { name: \"hero.json\", uri: \"assets/hero.json\", mediaType: \"application/json\" },\r\n atlas: { name: \"hero.atlas\", uri: \"assets/hero.atlas\", mediaType: \"text/plain\" },\r\n textures: [{ name: \"hero.png\", uri: \"assets/hero.png\", mediaType: \"image/png\" }],\r\n },\r\n });\r\n button.states.pressedAssetId = spineAsset;\r\n\r\n const result = validateProjectDocument(document);\r\n expect(result.issues).toMatchObject([{ code: \"INCOMPATIBLE_ASSET_REFERENCE\", path: \"/scenes/0/nodes/2/states/pressedAssetId\" }]);\r\n });\r\n\r\n it(\"accepts a checkbox without hover states, and accepts one with valid hover states\", () => {\r\n const document = createProjectDocumentFixture();\r\n const checkbox = addCheckboxNode(document);\r\n expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });\r\n\r\n checkbox.states.uncheckedHoverAssetId = checkbox.states.uncheckedAssetId;\r\n checkbox.states.checkedHoverAssetId = checkbox.states.checkedAssetId;\r\n expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });\r\n });\r\n\r\n it(\"reports the offending state field when a checkbox hover state references a non-image asset\", () => {\r\n const document = createProjectDocumentFixture();\r\n const checkbox = addCheckboxNode(document);\r\n const spineAsset = stableId(31);\r\n document.assets.push({\r\n id: spineAsset,\r\n name: \"Hero\",\r\n type: \"spine\",\r\n files: {\r\n skeleton: { name: \"hero.json\", uri: \"assets/hero.json\", mediaType: \"application/json\" },\r\n atlas: { name: \"hero.atlas\", uri: \"assets/hero.atlas\", mediaType: \"text/plain\" },\r\n textures: [{ name: \"hero.png\", uri: \"assets/hero.png\", mediaType: \"image/png\" }],\r\n },\r\n });\r\n checkbox.states.checkedHoverAssetId = spineAsset;\r\n\r\n const result = validateProjectDocument(document);\r\n expect(result.issues).toMatchObject([{ code: \"INCOMPATIBLE_ASSET_REFERENCE\", path: \"/scenes/0/nodes/2/states/checkedHoverAssetId\" }]);\r\n });\r\n\r\n it(\"migrates a v2 document to v3 without changing its existing nodes\", () => {\r\n const document = createProjectDocumentFixture();\r\n const v2Nodes = structuredClone(document.scenes[0]!.nodes);\r\n (document as { schemaVersion: number }).schemaVersion = 2;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect(migrated.scenes[0]!.nodes).toEqual(v2Nodes);\r\n });\r\n\r\n it(\"migrates a v3 document to v4 without changing its existing assets or nodes\", () => {\r\n const document = createProjectDocumentFixture();\r\n const v3Assets = structuredClone(document.assets);\r\n const v3Nodes = structuredClone(document.scenes[0]!.nodes);\r\n (document as { schemaVersion: number }).schemaVersion = 3;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect(migrated.assets).toEqual(v3Assets);\r\n expect(migrated.scenes[0]!.nodes).toEqual(v3Nodes);\r\n });\r\n\r\n it(\"migrates a v4 document to v5 without changing its existing assets or nodes\", () => {\r\n const document = createProjectDocumentFixture();\r\n const v4Assets = structuredClone(document.assets);\r\n const v4Nodes = structuredClone(document.scenes[0]!.nodes);\r\n (document as { schemaVersion: number }).schemaVersion = 4;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect(migrated.assets).toEqual(v4Assets);\r\n expect(migrated.scenes[0]!.nodes).toEqual(v4Nodes);\r\n });\r\n\r\n it(\"rejects a sound asset with an empty source uri\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.assets.push({\r\n id: stableId(45),\r\n name: \"Click\",\r\n type: \"sound\",\r\n source: { uri: \"\", mediaType: \"audio/wav\" },\r\n });\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"STRUCTURAL_SCHEMA\")).toBe(true);\r\n });\r\n\r\n it(\"allows zero or negative sizeDelta on a stretched axis\", () => {\r\n const document = createProjectDocumentFixture();\r\n const transform = document.scenes[0]!.nodes[1]!.transform;\r\n transform.anchorMinY = 0;\r\n transform.anchorMaxY = 1;\r\n transform.height = 0;\r\n expect(validateProjectDocument(document).valid).toBe(true);\r\n transform.height = -100;\r\n expect(validateProjectDocument(document).valid).toBe(true);\r\n });\r\n\r\n it(\"migrates v7 reference viewports through the v11 Unity sizeDelta contract\", () => {\r\n const document = createProjectDocumentFixture();\r\n const referenceViewports = structuredClone(document.scenes[0]!.layout.referenceViewports);\r\n const transform = document.scenes[0]!.nodes[1]!.transform;\r\n transform.anchorMinX = 0;\r\n transform.anchorMaxX = 1;\r\n transform.width = 50 - referenceViewports.desktop.width;\r\n (document as { schemaVersion: number }).schemaVersion = 7;\r\n delete (document.scenes[0]!.layout as Partial<typeof document.scenes[0][\"layout\"]>).preferredViewports;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n\r\n expect(migrated.scenes[0]!.layout.preferredViewports).toEqual(referenceViewports);\r\n expect(migrated.scenes[0]!.nodes[1]!.transform.width).toBe(50 - referenceViewports.desktop.width);\r\n });\r\n\r\n it(\"removes the v8 responsive toggle while preserving its preferred-space rect\", () => {\r\n const document = createProjectDocumentFixture() as unknown as Record<string, unknown>;\r\n document.schemaVersion = 8;\r\n const typed = document as unknown as ProjectDocument;\r\n const transform = typed.scenes[0]!.nodes[1]!.transform as unknown as Record<string, unknown>;\r\n transform.anchorMinY = 0;\r\n transform.anchorMaxY = 1;\r\n transform.y = 515;\r\n transform.width = 50;\r\n transform.height = 50;\r\n transform.responsiveSize = {\r\n mode: \"scale-stretched-axes\",\r\n referenceParentWidth: 1920,\r\n referenceParentHeight: 1080,\r\n };\r\n\r\n const migrated = migrateProjectDocument(document);\r\n const migratedTransform = migrated.scenes[0]!.nodes[1]!.transform as unknown as Record<string, unknown>;\r\n\r\n expect(migratedTransform).not.toHaveProperty(\"responsiveSize\");\r\n expect(migratedTransform).toMatchObject({ y: 515, width: 50, height: 50 - 1080 });\r\n });\r\n\r\n it(\"migrates v9 point-anchor rects into the preferred coordinate space\", () => {\r\n const document = createProjectDocumentFixture();\r\n (document as { schemaVersion: number }).schemaVersion = 9;\r\n document.scenes[0]!.layout.referenceViewports.desktop = { width: 3840, height: 2160 };\r\n document.scenes[0]!.layout.preferredViewports.desktop = { width: 1920, height: 1080 };\r\n const transform = document.scenes[0]!.nodes[1]!.transform;\r\n transform.x = 100;\r\n transform.y = 200;\r\n transform.width = 50;\r\n transform.height = 80;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n\r\n expect(migrated.scenes[0]!.nodes[1]!.transform).toMatchObject({\r\n x: 50,\r\n y: 100,\r\n width: 25,\r\n height: 40,\r\n });\r\n });\r\n\r\n it(\"migrates a v10 absolute stretch rect to anchoredPosition and sizeDelta\", () => {\r\n const document = createProjectDocumentFixture();\r\n (document as { schemaVersion: number }).schemaVersion = 10;\r\n const transform = document.scenes[0]!.nodes[1]!.transform;\r\n transform.anchorMinX = 0;\r\n transform.anchorMaxX = 1;\r\n transform.pivotX = 0.5;\r\n transform.x = 25;\r\n transform.width = 50;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n\r\n expect(migrated.scenes[0]!.nodes[1]!.transform).toMatchObject({\r\n x: 25 - 1920 * 0.5,\r\n width: 50 - 1920,\r\n });\r\n });\r\n\r\n it(\"migrates v11 documents with editor-only disabled by default\", () => {\r\n const document = createProjectDocumentFixture();\r\n (document as { schemaVersion: number }).schemaVersion = 11;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect(migrated.scenes[0]!.nodes[0]!.editorOnly).toBeUndefined();\r\n expect(validateProjectDocument(migrated).valid).toBe(true);\r\n });\r\n\r\n it(\"migrates v18 base presentation values without changing scene, prefab, or local nodes\", () => {\r\n const document = createProjectDocumentFixture();\r\n const prefab = document.prefabs[0]!;\r\n const definitionId = stableId(70);\r\n prefab.rootNodeIds = [definitionId];\r\n prefab.nodes = [{\r\n id: definitionId, name: \"Definition label\", type: \"text\", text: \"Definition\", parentId: null, children: [], visible: true,\r\n style: { fontFamily: \"Arial\", fontSize: 20, fontWeight: \"normal\", fontStyle: \"normal\", fill: \"#FFFFFF\", align: \"left\", verticalAlign: \"top\", wordWrap: false, breakWords: false, letterSpacing: 0 },\r\n transform: { x: 0, y: 0, width: 100, height: 30, scaleX: 1, scaleY: 1, rotation: 0 },\r\n }];\r\n const root = document.scenes[0]!.nodes[0]!;\r\n const instanceId = stableId(71);\r\n root.children.push(instanceId);\r\n document.scenes[0]!.nodes.push({\r\n id: instanceId, name: \"Instance\", type: \"prefab-instance\", prefabId: prefab.id, parentId: root.id, children: [], visible: true,\r\n transform: { x: 0, y: 0, width: 100, height: 30, scaleX: 1, scaleY: 1, rotation: 0 },\r\n locallyAddedNodes: [{\r\n id: stableId(72), name: \"Local label\", type: \"text\", text: \"Local\", parentId: definitionId, children: [], visible: true,\r\n style: { fontFamily: \"Arial\", fontSize: 18, fontWeight: \"bold\", fontStyle: \"normal\", fill: \"#FFFFFF\", align: \"center\", verticalAlign: \"middle\", wordWrap: false, breakWords: false, letterSpacing: 1 },\r\n transform: { x: 0, y: 0, width: 80, height: 20, scaleX: 1, scaleY: 1, rotation: 0 },\r\n }],\r\n });\r\n const previousOwners = structuredClone({ scenes: document.scenes, prefabs: document.prefabs });\r\n (document as { schemaVersion: number }).schemaVersion = 18;\r\n\r\n const migrated = migrateProjectDocument(document);\r\n\r\n expect(migrated.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);\r\n expect({ scenes: migrated.scenes, prefabs: migrated.prefabs }).toEqual(previousOwners);\r\n expect(validateProjectDocument(migrated)).toEqual({ valid: true, issues: [] });\r\n });\r\n\r\n it(\"validates sparse text and Spine presentation overrides\", () => {\r\n const document = createProjectDocumentFixture();\r\n const root = document.scenes[0]!.nodes[0]!;\r\n const textId = stableId(73);\r\n root.children.push(textId);\r\n document.scenes[0]!.nodes.push({\r\n id: textId, name: \"Responsive label\", type: \"text\", text: \"Label\", parentId: root.id, children: [], visible: true,\r\n style: { fontFamily: \"Arial\", fontSize: 24, fontWeight: \"normal\", fontStyle: \"normal\", fill: \"#FFFFFF\", align: \"left\", verticalAlign: \"top\", wordWrap: false, breakWords: false, letterSpacing: 0 },\r\n textStyleOverrides: { mobile: { fontSize: 36, align: \"center\" } },\r\n transform: { x: 0, y: 0, width: 200, height: 60, scaleX: 1, scaleY: 1, rotation: 0 },\r\n });\r\n const spineAssetId = stableId(74);\r\n document.assets.push({ id: spineAssetId, name: \"Hero\", type: \"spine\", files: { skeleton: { name: \"hero.json\", uri: \"assets/hero.json\", mediaType: \"application/json\" }, atlas: { name: \"hero.atlas\", uri: \"assets/hero.atlas\", mediaType: \"text/plain\" }, textures: [{ name: \"hero.png\", uri: \"assets/hero.png\", mediaType: \"image/png\" }] } });\r\n const spineId = stableId(75);\r\n root.children.push(spineId);\r\n document.scenes[0]!.nodes.push({\r\n id: spineId, name: \"Hero\", type: \"spine\", assetId: spineAssetId, animation: \"idle\", autoplay: true, loop: true, animationSpeed: 1,\r\n spineOverrides: { mobile: { animation: \"portrait-idle\", loop: false, animationSpeed: 0.8 } },\r\n parentId: root.id, children: [], visible: true, transform: { x: 0, y: 0, width: 200, height: 200, scaleX: 1, scaleY: 1, rotation: 0 },\r\n });\r\n\r\n expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });\r\n });\r\n\r\n it(\"accepts persistent editor lock metadata without changing runtime node fields\", () => {\r\n const document = createProjectDocumentFixture();\r\n document.scenes[0]!.nodes[0]!.locked = true;\r\n\r\n expect(validateProjectDocument(document).valid).toBe(true);\r\n expect(migrateProjectDocument(document).scenes[0]!.nodes[0]!.locked).toBe(true);\r\n });\r\n\r\n it(\"rejects a button press sound that references an image asset\", () => {\r\n const document = createProjectDocumentFixture();\r\n const button = addButtonNode(document);\r\n button.sounds = { pressAssetId: button.states.normalAssetId };\r\n\r\n const result = validateProjectDocument(document);\r\n expect(result.issues).toMatchObject([{ code: \"INCOMPATIBLE_ASSET_REFERENCE\", path: \"/scenes/0/nodes/2/sounds/pressAssetId\" }]);\r\n });\r\n\r\n it(\"accepts an image node whose assetId is an atlas frame id\", () => {\r\n const document = createProjectDocumentFixture();\r\n addAtlasAssetWithFrame(document);\r\n expect(validateProjectDocument(document)).toEqual({ valid: true, issues: [] });\r\n });\r\n\r\n it(\"rejects an atlas asset with an incomplete files object\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.assets.push({\r\n id: stableId(42),\r\n name: \"Broken atlas\",\r\n type: \"atlas\",\r\n files: { json: { name: \"atlas.json\", uri: \"assets/atlas.json\", mediaType: \"application/json\" } },\r\n frames: { \"icon.png\": stableId(43) },\r\n } as never);\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"STRUCTURAL_SCHEMA\")).toBe(true);\r\n });\r\n\r\n it(\"rejects an atlas asset without a frames map\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.assets.push({\r\n id: stableId(44),\r\n name: \"Broken atlas\",\r\n type: \"atlas\",\r\n files: {\r\n json: { name: \"atlas.json\", uri: \"assets/atlas.json\", mediaType: \"application/json\" },\r\n texture: { name: \"atlas.png\", uri: \"assets/atlas.png\", mediaType: \"image/png\" },\r\n },\r\n } as never);\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"STRUCTURAL_SCHEMA\")).toBe(true);\r\n });\r\n\r\n it.each([\"desktop\", \"mobile\"])(\"rejects missing %s viewport\", (profile) => {\r\n const result = validateFixtureMutation((document) => {\r\n delete (document.scenes[0]!.layout.referenceViewports as Record<string, unknown>)[profile];\r\n });\r\n expect(result.issues[0]!.code).toBe(\"STRUCTURAL_SCHEMA\");\r\n });\r\n\r\n it(\"reports duplicate IDs\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[1]!.id = document.scenes[0]!.nodes[0]!.id;\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"DUPLICATE_ID\")).toBe(true);\r\n });\r\n\r\n it(\"reports missing child and asset references\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[0]!.children = [stableId(99)];\r\n (document.scenes[0]!.nodes[1] as { assetId: string }).assetId = stableId(98);\r\n });\r\n expect(result.issues.map((issue) => issue.code)).toEqual(\r\n expect.arrayContaining([\"MISSING_CHILD_REFERENCE\", \"MISSING_ASSET_REFERENCE\"]),\r\n );\r\n });\r\n\r\n it(\"reports missing prefab references\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[1] = {\r\n ...document.scenes[0]!.nodes[1]!,\r\n type: \"prefab-instance\",\r\n prefabId: stableId(99),\r\n };\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"MISSING_PREFAB_REFERENCE\")).toBe(true);\r\n });\r\n\r\n it(\"reports inconsistent parent and children\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[1]!.parentId = null;\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"HIERARCHY_PARENT_MISMATCH\")).toBe(true);\r\n });\r\n\r\n it(\"reports cycles\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n const nodes = document.scenes[0]!.nodes;\r\n nodes[0]!.parentId = nodes[1]!.id;\r\n nodes[1]!.children = [nodes[0]!.id];\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"HIERARCHY_CYCLE\")).toBe(true);\r\n });\r\n\r\n it(\"reports duplicate binding keys\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[0]!.bindingKey = \"target\";\r\n document.scenes[0]!.nodes[1]!.bindingKey = \"target\";\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"DUPLICATE_BINDING_KEY\")).toBe(true);\r\n });\r\n\r\n it(\"rejects an incomplete spine asset\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.assets[0] = {\r\n id: stableId(5),\r\n name: \"Hero\",\r\n type: \"spine\",\r\n files: {\r\n skeleton: { name: \"hero.json\", uri: \"hero.json\", mediaType: \"application/json\" },\r\n textures: [{ name: \"hero.png\", uri: \"hero.png\", mediaType: \"image/png\" }],\r\n },\r\n } as never;\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"STRUCTURAL_SCHEMA\")).toBe(true);\r\n });\r\n\r\n it(\"rejects unknown profile keys and schema versions\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[0]!.layoutOverrides = { tablet: {} } as never;\r\n (document as { schemaVersion: number }).schemaVersion = 0;\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"STRUCTURAL_SCHEMA\")).toBe(true);\r\n });\r\n\r\n it(\"clones and validates the current version without mutating input\", () => {\r\n const input = createProjectDocumentFixture();\r\n const output = migrateProjectDocument(input);\r\n expect(output).toEqual(input);\r\n expect(output).not.toBe(input);\r\n output.project.name = \"Changed\";\r\n expect(input.project.name).toBe(\"Project\");\r\n });\r\n\r\n it(\"rejects non-finite numbers\", () => {\r\n const result = validateFixtureMutation((document) => {\r\n document.scenes[0]!.nodes[0]!.transform.x = Number.NaN;\r\n });\r\n expect(result.issues.some((issue) => issue.code === \"NON_FINITE_NUMBER\")).toBe(true);\r\n });\r\n\r\n it(\"serializes deterministically without mutating the document\", () => {\r\n const input = createProjectDocumentFixture();\r\n const before = structuredClone(input);\r\n const reordered = Object.fromEntries(Object.entries(input).reverse()) as ProjectDocument;\r\n\r\n expect(serializeProjectDocument(input)).toBe(serializeProjectDocument(reordered));\r\n expect(serializeProjectDocument(input).endsWith(\"\\n\")).toBe(true);\r\n expect(input).toEqual(before);\r\n });\r\n});\r\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=manifest.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifest.test.d.ts","sourceRoot":"","sources":["../src/manifest.test.ts"],"names":[],"mappings":""}