pixifact 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/compiler/builtinScenes.d.ts +0 -5
- package/dist/compiler/builtinScenes.js +0 -26
- package/dist/compiler/commands/index.js +8 -5
- package/dist/compiler/compileScenes.d.ts +4 -1
- package/dist/compiler/compileScenes.js +40 -11
- package/dist/compiler/index.d.ts +0 -5
- package/dist/compiler/index.js +0 -5
- package/dist/compiler/pixiNodeSchema.d.ts +4 -3
- package/dist/compiler/pixiNodeSchema.js +60 -6
- package/dist/compiler/sceneValidation.d.ts +3 -1
- package/dist/compiler/sceneValidation.js +105 -6
- package/dist/compiler/spec.d.ts +19 -8
- package/dist/compiler/spec.js +3 -1
- package/dist/compiler/templateParser.js +19 -0
- package/dist/compiler/templateSerializer.js +7 -1
- package/dist/compiler/typescriptCompiler.js +118 -51
- package/dist/compiler-node/builtinSceneInterfaces.d.ts +6 -0
- package/dist/compiler-node/builtinSceneInterfaces.js +27 -0
- package/dist/compiler-node/index.d.ts +2 -0
- package/dist/compiler-node/index.js +2 -0
- package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.d.ts +1 -1
- package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.js +157 -25
- package/dist/compiler-node/vite.d.ts +2 -1
- package/dist/compiler-node/vite.js +29 -2
- package/dist/platform/wechat/adapter.d.ts +316 -0
- package/dist/platform/wechat/adapter.js +26 -0
- package/dist/platform/wechat/application.d.ts +32 -0
- package/dist/platform/wechat/application.js +79 -0
- package/dist/platform/wechat/fetch.d.ts +1 -0
- package/dist/platform/wechat/fetch.js +145 -0
- package/dist/platform/wechat/index.d.ts +4 -0
- package/dist/platform/wechat/index.js +3 -0
- package/dist/platform/wechat/input.d.ts +12 -0
- package/dist/platform/wechat/input.js +93 -0
- package/dist/platform/wechat/lifecycle.d.ts +14 -0
- package/dist/platform/wechat/lifecycle.js +42 -0
- package/dist/platform/wechat/runtime.d.ts +49 -0
- package/dist/platform/wechat/runtime.js +189 -0
- package/dist/platform/wechat/subpackage.d.ts +1 -0
- package/dist/platform/wechat/subpackage.js +27 -0
- package/dist/platform/wechat/types.d.ts +105 -0
- package/dist/platform/wechat/types.js +3 -0
- package/dist/project/index.d.ts +23 -0
- package/dist/project/index.js +69 -0
- package/dist/runtime/BitmapLabel.d.ts +9 -0
- package/dist/runtime/BitmapLabel.js +7 -0
- package/dist/runtime/Label.d.ts +9 -0
- package/dist/runtime/Label.js +7 -0
- package/dist/runtime/ScrollContainer.d.ts +2 -0
- package/dist/runtime/ScrollContainer.js +12 -2
- package/dist/runtime/TextBoxControl.d.ts +48 -0
- package/dist/runtime/TextBoxControl.js +162 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/runtimeBehavior.d.ts +3 -0
- package/dist/runtime/runtimeBehavior.js +11 -0
- package/dist/{compiler → scene}/decorators.d.ts +2 -1
- package/dist/{compiler → scene}/decorators.js +12 -7
- package/dist/scene/index.d.ts +6 -0
- package/dist/scene/index.js +6 -0
- package/dist/scene/sceneAssetRuntime.d.ts +11 -0
- package/dist/scene/sceneAssetRuntime.js +43 -0
- package/dist/scene/sceneBindingRuntime.d.ts +10 -0
- package/dist/scene/sceneBindingRuntime.js +124 -0
- package/dist/{compiler → scene}/sceneRuntime.d.ts +7 -0
- package/dist/scene/sceneRuntime.js +85 -0
- package/package.json +11 -1
- package/dist/compiler/sceneRuntime.js +0 -22
- /package/dist/{compiler → scene}/eventRuntime.d.ts +0 -0
- /package/dist/{compiler → scene}/eventRuntime.js +0 -0
- /package/dist/{compiler → scene}/slotRuntime.d.ts +0 -0
- /package/dist/{compiler → scene}/slotRuntime.js +0 -0
package/dist/compiler/spec.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
export type SceneTemplatePrimitiveType = 'Group' | 'Container' | 'Sprite' | 'Text' | 'Graphics' | 'Rect' | 'Image' | 'NineImage' | 'TileImage' | 'BitmapText' | 'HTMLText' | 'Mesh' | 'NineSliceSprite' | 'TilingSprite' | 'DOMContainer' | 'GridContainer' | 'HBoxContainer' | 'ScrollContainer' | 'VBoxContainer';
|
|
1
|
+
export type SceneTemplatePrimitiveType = 'Group' | 'Container' | 'Sprite' | 'Text' | 'Label' | 'BitmapLabel' | 'Graphics' | 'Rect' | 'Image' | 'NineImage' | 'TileImage' | 'BitmapText' | 'HTMLText' | 'Mesh' | 'NineSliceSprite' | 'TilingSprite' | 'DOMContainer' | 'GridContainer' | 'HBoxContainer' | 'ScrollContainer' | 'VBoxContainer';
|
|
2
2
|
export type SceneTemplateScalarValue = string | number | boolean;
|
|
3
3
|
export type SceneTemplateStructValue = Record<string, SceneTemplateScalarValue>;
|
|
4
|
-
export
|
|
4
|
+
export interface SceneTemplateBindingValue {
|
|
5
|
+
kind: 'binding';
|
|
6
|
+
path: [string] | [string, string];
|
|
7
|
+
}
|
|
8
|
+
export type SceneTemplateValue = SceneTemplateScalarValue | SceneTemplateStructValue | SceneTemplateBindingValue;
|
|
9
|
+
export declare function isSceneTemplateBindingValue(value: SceneTemplateValue | undefined): value is SceneTemplateBindingValue;
|
|
5
10
|
export type SceneTemplatePrimitivePropType = 'string' | 'number' | 'boolean';
|
|
6
11
|
export interface SceneTemplatePrimitivePropContract {
|
|
7
12
|
type: SceneTemplatePrimitivePropType;
|
|
@@ -17,7 +22,14 @@ export interface SceneTemplateStructPropContract {
|
|
|
17
22
|
sourceScene?: string;
|
|
18
23
|
fields: Record<string, SceneTemplateStructFieldContract>;
|
|
19
24
|
}
|
|
20
|
-
export type
|
|
25
|
+
export type SceneTemplateVariantFields = Record<string, SceneTemplateScalarValue>;
|
|
26
|
+
export type SceneTemplateVariants = Record<string, SceneTemplateVariantFields>;
|
|
27
|
+
export interface SceneTemplateVariantPropContract {
|
|
28
|
+
type: 'variant';
|
|
29
|
+
default: string;
|
|
30
|
+
variants: SceneTemplateVariants;
|
|
31
|
+
}
|
|
32
|
+
export type SceneTemplatePropContract = SceneTemplatePrimitivePropContract | SceneTemplateStructPropContract | SceneTemplateVariantPropContract;
|
|
21
33
|
export interface SceneTemplateEventContract {
|
|
22
34
|
type: 'action';
|
|
23
35
|
}
|
|
@@ -73,8 +85,8 @@ export interface CompileSceneTemplateOptions {
|
|
|
73
85
|
scriptImport?: SceneTemplateScriptImport;
|
|
74
86
|
sceneImports?: SceneTemplateScriptImport[];
|
|
75
87
|
sceneClassAliases?: Record<string, string>;
|
|
88
|
+
sceneDependencies?: string[];
|
|
76
89
|
sceneInterfaces?: Record<string, SceneTemplateInterface>;
|
|
77
|
-
textureImports?: Record<string, string>;
|
|
78
90
|
}
|
|
79
91
|
export interface SceneScriptInterface {
|
|
80
92
|
scene: string;
|
|
@@ -84,11 +96,10 @@ export interface SceneScriptInterface {
|
|
|
84
96
|
}
|
|
85
97
|
export type SceneClassDecorator = ClassDecorator;
|
|
86
98
|
export type SceneMemberDecorator = PropertyDecorator & MethodDecorator;
|
|
87
|
-
export type
|
|
88
|
-
export type ScenePropType = StringConstructor | NumberConstructor | BooleanConstructor | SceneStructConstructor;
|
|
99
|
+
export type SceneVariants = Record<string, Record<string, SceneTemplateScalarValue>>;
|
|
89
100
|
export interface ScenePropDecoratorOptions {
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
default?: SceneTemplateScalarValue;
|
|
102
|
+
variants?: SceneVariants;
|
|
92
103
|
}
|
|
93
104
|
export interface SceneEventDecoratorOptions {
|
|
94
105
|
name?: string;
|
package/dist/compiler/spec.js
CHANGED
|
@@ -5,6 +5,8 @@ const pixiTypes = new Set([
|
|
|
5
5
|
'Container',
|
|
6
6
|
'Sprite',
|
|
7
7
|
'Text',
|
|
8
|
+
'Label',
|
|
9
|
+
'BitmapLabel',
|
|
8
10
|
'Graphics',
|
|
9
11
|
'Rect',
|
|
10
12
|
'Image',
|
|
@@ -148,6 +150,10 @@ function isEventAttribute(name) {
|
|
|
148
150
|
return eventName(name) !== undefined;
|
|
149
151
|
}
|
|
150
152
|
function parseAttributeValue(name, value) {
|
|
153
|
+
const binding = parseBindingValue(value);
|
|
154
|
+
if (binding) {
|
|
155
|
+
return binding;
|
|
156
|
+
}
|
|
151
157
|
if (pixiSceneFieldSchema(name)?.type === 'string') {
|
|
152
158
|
return value;
|
|
153
159
|
}
|
|
@@ -161,6 +167,19 @@ function parseAttributeValue(name, value) {
|
|
|
161
167
|
return Number.parseInt(value.slice(1), 16);
|
|
162
168
|
return value;
|
|
163
169
|
}
|
|
170
|
+
function parseBindingValue(value) {
|
|
171
|
+
const match = /^\{([A-Za-z_$][\w$]*)(?:\.([A-Za-z_$][\w$]*))?\}$/.exec(value);
|
|
172
|
+
if (!match) {
|
|
173
|
+
if (value.startsWith('{') || value.endsWith('}')) {
|
|
174
|
+
throw new Error(`Unsupported Scene binding "${value}". Use {prop} or {variant.field}.`);
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
kind: 'binding',
|
|
180
|
+
path: match[2] ? [match[1], match[2]] : [match[1]],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
164
183
|
function removeAttribute(element, name) {
|
|
165
184
|
const attributes = { ...element.attributes };
|
|
166
185
|
delete attributes[name];
|
|
@@ -79,18 +79,24 @@ function serializeAttributes(attributes) {
|
|
|
79
79
|
}
|
|
80
80
|
function flattenAttributes(attributes) {
|
|
81
81
|
return attributes.flatMap(([name, value]) => {
|
|
82
|
-
if (!value || typeof value !== 'object') {
|
|
82
|
+
if (!value || typeof value !== 'object' || isBindingValue(value)) {
|
|
83
83
|
return [[name, value]];
|
|
84
84
|
}
|
|
85
85
|
return Object.entries(value).map(([field, fieldValue]) => [`${name}.${field}`, fieldValue]);
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
function formatAttributeValue(name, value) {
|
|
89
|
+
if (isBindingValue(value)) {
|
|
90
|
+
return `{${value.path.join('.')}}`;
|
|
91
|
+
}
|
|
89
92
|
if (typeof value === 'number' && colorPropNames.has(name)) {
|
|
90
93
|
return `#${value.toString(16).padStart(6, '0').slice(-6)}`;
|
|
91
94
|
}
|
|
92
95
|
return String(value);
|
|
93
96
|
}
|
|
97
|
+
function isBindingValue(value) {
|
|
98
|
+
return typeof value === 'object' && value.kind === 'binding';
|
|
99
|
+
}
|
|
94
100
|
function escapeAttribute(value) {
|
|
95
101
|
return value
|
|
96
102
|
.replaceAll('&', '&')
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { pixiSceneDisplayProps, pixiSceneGraphicsProps, pixiSceneLayoutProps, pixiSceneRectProps, pixiSceneSpriteLikeProps, pixiSceneTextStyleProps, pixiSceneTransformProps, } from './pixiNodeSchema.js';
|
|
1
|
+
import { pixiSceneDisplayProps, pixiSceneGraphicsProps, pixiSceneLabelProps, pixiSceneLayoutProps, pixiSceneRectProps, pixiSceneSpriteLikeProps, pixiSceneTextStyleProps, pixiSceneTransformProps, } from './pixiNodeSchema.js';
|
|
2
|
+
import { compilerSceneNodeLocator } from './commands/index.js';
|
|
2
3
|
const transformProps = new Set(pixiSceneTransformProps);
|
|
3
4
|
const layoutProps = new Set(pixiSceneLayoutProps);
|
|
4
5
|
const pixiProps = new Set(pixiSceneDisplayProps);
|
|
5
6
|
const spriteProps = new Set(pixiSceneSpriteLikeProps);
|
|
6
7
|
const graphicsProps = new Set(pixiSceneGraphicsProps);
|
|
8
|
+
const labelProps = new Set(pixiSceneLabelProps);
|
|
7
9
|
const rectProps = new Set(pixiSceneRectProps);
|
|
8
10
|
const textStyleProps = new Set(pixiSceneTextStyleProps);
|
|
9
|
-
const runtimeNodeTypes = new Set(['Group', 'GridContainer', 'HBoxContainer', 'ScrollContainer', 'VBoxContainer', 'Rect', 'Image', 'NineImage', 'TileImage']);
|
|
11
|
+
const runtimeNodeTypes = new Set(['Group', 'GridContainer', 'HBoxContainer', 'ScrollContainer', 'VBoxContainer', 'Label', 'BitmapLabel', 'Rect', 'Image', 'NineImage', 'TileImage']);
|
|
10
12
|
const runtimeNodeProps = new Set(['columns', 'gap', 'gapX', 'gapY', 'alignX', 'alignY', 'justify', 'direction', 'scrollX', 'scrollY']);
|
|
13
|
+
function isSceneBindingValue(value) {
|
|
14
|
+
return !!value && typeof value === 'object' && value.kind === 'binding';
|
|
15
|
+
}
|
|
11
16
|
export function compileSceneTemplateToTs(template, options = {}) {
|
|
12
17
|
const context = new CompileContext(template, options);
|
|
13
18
|
return context.compile();
|
|
@@ -37,16 +42,18 @@ class CompileContext {
|
|
|
37
42
|
const functionName = this.options.functionName || `mount${this.template.name}Scene`;
|
|
38
43
|
const actionsParameter = this.options.actionsParameter || 'actions';
|
|
39
44
|
const partsType = this.#formatPartsType();
|
|
40
|
-
const
|
|
45
|
+
const texturePreparation = this.#formatTexturePreparation();
|
|
41
46
|
this.#lines.push(`export function ${functionName}(root: Group${this.#hasEvents() ? `, ${actionsParameter}: Record<string, () => void> = {}` : ''}) {`);
|
|
47
|
+
this.#lines.push(' const __pixifactNodes: Record<string, Container> = {};');
|
|
42
48
|
this.#lines.push(' const __pixifactSlots: Record<string, Container> = {};');
|
|
43
49
|
this.#applyRootProps();
|
|
44
|
-
for (const child of this.template.children) {
|
|
45
|
-
this.#compileNode(child, 'root', actionsParameter);
|
|
50
|
+
for (const [index, child] of this.template.children.entries()) {
|
|
51
|
+
this.#compileNode(child, 'root', actionsParameter, String(index));
|
|
46
52
|
}
|
|
47
53
|
this.#lines.push(' return {');
|
|
48
54
|
this.#lines.push(' root,');
|
|
49
55
|
this.#lines.push(` parts: { ${this.#parts.map((part) => part.id).join(', ')} },`);
|
|
56
|
+
this.#lines.push(' nodes: __pixifactNodes,');
|
|
50
57
|
this.#lines.push(' slots: __pixifactSlots,');
|
|
51
58
|
this.#lines.push(' };');
|
|
52
59
|
this.#lines.push('}');
|
|
@@ -57,7 +64,10 @@ class CompileContext {
|
|
|
57
64
|
}
|
|
58
65
|
this.#lines.push('');
|
|
59
66
|
this.#lines.push(`registerScene(${JSON.stringify(this.options.registrationPath)}, {`);
|
|
67
|
+
this.#lines.push(` assets: ${JSON.stringify([...this.#textures.keys()])},`);
|
|
68
|
+
this.#lines.push(` dependencies: ${JSON.stringify(this.options.sceneDependencies ?? [])},`);
|
|
60
69
|
this.#lines.push(` mount: ${functionName},`);
|
|
70
|
+
this.#lines.push(` prepare: ${this.#prepareFunctionName()},`);
|
|
61
71
|
this.#lines.push('});');
|
|
62
72
|
if (this.options.scriptImport) {
|
|
63
73
|
this.#lines.push(`registerSceneClass(${this.options.scriptImport.localName}, ${JSON.stringify(this.options.registrationPath)});`);
|
|
@@ -66,7 +76,7 @@ class CompileContext {
|
|
|
66
76
|
const imports = this.#formatImports();
|
|
67
77
|
return [
|
|
68
78
|
imports,
|
|
69
|
-
|
|
79
|
+
texturePreparation,
|
|
70
80
|
partsType,
|
|
71
81
|
this.#lines.join('\n'),
|
|
72
82
|
].filter(Boolean).join('\n\n') + '\n';
|
|
@@ -79,9 +89,6 @@ class CompileContext {
|
|
|
79
89
|
])];
|
|
80
90
|
const runtimeImports = [...new Set(['Group', ...[...this.#pixiRuntimeImports].sort()])];
|
|
81
91
|
const lines = [`import { ${imports.join(', ')} } from 'pixi.js';`, `import { ${runtimeImports.join(', ')} } from 'pixifact/runtime';`];
|
|
82
|
-
for (const [texture, variable] of this.#textureImportEntries()) {
|
|
83
|
-
lines.push(`import ${variable} from ${JSON.stringify(this.options.textureImports?.[texture])};`);
|
|
84
|
-
}
|
|
85
92
|
for (const sceneImport of this.options.sceneImports ?? []) {
|
|
86
93
|
const classImport = sceneImport.exportName === sceneImport.localName
|
|
87
94
|
? sceneImport.exportName
|
|
@@ -98,7 +105,7 @@ class CompileContext {
|
|
|
98
105
|
lines.push(`import { ${this.options.scriptImport.exportName} as ${this.options.scriptImport.localName} } from ${JSON.stringify(this.options.scriptImport.source)};`);
|
|
99
106
|
}
|
|
100
107
|
if (this.#runtimeImports.size > 0) {
|
|
101
|
-
lines.push(`import { ${[...this.#runtimeImports].sort().join(', ')} } from 'pixifact/
|
|
108
|
+
lines.push(`import { ${[...this.#runtimeImports].sort().join(', ')} } from 'pixifact/scene';`);
|
|
102
109
|
}
|
|
103
110
|
return lines.join('\n');
|
|
104
111
|
}
|
|
@@ -109,6 +116,7 @@ class CompileContext {
|
|
|
109
116
|
lines.push(` ${part.id}: ${part.type};`);
|
|
110
117
|
}
|
|
111
118
|
lines.push(' };');
|
|
119
|
+
lines.push(' nodes: Record<string, Container>;');
|
|
112
120
|
lines.push(' slots: Record<string, Container>;');
|
|
113
121
|
lines.push('};');
|
|
114
122
|
return lines.join('\n');
|
|
@@ -174,16 +182,27 @@ class CompileContext {
|
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
184
|
}
|
|
177
|
-
#
|
|
185
|
+
#formatTexturePreparation() {
|
|
178
186
|
if (this.#textures.size === 0) {
|
|
179
|
-
return
|
|
187
|
+
return `export async function ${this.#prepareFunctionName()}() {}`;
|
|
180
188
|
}
|
|
181
|
-
this.#pixiImports.add('
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
this.#pixiImports.add('Texture');
|
|
190
|
+
this.#runtimeImports.add('loadSceneTexture');
|
|
191
|
+
const entries = [...this.#textures.entries()];
|
|
192
|
+
return [
|
|
193
|
+
...entries.map(([, variable]) => `let ${variable}: Texture;`),
|
|
194
|
+
'',
|
|
195
|
+
`export async function ${this.#prepareFunctionName()}() {`,
|
|
196
|
+
` [${entries.map(([, variable]) => variable).join(', ')}] = await Promise.all([`,
|
|
197
|
+
...entries.map(([texture]) => ` loadSceneTexture(${JSON.stringify(texture)}),`),
|
|
198
|
+
' ]);',
|
|
199
|
+
'}',
|
|
200
|
+
].join('\n');
|
|
201
|
+
}
|
|
202
|
+
#prepareFunctionName() {
|
|
203
|
+
return `prepare${this.template.name}Scene`;
|
|
204
|
+
}
|
|
205
|
+
#compileNode(node, parent, actionsParameter, path) {
|
|
187
206
|
if (node.kind === 'slotOutlet') {
|
|
188
207
|
this.#runtimeImports.add('registerSlot');
|
|
189
208
|
this.#lines.push(` __pixifactSlots[${JSON.stringify(node.name)}] = ${parent};`);
|
|
@@ -191,26 +210,30 @@ class CompileContext {
|
|
|
191
210
|
return;
|
|
192
211
|
}
|
|
193
212
|
if (node.kind === 'sceneInstance') {
|
|
194
|
-
this.#compileSceneInstance(node, parent, actionsParameter);
|
|
213
|
+
this.#compileSceneInstance(node, parent, actionsParameter, path);
|
|
195
214
|
return;
|
|
196
215
|
}
|
|
197
|
-
this.#compilePixiNode(node, parent, actionsParameter);
|
|
216
|
+
this.#compilePixiNode(node, parent, actionsParameter, path);
|
|
198
217
|
}
|
|
199
|
-
#compilePixiNode(node, parent, actionsParameter) {
|
|
218
|
+
#compilePixiNode(node, parent, actionsParameter, path) {
|
|
200
219
|
const variable = node.id || this.#anonymousName(node.type);
|
|
220
|
+
const locator = compilerSceneNodeLocator(node, path);
|
|
201
221
|
this.#lines.push(` const ${variable} = ${this.#constructPixiNode(node)};`);
|
|
202
222
|
this.#applyNodeId(variable, node.id);
|
|
203
223
|
this.#applyPixiProps(variable, node.props, false, undefined, node.type);
|
|
204
224
|
this.#applyParentSorting(parent, node.props);
|
|
205
225
|
this.#lines.push(` ${parent}.addChild(${variable});`);
|
|
206
|
-
|
|
207
|
-
|
|
226
|
+
this.#lines.push(` __pixifactNodes[${JSON.stringify(locator)}] = ${variable};`);
|
|
227
|
+
for (const [index, child] of node.children.entries()) {
|
|
228
|
+
this.#compileNode(child, variable, actionsParameter, `${locator}/${index}`);
|
|
208
229
|
}
|
|
209
230
|
}
|
|
210
|
-
#compileSceneInstance(node, parent, actionsParameter) {
|
|
231
|
+
#compileSceneInstance(node, parent, actionsParameter, path) {
|
|
211
232
|
const variable = node.id || this.#anonymousName(node.type);
|
|
233
|
+
const locator = compilerSceneNodeLocator(node, path);
|
|
212
234
|
const constructorName = this.#sceneConstructorName(node);
|
|
213
|
-
|
|
235
|
+
const constructorArgs = this.#sceneInstanceConstructorArgs(variable, node);
|
|
236
|
+
this.#lines.push(` const ${variable} = new ${constructorName}(${constructorArgs});`);
|
|
214
237
|
this.#applyPixiProps(variable, node.props, true, node);
|
|
215
238
|
for (const [name, action] of Object.entries(node.events)) {
|
|
216
239
|
this.#runtimeImports.add('connectSceneEvent');
|
|
@@ -218,30 +241,34 @@ class CompileContext {
|
|
|
218
241
|
}
|
|
219
242
|
this.#applyParentSorting(parent, node.props);
|
|
220
243
|
this.#lines.push(` ${parent}.addChild(${variable});`);
|
|
244
|
+
this.#lines.push(` __pixifactNodes[${JSON.stringify(locator)}] = ${variable};`);
|
|
221
245
|
for (const [slot, children] of Object.entries(node.slots)) {
|
|
222
|
-
for (const child of children) {
|
|
223
|
-
const childVariable = this.#compileSlottedNode(child, variable, actionsParameter);
|
|
246
|
+
for (const [index, child] of children.entries()) {
|
|
247
|
+
const childVariable = this.#compileSlottedNode(child, variable, actionsParameter, `${locator}/slot:${slot}/${index}`);
|
|
224
248
|
this.#runtimeImports.add('mount');
|
|
225
249
|
this.#lines.push(` mount(${variable}, ${childVariable}, ${JSON.stringify(slot)});`);
|
|
226
250
|
}
|
|
227
251
|
}
|
|
228
252
|
}
|
|
229
|
-
#compileSlottedNode(node, slotTarget, actionsParameter) {
|
|
253
|
+
#compileSlottedNode(node, slotTarget, actionsParameter, path) {
|
|
230
254
|
if (node.kind === 'slotOutlet') {
|
|
231
255
|
throw new Error(`Cannot place <slot> inside ${slotTarget}.`);
|
|
232
256
|
}
|
|
233
257
|
if (node.kind === 'sceneInstance') {
|
|
234
258
|
const variable = node.id || this.#anonymousName(node.type);
|
|
259
|
+
const locator = compilerSceneNodeLocator(node, path);
|
|
235
260
|
const constructorName = this.#sceneConstructorName(node);
|
|
236
|
-
|
|
261
|
+
const constructorArgs = this.#sceneInstanceConstructorArgs(variable, node);
|
|
262
|
+
this.#lines.push(` const ${variable} = new ${constructorName}(${constructorArgs});`);
|
|
237
263
|
this.#applyPixiProps(variable, node.props, true, node);
|
|
238
264
|
for (const [name, action] of Object.entries(node.events)) {
|
|
239
265
|
this.#runtimeImports.add('connectSceneEvent');
|
|
240
266
|
this.#lines.push(` connectSceneEvent(${variable}.${name}, ${JSON.stringify(action)}, root, ${actionsParameter});`);
|
|
241
267
|
}
|
|
268
|
+
this.#lines.push(` __pixifactNodes[${JSON.stringify(locator)}] = ${variable};`);
|
|
242
269
|
for (const [slot, children] of Object.entries(node.slots)) {
|
|
243
|
-
for (const child of children) {
|
|
244
|
-
const childVariable = this.#compileSlottedNode(child, variable, actionsParameter);
|
|
270
|
+
for (const [index, child] of children.entries()) {
|
|
271
|
+
const childVariable = this.#compileSlottedNode(child, variable, actionsParameter, `${locator}/slot:${slot}/${index}`);
|
|
245
272
|
this.#runtimeImports.add('mount');
|
|
246
273
|
this.#lines.push(` mount(${variable}, ${childVariable}, ${JSON.stringify(slot)});`);
|
|
247
274
|
}
|
|
@@ -249,17 +276,19 @@ class CompileContext {
|
|
|
249
276
|
return variable;
|
|
250
277
|
}
|
|
251
278
|
const variable = node.id || this.#anonymousName(node.type);
|
|
279
|
+
const locator = compilerSceneNodeLocator(node, path);
|
|
252
280
|
this.#lines.push(` const ${variable} = ${this.#constructPixiNode(node)};`);
|
|
253
281
|
this.#applyNodeId(variable, node.id);
|
|
254
282
|
this.#applyPixiProps(variable, node.props, false, undefined, node.type);
|
|
255
|
-
|
|
256
|
-
|
|
283
|
+
this.#lines.push(` __pixifactNodes[${JSON.stringify(locator)}] = ${variable};`);
|
|
284
|
+
for (const [index, child] of node.children.entries()) {
|
|
285
|
+
this.#compileNode(child, variable, actionsParameter, `${locator}/${index}`);
|
|
257
286
|
}
|
|
258
287
|
return variable;
|
|
259
288
|
}
|
|
260
289
|
#constructPixiNode(node) {
|
|
261
290
|
if (node.type === 'Text' || node.type === 'BitmapText' || node.type === 'HTMLText') {
|
|
262
|
-
const text = this.#stringValue(node.props.text ?? '');
|
|
291
|
+
const text = this.#stringValue(isSceneBindingValue(node.props.text) ? '' : node.props.text ?? '');
|
|
263
292
|
const style = this.#styleObject(node.props);
|
|
264
293
|
return `new ${node.type}({ text: ${text}${style ? `, style: ${style}` : ''} })`;
|
|
265
294
|
}
|
|
@@ -285,6 +314,31 @@ class CompileContext {
|
|
|
285
314
|
#sceneConstructorName(node) {
|
|
286
315
|
return this.options.sceneClassAliases?.[node.scene] ?? node.type;
|
|
287
316
|
}
|
|
317
|
+
#sceneInstanceConstructorArgs(variable, node) {
|
|
318
|
+
const sceneInterface = this.options.sceneInterfaces?.[node.scene];
|
|
319
|
+
if (!sceneInterface) {
|
|
320
|
+
return '';
|
|
321
|
+
}
|
|
322
|
+
const entries = [];
|
|
323
|
+
for (const [key, value] of Object.entries(node.props)) {
|
|
324
|
+
const contract = sceneInterface.props[key];
|
|
325
|
+
if (!contract) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (isSceneBindingValue(value)) {
|
|
329
|
+
this.#runtimeImports.add('readSceneBindingValue');
|
|
330
|
+
entries.push(`${key}: readSceneBindingValue(root, ${JSON.stringify(value)})`);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (contract.type === 'struct' && value && typeof value === 'object') {
|
|
334
|
+
const structVariable = this.#createStructValue(variable, key, value, contract);
|
|
335
|
+
entries.push(`${key}: ${structVariable}`);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
entries.push(`${key}: ${this.#value(value)}`);
|
|
339
|
+
}
|
|
340
|
+
return entries.length > 0 ? `{ ${entries.join(', ')} }` : '';
|
|
341
|
+
}
|
|
288
342
|
#sceneStructImports(sceneImport) {
|
|
289
343
|
const scene = this.#sceneImportScene(sceneImport);
|
|
290
344
|
if (!scene) {
|
|
@@ -355,6 +409,18 @@ class CompileContext {
|
|
|
355
409
|
return contract.sourceScene ?? instanceScene;
|
|
356
410
|
}
|
|
357
411
|
#applyPixiProps(variable, props, instance = false, sceneInstance, pixiType) {
|
|
412
|
+
const publicProps = new Set(Object.keys(sceneInstance ? this.options.sceneInterfaces?.[sceneInstance.scene]?.props ?? {} : {}));
|
|
413
|
+
const bindingEntries = Object.entries(props).filter((entry) => (isSceneBindingValue(entry[1]) && !publicProps.has(entry[0])));
|
|
414
|
+
props = Object.fromEntries(Object.entries(props).filter(([, value]) => !isSceneBindingValue(value)));
|
|
415
|
+
if (sceneInstance) {
|
|
416
|
+
props = Object.fromEntries(Object.entries(props).filter(([key]) => !publicProps.has(key)));
|
|
417
|
+
for (const [key, value] of Object.entries(sceneInstance.props)) {
|
|
418
|
+
if (publicProps.has(key) && isSceneBindingValue(value)) {
|
|
419
|
+
this.#runtimeImports.add('bindSceneNodeProp');
|
|
420
|
+
this.#lines.push(` bindSceneNodeProp(root, ${JSON.stringify(value)}, ${variable}, ${JSON.stringify(key)});`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
358
424
|
const x = props.x;
|
|
359
425
|
const y = props.y;
|
|
360
426
|
if (x !== undefined || y !== undefined) {
|
|
@@ -390,6 +456,10 @@ class CompileContext {
|
|
|
390
456
|
this.#drawGraphics(variable, props);
|
|
391
457
|
}
|
|
392
458
|
for (const [key, value] of Object.entries(props)) {
|
|
459
|
+
if (!instance && (pixiType === 'Label' || pixiType === 'BitmapLabel') && labelProps.has(key)) {
|
|
460
|
+
this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
393
463
|
if (!instance && runtimeNodeProps.has(key)) {
|
|
394
464
|
this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
|
|
395
465
|
continue;
|
|
@@ -413,7 +483,7 @@ class CompileContext {
|
|
|
413
483
|
if (instance && layoutProps.has(key)) {
|
|
414
484
|
continue;
|
|
415
485
|
}
|
|
416
|
-
if (instance && value && typeof value === 'object') {
|
|
486
|
+
if (instance && value && typeof value === 'object' && !isSceneBindingValue(value)) {
|
|
417
487
|
this.#applyStructProp(variable, key, value, sceneInstance);
|
|
418
488
|
continue;
|
|
419
489
|
}
|
|
@@ -421,6 +491,10 @@ class CompileContext {
|
|
|
421
491
|
this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
|
|
422
492
|
}
|
|
423
493
|
}
|
|
494
|
+
for (const [key, binding] of bindingEntries) {
|
|
495
|
+
this.#runtimeImports.add('bindSceneNodeProp');
|
|
496
|
+
this.#lines.push(` bindSceneNodeProp(root, ${JSON.stringify(binding)}, ${variable}, ${JSON.stringify(key)});`);
|
|
497
|
+
}
|
|
424
498
|
}
|
|
425
499
|
#applyRootProps() {
|
|
426
500
|
const props = { ...this.template.props };
|
|
@@ -451,12 +525,16 @@ class CompileContext {
|
|
|
451
525
|
this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
|
|
452
526
|
return;
|
|
453
527
|
}
|
|
528
|
+
const structVariable = this.#createStructValue(variable, key, value, contract);
|
|
529
|
+
this.#lines.push(` ${variable}.${key} = ${structVariable};`);
|
|
530
|
+
}
|
|
531
|
+
#createStructValue(variable, key, value, contract) {
|
|
454
532
|
const structVariable = `${variable}${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
455
533
|
this.#lines.push(` const ${structVariable} = new ${contract.struct}();`);
|
|
456
534
|
for (const [field, fieldValue] of Object.entries(value)) {
|
|
457
535
|
this.#lines.push(` ${structVariable}.${field} = ${this.#value(fieldValue)};`);
|
|
458
536
|
}
|
|
459
|
-
|
|
537
|
+
return structVariable;
|
|
460
538
|
}
|
|
461
539
|
#sceneInstanceStructContract(sceneInstance, key) {
|
|
462
540
|
const contract = sceneInstance ? this.options.sceneInterfaces?.[sceneInstance.scene]?.props[key] : undefined;
|
|
@@ -527,7 +605,7 @@ class CompileContext {
|
|
|
527
605
|
const entries = [];
|
|
528
606
|
for (const key of pixiSceneTextStyleProps) {
|
|
529
607
|
const value = props[key];
|
|
530
|
-
if (value !== undefined) {
|
|
608
|
+
if (value !== undefined && !isSceneBindingValue(value)) {
|
|
531
609
|
entries.push(`${key}: ${key === 'fontWeight' ? JSON.stringify(String(value)) : this.#value(value)}`);
|
|
532
610
|
}
|
|
533
611
|
}
|
|
@@ -578,20 +656,6 @@ class CompileContext {
|
|
|
578
656
|
this.#textures.set(texture, variable);
|
|
579
657
|
return variable;
|
|
580
658
|
}
|
|
581
|
-
#textureImportEntries() {
|
|
582
|
-
return [...this.#textures.keys()]
|
|
583
|
-
.filter((texture) => this.options.textureImports?.[texture])
|
|
584
|
-
.map((texture, index) => [texture, `__pixifactTextureUrl${index + 1}`]);
|
|
585
|
-
}
|
|
586
|
-
#textureImportVariable(texture) {
|
|
587
|
-
const index = [...this.#textures.keys()]
|
|
588
|
-
.filter((key) => this.options.textureImports?.[key])
|
|
589
|
-
.indexOf(texture);
|
|
590
|
-
return index >= 0 ? `__pixifactTextureUrl${index + 1}` : undefined;
|
|
591
|
-
}
|
|
592
|
-
#textureLoadSource(texture) {
|
|
593
|
-
return this.#textureImportVariable(texture) ?? this.#value(texture);
|
|
594
|
-
}
|
|
595
659
|
#textureValue(value) {
|
|
596
660
|
return typeof value === 'string' ? this.#textureVariable(value) : this.#value(value);
|
|
597
661
|
}
|
|
@@ -599,6 +663,9 @@ class CompileContext {
|
|
|
599
663
|
if (typeof value === 'string') {
|
|
600
664
|
return JSON.stringify(value);
|
|
601
665
|
}
|
|
666
|
+
if (isSceneBindingValue(value)) {
|
|
667
|
+
throw new Error(`Scene binding ${value.path.join('.')} must be compiled as a binding target.`);
|
|
668
|
+
}
|
|
602
669
|
if (value && typeof value === 'object') {
|
|
603
670
|
return `{ ${Object.entries(value).map(([key, fieldValue]) => `${key}: ${this.#scalarValue(fieldValue)}`).join(', ')} }`;
|
|
604
671
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SceneTemplateInterface } from '../compiler/spec.js';
|
|
2
|
+
import { type BuiltinSceneScriptSources } from '../compiler/builtinScenes.js';
|
|
3
|
+
export declare function builtinSceneInterface(assetId: string, scriptSources: BuiltinSceneScriptSources): SceneTemplateInterface;
|
|
4
|
+
export declare function builtinSceneInterfaces(scriptSources: BuiltinSceneScriptSources): {
|
|
5
|
+
[k: string]: SceneTemplateInterface;
|
|
6
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { builtinSceneAssetId, builtinSceneAssetIds, builtinSceneNameFromAssetId, builtinSceneNames, } from '../compiler/builtinScenes.js';
|
|
2
|
+
import { extractSceneScriptInterfaces } from './scriptInterfaceExtractor.js';
|
|
3
|
+
export function builtinSceneInterface(assetId, scriptSources) {
|
|
4
|
+
return builtinSceneInterfaceDescriptors(scriptSources)[assetId].interface;
|
|
5
|
+
}
|
|
6
|
+
export function builtinSceneInterfaces(scriptSources) {
|
|
7
|
+
const descriptors = builtinSceneInterfaceDescriptors(scriptSources);
|
|
8
|
+
return Object.fromEntries(builtinSceneAssetIds().map((assetId) => [assetId, descriptors[assetId].interface]));
|
|
9
|
+
}
|
|
10
|
+
function builtinSceneInterfaceDescriptors(scriptSources) {
|
|
11
|
+
const descriptors = extractSceneScriptInterfaces(builtinSceneNames.map((name) => ({
|
|
12
|
+
scene: builtinSceneAssetId(name),
|
|
13
|
+
fileName: `${name}.ts`,
|
|
14
|
+
source: scriptSources[name],
|
|
15
|
+
})));
|
|
16
|
+
for (const assetId of builtinSceneAssetIds()) {
|
|
17
|
+
const name = builtinSceneNameFromAssetId(assetId);
|
|
18
|
+
const descriptor = descriptors[assetId];
|
|
19
|
+
if (!descriptor) {
|
|
20
|
+
throw new Error(`Built-in Scene "${assetId}" is missing a @scene script.`);
|
|
21
|
+
}
|
|
22
|
+
if (descriptor.className !== name) {
|
|
23
|
+
throw new Error(`Built-in Scene "${assetId}" name must match @scene class "${descriptor.className}".`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return descriptors;
|
|
27
|
+
}
|