pixifact 0.1.3 → 0.1.4
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 +3 -3
- package/dist/builtin-scenes/CenterContainer.d.ts +13 -0
- package/dist/builtin-scenes/CenterContainer.js +71 -0
- package/dist/builtin-scenes/CenterContainer.scene +3 -0
- package/dist/builtin-scenes/CenterContainer.ts +77 -0
- package/dist/builtin-scenes/Control.d.ts +44 -0
- package/dist/builtin-scenes/Control.js +206 -0
- package/dist/builtin-scenes/Control.scene +3 -0
- package/dist/builtin-scenes/Control.ts +233 -0
- package/dist/builtin-scenes/FlexItem.d.ts +45 -0
- package/dist/builtin-scenes/FlexItem.js +164 -0
- package/dist/builtin-scenes/FlexItem.scene +3 -0
- package/dist/builtin-scenes/FlexItem.ts +180 -0
- package/dist/builtin-scenes/FlexLayout.d.ts +29 -0
- package/dist/builtin-scenes/FlexLayout.js +358 -0
- package/dist/builtin-scenes/FlexLayout.scene +3 -0
- package/dist/builtin-scenes/FlexLayout.ts +409 -0
- package/dist/builtin-scenes/HBoxContainer.d.ts +15 -0
- package/dist/builtin-scenes/HBoxContainer.js +70 -0
- package/dist/builtin-scenes/HBoxContainer.scene +3 -0
- package/dist/builtin-scenes/HBoxContainer.ts +75 -0
- package/dist/builtin-scenes/MarginContainer.d.ts +23 -0
- package/dist/builtin-scenes/MarginContainer.js +131 -0
- package/dist/builtin-scenes/MarginContainer.scene +3 -0
- package/dist/builtin-scenes/MarginContainer.ts +139 -0
- package/dist/builtin-scenes/VBoxContainer.d.ts +15 -0
- package/dist/builtin-scenes/VBoxContainer.js +70 -0
- package/dist/builtin-scenes/VBoxContainer.scene +3 -0
- package/dist/builtin-scenes/VBoxContainer.ts +75 -0
- package/dist/builtin-scenes/controlLayout.d.ts +57 -0
- package/dist/builtin-scenes/controlLayout.js +202 -0
- package/dist/builtin-scenes/controlLayout.ts +270 -0
- package/dist/compiler/builtinScenes.d.ts +14 -0
- package/dist/compiler/builtinScenes.js +62 -0
- package/dist/compiler/compileScenes.js +126 -19
- package/dist/compiler/decorators.js +3 -0
- package/dist/compiler/index.d.ts +1 -0
- package/dist/compiler/index.js +1 -0
- package/dist/compiler/sceneAssetPair.js +19 -0
- package/dist/compiler/sceneRuntime.d.ts +5 -4
- package/dist/compiler/scriptInterfaceExtractor.d.ts +5 -0
- package/dist/compiler/scriptInterfaceExtractor.js +214 -8
- package/dist/compiler/spec.d.ts +2 -0
- package/dist/compiler/templateParser.js +4 -3
- package/dist/compiler/templateSerializer.js +2 -1
- package/dist/compiler/typescriptCompiler.js +87 -13
- package/dist/compiler-node/builtinSceneAssets.d.ts +8 -0
- package/dist/compiler-node/builtinSceneAssets.js +57 -0
- package/dist/compiler-node/index.d.ts +1 -0
- package/dist/compiler-node/index.js +1 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.js +24 -0
- package/dist/index.d.ts +2 -5
- package/dist/index.js +2 -5
- package/dist/{authoring/ProjectConfig.d.ts → project/index.d.ts} +7 -0
- package/dist/{authoring/ProjectConfig.js → project/index.js} +22 -0
- package/dist/runtime/Group.d.ts +18 -0
- package/dist/runtime/Group.js +45 -0
- package/dist/runtime/index.d.ts +1 -9
- package/dist/runtime/index.js +1 -9
- package/package.json +4 -26
- package/dist/authoring/ActionRegistry.d.ts +0 -10
- package/dist/authoring/ActionRegistry.js +0 -26
- package/dist/authoring/ComponentPalette.d.ts +0 -16
- package/dist/authoring/ComponentPalette.js +0 -50
- package/dist/authoring/DesignToken.d.ts +0 -16
- package/dist/authoring/DesignToken.js +0 -33
- package/dist/authoring/DiffModel.d.ts +0 -10
- package/dist/authoring/DiffModel.js +0 -104
- package/dist/authoring/InspectorModel.d.ts +0 -27
- package/dist/authoring/InspectorModel.js +0 -139
- package/dist/authoring/LogicGraph.d.ts +0 -66
- package/dist/authoring/LogicGraph.js +0 -184
- package/dist/authoring/OverrideJournal.d.ts +0 -18
- package/dist/authoring/OverrideJournal.js +0 -23
- package/dist/authoring/PreferenceMemory.d.ts +0 -21
- package/dist/authoring/PreferenceMemory.js +0 -39
- package/dist/authoring/RuntimePreview.d.ts +0 -11
- package/dist/authoring/RuntimePreview.js +0 -25
- package/dist/authoring/SceneDocument.d.ts +0 -74
- package/dist/authoring/SceneDocument.js +0 -332
- package/dist/authoring/SceneProjectState.d.ts +0 -20
- package/dist/authoring/SceneProjectState.js +0 -8
- package/dist/authoring/SceneSelection.d.ts +0 -11
- package/dist/authoring/SceneSelection.js +0 -1
- package/dist/authoring/index.d.ts +0 -13
- package/dist/authoring/index.js +0 -13
- package/dist/commands/Command.d.ts +0 -63
- package/dist/commands/Command.js +0 -1
- package/dist/commands/CommandStack.d.ts +0 -14
- package/dist/commands/CommandStack.js +0 -45
- package/dist/commands/applyCommand.d.ts +0 -23
- package/dist/commands/applyCommand.js +0 -316
- package/dist/commands/index.d.ts +0 -4
- package/dist/commands/index.js +0 -4
- package/dist/commands/utils.d.ts +0 -17
- package/dist/commands/utils.js +0 -77
- package/dist/commands/validateCommand.d.ts +0 -12
- package/dist/commands/validateCommand.js +0 -285
- package/dist/nodes/Input.d.ts +0 -91
- package/dist/nodes/Input.js +0 -352
- package/dist/nodes/Textarea.d.ts +0 -10
- package/dist/nodes/Textarea.js +0 -38
- package/dist/nodes/components/Button.d.ts +0 -8
- package/dist/nodes/components/Button.js +0 -45
- package/dist/nodes/components/InputField.d.ts +0 -12
- package/dist/nodes/components/InputField.js +0 -53
- package/dist/nodes/components/ProgressBar.d.ts +0 -14
- package/dist/nodes/components/ProgressBar.js +0 -66
- package/dist/nodes/components/ScrollRect.d.ts +0 -23
- package/dist/nodes/components/ScrollRect.js +0 -108
- package/dist/nodes/components/Selectable.d.ts +0 -32
- package/dist/nodes/components/Selectable.js +0 -153
- package/dist/nodes/components/index.d.ts +0 -5
- package/dist/nodes/components/index.js +0 -5
- package/dist/nodes/graphics/Graphic.d.ts +0 -14
- package/dist/nodes/graphics/Graphic.js +0 -47
- package/dist/nodes/graphics/ImageGraphic.d.ts +0 -9
- package/dist/nodes/graphics/ImageGraphic.js +0 -42
- package/dist/nodes/graphics/RoundedRectGraphic.d.ts +0 -13
- package/dist/nodes/graphics/RoundedRectGraphic.js +0 -65
- package/dist/nodes/graphics/TextGraphic.d.ts +0 -13
- package/dist/nodes/graphics/TextGraphic.js +0 -70
- package/dist/nodes/graphics/index.d.ts +0 -4
- package/dist/nodes/graphics/index.js +0 -4
- package/dist/nodes/index.d.ts +0 -3
- package/dist/nodes/index.js +0 -3
- package/dist/runtime/Application.d.ts +0 -15
- package/dist/runtime/Application.js +0 -67
- package/dist/runtime/GameObject.d.ts +0 -100
- package/dist/runtime/GameObject.js +0 -297
- package/dist/runtime/GameObjectEvent.d.ts +0 -52
- package/dist/runtime/GameObjectEvent.js +0 -38
- package/dist/runtime/Transform.d.ts +0 -32
- package/dist/runtime/Transform.js +0 -157
- package/dist/runtime/component/Component.d.ts +0 -13
- package/dist/runtime/component/Component.js +0 -13
- package/dist/runtime/component/ComponentRegistry.d.ts +0 -49
- package/dist/runtime/component/ComponentRegistry.js +0 -25
- package/dist/runtime/component/Flex.d.ts +0 -6
- package/dist/runtime/component/Flex.js +0 -15
- package/dist/runtime/component/FlexGroup.d.ts +0 -26
- package/dist/runtime/component/FlexGroup.js +0 -136
- package/dist/runtime/component/GridLayout.d.ts +0 -47
- package/dist/runtime/component/GridLayout.js +0 -129
- package/dist/runtime/component/Layout.d.ts +0 -104
- package/dist/runtime/component/Layout.js +0 -248
- package/dist/runtime/component/decorators.d.ts +0 -4
- package/dist/runtime/component/decorators.js +0 -52
- package/dist/runtime/component/index.d.ts +0 -7
- package/dist/runtime/component/index.js +0 -7
- package/dist/runtime/graphics/index.d.ts +0 -11
- package/dist/runtime/graphics/index.js +0 -29
- package/dist/runtime/group/index.d.ts +0 -39
- package/dist/runtime/group/index.js +0 -102
- package/dist/runtime/image/Image.d.ts +0 -19
- package/dist/runtime/image/Image.js +0 -60
- package/dist/runtime/image/NineSliceImage.d.ts +0 -23
- package/dist/runtime/image/NineSliceImage.js +0 -64
- package/dist/runtime/image/index.d.ts +0 -2
- package/dist/runtime/image/index.js +0 -2
- package/dist/runtime/label/Label.d.ts +0 -11
- package/dist/runtime/label/Label.js +0 -26
- package/dist/runtime/label/LabelStyle.d.ts +0 -3
- package/dist/runtime/label/LabelStyle.js +0 -3
- package/dist/runtime/label/index.d.ts +0 -2
- package/dist/runtime/label/index.js +0 -2
- package/dist/runtime/utils/index.d.ts +0 -1
- package/dist/runtime/utils/index.js +0 -1
- package/dist/runtime/utils/onlyOnceQueueMicrotask.d.ts +0 -1
- package/dist/runtime/utils/onlyOnceQueueMicrotask.js +0 -12
- package/dist/runtime/utils/setProps.d.ts +0 -10
- package/dist/runtime/utils/setProps.js +0 -17
- package/dist/scene/dsl.d.ts +0 -25
- package/dist/scene/dsl.js +0 -112
- package/dist/scene/index.d.ts +0 -5
- package/dist/scene/index.js +0 -5
- package/dist/scene/instantiate.d.ts +0 -8
- package/dist/scene/instantiate.js +0 -208
- package/dist/scene/nodesDsl.d.ts +0 -42
- package/dist/scene/nodesDsl.js +0 -169
- package/dist/scene/spec.d.ts +0 -100
- package/dist/scene/spec.js +0 -1
- package/dist/scene/templates.d.ts +0 -21
- package/dist/scene/templates.js +0 -239
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { access, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { builtinSceneAssetIds, builtinSceneNameFromAssetId, isBuiltinSceneAssetId, } from './builtinScenes.js';
|
|
4
5
|
import { defaultSceneSourceRoots, generatedSceneModuleImport, generatedSceneModulePath, isIgnoredSceneSourceDirectory, normalizeSceneAssetId, pairedSceneScriptPath, resolveSceneReference, sceneClassAlias, sceneLocalName, toPosixPath, } from './sceneAssetPair.js';
|
|
5
|
-
import {
|
|
6
|
+
import { builtinSceneScriptPath, readBuiltinSceneScriptSources, readBuiltinSceneSource, } from '../compiler-node/builtinSceneAssets.js';
|
|
7
|
+
import { extractSceneScriptInterfaces } from './scriptInterfaceExtractor.js';
|
|
6
8
|
import { findMissingScenePartReferences } from './scenePartValidation.js';
|
|
7
9
|
import { parseSceneTemplate } from './templateParser.js';
|
|
8
10
|
import { compileSceneTemplateToTs } from './typescriptCompiler.js';
|
|
@@ -21,24 +23,48 @@ export async function compileScenes(options) {
|
|
|
21
23
|
? options.projectRoot
|
|
22
24
|
: fileURLToPath(options.projectRoot);
|
|
23
25
|
const generatedDir = path.resolve(projectRoot, options.generatedDir ?? '.pixifact/generated');
|
|
24
|
-
const
|
|
26
|
+
const projectScenePaths = await collectSceneAssetIds(projectRoot, options.sourceRoots);
|
|
27
|
+
const sceneRecords = [
|
|
28
|
+
...projectScenePaths.map((scenePath) => ({ scenePath, kind: 'project' })),
|
|
29
|
+
...builtinSceneAssetIds().map((scenePath) => ({ scenePath, kind: 'builtin' })),
|
|
30
|
+
];
|
|
31
|
+
const builtinScriptSources = await readBuiltinSceneScriptSources();
|
|
25
32
|
await mkdir(generatedDir, { recursive: true });
|
|
33
|
+
const sceneSources = new Map();
|
|
26
34
|
const templates = new Map();
|
|
27
|
-
for (const
|
|
28
|
-
const
|
|
35
|
+
for (const record of sceneRecords) {
|
|
36
|
+
const { scenePath } = record;
|
|
37
|
+
const source = record.kind === 'builtin'
|
|
38
|
+
? await readBuiltinSceneSource(scenePath)
|
|
39
|
+
: await readFile(path.resolve(projectRoot, scenePath), 'utf8');
|
|
40
|
+
sceneSources.set(scenePath, source);
|
|
29
41
|
try {
|
|
30
42
|
const template = parseSceneTemplate(source);
|
|
31
43
|
assertSceneLocalName(scenePath, template);
|
|
32
|
-
const descriptor = await readPairedSceneScript(projectRoot, scenePath, template);
|
|
33
|
-
template.interface = descriptor.interface;
|
|
34
44
|
templates.set(scenePath, normalizeSceneReferences(scenePath, template));
|
|
35
45
|
}
|
|
36
46
|
catch (error) {
|
|
37
47
|
throw new CompileSceneError(error instanceof Error ? error.message : String(error), scenePath, source);
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
|
-
const
|
|
41
|
-
for (const
|
|
50
|
+
const sceneScriptDescriptors = await readSceneScriptDescriptors(projectRoot, projectScenePaths, builtinScriptSources, sceneSources);
|
|
51
|
+
for (const record of sceneRecords) {
|
|
52
|
+
const { scenePath } = record;
|
|
53
|
+
const template = templates.get(scenePath);
|
|
54
|
+
if (!template) {
|
|
55
|
+
throw new Error(`Missing parsed template for ${scenePath}.`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
template.interface = bindSceneScriptInterface(scenePath, template, sceneScriptDescriptors[scenePath]).interface;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new CompileSceneError(error instanceof Error ? error.message : String(error), scenePath, sceneSources.get(scenePath));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const projectRegistryImports = [];
|
|
65
|
+
const builtinRegistryImports = [];
|
|
66
|
+
for (const record of sceneRecords) {
|
|
67
|
+
const { scenePath } = record;
|
|
42
68
|
const template = templates.get(scenePath);
|
|
43
69
|
if (!template) {
|
|
44
70
|
throw new Error(`Missing parsed template for ${scenePath}.`);
|
|
@@ -51,7 +77,7 @@ export async function compileScenes(options) {
|
|
|
51
77
|
scriptImport: {
|
|
52
78
|
exportName: template.name,
|
|
53
79
|
localName: sceneClassAlias(scenePath),
|
|
54
|
-
source: importSourceFor(
|
|
80
|
+
source: importSourceFor(sceneScriptAbsolutePath(projectRoot, scenePath), generatedFileDir),
|
|
55
81
|
},
|
|
56
82
|
sceneImports: sceneImportsFor(template, templates, projectRoot, generatedFileDir),
|
|
57
83
|
sceneClassAliases: sceneClassAliasesFor(template),
|
|
@@ -60,9 +86,43 @@ export async function compileScenes(options) {
|
|
|
60
86
|
});
|
|
61
87
|
await mkdir(path.dirname(generatedFile), { recursive: true });
|
|
62
88
|
await writeFile(generatedFile, code);
|
|
63
|
-
|
|
89
|
+
if (record.kind === 'project') {
|
|
90
|
+
projectRegistryImports.push(`import ${JSON.stringify(generatedSceneModuleImport(scenePath))};`);
|
|
91
|
+
}
|
|
92
|
+
else if (sceneIsReferencedByProjectScenes(scenePath, projectScenePaths, templates)) {
|
|
93
|
+
builtinRegistryImports.push(`import ${JSON.stringify(generatedSceneModuleImport(scenePath))};`);
|
|
94
|
+
}
|
|
64
95
|
}
|
|
65
|
-
await writeFile(path.join(generatedDir, 'scenes.generated.ts'), `${
|
|
96
|
+
await writeFile(path.join(generatedDir, 'scenes.generated.ts'), `${[
|
|
97
|
+
...builtinRegistryImports,
|
|
98
|
+
...projectRegistryImports,
|
|
99
|
+
].join('\n')}\n`);
|
|
100
|
+
}
|
|
101
|
+
function sceneIsReferencedByProjectScenes(scenePath, projectScenePaths, templates) {
|
|
102
|
+
if (!isBuiltinSceneAssetId(scenePath)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const visited = new Set();
|
|
106
|
+
const stack = [...projectScenePaths];
|
|
107
|
+
while (stack.length > 0) {
|
|
108
|
+
const current = stack.pop();
|
|
109
|
+
if (visited.has(current)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
visited.add(current);
|
|
113
|
+
for (const referencedScenePath of collectSceneInstancePaths(templates.get(current)?.children ?? [])) {
|
|
114
|
+
if (referencedScenePath === scenePath) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
stack.push(referencedScenePath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
function sceneScriptAbsolutePath(projectRoot, scenePath) {
|
|
123
|
+
return isBuiltinSceneAssetId(scenePath)
|
|
124
|
+
? builtinSceneScriptPath(scenePath)
|
|
125
|
+
: path.resolve(projectRoot, pairedSceneScriptPath(scenePath));
|
|
66
126
|
}
|
|
67
127
|
async function collectSceneAssetIds(projectRoot, sourceRoots = defaultSceneSourceRoots) {
|
|
68
128
|
const scenes = [];
|
|
@@ -97,19 +157,39 @@ async function exists(filePath) {
|
|
|
97
157
|
return false;
|
|
98
158
|
}
|
|
99
159
|
}
|
|
160
|
+
async function readSceneScriptDescriptors(projectRoot, projectScenePaths, builtinScriptSources, sceneSources) {
|
|
161
|
+
const sources = builtinSceneAssetIds().map((scene) => {
|
|
162
|
+
const name = builtinSceneNameFromAssetId(scene);
|
|
163
|
+
return {
|
|
164
|
+
scene,
|
|
165
|
+
fileName: builtinSceneScriptPath(scene),
|
|
166
|
+
source: builtinScriptSources[name],
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
for (const scenePath of projectScenePaths) {
|
|
170
|
+
const scriptPath = pairedSceneScriptPath(scenePath);
|
|
171
|
+
const absoluteScriptPath = path.resolve(projectRoot, scriptPath);
|
|
172
|
+
if (!await exists(absoluteScriptPath)) {
|
|
173
|
+
throw new CompileSceneError(`Scene "${scenePath}" requires paired script "${scriptPath}".`, scenePath, sceneSources.get(scenePath));
|
|
174
|
+
}
|
|
175
|
+
sources.push({
|
|
176
|
+
scene: scenePath,
|
|
177
|
+
fileName: absoluteScriptPath,
|
|
178
|
+
source: await readFile(absoluteScriptPath, 'utf8'),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return extractSceneScriptInterfaces(sources);
|
|
182
|
+
}
|
|
100
183
|
function assertSceneLocalName(scenePath, template) {
|
|
101
184
|
const expected = sceneLocalName(scenePath);
|
|
102
185
|
if (template.name !== expected) {
|
|
103
186
|
throw new Error(`Scene "${scenePath}" name "${template.name}" must match file basename "${expected}".`);
|
|
104
187
|
}
|
|
105
188
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!await exists(absoluteScriptPath)) {
|
|
110
|
-
throw new Error(`Scene "${scenePath}" requires paired script "${scriptPath}".`);
|
|
189
|
+
function bindSceneScriptInterface(scenePath, template, descriptor) {
|
|
190
|
+
if (!descriptor) {
|
|
191
|
+
throw new Error(`Scene "${scenePath}" requires a @scene script class.`);
|
|
111
192
|
}
|
|
112
|
-
const descriptor = extractSceneScriptInterface(await readFile(absoluteScriptPath, 'utf8'), absoluteScriptPath, { scene: scenePath });
|
|
113
193
|
if (descriptor.className !== template.name) {
|
|
114
194
|
throw new Error(`Scene "${scenePath}" name "${template.name}" must match @scene class "${descriptor.className}".`);
|
|
115
195
|
}
|
|
@@ -141,7 +221,7 @@ function normalizeSceneReferences(scenePath, template) {
|
|
|
141
221
|
return next;
|
|
142
222
|
}
|
|
143
223
|
function sceneImportsFor(template, templates, projectRoot, generatedFileDir) {
|
|
144
|
-
return [...
|
|
224
|
+
return [...collectSceneImportPaths(template, templates)]
|
|
145
225
|
.sort()
|
|
146
226
|
.map((scenePath) => {
|
|
147
227
|
const sceneTemplate = templates.get(scenePath);
|
|
@@ -149,12 +229,39 @@ function sceneImportsFor(template, templates, projectRoot, generatedFileDir) {
|
|
|
149
229
|
throw new Error(`Scene "${template.name}" references unknown Scene "${scenePath}".`);
|
|
150
230
|
}
|
|
151
231
|
return {
|
|
232
|
+
scene: scenePath,
|
|
152
233
|
exportName: sceneTemplate.name,
|
|
153
234
|
localName: sceneClassAlias(scenePath),
|
|
154
|
-
source: importSourceFor(
|
|
235
|
+
source: importSourceFor(sceneScriptAbsolutePath(projectRoot, scenePath), generatedFileDir),
|
|
155
236
|
};
|
|
156
237
|
});
|
|
157
238
|
}
|
|
239
|
+
function collectSceneImportPaths(template, templates) {
|
|
240
|
+
const scenePaths = collectSceneInstancePaths(template.children);
|
|
241
|
+
collectSceneStructSourcePaths(template.children, templates, scenePaths);
|
|
242
|
+
return scenePaths;
|
|
243
|
+
}
|
|
244
|
+
function collectSceneStructSourcePaths(nodes, templates, scenePaths) {
|
|
245
|
+
for (const node of nodes) {
|
|
246
|
+
if (node.kind === 'slotOutlet') {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (node.kind === 'pixi') {
|
|
250
|
+
collectSceneStructSourcePaths(node.children, templates, scenePaths);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const sceneInterface = templates.get(node.scene)?.interface;
|
|
254
|
+
for (const [key, value] of Object.entries(node.props)) {
|
|
255
|
+
const contract = value && typeof value === 'object' ? sceneInterface?.props[key] : undefined;
|
|
256
|
+
if (contract?.type === 'struct' && contract.sourceScene) {
|
|
257
|
+
scenePaths.add(contract.sourceScene);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
for (const children of Object.values(node.slots)) {
|
|
261
|
+
collectSceneStructSourcePaths(children, templates, scenePaths);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
158
265
|
function sceneClassAliasesFor(template) {
|
|
159
266
|
return Object.fromEntries([...collectSceneInstancePaths(template.children)].map((scenePath) => [scenePath, sceneClassAlias(scenePath)]));
|
|
160
267
|
}
|
|
@@ -5,6 +5,9 @@ export function scene() {
|
|
|
5
5
|
const SceneClass = class extends constructor {
|
|
6
6
|
constructor(...args) {
|
|
7
7
|
super(...args);
|
|
8
|
+
if (new.target !== SceneClass) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
8
11
|
const result = mountSceneClass(this, SceneClass);
|
|
9
12
|
const metadata = sceneMetadata(constructor);
|
|
10
13
|
for (const [property, id] of metadata.parts) {
|
package/dist/compiler/index.d.ts
CHANGED
package/dist/compiler/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { builtinSceneAssetId, builtinSceneNameFromAssetId, isBuiltinSceneAssetId } from './builtinScenes.js';
|
|
1
2
|
export const defaultSceneSourceRoots = ['src'];
|
|
2
3
|
export const ignoredSceneSourceDirectories = new Set([
|
|
3
4
|
'node_modules',
|
|
@@ -45,6 +46,9 @@ function posixJoin(...parts) {
|
|
|
45
46
|
return normalizePosixPath(parts.filter(Boolean).join('/'));
|
|
46
47
|
}
|
|
47
48
|
export function normalizeSceneAssetId(value) {
|
|
49
|
+
if (isBuiltinSceneAssetId(value)) {
|
|
50
|
+
return builtinSceneAssetId(builtinSceneNameFromAssetId(value));
|
|
51
|
+
}
|
|
48
52
|
const normalized = toPosixPath(value).replace(/^\.\/+/, '').replace(/^\/+/, '');
|
|
49
53
|
const parts = normalized.split('/').filter(Boolean);
|
|
50
54
|
if (parts.includes('..')) {
|
|
@@ -59,19 +63,31 @@ export function isIgnoredSceneSourceDirectory(name) {
|
|
|
59
63
|
return ignoredSceneSourceDirectories.has(name);
|
|
60
64
|
}
|
|
61
65
|
export function sceneLocalName(scenePath) {
|
|
66
|
+
if (isBuiltinSceneAssetId(scenePath)) {
|
|
67
|
+
return builtinSceneNameFromAssetId(scenePath);
|
|
68
|
+
}
|
|
62
69
|
return posixBasename(normalizeSceneAssetId(scenePath), '.scene');
|
|
63
70
|
}
|
|
64
71
|
export function pairedSceneScriptPath(scenePath) {
|
|
72
|
+
if (isBuiltinSceneAssetId(scenePath)) {
|
|
73
|
+
return `${builtinSceneNameFromAssetId(scenePath)}.ts`;
|
|
74
|
+
}
|
|
65
75
|
const assetId = normalizeSceneAssetId(scenePath);
|
|
66
76
|
return `${assetId.slice(0, -'.scene'.length)}.ts`;
|
|
67
77
|
}
|
|
68
78
|
export function generatedSceneModulePath(scenePath) {
|
|
79
|
+
if (isBuiltinSceneAssetId(scenePath)) {
|
|
80
|
+
return `pixifact-builtin/${builtinSceneNameFromAssetId(scenePath)}.scene.generated.ts`;
|
|
81
|
+
}
|
|
69
82
|
return `${normalizeSceneAssetId(scenePath).slice(0, -'.scene'.length)}.scene.generated.ts`;
|
|
70
83
|
}
|
|
71
84
|
export function generatedSceneModuleImport(scenePath) {
|
|
72
85
|
return `./${generatedSceneModulePath(scenePath).replace(/\.ts$/, '')}`;
|
|
73
86
|
}
|
|
74
87
|
export function sceneClassAlias(scenePath) {
|
|
88
|
+
if (isBuiltinSceneAssetId(scenePath)) {
|
|
89
|
+
return `BuiltinSceneClass_${builtinSceneNameFromAssetId(scenePath)}`;
|
|
90
|
+
}
|
|
75
91
|
const base = normalizeSceneAssetId(scenePath)
|
|
76
92
|
.slice(0, -'.scene'.length)
|
|
77
93
|
.split('/')
|
|
@@ -81,6 +97,9 @@ export function sceneClassAlias(scenePath) {
|
|
|
81
97
|
}
|
|
82
98
|
export function resolveSceneReference(fromScenePath, reference) {
|
|
83
99
|
const value = toPosixPath(reference.trim());
|
|
100
|
+
if (isBuiltinSceneAssetId(value)) {
|
|
101
|
+
return normalizeSceneAssetId(value);
|
|
102
|
+
}
|
|
84
103
|
if (!value.endsWith('.scene')) {
|
|
85
104
|
throw new Error('Scene references must use .scene paths.');
|
|
86
105
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { Container } from 'pixi.js';
|
|
2
|
+
import type { Group } from '../runtime/index.js';
|
|
2
3
|
export interface SceneMountResult {
|
|
3
|
-
root:
|
|
4
|
+
root: Group;
|
|
4
5
|
parts: Record<string, Container>;
|
|
5
6
|
slots: Record<string, Container>;
|
|
6
7
|
}
|
|
7
8
|
export interface SceneDefinition {
|
|
8
|
-
mount(root:
|
|
9
|
+
mount(root: Group): SceneMountResult;
|
|
9
10
|
}
|
|
10
11
|
export declare function registerScene(path: string, definition: SceneDefinition): void;
|
|
11
12
|
export declare function registerSceneClass(constructor: object, path: string): void;
|
|
12
|
-
export declare function mountScene(root:
|
|
13
|
-
export declare function mountSceneClass(root:
|
|
13
|
+
export declare function mountScene(root: Group, path: string): SceneMountResult;
|
|
14
|
+
export declare function mountSceneClass(root: Group, constructor: object): SceneMountResult;
|
|
@@ -2,5 +2,10 @@ import type { SceneScriptInterface } from './spec.js';
|
|
|
2
2
|
export interface ExtractSceneScriptInterfaceOptions {
|
|
3
3
|
scene: string;
|
|
4
4
|
}
|
|
5
|
+
export interface ExtractSceneScriptInterfaceSource extends ExtractSceneScriptInterfaceOptions {
|
|
6
|
+
source: string;
|
|
7
|
+
fileName?: string;
|
|
8
|
+
}
|
|
5
9
|
export declare function extractSceneScriptInterface(source: string, fileName: string | undefined, options: ExtractSceneScriptInterfaceOptions): SceneScriptInterface;
|
|
10
|
+
export declare function extractSceneScriptInterfaces(sources: readonly ExtractSceneScriptInterfaceSource[]): Record<string, SceneScriptInterface>;
|
|
6
11
|
export declare function emitSceneScriptInterfaceDescriptor(source: string, fileName: string | undefined, options: ExtractSceneScriptInterfaceOptions): string;
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
export function extractSceneScriptInterface(source, fileName = 'scene-script.ts', options) {
|
|
3
|
+
const descriptors = composeSceneScriptClasses(extractSceneScriptClasses(source, fileName, options));
|
|
4
|
+
const descriptor = descriptors[options.scene];
|
|
5
|
+
if (!descriptor) {
|
|
6
|
+
throw new Error('No @scene decorator found.');
|
|
7
|
+
}
|
|
8
|
+
return descriptor;
|
|
9
|
+
}
|
|
10
|
+
export function extractSceneScriptInterfaces(sources) {
|
|
11
|
+
return composeSceneScriptClasses(sources.flatMap((source) => extractSceneScriptClasses(source.source, source.fileName ?? 'scene-script.ts', { scene: source.scene })));
|
|
12
|
+
}
|
|
13
|
+
function extractSceneScriptClasses(source, fileName, options) {
|
|
3
14
|
const sourceFile = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
15
|
+
const sourceId = normalizeScriptSourceId(fileName);
|
|
16
|
+
const imports = collectNamedImports(sourceFile, sourceId);
|
|
4
17
|
const structClasses = collectStructClasses(sourceFile);
|
|
18
|
+
const classes = [];
|
|
5
19
|
for (const statement of sourceFile.statements) {
|
|
6
20
|
if (!ts.isClassDeclaration(statement)) {
|
|
7
21
|
continue;
|
|
8
22
|
}
|
|
9
|
-
|
|
10
|
-
continue;
|
|
11
|
-
}
|
|
23
|
+
const isSceneClass = hasSceneDecorator(statement);
|
|
12
24
|
const className = statement.name?.text;
|
|
13
25
|
if (!className) {
|
|
14
|
-
|
|
26
|
+
if (isSceneClass) {
|
|
27
|
+
throw new Error('Scene script class is missing a name.');
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
15
30
|
}
|
|
16
31
|
const props = {};
|
|
17
32
|
const events = {};
|
|
@@ -39,22 +54,199 @@ export function extractSceneScriptInterface(source, fileName = 'scene-script.ts'
|
|
|
39
54
|
parts[name] = typeof part.id === 'string' ? part.id : name;
|
|
40
55
|
}
|
|
41
56
|
}
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
const parentClassName = parentClassNameOf(statement);
|
|
58
|
+
if (!isSceneClass && !parentClassName && !hasPublicContract(props, events, slots, parts)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
classes.push({
|
|
62
|
+
sourceId,
|
|
63
|
+
scriptScene: options.scene,
|
|
64
|
+
...(isSceneClass ? { scene: options.scene } : {}),
|
|
44
65
|
className,
|
|
66
|
+
...(parentClassName ? { parentClassName } : {}),
|
|
67
|
+
imports,
|
|
45
68
|
interface: {
|
|
46
69
|
props,
|
|
47
70
|
events,
|
|
48
71
|
slots,
|
|
49
72
|
},
|
|
50
73
|
parts,
|
|
51
|
-
};
|
|
74
|
+
});
|
|
52
75
|
}
|
|
53
|
-
|
|
76
|
+
return classes;
|
|
54
77
|
}
|
|
55
78
|
export function emitSceneScriptInterfaceDescriptor(source, fileName = 'scene-script.ts', options) {
|
|
56
79
|
return `${JSON.stringify(extractSceneScriptInterface(source, fileName, options), null, 2)}\n`;
|
|
57
80
|
}
|
|
81
|
+
function composeSceneScriptClasses(classes) {
|
|
82
|
+
const classesByName = new Map();
|
|
83
|
+
const classesBySourceAndName = new Map();
|
|
84
|
+
for (const item of classes) {
|
|
85
|
+
const bucket = classesByName.get(item.className) ?? [];
|
|
86
|
+
bucket.push(item);
|
|
87
|
+
classesByName.set(item.className, bucket);
|
|
88
|
+
classesBySourceAndName.set(sourceClassKey(item.sourceId, item.className), item);
|
|
89
|
+
}
|
|
90
|
+
const composed = new Map();
|
|
91
|
+
const visiting = new Set();
|
|
92
|
+
function compose(item) {
|
|
93
|
+
const cached = composed.get(item);
|
|
94
|
+
if (cached) {
|
|
95
|
+
return cached;
|
|
96
|
+
}
|
|
97
|
+
if (visiting.has(item)) {
|
|
98
|
+
throw new Error(`Scene script class "${item.className}" has a circular inheritance chain.`);
|
|
99
|
+
}
|
|
100
|
+
visiting.add(item);
|
|
101
|
+
const parent = item.parentClassName ? resolveParentClass(item, classesByName, classesBySourceAndName) : undefined;
|
|
102
|
+
const parentInterface = parent ? inheritedSceneInterface(compose(parent), parent.scriptScene, item.scriptScene) : emptySceneInterface();
|
|
103
|
+
const sceneInterface = mergeSceneInterfaces(parentInterface, item.interface);
|
|
104
|
+
visiting.delete(item);
|
|
105
|
+
composed.set(item, sceneInterface);
|
|
106
|
+
return sceneInterface;
|
|
107
|
+
}
|
|
108
|
+
const result = {};
|
|
109
|
+
for (const item of classes) {
|
|
110
|
+
if (!item.scene) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (result[item.scene]) {
|
|
114
|
+
throw new Error(`Scene script "${item.scene}" has multiple @scene classes.`);
|
|
115
|
+
}
|
|
116
|
+
result[item.scene] = {
|
|
117
|
+
scene: item.scene,
|
|
118
|
+
className: item.className,
|
|
119
|
+
interface: compose(item),
|
|
120
|
+
parts: item.parts,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
function resolveParentClass(item, classesByName, classesBySourceAndName) {
|
|
126
|
+
const parentClassName = item.parentClassName ?? '';
|
|
127
|
+
const sameSourceParent = classesBySourceAndName.get(sourceClassKey(item.sourceId, parentClassName));
|
|
128
|
+
if (sameSourceParent) {
|
|
129
|
+
return sameSourceParent;
|
|
130
|
+
}
|
|
131
|
+
const importedSource = item.imports.get(parentClassName);
|
|
132
|
+
if (importedSource) {
|
|
133
|
+
return classesBySourceAndName.get(sourceClassKey(importedSource, parentClassName));
|
|
134
|
+
}
|
|
135
|
+
const candidates = classesByName.get(parentClassName) ?? [];
|
|
136
|
+
if (candidates.length === 0) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
if (candidates.length > 1) {
|
|
140
|
+
throw new Error(`Scene script parent class "${item.parentClassName}" is ambiguous for "${item.className}".`);
|
|
141
|
+
}
|
|
142
|
+
return candidates[0];
|
|
143
|
+
}
|
|
144
|
+
function sourceClassKey(sourceId, className) {
|
|
145
|
+
return `${sourceId}:${className}`;
|
|
146
|
+
}
|
|
147
|
+
function emptySceneInterface() {
|
|
148
|
+
return {
|
|
149
|
+
props: {},
|
|
150
|
+
events: {},
|
|
151
|
+
slots: {},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function mergeSceneInterfaces(parent, own) {
|
|
155
|
+
return {
|
|
156
|
+
props: {
|
|
157
|
+
...parent.props,
|
|
158
|
+
...own.props,
|
|
159
|
+
},
|
|
160
|
+
events: {
|
|
161
|
+
...parent.events,
|
|
162
|
+
...own.events,
|
|
163
|
+
},
|
|
164
|
+
slots: {
|
|
165
|
+
...parent.slots,
|
|
166
|
+
...own.slots,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function inheritedSceneInterface(parent, parentSourceScene, childSourceScene) {
|
|
171
|
+
return {
|
|
172
|
+
props: Object.fromEntries(Object.entries(parent.props).map(([name, contract]) => {
|
|
173
|
+
if (contract.type !== 'struct') {
|
|
174
|
+
return [name, contract];
|
|
175
|
+
}
|
|
176
|
+
const sourceScene = contract.sourceScene ?? parentSourceScene;
|
|
177
|
+
return [
|
|
178
|
+
name,
|
|
179
|
+
sourceScene === childSourceScene
|
|
180
|
+
? contract
|
|
181
|
+
: { ...contract, sourceScene },
|
|
182
|
+
];
|
|
183
|
+
})),
|
|
184
|
+
events: parent.events,
|
|
185
|
+
slots: parent.slots,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function hasPublicContract(props, events, slots, parts) {
|
|
189
|
+
return Object.keys(props).length > 0
|
|
190
|
+
|| Object.keys(events).length > 0
|
|
191
|
+
|| Object.keys(slots).length > 0
|
|
192
|
+
|| Object.keys(parts).length > 0;
|
|
193
|
+
}
|
|
194
|
+
function collectNamedImports(sourceFile, sourceId) {
|
|
195
|
+
const imports = new Map();
|
|
196
|
+
for (const statement of sourceFile.statements) {
|
|
197
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const moduleSpecifier = statement.moduleSpecifier.text;
|
|
201
|
+
if (!moduleSpecifier.startsWith('.')) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const namedBindings = statement.importClause?.namedBindings;
|
|
205
|
+
if (!namedBindings || !ts.isNamedImports(namedBindings)) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const targetSource = resolveScriptSourceId(sourceId, moduleSpecifier);
|
|
209
|
+
for (const element of namedBindings.elements) {
|
|
210
|
+
imports.set(element.name.text, targetSource);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return imports;
|
|
214
|
+
}
|
|
215
|
+
function normalizeScriptSourceId(value) {
|
|
216
|
+
const normalized = normalizePosixPath(value);
|
|
217
|
+
return hasScriptExtension(normalized) ? normalized : `${normalized}.ts`;
|
|
218
|
+
}
|
|
219
|
+
function resolveScriptSourceId(fromSourceId, moduleSpecifier) {
|
|
220
|
+
const dirname = posixDirname(fromSourceId);
|
|
221
|
+
return normalizeScriptSourceId(normalizePosixPath(`${dirname}/${moduleSpecifier}`));
|
|
222
|
+
}
|
|
223
|
+
function hasScriptExtension(value) {
|
|
224
|
+
return /\.[cm]?[tj]sx?$/.test(value);
|
|
225
|
+
}
|
|
226
|
+
function posixDirname(value) {
|
|
227
|
+
const normalized = normalizePosixPath(value);
|
|
228
|
+
const index = normalized.lastIndexOf('/');
|
|
229
|
+
return index >= 0 ? normalized.slice(0, index) : '';
|
|
230
|
+
}
|
|
231
|
+
function normalizePosixPath(value) {
|
|
232
|
+
const segments = [];
|
|
233
|
+
for (const segment of value.replaceAll('\\', '/').split('/')) {
|
|
234
|
+
if (!segment || segment === '.') {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (segment === '..') {
|
|
238
|
+
if (segments.length && segments[segments.length - 1] !== '..') {
|
|
239
|
+
segments.pop();
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
segments.push(segment);
|
|
243
|
+
}
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
segments.push(segment);
|
|
247
|
+
}
|
|
248
|
+
return segments.join('/');
|
|
249
|
+
}
|
|
58
250
|
function hasSceneDecorator(node) {
|
|
59
251
|
const decorator = decorators(node).find((item) => decoratorName(item) === 'scene');
|
|
60
252
|
if (!decorator) {
|
|
@@ -66,6 +258,20 @@ function hasSceneDecorator(node) {
|
|
|
66
258
|
}
|
|
67
259
|
return true;
|
|
68
260
|
}
|
|
261
|
+
function parentClassNameOf(node) {
|
|
262
|
+
const heritage = node.heritageClauses?.find((item) => item.token === ts.SyntaxKind.ExtendsKeyword);
|
|
263
|
+
const parent = heritage?.types[0]?.expression;
|
|
264
|
+
if (!parent) {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
if (ts.isIdentifier(parent)) {
|
|
268
|
+
return parent.text;
|
|
269
|
+
}
|
|
270
|
+
if (ts.isPropertyAccessExpression(parent)) {
|
|
271
|
+
return parent.name.text;
|
|
272
|
+
}
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
69
275
|
function memberDecoratorOptions(member, name) {
|
|
70
276
|
const decorator = decorators(member).find((item) => decoratorName(item) === name);
|
|
71
277
|
if (!decorator) {
|
package/dist/compiler/spec.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface SceneTemplateStructFieldContract {
|
|
|
14
14
|
export interface SceneTemplateStructPropContract {
|
|
15
15
|
type: 'struct';
|
|
16
16
|
struct: string;
|
|
17
|
+
sourceScene?: string;
|
|
17
18
|
fields: Record<string, SceneTemplateStructFieldContract>;
|
|
18
19
|
}
|
|
19
20
|
export type SceneTemplatePropContract = SceneTemplatePrimitivePropContract | SceneTemplateStructPropContract;
|
|
@@ -56,6 +57,7 @@ export interface SlotOutletTemplateNode {
|
|
|
56
57
|
name: string;
|
|
57
58
|
}
|
|
58
59
|
export interface SceneTemplateScriptImport {
|
|
60
|
+
scene?: string;
|
|
59
61
|
exportName: string;
|
|
60
62
|
localName: string;
|
|
61
63
|
source: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pixiSceneFieldSchema } from './pixiNodeSchema.js';
|
|
2
|
+
import { builtinSceneAssetId, isBuiltinSceneName } from './builtinScenes.js';
|
|
2
3
|
const pixiTypes = new Set([
|
|
3
4
|
'Container',
|
|
4
5
|
'Sprite',
|
|
@@ -61,7 +62,7 @@ function parseTemplateNode(element) {
|
|
|
61
62
|
};
|
|
62
63
|
return node;
|
|
63
64
|
}
|
|
64
|
-
if (element.attributes.scene) {
|
|
65
|
+
if (element.attributes.scene !== undefined || isBuiltinSceneName(element.name)) {
|
|
65
66
|
const slots = {};
|
|
66
67
|
for (const child of element.children) {
|
|
67
68
|
const slot = child.attributes.slot || 'default';
|
|
@@ -71,7 +72,7 @@ function parseTemplateNode(element) {
|
|
|
71
72
|
const node = {
|
|
72
73
|
kind: 'sceneInstance',
|
|
73
74
|
type: element.name,
|
|
74
|
-
scene: element.attributes.scene,
|
|
75
|
+
scene: element.attributes.scene !== undefined ? element.attributes.scene : builtinSceneAssetId(element.name),
|
|
75
76
|
props: parseProps(element, ['id', 'scene', 'slot'], isEventAttribute),
|
|
76
77
|
events: parseEvents(element),
|
|
77
78
|
slots,
|
|
@@ -79,7 +80,7 @@ function parseTemplateNode(element) {
|
|
|
79
80
|
};
|
|
80
81
|
return node;
|
|
81
82
|
}
|
|
82
|
-
throw new Error(`Unsupported template tag <${element.name}
|
|
83
|
+
throw new Error(`Unsupported template tag <${element.name}>. Add scene="..." or use a built-in Scene name.`);
|
|
83
84
|
}
|
|
84
85
|
function parseProps(element, omitted, shouldOmit = () => false) {
|
|
85
86
|
const props = {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBuiltinSceneAssetId } from './builtinScenes.js';
|
|
1
2
|
const colorPropNames = new Set([
|
|
2
3
|
'backgroundColor',
|
|
3
4
|
'borderColor',
|
|
@@ -40,7 +41,7 @@ function serializeTemplateNode(node, depth, extraAttributes = []) {
|
|
|
40
41
|
}
|
|
41
42
|
const attributes = [
|
|
42
43
|
...(node.id ? [['id', node.id]] : []),
|
|
43
|
-
['scene', node.scene],
|
|
44
|
+
...(isBuiltinSceneAssetId(node.scene) ? [] : [['scene', node.scene]]),
|
|
44
45
|
...extraAttributes,
|
|
45
46
|
...Object.entries(node.props),
|
|
46
47
|
...Object.entries(node.events).map(([name, value]) => [`@${name}`, value]),
|