@openfairygui/cli 0.2.0-alpha.10 → 0.2.0-alpha.12
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/dist/cli.mjs +1320 -760
- package/package.json +6 -4
- package/src/cli.ts +30 -535
- package/src/commands/backend-capabilities.ts +37 -0
- package/src/commands/inspect.ts +44 -0
- package/src/commands/publish.ts +67 -0
- package/src/commands/restore.ts +209 -0
- package/src/utils/package-version.ts +22 -0
- package/src/utils/project-input.ts +26 -0
- package/src/utils/project-type.ts +31 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,10 +1,177 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { Command } from "commander";
|
|
2
3
|
import { createNodeBackendRuntime } from "@openfairygui/backend/node";
|
|
3
|
-
import * as fs$1 from "node:fs/promises";
|
|
4
|
-
import fs from "node:fs/promises";
|
|
5
4
|
import * as path$1 from "node:path";
|
|
6
5
|
import path from "node:path";
|
|
7
|
-
import
|
|
6
|
+
import * as fs$1 from "node:fs/promises";
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
//#region src/commands/backend-capabilities.ts
|
|
9
|
+
function registerBackendCapabilitiesCommand(program) {
|
|
10
|
+
program.command("backend-capabilities").description("Open a backend session, print runtime capabilities, then close it").argument("<project-dir>", "Project root directory").action(async (projectDir) => {
|
|
11
|
+
const runtime = createNodeBackendRuntime();
|
|
12
|
+
const opened = await runtime.openSession({ projectPath: path.resolve(projectDir) });
|
|
13
|
+
if (!opened.ok) throw new Error(`backend-capabilities: ${opened.error.message}`);
|
|
14
|
+
const capabilities = runtime.getCapabilities();
|
|
15
|
+
if (!capabilities.ok) {
|
|
16
|
+
await runtime.closeSession({ sessionId: opened.data.sessionId });
|
|
17
|
+
throw new Error("backend-capabilities: failed to read capabilities");
|
|
18
|
+
}
|
|
19
|
+
console.log(`Session: ${opened.data.sessionId}`);
|
|
20
|
+
console.log(`Project: ${opened.data.canonicalProjectPath}`);
|
|
21
|
+
console.log(`Revision: ${opened.data.revision}`);
|
|
22
|
+
console.log(`Runtime owner: ${capabilities.data.runtimeOwner}`);
|
|
23
|
+
console.log(`Transaction owner: ${capabilities.data.transactionKernelOwner}`);
|
|
24
|
+
console.log(`App seam owner: ${capabilities.data.appSeamOwner}`);
|
|
25
|
+
const closed = await runtime.closeSession({ sessionId: opened.data.sessionId });
|
|
26
|
+
if (!closed.ok) throw new Error(`backend-capabilities: ${closed.error.message}`);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region ../functions/src/inspect.ts
|
|
31
|
+
function mapResource(resource) {
|
|
32
|
+
return {
|
|
33
|
+
name: resource.getName(),
|
|
34
|
+
id: resource.getId(),
|
|
35
|
+
path: resource.getPath?.() ?? "/",
|
|
36
|
+
exported: resource.getExported?.() ?? false
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function mapComponentDetail(component, totals) {
|
|
40
|
+
const children = component.listChildren();
|
|
41
|
+
const controllers = component.listControllers();
|
|
42
|
+
const transitions = component.listTransitions();
|
|
43
|
+
totals.displayObjects += children.length;
|
|
44
|
+
totals.controllers += controllers.length;
|
|
45
|
+
totals.transitions += transitions.length;
|
|
46
|
+
for (const child of children) totals.gears += child.listGears().length;
|
|
47
|
+
return {
|
|
48
|
+
name: component.getName(),
|
|
49
|
+
id: component.getId(),
|
|
50
|
+
childCount: children.length,
|
|
51
|
+
controllerCount: controllers.length,
|
|
52
|
+
transitionCount: transitions.length
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generates a detailed report of the project contents.
|
|
57
|
+
*
|
|
58
|
+
* Unlike other transforms, `inspect()` does NOT modify the document —
|
|
59
|
+
* it returns a structured report.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* const report = inspect(doc);
|
|
63
|
+
* console.log(`${report.totals.packages} packages, ${report.totals.components} components`);
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function inspect(doc) {
|
|
67
|
+
const root = doc.getRoot();
|
|
68
|
+
const totals = {
|
|
69
|
+
packages: 0,
|
|
70
|
+
images: 0,
|
|
71
|
+
sounds: 0,
|
|
72
|
+
fonts: 0,
|
|
73
|
+
movieClips: 0,
|
|
74
|
+
components: 0,
|
|
75
|
+
displayObjects: 0,
|
|
76
|
+
gears: 0,
|
|
77
|
+
controllers: 0,
|
|
78
|
+
transitions: 0
|
|
79
|
+
};
|
|
80
|
+
const packages = root.listPackages().map((pkg) => {
|
|
81
|
+
totals.packages++;
|
|
82
|
+
const resources = pkg.listResources();
|
|
83
|
+
const images = resources.filter((r) => r.propertyType === "ImageResource");
|
|
84
|
+
const sounds = resources.filter((r) => r.propertyType === "SoundResource");
|
|
85
|
+
const fonts = resources.filter((r) => r.propertyType === "FontResource");
|
|
86
|
+
const movieClips = resources.filter((r) => r.propertyType === "MovieClipResource");
|
|
87
|
+
const components = pkg.listComponents();
|
|
88
|
+
totals.images += images.length;
|
|
89
|
+
totals.sounds += sounds.length;
|
|
90
|
+
totals.fonts += fonts.length;
|
|
91
|
+
totals.movieClips += movieClips.length;
|
|
92
|
+
totals.components += components.length;
|
|
93
|
+
const componentDetails = components.map((component) => mapComponentDetail(component, totals));
|
|
94
|
+
return {
|
|
95
|
+
name: pkg.getName(),
|
|
96
|
+
id: pkg.getId(),
|
|
97
|
+
publishName: pkg.getPublishName() || pkg.getName(),
|
|
98
|
+
resources: {
|
|
99
|
+
images: {
|
|
100
|
+
count: images.length,
|
|
101
|
+
details: images.map(mapResource)
|
|
102
|
+
},
|
|
103
|
+
sounds: {
|
|
104
|
+
count: sounds.length,
|
|
105
|
+
details: sounds.map(mapResource)
|
|
106
|
+
},
|
|
107
|
+
fonts: {
|
|
108
|
+
count: fonts.length,
|
|
109
|
+
details: fonts.map(mapResource)
|
|
110
|
+
},
|
|
111
|
+
movieClips: {
|
|
112
|
+
count: movieClips.length,
|
|
113
|
+
details: movieClips.map(mapResource)
|
|
114
|
+
},
|
|
115
|
+
components: {
|
|
116
|
+
count: components.length,
|
|
117
|
+
details: components.map(mapResource)
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
componentDetails
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
projectId: root.getProjectId(),
|
|
125
|
+
projectType: root.getProjectType(),
|
|
126
|
+
version: root.getVersion(),
|
|
127
|
+
packages,
|
|
128
|
+
totals
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region ../functions/src/utils.ts
|
|
133
|
+
/**
|
|
134
|
+
* Wraps a transform function, assigning it a name for the transform stack.
|
|
135
|
+
*/
|
|
136
|
+
function createTransform(name, fn) {
|
|
137
|
+
Object.defineProperty(fn, "name", { value: name });
|
|
138
|
+
return fn;
|
|
139
|
+
}
|
|
140
|
+
function parseTextureSetMode(value) {
|
|
141
|
+
const raw = value?.trim() ?? "";
|
|
142
|
+
if (!raw) return {
|
|
143
|
+
kind: "auto",
|
|
144
|
+
raw: ""
|
|
145
|
+
};
|
|
146
|
+
if (raw === "alone") return {
|
|
147
|
+
kind: "standalone",
|
|
148
|
+
raw,
|
|
149
|
+
sizeMode: "default"
|
|
150
|
+
};
|
|
151
|
+
if (raw === "alone_npot") return {
|
|
152
|
+
kind: "standalone",
|
|
153
|
+
raw,
|
|
154
|
+
sizeMode: "npot"
|
|
155
|
+
};
|
|
156
|
+
if (raw === "alone_mof") return {
|
|
157
|
+
kind: "standalone",
|
|
158
|
+
raw,
|
|
159
|
+
sizeMode: "multipleOf4"
|
|
160
|
+
};
|
|
161
|
+
if (/^\d+$/.test(raw)) {
|
|
162
|
+
const pageIndex = Number(raw);
|
|
163
|
+
if (pageIndex >= 0 && pageIndex <= 10) return {
|
|
164
|
+
kind: "page",
|
|
165
|
+
raw,
|
|
166
|
+
pageIndex
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
kind: "auto",
|
|
171
|
+
raw
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//#endregion
|
|
8
175
|
//#region ../../node_modules/.pnpm/property-graph@4.1.0/node_modules/property-graph/dist/index.mjs
|
|
9
176
|
var EventDispatcher = class {
|
|
10
177
|
_listeners = {};
|
|
@@ -1688,6 +1855,7 @@ var MovieClipResource = class extends ExtensibleProperty {
|
|
|
1688
1855
|
highResolutionItemIds: [],
|
|
1689
1856
|
fileName: "",
|
|
1690
1857
|
exported: false,
|
|
1858
|
+
textureSetMode: "",
|
|
1691
1859
|
width: 0,
|
|
1692
1860
|
height: 0,
|
|
1693
1861
|
interval: 0,
|
|
@@ -1739,6 +1907,12 @@ var MovieClipResource = class extends ExtensibleProperty {
|
|
|
1739
1907
|
setExported(v) {
|
|
1740
1908
|
return this.set("exported", v);
|
|
1741
1909
|
}
|
|
1910
|
+
getTextureSetMode() {
|
|
1911
|
+
return this.get("textureSetMode");
|
|
1912
|
+
}
|
|
1913
|
+
setTextureSetMode(v) {
|
|
1914
|
+
return this.set("textureSetMode", v);
|
|
1915
|
+
}
|
|
1742
1916
|
getWidth() {
|
|
1743
1917
|
return this.get("width");
|
|
1744
1918
|
}
|
|
@@ -4451,6 +4625,8 @@ var GComponent = class extends GObject {
|
|
|
4451
4625
|
instanceController: "",
|
|
4452
4626
|
instancePage: "",
|
|
4453
4627
|
instanceChecked: false,
|
|
4628
|
+
instanceSound: "",
|
|
4629
|
+
instanceSoundVolumeScale: 1,
|
|
4454
4630
|
instancePromptText: "",
|
|
4455
4631
|
instanceSelectionController: "",
|
|
4456
4632
|
instanceVisibleItemCount: 0,
|
|
@@ -4723,6 +4899,18 @@ var GComponent = class extends GObject {
|
|
|
4723
4899
|
setInstanceChecked(v) {
|
|
4724
4900
|
return this.setComponentProp("instanceChecked", v);
|
|
4725
4901
|
}
|
|
4902
|
+
getInstanceSound() {
|
|
4903
|
+
return firstString$1(this.getComponentProp("instanceSound"));
|
|
4904
|
+
}
|
|
4905
|
+
setInstanceSound(v) {
|
|
4906
|
+
return this.setComponentProp("instanceSound", v);
|
|
4907
|
+
}
|
|
4908
|
+
getInstanceSoundVolumeScale() {
|
|
4909
|
+
return this.getComponentProp("instanceSoundVolumeScale");
|
|
4910
|
+
}
|
|
4911
|
+
setInstanceSoundVolumeScale(v) {
|
|
4912
|
+
return this.setComponentProp("instanceSoundVolumeScale", v);
|
|
4913
|
+
}
|
|
4726
4914
|
getInstancePromptText() {
|
|
4727
4915
|
return firstString$1(this.getComponentProp("instancePromptText"));
|
|
4728
4916
|
}
|
|
@@ -9081,6 +9269,7 @@ var Document = class Document {
|
|
|
9081
9269
|
_graph = new Graph();
|
|
9082
9270
|
_root = new Root(this._graph);
|
|
9083
9271
|
_logger = Logger.DEFAULT_INSTANCE;
|
|
9272
|
+
_projectDir = "";
|
|
9084
9273
|
static _GRAPH_DOCUMENTS = /* @__PURE__ */ new WeakMap();
|
|
9085
9274
|
static fromGraph(graph) {
|
|
9086
9275
|
return Document._GRAPH_DOCUMENTS.get(graph) || null;
|
|
@@ -9102,6 +9291,13 @@ var Document = class Document {
|
|
|
9102
9291
|
this._logger = logger;
|
|
9103
9292
|
return this;
|
|
9104
9293
|
}
|
|
9294
|
+
getProjectDir() {
|
|
9295
|
+
return this._projectDir;
|
|
9296
|
+
}
|
|
9297
|
+
setProjectDir(projectDir) {
|
|
9298
|
+
this._projectDir = projectDir;
|
|
9299
|
+
return this;
|
|
9300
|
+
}
|
|
9105
9301
|
async transform(...transforms) {
|
|
9106
9302
|
const stack = transforms.map((fn) => fn.name);
|
|
9107
9303
|
for (const transform of transforms) await transform(this, { stack });
|
|
@@ -9282,6 +9478,7 @@ const PACKAGE_FONT_RESOURCE_ATTRS = {
|
|
|
9282
9478
|
renderMode: { canonical: "renderMode" },
|
|
9283
9479
|
samplePointSize: { canonical: "samplePointSize" }
|
|
9284
9480
|
};
|
|
9481
|
+
const PACKAGE_MOVIE_CLIP_RESOURCE_ATTRS = { atlas: { canonical: "atlas" } };
|
|
9285
9482
|
const PACKAGE_SKELETON_RESOURCE_ATTRS = {
|
|
9286
9483
|
width: { canonical: "width" },
|
|
9287
9484
|
height: { canonical: "height" },
|
|
@@ -9518,7 +9715,10 @@ const LIST_PANEL_ATTRS = {
|
|
|
9518
9715
|
const BUTTON_EXTENSION_ATTRS = {
|
|
9519
9716
|
mode: { canonical: "mode" },
|
|
9520
9717
|
sound: { canonical: "sound" },
|
|
9521
|
-
soundVolumeScale: {
|
|
9718
|
+
soundVolumeScale: {
|
|
9719
|
+
canonical: "soundVolumeScale",
|
|
9720
|
+
aliases: ["volume"]
|
|
9721
|
+
},
|
|
9522
9722
|
downEffect: { canonical: "downEffect" },
|
|
9523
9723
|
downEffectValue: { canonical: "downEffectValue" },
|
|
9524
9724
|
title: { canonical: "title" },
|
|
@@ -9644,6 +9844,7 @@ const PACKAGE_PUBLISH_NODE = defineNode(PACKAGE_PUBLISH_ATTRS, { atlas: PACKAGE_
|
|
|
9644
9844
|
const PACKAGE_RESOURCE_NODE = defineNode(PACKAGE_RESOURCE_BASE_ATTRS);
|
|
9645
9845
|
const PACKAGE_IMAGE_RESOURCE_NODE = defineNode(PACKAGE_IMAGE_RESOURCE_ATTRS);
|
|
9646
9846
|
const PACKAGE_FONT_RESOURCE_NODE = defineNode(PACKAGE_FONT_RESOURCE_ATTRS);
|
|
9847
|
+
const PACKAGE_MOVIE_CLIP_RESOURCE_NODE = defineNode(PACKAGE_MOVIE_CLIP_RESOURCE_ATTRS);
|
|
9647
9848
|
const PACKAGE_SKELETON_RESOURCE_NODE = defineNode(PACKAGE_SKELETON_RESOURCE_ATTRS);
|
|
9648
9849
|
const DISPLAY_OBJECT_NODE = defineNode(DISPLAY_OBJECT_IDENTITY_ATTRS);
|
|
9649
9850
|
const BUTTON_EXTENSION_NODE = defineNode(BUTTON_EXTENSION_ATTRS);
|
|
@@ -9734,6 +9935,7 @@ const PROJECT_XML_PROTOCOL = {
|
|
|
9734
9935
|
packageResource: PACKAGE_RESOURCE_NODE,
|
|
9735
9936
|
packageImageResource: PACKAGE_IMAGE_RESOURCE_NODE,
|
|
9736
9937
|
packageFontResource: PACKAGE_FONT_RESOURCE_NODE,
|
|
9938
|
+
packageMovieClipResource: PACKAGE_MOVIE_CLIP_RESOURCE_NODE,
|
|
9737
9939
|
packageSkeletonResource: PACKAGE_SKELETON_RESOURCE_NODE,
|
|
9738
9940
|
displayObject: DISPLAY_OBJECT_NODE,
|
|
9739
9941
|
image: IMAGE_NODE,
|
|
@@ -10177,6 +10379,7 @@ var ProjectReader = class {
|
|
|
10177
10379
|
const fs = this._fs;
|
|
10178
10380
|
const doc = new Document();
|
|
10179
10381
|
const basePath = getProjectBasePath(fs, projectPath);
|
|
10382
|
+
doc.setProjectDir(basePath);
|
|
10180
10383
|
const ctx = new ReaderContext(doc, basePath);
|
|
10181
10384
|
const projDesc = getXmlNode(parseXML(await fs.readFile(projectPath)).projectDescription);
|
|
10182
10385
|
if (projDesc) {
|
|
@@ -10493,6 +10696,8 @@ var ProjectReader = class {
|
|
|
10493
10696
|
res.setBranch(branchName);
|
|
10494
10697
|
res.setFileName(name);
|
|
10495
10698
|
res.setExported(exported);
|
|
10699
|
+
const textureSetMode = readXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageMovieClipResource.attrs.atlas);
|
|
10700
|
+
if (textureSetMode !== void 0) res.setTextureSetMode(textureSetMode);
|
|
10496
10701
|
pkg.addResource(res);
|
|
10497
10702
|
ctx.registerResource(pkg.getId(), id, res);
|
|
10498
10703
|
return res;
|
|
@@ -11752,6 +11957,10 @@ var ProjectReader = class {
|
|
|
11752
11957
|
if (page !== void 0) componentObj.setInstancePage?.(page);
|
|
11753
11958
|
const checked = extSpecs.checked ? readXmlAttr(extAttrs, extSpecs.checked) : void 0;
|
|
11754
11959
|
if (checked !== void 0) componentObj.setInstanceChecked?.(parseBool(checked));
|
|
11960
|
+
const sound = extSpecs.sound ? readXmlAttr(extAttrs, extSpecs.sound) : void 0;
|
|
11961
|
+
if (sound !== void 0) componentObj.setInstanceSound?.(sound);
|
|
11962
|
+
const soundVolumeScale = extSpecs.soundVolumeScale ? readXmlAttr(extAttrs, extSpecs.soundVolumeScale) : void 0;
|
|
11963
|
+
if (soundVolumeScale !== void 0) componentObj.setInstanceSoundVolumeScale?.(parseFloat2(soundVolumeScale, 1));
|
|
11755
11964
|
const prompt = extSpecs.prompt ? readXmlAttr(extAttrs, extSpecs.prompt) : void 0;
|
|
11756
11965
|
if (prompt !== void 0) componentObj.setInstancePromptText?.(prompt);
|
|
11757
11966
|
const selectionController = extSpecs.selectionController ? readXmlAttr(extAttrs, extSpecs.selectionController) : void 0;
|
|
@@ -12418,6 +12627,10 @@ var ProjectWriter = class {
|
|
|
12418
12627
|
const samplePointSize = fontRes.getSamplePointSize?.() ?? 0;
|
|
12419
12628
|
if (samplePointSize !== 0) writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageFontResource.attrs.samplePointSize, String(samplePointSize));
|
|
12420
12629
|
}
|
|
12630
|
+
if (res.propertyType === "MovieClipResource") {
|
|
12631
|
+
const textureSetMode = res.getTextureSetMode?.() ?? "";
|
|
12632
|
+
if (textureSetMode) writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageMovieClipResource.attrs.atlas, textureSetMode);
|
|
12633
|
+
}
|
|
12421
12634
|
if (res.propertyType === "SpineResource" || res.propertyType === "DragonBonesResource") {
|
|
12422
12635
|
const skeletonRes = res;
|
|
12423
12636
|
writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageSkeletonResource.attrs.width, String(skeletonRes.getWidth?.() ?? 0));
|
|
@@ -13099,6 +13312,8 @@ var ProjectWriter = class {
|
|
|
13099
13312
|
if (typedObj.getInstanceController?.() && extSpecs.controller) writeXmlAttr(extAttrs, extSpecs.controller, typedObj.getInstanceController?.());
|
|
13100
13313
|
if (typedObj.getInstancePage?.() && extSpecs.page) writeXmlAttr(extAttrs, extSpecs.page, typedObj.getInstancePage?.());
|
|
13101
13314
|
if (typedObj.getInstanceChecked?.() && extSpecs.checked) writeXmlAttr(extAttrs, extSpecs.checked, "1");
|
|
13315
|
+
if (typedObj.getInstanceSound?.() && extSpecs.sound) writeXmlAttr(extAttrs, extSpecs.sound, typedObj.getInstanceSound?.());
|
|
13316
|
+
if ((typedObj.getInstanceSoundVolumeScale?.() ?? 1) !== 1 && extSpecs.soundVolumeScale) writeXmlAttr(extAttrs, extSpecs.soundVolumeScale, String(typedObj.getInstanceSoundVolumeScale?.() ?? 1));
|
|
13102
13317
|
if (typedObj.getInstancePromptText?.() && extSpecs.prompt) writeXmlAttr(extAttrs, extSpecs.prompt, typedObj.getInstancePromptText?.());
|
|
13103
13318
|
if (typedObj.getInstanceSelectionController?.() && extSpecs.selectionController) writeXmlAttr(extAttrs, extSpecs.selectionController, typedObj.getInstanceSelectionController?.());
|
|
13104
13319
|
if ((typedObj.getInstanceVisibleItemCount?.() ?? 0) > 0 && extSpecs.visibleItemCount) writeXmlAttr(extAttrs, extSpecs.visibleItemCount, String(typedObj.getInstanceVisibleItemCount?.() ?? 0));
|
|
@@ -17569,8 +17784,8 @@ function decodeChildBlock6(resource, child, childBuf) {
|
|
|
17569
17784
|
if (relatedControllerIndex >= 0) component.setInstanceController(resource.listControllers()[relatedControllerIndex]?.getName() ?? "");
|
|
17570
17785
|
}
|
|
17571
17786
|
component.setInstancePage(childBuf.readS() ?? "");
|
|
17572
|
-
childBuf.readS();
|
|
17573
|
-
if (childBuf.readBool() && remainingBytes(childBuf) >= 4) childBuf.getFloat32();
|
|
17787
|
+
component.setInstanceSound(childBuf.readS() ?? "");
|
|
17788
|
+
if (childBuf.readBool() && remainingBytes(childBuf) >= 4) component.setInstanceSoundVolumeScale(childBuf.getFloat32());
|
|
17574
17789
|
if (remainingBytes(childBuf) >= 1) component.setInstanceChecked(childBuf.readBool());
|
|
17575
17790
|
break;
|
|
17576
17791
|
case "Label":
|
|
@@ -18144,8 +18359,9 @@ const BinItemType$1 = {
|
|
|
18144
18359
|
Font: 5,
|
|
18145
18360
|
Swf: 6,
|
|
18146
18361
|
Misc: 7,
|
|
18147
|
-
|
|
18148
|
-
|
|
18362
|
+
Unknown: 8,
|
|
18363
|
+
Spine: 9,
|
|
18364
|
+
DragonBones: 10
|
|
18149
18365
|
};
|
|
18150
18366
|
function normalizePackageResourcePath(path) {
|
|
18151
18367
|
const normalized = path.replace(/\\/g, "/").trim();
|
|
@@ -19983,8 +20199,13 @@ function _writeExtensionInstanceData(buf, extType, child, comp, pkg, version) {
|
|
|
19983
20199
|
buf.writeInt16(ctrlIdx >= 0 ? ctrlIdx : -1);
|
|
19984
20200
|
} else buf.writeInt16(-1);
|
|
19985
20201
|
buf.writeS(child.getInstancePage?.() ?? null);
|
|
19986
|
-
|
|
19987
|
-
buf.
|
|
20202
|
+
const sound = child.getInstanceSound?.() ?? null;
|
|
20203
|
+
buf.writeSEx(remapLocalUiUrl(pkg, sound) ?? null, false, false);
|
|
20204
|
+
const soundVolume = child.getInstanceSoundVolumeScale?.();
|
|
20205
|
+
if (soundVolume !== void 0 && soundVolume !== null && soundVolume !== 1) {
|
|
20206
|
+
buf.writeBool(true);
|
|
20207
|
+
buf.writeFloat32(soundVolume);
|
|
20208
|
+
} else buf.writeBool(false);
|
|
19988
20209
|
buf.writeBool(child.getInstanceChecked?.() ?? false);
|
|
19989
20210
|
break;
|
|
19990
20211
|
}
|
|
@@ -20165,8 +20386,9 @@ const BinItemType = {
|
|
|
20165
20386
|
Atlas: 4,
|
|
20166
20387
|
Font: 5,
|
|
20167
20388
|
Misc: 7,
|
|
20168
|
-
|
|
20169
|
-
|
|
20389
|
+
Unknown: 8,
|
|
20390
|
+
Spine: 9,
|
|
20391
|
+
DragonBones: 10
|
|
20170
20392
|
};
|
|
20171
20393
|
/**
|
|
20172
20394
|
* Maps our PropertyType to the editor's type string used for sorting.
|
|
@@ -20825,228 +21047,60 @@ var PlatformIO = class {
|
|
|
20825
21047
|
}
|
|
20826
21048
|
};
|
|
20827
21049
|
//#endregion
|
|
20828
|
-
//#region ../
|
|
20829
|
-
|
|
20830
|
-
|
|
20831
|
-
|
|
20832
|
-
|
|
20833
|
-
|
|
20834
|
-
|
|
20835
|
-
|
|
20836
|
-
|
|
20837
|
-
|
|
20838
|
-
|
|
20839
|
-
|
|
20840
|
-
|
|
20841
|
-
|
|
20842
|
-
|
|
20843
|
-
|
|
20844
|
-
|
|
20845
|
-
|
|
20846
|
-
|
|
20847
|
-
|
|
20848
|
-
|
|
20849
|
-
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
20853
|
-
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
20861
|
-
|
|
20862
|
-
|
|
20863
|
-
|
|
20864
|
-
|
|
20865
|
-
|
|
20866
|
-
|
|
20867
|
-
|
|
20868
|
-
|
|
20869
|
-
|
|
20870
|
-
|
|
20871
|
-
|
|
20872
|
-
|
|
20873
|
-
|
|
20874
|
-
|
|
20875
|
-
|
|
20876
|
-
|
|
20877
|
-
|
|
20878
|
-
|
|
20879
|
-
|
|
20880
|
-
|
|
20881
|
-
|
|
20882
|
-
}
|
|
20883
|
-
};
|
|
20884
|
-
//#endregion
|
|
20885
|
-
//#region ../functions/src/inspect.ts
|
|
20886
|
-
function mapResource(resource) {
|
|
20887
|
-
return {
|
|
20888
|
-
name: resource.getName(),
|
|
20889
|
-
id: resource.getId(),
|
|
20890
|
-
path: resource.getPath?.() ?? "/",
|
|
20891
|
-
exported: resource.getExported?.() ?? false
|
|
20892
|
-
};
|
|
20893
|
-
}
|
|
20894
|
-
function mapComponentDetail(component, totals) {
|
|
20895
|
-
const children = component.listChildren();
|
|
20896
|
-
const controllers = component.listControllers();
|
|
20897
|
-
const transitions = component.listTransitions();
|
|
20898
|
-
totals.displayObjects += children.length;
|
|
20899
|
-
totals.controllers += controllers.length;
|
|
20900
|
-
totals.transitions += transitions.length;
|
|
20901
|
-
for (const child of children) totals.gears += child.listGears().length;
|
|
20902
|
-
return {
|
|
20903
|
-
name: component.getName(),
|
|
20904
|
-
id: component.getId(),
|
|
20905
|
-
childCount: children.length,
|
|
20906
|
-
controllerCount: controllers.length,
|
|
20907
|
-
transitionCount: transitions.length
|
|
20908
|
-
};
|
|
20909
|
-
}
|
|
20910
|
-
/**
|
|
20911
|
-
* Generates a detailed report of the project contents.
|
|
20912
|
-
*
|
|
20913
|
-
* Unlike other transforms, `inspect()` does NOT modify the document —
|
|
20914
|
-
* it returns a structured report.
|
|
20915
|
-
*
|
|
20916
|
-
* ```ts
|
|
20917
|
-
* const report = inspect(doc);
|
|
20918
|
-
* console.log(`${report.totals.packages} packages, ${report.totals.components} components`);
|
|
20919
|
-
* ```
|
|
20920
|
-
*/
|
|
20921
|
-
function inspect(doc) {
|
|
20922
|
-
const root = doc.getRoot();
|
|
20923
|
-
const totals = {
|
|
20924
|
-
packages: 0,
|
|
20925
|
-
images: 0,
|
|
20926
|
-
sounds: 0,
|
|
20927
|
-
fonts: 0,
|
|
20928
|
-
movieClips: 0,
|
|
20929
|
-
components: 0,
|
|
20930
|
-
displayObjects: 0,
|
|
20931
|
-
gears: 0,
|
|
20932
|
-
controllers: 0,
|
|
20933
|
-
transitions: 0
|
|
20934
|
-
};
|
|
20935
|
-
const packages = root.listPackages().map((pkg) => {
|
|
20936
|
-
totals.packages++;
|
|
20937
|
-
const resources = pkg.listResources();
|
|
20938
|
-
const images = resources.filter((r) => r.propertyType === "ImageResource");
|
|
20939
|
-
const sounds = resources.filter((r) => r.propertyType === "SoundResource");
|
|
20940
|
-
const fonts = resources.filter((r) => r.propertyType === "FontResource");
|
|
20941
|
-
const movieClips = resources.filter((r) => r.propertyType === "MovieClipResource");
|
|
20942
|
-
const components = pkg.listComponents();
|
|
20943
|
-
totals.images += images.length;
|
|
20944
|
-
totals.sounds += sounds.length;
|
|
20945
|
-
totals.fonts += fonts.length;
|
|
20946
|
-
totals.movieClips += movieClips.length;
|
|
20947
|
-
totals.components += components.length;
|
|
20948
|
-
const componentDetails = components.map((component) => mapComponentDetail(component, totals));
|
|
20949
|
-
return {
|
|
20950
|
-
name: pkg.getName(),
|
|
20951
|
-
id: pkg.getId(),
|
|
20952
|
-
publishName: pkg.getPublishName() || pkg.getName(),
|
|
20953
|
-
resources: {
|
|
20954
|
-
images: {
|
|
20955
|
-
count: images.length,
|
|
20956
|
-
details: images.map(mapResource)
|
|
20957
|
-
},
|
|
20958
|
-
sounds: {
|
|
20959
|
-
count: sounds.length,
|
|
20960
|
-
details: sounds.map(mapResource)
|
|
20961
|
-
},
|
|
20962
|
-
fonts: {
|
|
20963
|
-
count: fonts.length,
|
|
20964
|
-
details: fonts.map(mapResource)
|
|
20965
|
-
},
|
|
20966
|
-
movieClips: {
|
|
20967
|
-
count: movieClips.length,
|
|
20968
|
-
details: movieClips.map(mapResource)
|
|
20969
|
-
},
|
|
20970
|
-
components: {
|
|
20971
|
-
count: components.length,
|
|
20972
|
-
details: components.map(mapResource)
|
|
20973
|
-
}
|
|
20974
|
-
},
|
|
20975
|
-
componentDetails
|
|
20976
|
-
};
|
|
20977
|
-
});
|
|
20978
|
-
return {
|
|
20979
|
-
projectId: root.getProjectId(),
|
|
20980
|
-
projectType: root.getProjectType(),
|
|
20981
|
-
version: root.getVersion(),
|
|
20982
|
-
packages,
|
|
20983
|
-
totals
|
|
20984
|
-
};
|
|
20985
|
-
}
|
|
20986
|
-
//#endregion
|
|
20987
|
-
//#region ../functions/src/utils.ts
|
|
20988
|
-
/**
|
|
20989
|
-
* Wraps a transform function, assigning it a name for the transform stack.
|
|
20990
|
-
*/
|
|
20991
|
-
function createTransform(name, fn) {
|
|
20992
|
-
Object.defineProperty(fn, "name", { value: name });
|
|
20993
|
-
return fn;
|
|
20994
|
-
}
|
|
20995
|
-
//#endregion
|
|
20996
|
-
//#region ../functions/src/max-rects-compat.ts
|
|
20997
|
-
const NO_ROTATION = 2;
|
|
20998
|
-
const MAX_SCORE = 2147483647;
|
|
20999
|
-
const MAX_RECTS_METHOD = {
|
|
21000
|
-
BestShortSideFit: 0,
|
|
21001
|
-
BestLongSideFit: 1,
|
|
21002
|
-
BestAreaFit: 2,
|
|
21003
|
-
BottomLeftRule: 3,
|
|
21004
|
-
ContactPointRule: 4
|
|
21005
|
-
};
|
|
21006
|
-
const COMPAT_NODE_RECT_FLAGS = {
|
|
21007
|
-
DUPLICATE_PADDING: 1,
|
|
21008
|
-
NO_ROTATION
|
|
21009
|
-
};
|
|
21010
|
-
var MaxRectsCompat = class MaxRectsCompat {
|
|
21011
|
-
static helperRect = createNodeRect();
|
|
21012
|
-
binWidth = 0;
|
|
21013
|
-
binHeight = 0;
|
|
21014
|
-
allowRotations = false;
|
|
21015
|
-
usedRectangles = [];
|
|
21016
|
-
freeRectangles = [];
|
|
21017
|
-
init(width, height, allowRotations = false) {
|
|
21018
|
-
this.binWidth = width;
|
|
21019
|
-
this.binHeight = height;
|
|
21020
|
-
this.allowRotations = allowRotations;
|
|
21021
|
-
this.usedRectangles.length = 0;
|
|
21022
|
-
this.freeRectangles.length = 0;
|
|
21023
|
-
this.freeRectangles.push({
|
|
21024
|
-
...createNodeRect(),
|
|
21025
|
-
x: 0,
|
|
21026
|
-
y: 0,
|
|
21027
|
-
width,
|
|
21028
|
-
height
|
|
21029
|
-
});
|
|
21030
|
-
}
|
|
21031
|
-
insert(rect, method) {
|
|
21032
|
-
const newNode = this.scoreRect(rect, method);
|
|
21033
|
-
if (newNode.height === 0) return null;
|
|
21034
|
-
const placed = cloneNodeRect(newNode);
|
|
21035
|
-
this.placeRect(placed);
|
|
21036
|
-
return placed;
|
|
21037
|
-
}
|
|
21038
|
-
pack(rects, method) {
|
|
21039
|
-
const remaining = rects.map(cloneNodeRect);
|
|
21040
|
-
while (remaining.length > 0) {
|
|
21041
|
-
let bestIndex = -1;
|
|
21042
|
-
const bestNode = createNodeRect();
|
|
21043
|
-
bestNode.score1 = MAX_SCORE;
|
|
21044
|
-
bestNode.score2 = MAX_SCORE;
|
|
21045
|
-
for (let index = 0; index < remaining.length; index += 1) {
|
|
21046
|
-
const candidate = this.scoreRect(remaining[index], method);
|
|
21047
|
-
if (candidate.score1 < bestNode.score1 || candidate.score1 === bestNode.score1 && candidate.score2 < bestNode.score2) {
|
|
21048
|
-
copyNodeRect(bestNode, candidate);
|
|
21049
|
-
bestIndex = index;
|
|
21050
|
+
//#region ../functions/src/max-rects-compat.ts
|
|
21051
|
+
const NO_ROTATION = 2;
|
|
21052
|
+
const MAX_SCORE = 2147483647;
|
|
21053
|
+
const MAX_RECTS_METHOD = {
|
|
21054
|
+
BestShortSideFit: 0,
|
|
21055
|
+
BestLongSideFit: 1,
|
|
21056
|
+
BestAreaFit: 2,
|
|
21057
|
+
BottomLeftRule: 3,
|
|
21058
|
+
ContactPointRule: 4
|
|
21059
|
+
};
|
|
21060
|
+
const COMPAT_NODE_RECT_FLAGS = {
|
|
21061
|
+
DUPLICATE_PADDING: 1,
|
|
21062
|
+
NO_ROTATION
|
|
21063
|
+
};
|
|
21064
|
+
var MaxRectsCompat = class MaxRectsCompat {
|
|
21065
|
+
static helperRect = createNodeRect();
|
|
21066
|
+
binWidth = 0;
|
|
21067
|
+
binHeight = 0;
|
|
21068
|
+
allowRotations = false;
|
|
21069
|
+
usedRectangles = [];
|
|
21070
|
+
freeRectangles = [];
|
|
21071
|
+
init(width, height, allowRotations = false) {
|
|
21072
|
+
this.binWidth = width;
|
|
21073
|
+
this.binHeight = height;
|
|
21074
|
+
this.allowRotations = allowRotations;
|
|
21075
|
+
this.usedRectangles.length = 0;
|
|
21076
|
+
this.freeRectangles.length = 0;
|
|
21077
|
+
this.freeRectangles.push({
|
|
21078
|
+
...createNodeRect(),
|
|
21079
|
+
x: 0,
|
|
21080
|
+
y: 0,
|
|
21081
|
+
width,
|
|
21082
|
+
height
|
|
21083
|
+
});
|
|
21084
|
+
}
|
|
21085
|
+
insert(rect, method) {
|
|
21086
|
+
const newNode = this.scoreRect(rect, method);
|
|
21087
|
+
if (newNode.height === 0) return null;
|
|
21088
|
+
const placed = cloneNodeRect(newNode);
|
|
21089
|
+
this.placeRect(placed);
|
|
21090
|
+
return placed;
|
|
21091
|
+
}
|
|
21092
|
+
pack(rects, method) {
|
|
21093
|
+
const remaining = rects.map(cloneNodeRect);
|
|
21094
|
+
while (remaining.length > 0) {
|
|
21095
|
+
let bestIndex = -1;
|
|
21096
|
+
const bestNode = createNodeRect();
|
|
21097
|
+
bestNode.score1 = MAX_SCORE;
|
|
21098
|
+
bestNode.score2 = MAX_SCORE;
|
|
21099
|
+
for (let index = 0; index < remaining.length; index += 1) {
|
|
21100
|
+
const candidate = this.scoreRect(remaining[index], method);
|
|
21101
|
+
if (candidate.score1 < bestNode.score1 || candidate.score1 === bestNode.score1 && candidate.score2 < bestNode.score2) {
|
|
21102
|
+
copyNodeRect(bestNode, candidate);
|
|
21103
|
+
bestIndex = index;
|
|
21050
21104
|
}
|
|
21051
21105
|
}
|
|
21052
21106
|
if (bestIndex === -1) break;
|
|
@@ -21707,6 +21761,19 @@ const ATLAS_DEFAULTS = {
|
|
|
21707
21761
|
function getPublishedItemId(resource) {
|
|
21708
21762
|
return (resource.getExtras() ?? {})._publishedId ?? resource.getId();
|
|
21709
21763
|
}
|
|
21764
|
+
function getSelectedSkeletonDependencyImageIds(resources) {
|
|
21765
|
+
const imageIds = /* @__PURE__ */ new Set();
|
|
21766
|
+
const resourcesById = new Map(resources.map((resource) => [resource.getId(), resource]));
|
|
21767
|
+
for (const resource of resources) {
|
|
21768
|
+
if (!isSkeletonResource$1(resource)) continue;
|
|
21769
|
+
for (const requiredId of resource.getRequireIds()) {
|
|
21770
|
+
if (!requiredId) continue;
|
|
21771
|
+
const required = resourcesById.get(requiredId);
|
|
21772
|
+
if (required && isImageResource$1(required)) imageIds.add(requiredId);
|
|
21773
|
+
}
|
|
21774
|
+
}
|
|
21775
|
+
return imageIds;
|
|
21776
|
+
}
|
|
21710
21777
|
function resolveFontFileName(fontName) {
|
|
21711
21778
|
return /\.fnt$/i.test(fontName) ? fontName : `${fontName}.fnt`;
|
|
21712
21779
|
}
|
|
@@ -21816,7 +21883,7 @@ async function resolveEditorCompatibleResourceOrder(pkg, allResources, options)
|
|
|
21816
21883
|
*
|
|
21817
21884
|
* This transform performs MaxRects bin-packing on all ImageResource items
|
|
21818
21885
|
* within each package, creating Atlas and Sprite property nodes. When an
|
|
21819
|
-
*
|
|
21886
|
+
* a raster backend is provided, it also composites the actual PNG files.
|
|
21820
21887
|
*
|
|
21821
21888
|
* When `trimImage` is enabled and encoder is available, transparent pixels
|
|
21822
21889
|
* at image edges are trimmed before packing. The trimmed offset and original
|
|
@@ -21843,12 +21910,18 @@ function atlas(_options = {}) {
|
|
|
21843
21910
|
const logger = doc.getLogger();
|
|
21844
21911
|
const encoder = options.encoder;
|
|
21845
21912
|
const doTrim = options.trimImage && !!encoder && !!options.basePath;
|
|
21913
|
+
const packageFilter = options.packages ? new Set(options.packages) : null;
|
|
21846
21914
|
for (const pkg of root.listPackages()) {
|
|
21915
|
+
if (packageFilter && !packageFilter.has(pkg.getName())) continue;
|
|
21847
21916
|
const selectedPublishIds = new Set((pkg.getExtras() ?? {}).publishedResourceIds ?? []);
|
|
21848
21917
|
const allResources = selectedPublishIds.size > 0 ? pkg.listResources().filter((resource) => selectedPublishIds.has(resource.getId())) : pkg.listResources();
|
|
21918
|
+
const skeletonDependencyImageIds = getSelectedSkeletonDependencyImageIds(allResources);
|
|
21849
21919
|
const orderedResources = await resolveEditorCompatibleResourceOrder(pkg, allResources, options);
|
|
21850
21920
|
const orderedAllResources = sortResourcesByOrder(allResources, new Map(orderedResources.map((resource, index) => [resource.getId(), index])), new Map(allResources.map((resource, index) => [resource.getId(), index])));
|
|
21851
|
-
if (!allResources.some((resource) =>
|
|
21921
|
+
if (!allResources.some((resource) => {
|
|
21922
|
+
if (isImageResource$1(resource) && skeletonDependencyImageIds.has(resource.getId())) return false;
|
|
21923
|
+
return isPackableResource(resource);
|
|
21924
|
+
})) continue;
|
|
21852
21925
|
const inputs = [];
|
|
21853
21926
|
const referencedIds = /* @__PURE__ */ new Set();
|
|
21854
21927
|
const resourceMap = /* @__PURE__ */ new Map();
|
|
@@ -21917,6 +21990,7 @@ function atlas(_options = {}) {
|
|
|
21917
21990
|
}
|
|
21918
21991
|
for (const res of orderedAllResources) if (isImageResource$1(res)) {
|
|
21919
21992
|
const resId = res.getId();
|
|
21993
|
+
if (skeletonDependencyImageIds.has(resId)) continue;
|
|
21920
21994
|
if (selectedPublishIds.size === 0 && !res.getExported() && referencedIds.size > 0 && !referencedIds.has(resId)) continue;
|
|
21921
21995
|
await _collectImage(res, pkg, inputs, encoder, options, doTrim, logger);
|
|
21922
21996
|
} else if (isMovieClipResource$1(res)) {
|
|
@@ -21929,137 +22003,59 @@ function atlas(_options = {}) {
|
|
|
21929
22003
|
await _collectFontTexture(doc, res, pkg, options);
|
|
21930
22004
|
}
|
|
21931
22005
|
if (inputs.length === 0) continue;
|
|
21932
|
-
const branchGroups = buildBranchAtlasGroups(doc, inputs, options);
|
|
21933
22006
|
let totalPageCount = 0;
|
|
21934
22007
|
let usedDirectOutput = false;
|
|
22008
|
+
const { autoInputs, fixedPageGroups, standaloneGroups, reservedPageIndexes } = groupStandaloneInputs(doc, inputs, options);
|
|
22009
|
+
const branchGroups = buildBranchAtlasGroups(doc, autoInputs, options);
|
|
22010
|
+
const branchPageOffsets = /* @__PURE__ */ new Map();
|
|
21935
22011
|
for (const group of branchGroups) {
|
|
21936
|
-
const directOutput = resolveDirectImageOutput(group.inputs, options);
|
|
22012
|
+
const directOutput = fixedPageGroups.length === 0 && standaloneGroups.length === 0 ? resolveDirectImageOutput(group.inputs, options) : null;
|
|
21937
22013
|
if (directOutput) {
|
|
21938
22014
|
await emitDirectImageOutput(doc, pkg, directOutput, encoder, options, logger, group.branchName, group.branchOrdinal);
|
|
21939
22015
|
usedDirectOutput = true;
|
|
21940
22016
|
totalPageCount += 1;
|
|
21941
22017
|
continue;
|
|
21942
22018
|
}
|
|
21943
|
-
const
|
|
21944
|
-
|
|
22019
|
+
const pageStart = reserveAutoPageStart(branchPageOffsets, group.branchOrdinal, reservedPageIndexes);
|
|
22020
|
+
const emittedPageCount = await emitPagedAtlasGroup(doc, pkg, allResources, group.inputs, {
|
|
22021
|
+
branchName: group.branchName,
|
|
22022
|
+
branchOrdinal: group.branchOrdinal,
|
|
22023
|
+
pageStart,
|
|
22024
|
+
fileNameAt: (pageIndex) => resolveAtlasOutputFileName(pkg, pageIndex, group.branchName),
|
|
22025
|
+
options,
|
|
22026
|
+
encoder,
|
|
22027
|
+
logger
|
|
21945
22028
|
});
|
|
21946
|
-
|
|
21947
|
-
|
|
21948
|
-
|
|
21949
|
-
|
|
21950
|
-
|
|
21951
|
-
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
|
|
21955
|
-
|
|
21956
|
-
|
|
21957
|
-
|
|
21958
|
-
|
|
21959
|
-
|
|
21960
|
-
|
|
21961
|
-
|
|
21962
|
-
|
|
21963
|
-
|
|
21964
|
-
|
|
21965
|
-
|
|
21966
|
-
|
|
21967
|
-
|
|
21968
|
-
|
|
21969
|
-
|
|
21970
|
-
|
|
21971
|
-
|
|
21972
|
-
|
|
21973
|
-
|
|
21974
|
-
|
|
21975
|
-
|
|
21976
|
-
const rotated = pr.rotated;
|
|
21977
|
-
const sprite = doc.createSprite();
|
|
21978
|
-
sprite.setItemId(input.id);
|
|
21979
|
-
sprite.setRectX(pr.x);
|
|
21980
|
-
sprite.setRectY(pr.y);
|
|
21981
|
-
sprite.setRectWidth(packedSize.width);
|
|
21982
|
-
sprite.setRectHeight(packedSize.height);
|
|
21983
|
-
sprite.setRotated(rotated);
|
|
21984
|
-
sprite.setOffsetX(input.offsetX);
|
|
21985
|
-
sprite.setOffsetY(input.offsetY);
|
|
21986
|
-
sprite.setOriginalWidth(input.originalWidth);
|
|
21987
|
-
sprite.setOriginalHeight(input.originalHeight);
|
|
21988
|
-
sprite.setAtlas(atlasNode);
|
|
21989
|
-
atlasNode.addSprite(sprite);
|
|
21990
|
-
}
|
|
21991
|
-
for (const res of allResources) {
|
|
21992
|
-
if (!isFontResource$1(res)) continue;
|
|
21993
|
-
const alias = res.getExtras()?._fontSpriteAlias;
|
|
21994
|
-
if (!alias) continue;
|
|
21995
|
-
const imgSprite = page.outputRects.find((result) => group.inputs[result.index]?.id === alias.textureId);
|
|
21996
|
-
if (!imgSprite) continue;
|
|
21997
|
-
const imgInput = group.inputs[imgSprite.index];
|
|
21998
|
-
const fontSprite = doc.createSprite();
|
|
21999
|
-
fontSprite.setItemId(alias.fontId);
|
|
22000
|
-
fontSprite.setRectX(imgSprite.x);
|
|
22001
|
-
fontSprite.setRectY(imgSprite.y);
|
|
22002
|
-
fontSprite.setRectWidth(imgSprite.width);
|
|
22003
|
-
fontSprite.setRectHeight(imgSprite.height);
|
|
22004
|
-
fontSprite.setRotated(imgSprite.rotated);
|
|
22005
|
-
if (imgInput) {
|
|
22006
|
-
fontSprite.setOffsetX(imgInput.offsetX);
|
|
22007
|
-
fontSprite.setOffsetY(imgInput.offsetY);
|
|
22008
|
-
fontSprite.setOriginalWidth(imgInput.originalWidth);
|
|
22009
|
-
fontSprite.setOriginalHeight(imgInput.originalHeight);
|
|
22010
|
-
}
|
|
22011
|
-
fontSprite.setAtlas(atlasNode);
|
|
22012
|
-
atlasNode.addSprite(fontSprite);
|
|
22013
|
-
}
|
|
22014
|
-
}
|
|
22015
|
-
if (encoder && options.outputPath) {
|
|
22016
|
-
if (options.mkdir) await options.mkdir(options.outputPath);
|
|
22017
|
-
for (let p = 0; p < pages.length; p++) {
|
|
22018
|
-
const page = pages[p];
|
|
22019
|
-
const compositeInputs = [];
|
|
22020
|
-
for (const pr of page.outputRects) {
|
|
22021
|
-
const input = group.inputs[pr.index];
|
|
22022
|
-
if (!input) continue;
|
|
22023
|
-
if (pr.width <= 0 || pr.height <= 0 || input.width <= 0 || input.height <= 0) continue;
|
|
22024
|
-
try {
|
|
22025
|
-
let imgBuffer;
|
|
22026
|
-
if (input.trimBuffer) {
|
|
22027
|
-
imgBuffer = input.trimBuffer;
|
|
22028
|
-
if (imgBuffer.length === 0) continue;
|
|
22029
|
-
} else if (input.rasterizedBuffer) imgBuffer = input.rasterizedBuffer;
|
|
22030
|
-
else {
|
|
22031
|
-
if (!isImageResource$1(input.resource)) {
|
|
22032
|
-
logger.warn(`atlas: Non-image input "${input.id}" is missing inline buffer, skipping compositing.`);
|
|
22033
|
-
continue;
|
|
22034
|
-
}
|
|
22035
|
-
imgBuffer = await encoder(_resolveImagePath(input.resource, pkg, options.basePath)).toBuffer();
|
|
22036
|
-
}
|
|
22037
|
-
if (pr.rotated) imgBuffer = await encoder(imgBuffer).rotate(270).toBuffer();
|
|
22038
|
-
compositeInputs.push({
|
|
22039
|
-
input: imgBuffer,
|
|
22040
|
-
left: pr.x,
|
|
22041
|
-
top: pr.y
|
|
22042
|
-
});
|
|
22043
|
-
} catch {
|
|
22044
|
-
logger.warn(`atlas: Could not read image "${input.id}" for compositing.`);
|
|
22045
|
-
}
|
|
22046
|
-
}
|
|
22047
|
-
const atlasFileName = resolveAtlasOutputFileName(pkg, p, group.branchName);
|
|
22048
|
-
const outputFile = `${options.outputPath}/${atlasFileName}`;
|
|
22049
|
-
await encoder({ create: {
|
|
22050
|
-
width: page.width,
|
|
22051
|
-
height: page.height,
|
|
22052
|
-
channels: 4,
|
|
22053
|
-
background: {
|
|
22054
|
-
r: 0,
|
|
22055
|
-
g: 0,
|
|
22056
|
-
b: 0,
|
|
22057
|
-
alpha: 0
|
|
22058
|
-
}
|
|
22059
|
-
} }).composite(compositeInputs).png().toFile(outputFile);
|
|
22060
|
-
logger.info(`atlas: Generated ${atlasFileName} (${page.width}x${page.height}, ${page.outputRects.length} sprites)`);
|
|
22061
|
-
}
|
|
22062
|
-
}
|
|
22029
|
+
totalPageCount += emittedPageCount;
|
|
22030
|
+
branchPageOffsets.set(group.branchOrdinal, pageStart + emittedPageCount);
|
|
22031
|
+
}
|
|
22032
|
+
for (const group of fixedPageGroups) {
|
|
22033
|
+
const emittedPageCount = await emitPagedAtlasGroup(doc, pkg, allResources, group.inputs, {
|
|
22034
|
+
branchName: group.branchName,
|
|
22035
|
+
branchOrdinal: group.branchOrdinal,
|
|
22036
|
+
pageStart: group.pageIndex,
|
|
22037
|
+
forceSinglePage: true,
|
|
22038
|
+
fileNameAt: () => resolveAtlasOutputFileName(pkg, group.pageIndex, group.branchName),
|
|
22039
|
+
options,
|
|
22040
|
+
encoder,
|
|
22041
|
+
logger
|
|
22042
|
+
});
|
|
22043
|
+
totalPageCount += emittedPageCount;
|
|
22044
|
+
}
|
|
22045
|
+
const standalonePageOffsets = new Map(branchPageOffsets);
|
|
22046
|
+
for (const group of fixedPageGroups) {
|
|
22047
|
+
const nextPageIndex = group.pageIndex + 1;
|
|
22048
|
+
if (nextPageIndex > (standalonePageOffsets.get(group.branchOrdinal) ?? 0)) standalonePageOffsets.set(group.branchOrdinal, nextPageIndex);
|
|
22049
|
+
}
|
|
22050
|
+
for (const group of standaloneGroups) {
|
|
22051
|
+
const emittedPageCount = await emitStandaloneAtlasGroup(doc, pkg, group, {
|
|
22052
|
+
atlasIndexStart: standalonePageOffsets.get(group.branchOrdinal) ?? 0,
|
|
22053
|
+
options,
|
|
22054
|
+
encoder,
|
|
22055
|
+
logger
|
|
22056
|
+
});
|
|
22057
|
+
totalPageCount += emittedPageCount;
|
|
22058
|
+
standalonePageOffsets.set(group.branchOrdinal, (standalonePageOffsets.get(group.branchOrdinal) ?? 0) + emittedPageCount);
|
|
22063
22059
|
}
|
|
22064
22060
|
if (usedDirectOutput) logger.info(`atlas: Direct output for single image package "${pkg.getName()}".`);
|
|
22065
22061
|
logger.info(`atlas: Packed ${inputs.length} images into ${totalPageCount} atlas(es) for package "${pkg.getName()}".`);
|
|
@@ -22096,6 +22092,171 @@ function buildBranchAtlasGroups(doc, inputs, options) {
|
|
|
22096
22092
|
inputs: groups.get(branchName) ?? []
|
|
22097
22093
|
}));
|
|
22098
22094
|
}
|
|
22095
|
+
function reserveAutoPageStart(branchPageOffsets, branchOrdinal, reservedPageIndexes) {
|
|
22096
|
+
let pageIndex = branchPageOffsets.get(branchOrdinal) ?? 0;
|
|
22097
|
+
while (branchOrdinal === 0 && reservedPageIndexes.has(pageIndex)) pageIndex += 1;
|
|
22098
|
+
return pageIndex;
|
|
22099
|
+
}
|
|
22100
|
+
async function emitPagedAtlasGroup(doc, pkg, allResources, inputs, context) {
|
|
22101
|
+
if (inputs.length === 0) return 0;
|
|
22102
|
+
const pages = packAtlasPages(inputs, context.options, context.forceSinglePage === true);
|
|
22103
|
+
if (pages.length === 0) return 0;
|
|
22104
|
+
for (let pageOffset = 0; pageOffset < pages.length; pageOffset += 1) {
|
|
22105
|
+
const page = pages[pageOffset];
|
|
22106
|
+
const pageIndex = context.pageStart + pageOffset;
|
|
22107
|
+
const atlasNode = doc.createAtlas(`atlas${resolveAtlasIndex(context.branchOrdinal, pageIndex)}`);
|
|
22108
|
+
atlasNode.setIndex(resolveAtlasIndex(context.branchOrdinal, pageIndex));
|
|
22109
|
+
atlasNode.setFile(context.fileNameAt(pageIndex));
|
|
22110
|
+
atlasNode.setWidth(page.width);
|
|
22111
|
+
atlasNode.setHeight(page.height);
|
|
22112
|
+
pkg.addAtlas(atlasNode);
|
|
22113
|
+
attachSpritesToAtlas(doc, allResources, inputs, page.outputRects, atlasNode);
|
|
22114
|
+
await writeAtlasPageImage(pkg, inputs, page, atlasNode.getFile(), context.encoder, context.options, context.logger);
|
|
22115
|
+
}
|
|
22116
|
+
return pages.length;
|
|
22117
|
+
}
|
|
22118
|
+
async function emitStandaloneAtlasGroup(doc, pkg, group, context) {
|
|
22119
|
+
if (group.inputs.length === 0) return 0;
|
|
22120
|
+
const pages = packAtlasPages(group.inputs, context.options, true, group.sizeMode === "npot" ? {
|
|
22121
|
+
powerOfTwo: false,
|
|
22122
|
+
multipleOfFour: false,
|
|
22123
|
+
square: false
|
|
22124
|
+
} : group.sizeMode === "multipleOf4" ? {
|
|
22125
|
+
powerOfTwo: false,
|
|
22126
|
+
multipleOfFour: true,
|
|
22127
|
+
square: false
|
|
22128
|
+
} : void 0);
|
|
22129
|
+
if (pages.length === 0) return 0;
|
|
22130
|
+
for (let pageOffset = 0; pageOffset < pages.length; pageOffset += 1) {
|
|
22131
|
+
const page = pages[pageOffset];
|
|
22132
|
+
const baseFileName = resolveStandaloneAtlasOutputFileName(pkg, group.resource, group.branchName);
|
|
22133
|
+
const atlasFileName = pages.length <= 1 ? baseFileName : insertFileNameSuffix(baseFileName, `_${pageOffset}`);
|
|
22134
|
+
const atlasIndex = context.atlasIndexStart + pageOffset;
|
|
22135
|
+
const atlasNode = doc.createAtlas(`atlas${resolveAtlasIndex(group.branchOrdinal, atlasIndex)}`);
|
|
22136
|
+
atlasNode.setIndex(resolveAtlasIndex(group.branchOrdinal, atlasIndex));
|
|
22137
|
+
atlasNode.setFile(atlasFileName);
|
|
22138
|
+
const standaloneSize = resolveStandaloneAtlasSize(page.width, page.height, group.sizeMode, context.options);
|
|
22139
|
+
atlasNode.setWidth(standaloneSize.width);
|
|
22140
|
+
atlasNode.setHeight(standaloneSize.height);
|
|
22141
|
+
pkg.addAtlas(atlasNode);
|
|
22142
|
+
attachSpritesToAtlas(doc, [], group.inputs, page.outputRects, atlasNode);
|
|
22143
|
+
await writeAtlasPageImage(pkg, group.inputs, {
|
|
22144
|
+
...page,
|
|
22145
|
+
width: standaloneSize.width,
|
|
22146
|
+
height: standaloneSize.height
|
|
22147
|
+
}, atlasFileName, context.encoder, context.options, context.logger);
|
|
22148
|
+
}
|
|
22149
|
+
return pages.length;
|
|
22150
|
+
}
|
|
22151
|
+
function packAtlasPages(inputs, options, forceSinglePage, sizeOverrides) {
|
|
22152
|
+
const hasDuplicatePadding = inputs.some((input) => {
|
|
22153
|
+
return isImageResource$1(input.resource) && input.resource.getDuplicatePadding?.() === true;
|
|
22154
|
+
});
|
|
22155
|
+
return new MaxRectsPackerCompat({
|
|
22156
|
+
pot: sizeOverrides?.powerOfTwo ?? options.powerOfTwo,
|
|
22157
|
+
mof: sizeOverrides?.multipleOfFour ?? !options.powerOfTwo,
|
|
22158
|
+
padding: options.padding,
|
|
22159
|
+
rotation: options.allowRotation,
|
|
22160
|
+
minWidth: 16,
|
|
22161
|
+
minHeight: 16,
|
|
22162
|
+
maxWidth: options.maxSize,
|
|
22163
|
+
maxHeight: options.maxSize,
|
|
22164
|
+
square: sizeOverrides?.square ?? options.square,
|
|
22165
|
+
fast: options.fast,
|
|
22166
|
+
edgePadding: false,
|
|
22167
|
+
duplicatePadding: hasDuplicatePadding,
|
|
22168
|
+
multiPage: forceSinglePage ? false : options.multiPage,
|
|
22169
|
+
preserveInputOrderOnTie: options.preserveInputOrderOnTie
|
|
22170
|
+
}).pack(inputs.map((input, index) => inputToCompatRect(input, index))) ?? [];
|
|
22171
|
+
}
|
|
22172
|
+
function attachSpritesToAtlas(doc, allResources, inputs, outputRects, atlasNode) {
|
|
22173
|
+
for (const packedRect of outputRects) {
|
|
22174
|
+
const input = inputs[packedRect.index];
|
|
22175
|
+
if (!input) continue;
|
|
22176
|
+
const packedSize = resolvePackedRectSize(input, packedRect.width, packedRect.height, packedRect.rotated);
|
|
22177
|
+
const sprite = doc.createSprite();
|
|
22178
|
+
sprite.setItemId(input.id);
|
|
22179
|
+
sprite.setRectX(packedRect.x);
|
|
22180
|
+
sprite.setRectY(packedRect.y);
|
|
22181
|
+
sprite.setRectWidth(packedSize.width);
|
|
22182
|
+
sprite.setRectHeight(packedSize.height);
|
|
22183
|
+
sprite.setRotated(packedRect.rotated);
|
|
22184
|
+
sprite.setOffsetX(input.offsetX);
|
|
22185
|
+
sprite.setOffsetY(input.offsetY);
|
|
22186
|
+
sprite.setOriginalWidth(input.originalWidth);
|
|
22187
|
+
sprite.setOriginalHeight(input.originalHeight);
|
|
22188
|
+
sprite.setAtlas(atlasNode);
|
|
22189
|
+
atlasNode.addSprite(sprite);
|
|
22190
|
+
}
|
|
22191
|
+
for (const resource of allResources) {
|
|
22192
|
+
if (!isFontResource$1(resource)) continue;
|
|
22193
|
+
const alias = resource.getExtras()?._fontSpriteAlias;
|
|
22194
|
+
if (!alias) continue;
|
|
22195
|
+
const imageSprite = outputRects.find((result) => inputs[result.index]?.id === alias.textureId);
|
|
22196
|
+
if (!imageSprite) continue;
|
|
22197
|
+
const imageInput = inputs[imageSprite.index];
|
|
22198
|
+
const fontSprite = doc.createSprite();
|
|
22199
|
+
fontSprite.setItemId(alias.fontId);
|
|
22200
|
+
fontSprite.setRectX(imageSprite.x);
|
|
22201
|
+
fontSprite.setRectY(imageSprite.y);
|
|
22202
|
+
fontSprite.setRectWidth(imageSprite.width);
|
|
22203
|
+
fontSprite.setRectHeight(imageSprite.height);
|
|
22204
|
+
fontSprite.setRotated(imageSprite.rotated);
|
|
22205
|
+
if (imageInput) {
|
|
22206
|
+
fontSprite.setOffsetX(imageInput.offsetX);
|
|
22207
|
+
fontSprite.setOffsetY(imageInput.offsetY);
|
|
22208
|
+
fontSprite.setOriginalWidth(imageInput.originalWidth);
|
|
22209
|
+
fontSprite.setOriginalHeight(imageInput.originalHeight);
|
|
22210
|
+
}
|
|
22211
|
+
fontSprite.setAtlas(atlasNode);
|
|
22212
|
+
atlasNode.addSprite(fontSprite);
|
|
22213
|
+
}
|
|
22214
|
+
}
|
|
22215
|
+
async function writeAtlasPageImage(pkg, inputs, page, atlasFileName, encoder, options, logger) {
|
|
22216
|
+
if (!encoder || !options.outputPath) return;
|
|
22217
|
+
if (options.mkdir) await options.mkdir(options.outputPath);
|
|
22218
|
+
const compositeInputs = [];
|
|
22219
|
+
for (const packedRect of page.outputRects) {
|
|
22220
|
+
const input = inputs[packedRect.index];
|
|
22221
|
+
if (!input) continue;
|
|
22222
|
+
if (packedRect.width <= 0 || packedRect.height <= 0 || input.width <= 0 || input.height <= 0) continue;
|
|
22223
|
+
try {
|
|
22224
|
+
let imageBuffer;
|
|
22225
|
+
if (input.trimBuffer) {
|
|
22226
|
+
imageBuffer = input.trimBuffer;
|
|
22227
|
+
if (imageBuffer.length === 0) continue;
|
|
22228
|
+
} else if (input.rasterizedBuffer) imageBuffer = input.rasterizedBuffer;
|
|
22229
|
+
else {
|
|
22230
|
+
if (!isImageResource$1(input.resource)) {
|
|
22231
|
+
logger.warn(`atlas: Non-image input "${input.id}" is missing inline buffer, skipping compositing.`);
|
|
22232
|
+
continue;
|
|
22233
|
+
}
|
|
22234
|
+
imageBuffer = await encoder(_resolveImagePath(input.resource, pkg, options.basePath)).toBuffer();
|
|
22235
|
+
}
|
|
22236
|
+
if (packedRect.rotated) imageBuffer = await encoder(imageBuffer).rotate(270).toBuffer();
|
|
22237
|
+
compositeInputs.push({
|
|
22238
|
+
input: imageBuffer,
|
|
22239
|
+
left: packedRect.x,
|
|
22240
|
+
top: packedRect.y
|
|
22241
|
+
});
|
|
22242
|
+
} catch {
|
|
22243
|
+
logger.warn(`atlas: Could not read image "${input.id}" for compositing.`);
|
|
22244
|
+
}
|
|
22245
|
+
}
|
|
22246
|
+
const outputFile = `${options.outputPath}/${atlasFileName}`;
|
|
22247
|
+
await encoder({ create: {
|
|
22248
|
+
width: page.width,
|
|
22249
|
+
height: page.height,
|
|
22250
|
+
channels: 4,
|
|
22251
|
+
background: {
|
|
22252
|
+
r: 0,
|
|
22253
|
+
g: 0,
|
|
22254
|
+
b: 0,
|
|
22255
|
+
alpha: 0
|
|
22256
|
+
}
|
|
22257
|
+
} }).composite(compositeInputs).toFile(outputFile);
|
|
22258
|
+
logger.info(`atlas: Generated ${atlasFileName} (${page.width}x${page.height}, ${page.outputRects.length} sprites)`);
|
|
22259
|
+
}
|
|
22099
22260
|
function inputToCompatRect(input, index) {
|
|
22100
22261
|
const duplicatePadding = isImageResource$1(input.resource) && input.resource.getDuplicatePadding?.() === true;
|
|
22101
22262
|
return {
|
|
@@ -22210,14 +22371,47 @@ function resolveAtlasOutputFileName(pkg, pageIndex, branchName) {
|
|
|
22210
22371
|
const suffix = branchName ? `_${branchName}` : "";
|
|
22211
22372
|
return `${pkg.getPublishName() || pkg.getName()}_atlas${pageIndex}${suffix}.png`;
|
|
22212
22373
|
}
|
|
22374
|
+
function resolveStandaloneAtlasOutputFileName(pkg, resource, branchName) {
|
|
22375
|
+
const baseName = `${pkg.getPublishName() || pkg.getName()}_atlas_${getPublishedItemId(resource)}`;
|
|
22376
|
+
const suffix = branchName ? `_${branchName}` : "";
|
|
22377
|
+
if (isImageResource$1(resource)) return `${baseName}${suffix}${extname$1(resolveImageFileName$1(resource)) || ".png"}`;
|
|
22378
|
+
return `${baseName}${suffix}.png`;
|
|
22379
|
+
}
|
|
22380
|
+
function resolveStandaloneAtlasSize(width, height, sizeMode, options) {
|
|
22381
|
+
if (sizeMode === "npot") return {
|
|
22382
|
+
width,
|
|
22383
|
+
height
|
|
22384
|
+
};
|
|
22385
|
+
if (sizeMode === "multipleOf4") return {
|
|
22386
|
+
width: roundUpToMultiple(width, 4),
|
|
22387
|
+
height: roundUpToMultiple(height, 4)
|
|
22388
|
+
};
|
|
22389
|
+
return resolveDirectOutputAtlasSize(width, height, options);
|
|
22390
|
+
}
|
|
22213
22391
|
function resolveImageFileName$1(resource) {
|
|
22214
22392
|
const extras = resource.getExtras();
|
|
22215
22393
|
return resource.getFileName() || extras._fileName || resource.getName();
|
|
22216
22394
|
}
|
|
22395
|
+
function extname$1(fileName) {
|
|
22396
|
+
const normalized = fileName.replace(/\\/g, "/");
|
|
22397
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
22398
|
+
const lastDot = normalized.lastIndexOf(".");
|
|
22399
|
+
if (lastDot <= lastSlash) return "";
|
|
22400
|
+
return normalized.slice(lastDot);
|
|
22401
|
+
}
|
|
22402
|
+
function insertFileNameSuffix(fileName, suffix) {
|
|
22403
|
+
const extension = extname$1(fileName);
|
|
22404
|
+
if (!extension) return `${fileName}${suffix}`;
|
|
22405
|
+
return `${fileName.slice(0, -extension.length)}${suffix}${extension}`;
|
|
22406
|
+
}
|
|
22217
22407
|
function nextPow2(value) {
|
|
22218
22408
|
if (value <= 1) return 1;
|
|
22219
22409
|
return 2 ** Math.ceil(Math.log2(value));
|
|
22220
22410
|
}
|
|
22411
|
+
function roundUpToMultiple(value, base) {
|
|
22412
|
+
if (value <= 0) return 0;
|
|
22413
|
+
return Math.ceil(value / base) * base;
|
|
22414
|
+
}
|
|
22221
22415
|
function sortResourcesByOrder(resources, orderMap, inputOrderMap) {
|
|
22222
22416
|
const ordered = [...resources];
|
|
22223
22417
|
ordered.sort((left, right) => {
|
|
@@ -22233,8 +22427,65 @@ function sortResourcesByOrder(resources, orderMap, inputOrderMap) {
|
|
|
22233
22427
|
});
|
|
22234
22428
|
return ordered;
|
|
22235
22429
|
}
|
|
22430
|
+
function getResourceTextureSetMode(resource) {
|
|
22431
|
+
if (isImageResource$1(resource)) return parseTextureSetMode(resource.getTextureSetMode?.());
|
|
22432
|
+
return parseTextureSetMode(resource.getTextureSetMode?.());
|
|
22433
|
+
}
|
|
22434
|
+
function groupStandaloneInputs(doc, inputs, options) {
|
|
22435
|
+
const autoInputs = [];
|
|
22436
|
+
const fixedInputsByPage = /* @__PURE__ */ new Map();
|
|
22437
|
+
const standaloneGroups = /* @__PURE__ */ new Map();
|
|
22438
|
+
const reservedPageIndexes = /* @__PURE__ */ new Set();
|
|
22439
|
+
const discoveredBranchNames = [...new Set(inputs.map((input) => getInputBranchName(input)).filter((branchName) => !!branchName))];
|
|
22440
|
+
const orderedBranchNames = doc.getRoot().listBranches().filter((branchName) => discoveredBranchNames.includes(branchName));
|
|
22441
|
+
for (const branchName of discoveredBranchNames) if (!orderedBranchNames.includes(branchName)) orderedBranchNames.push(branchName);
|
|
22442
|
+
const branchOrdinalByName = /* @__PURE__ */ new Map();
|
|
22443
|
+
branchOrdinalByName.set("", 0);
|
|
22444
|
+
if (options.separatedAtlasForBranch) {
|
|
22445
|
+
let ordinal = 1;
|
|
22446
|
+
for (const branchName of orderedBranchNames) branchOrdinalByName.set(branchName, ordinal++);
|
|
22447
|
+
} else for (const branchName of orderedBranchNames) branchOrdinalByName.set(branchName, 0);
|
|
22448
|
+
for (const input of inputs) {
|
|
22449
|
+
const branchName = getInputBranchName(input);
|
|
22450
|
+
const branchOrdinal = branchOrdinalByName.get(branchName) ?? 0;
|
|
22451
|
+
const mode = getResourceTextureSetMode(input.resource);
|
|
22452
|
+
if (mode.kind === "standalone") {
|
|
22453
|
+
const key = `${branchName}\u0000${getPublishedItemId(input.resource)}`;
|
|
22454
|
+
const existing = standaloneGroups.get(key);
|
|
22455
|
+
if (existing) existing.inputs.push(input);
|
|
22456
|
+
else standaloneGroups.set(key, {
|
|
22457
|
+
resource: input.resource,
|
|
22458
|
+
branchName,
|
|
22459
|
+
branchOrdinal,
|
|
22460
|
+
sizeMode: mode.sizeMode,
|
|
22461
|
+
inputs: [input]
|
|
22462
|
+
});
|
|
22463
|
+
continue;
|
|
22464
|
+
}
|
|
22465
|
+
if (mode.kind === "page") {
|
|
22466
|
+
reservedPageIndexes.add(mode.pageIndex);
|
|
22467
|
+
const key = `${branchName}\u0000${mode.pageIndex}`;
|
|
22468
|
+
const existing = fixedInputsByPage.get(key);
|
|
22469
|
+
if (existing) existing.inputs.push(input);
|
|
22470
|
+
else fixedInputsByPage.set(key, {
|
|
22471
|
+
pageIndex: mode.pageIndex,
|
|
22472
|
+
branchName,
|
|
22473
|
+
branchOrdinal,
|
|
22474
|
+
inputs: [input]
|
|
22475
|
+
});
|
|
22476
|
+
continue;
|
|
22477
|
+
}
|
|
22478
|
+
autoInputs.push(input);
|
|
22479
|
+
}
|
|
22480
|
+
return {
|
|
22481
|
+
autoInputs,
|
|
22482
|
+
fixedPageGroups: [...fixedInputsByPage.values()].sort((left, right) => left.branchOrdinal - right.branchOrdinal || left.pageIndex - right.pageIndex),
|
|
22483
|
+
standaloneGroups: [...standaloneGroups.values()].sort((left, right) => left.branchOrdinal - right.branchOrdinal || getPublishedItemId(left.resource).localeCompare(getPublishedItemId(right.resource))),
|
|
22484
|
+
reservedPageIndexes
|
|
22485
|
+
};
|
|
22486
|
+
}
|
|
22236
22487
|
/**
|
|
22237
|
-
* Trim transparent edges from an image using
|
|
22488
|
+
* Trim transparent edges from an image using the host raster backend.
|
|
22238
22489
|
* Returns the trimmed buffer, dimensions, and offsets.
|
|
22239
22490
|
* Falls back to the original image if trim fails (e.g. no alpha channel, no transparent edges).
|
|
22240
22491
|
*/
|
|
@@ -22324,7 +22575,11 @@ async function _collectImage(resource, pkg, inputs, encoder, options, doTrim, lo
|
|
|
22324
22575
|
}
|
|
22325
22576
|
sourceHasAlpha = metadata.hasAlpha === true || metadata.channels === 4;
|
|
22326
22577
|
if (/\.svg$/i.test(resolveImageFileName$1(resource)) && declaredWidth > 0 && declaredHeight > 0) {
|
|
22327
|
-
rasterizedBuffer = await encoder(filePath).resize(
|
|
22578
|
+
rasterizedBuffer = await encoder(filePath).resize({
|
|
22579
|
+
width: declaredWidth,
|
|
22580
|
+
height: declaredHeight,
|
|
22581
|
+
fit: "fill"
|
|
22582
|
+
}).png().toBuffer();
|
|
22328
22583
|
sourceHasAlpha = true;
|
|
22329
22584
|
}
|
|
22330
22585
|
} catch {
|
|
@@ -22793,6 +23048,11 @@ const FGUI_TYPESCRIPT_BINDER_TEMPLATE = `{{generatedMark}}
|
|
|
22793
23048
|
}
|
|
22794
23049
|
`;
|
|
22795
23050
|
//#endregion
|
|
23051
|
+
//#region ../functions/src/plugins/types.ts
|
|
23052
|
+
function formatPluginError(error) {
|
|
23053
|
+
return error instanceof Error ? error.message : String(error);
|
|
23054
|
+
}
|
|
23055
|
+
//#endregion
|
|
22796
23056
|
//#region ../functions/src/codegen.ts
|
|
22797
23057
|
const AUTO_GENERATED_CODE_MARK = "/** This is an automatically generated class by FairyGUI. Please do not modify it. **/";
|
|
22798
23058
|
const DEFAULT_CLASS_NAME_PREFIX = "UI_";
|
|
@@ -22828,6 +23088,18 @@ async function publishCodeGeneration(doc, options) {
|
|
|
22828
23088
|
const logger = doc.getLogger();
|
|
22829
23089
|
const settings = resolveCodeGenerationSettings(doc);
|
|
22830
23090
|
if (!settings.allowGenCode) return;
|
|
23091
|
+
const plugins = options.plugins?.filter((plugin) => typeof plugin.plugin.genCode === "function") ?? [];
|
|
23092
|
+
if (plugins.length > 0) {
|
|
23093
|
+
let handled = false;
|
|
23094
|
+
for (const plugin of plugins) try {
|
|
23095
|
+
await plugin.plugin.genCode(doc, settings, options);
|
|
23096
|
+
handled = true;
|
|
23097
|
+
logger.info(`publish: Generated code using plugin "${plugin.name}"`);
|
|
23098
|
+
} catch (error) {
|
|
23099
|
+
logger.warn(`publish: Code generation plugin "${plugin.name}" failed: ${formatPluginError(error)}`);
|
|
23100
|
+
}
|
|
23101
|
+
if (handled) return;
|
|
23102
|
+
}
|
|
22831
23103
|
for (const pkg of options.packages) {
|
|
22832
23104
|
if (!pkg.getGenCode()) continue;
|
|
22833
23105
|
const plan = resolvePackageCodegenPlan(pkg, settings, options);
|
|
@@ -22926,9 +23198,9 @@ async function cleanupGeneratedFiles(directory, fs, extension = ".cs") {
|
|
|
22926
23198
|
}
|
|
22927
23199
|
}
|
|
22928
23200
|
function buildCodegenClasses(doc, pkg, plan) {
|
|
22929
|
-
const
|
|
23201
|
+
const codegenComponents = pkg.listComponents().sort((left, right) => left.getId().localeCompare(right.getId()));
|
|
22930
23202
|
const generatedById = /* @__PURE__ */ new Map();
|
|
22931
|
-
for (const component of
|
|
23203
|
+
for (const component of codegenComponents) {
|
|
22932
23204
|
const encodedClassName = `${plan.settings.classNamePrefix}${normalizeTypeName(component.getName()) || "Component"}`;
|
|
22933
23205
|
generatedById.set(component.getId(), {
|
|
22934
23206
|
classId: component.getId(),
|
|
@@ -22941,7 +23213,13 @@ function buildCodegenClasses(doc, pkg, plan) {
|
|
|
22941
23213
|
members: []
|
|
22942
23214
|
});
|
|
22943
23215
|
}
|
|
22944
|
-
for (const component of
|
|
23216
|
+
for (const component of codegenComponents) {
|
|
23217
|
+
const classInfo = generatedById.get(component.getId());
|
|
23218
|
+
if (!classInfo) continue;
|
|
23219
|
+
classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
|
|
23220
|
+
}
|
|
23221
|
+
for (const [componentId, classInfo] of generatedById) if (classInfo.members.every((member) => member.ignored)) generatedById.delete(componentId);
|
|
23222
|
+
for (const component of codegenComponents) {
|
|
22945
23223
|
const classInfo = generatedById.get(component.getId());
|
|
22946
23224
|
if (!classInfo) continue;
|
|
22947
23225
|
classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
|
|
@@ -22955,7 +23233,12 @@ function buildCodegenMembers(doc, pkg, component, plan, generatedById) {
|
|
|
22955
23233
|
let childIndex = 0;
|
|
22956
23234
|
let transitionIndex = 0;
|
|
22957
23235
|
for (const controller of component.listControllers()) members.push(createMember(ownerType, "controller", "Controller", controller.getName(), controllerIndex++, plan));
|
|
22958
|
-
for (const child of component.listChildren())
|
|
23236
|
+
for (const child of component.listChildren()) {
|
|
23237
|
+
if (!isRuntimeChild(child)) continue;
|
|
23238
|
+
const index = childIndex++;
|
|
23239
|
+
const resolvedChild = resolveChildType(doc, pkg, child, generatedById);
|
|
23240
|
+
members.push(createMember(ownerType, "child", resolvedChild.type, child.getName(), index, plan, resolvedChild.referencedComponent));
|
|
23241
|
+
}
|
|
22959
23242
|
for (const transition of component.listTransitions()) members.push(createMember(ownerType, "transition", "Transition", transition.getName(), transitionIndex++, plan));
|
|
22960
23243
|
const usedNames = /* @__PURE__ */ new Map();
|
|
22961
23244
|
for (const member of members) {
|
|
@@ -22967,7 +23250,10 @@ function buildCodegenMembers(doc, pkg, component, plan, generatedById) {
|
|
|
22967
23250
|
}
|
|
22968
23251
|
return members;
|
|
22969
23252
|
}
|
|
22970
|
-
function
|
|
23253
|
+
function isRuntimeChild(child) {
|
|
23254
|
+
return child.propertyType !== "GGroup" || child.getAdvanced?.() === true;
|
|
23255
|
+
}
|
|
23256
|
+
function createMember(ownerType, kind, type, originalName, index, plan, referencedComponent) {
|
|
22971
23257
|
const ignored = plan.settings.ignoreNoname && isDefaultMemberName(ownerType, kind, originalName);
|
|
22972
23258
|
return {
|
|
22973
23259
|
index,
|
|
@@ -22975,30 +23261,41 @@ function createMember(ownerType, kind, type, originalName, index, plan) {
|
|
|
22975
23261
|
name: applyMemberNamePrefix(originalName, plan.settings.memberNamePrefix),
|
|
22976
23262
|
originalName,
|
|
22977
23263
|
type,
|
|
22978
|
-
ignored
|
|
23264
|
+
ignored,
|
|
23265
|
+
referencedComponent
|
|
22979
23266
|
};
|
|
22980
23267
|
}
|
|
22981
23268
|
function resolveChildType(doc, pkg, child, generatedById) {
|
|
22982
23269
|
const src = child.getSrc?.();
|
|
22983
23270
|
if (src) {
|
|
22984
|
-
|
|
22985
|
-
if (
|
|
23271
|
+
let referencedComponent = null;
|
|
23272
|
+
if (src.startsWith("ui://")) {
|
|
23273
|
+
const rest = src.slice(5);
|
|
23274
|
+
const pkgId = rest.slice(0, 8);
|
|
23275
|
+
const resourceId = rest.slice(8);
|
|
23276
|
+
const targetPackage = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId);
|
|
23277
|
+
const targetResource = targetPackage?.getResourceById(resourceId);
|
|
23278
|
+
if (targetPackage && targetResource?.propertyType === "Component") referencedComponent = {
|
|
23279
|
+
component: targetResource,
|
|
23280
|
+
package: targetPackage
|
|
23281
|
+
};
|
|
23282
|
+
} else {
|
|
23283
|
+
const packageId = child.getPackageId?.();
|
|
23284
|
+
const targetPackage = packageId ? doc.getRoot().listPackages().find((candidate) => candidate.getId() === packageId) : pkg;
|
|
23285
|
+
const targetResource = targetPackage?.getResourceById(src);
|
|
23286
|
+
if (targetPackage && targetResource?.propertyType === "Component") referencedComponent = {
|
|
23287
|
+
component: targetResource,
|
|
23288
|
+
package: targetPackage
|
|
23289
|
+
};
|
|
23290
|
+
}
|
|
23291
|
+
if (referencedComponent) return {
|
|
23292
|
+
type: (referencedComponent.package === pkg ? generatedById.get(referencedComponent.component.getId()) : void 0)?.encodedClassName ?? resolveComponentBaseType(referencedComponent.component),
|
|
23293
|
+
referencedComponent
|
|
23294
|
+
};
|
|
22986
23295
|
}
|
|
22987
23296
|
const instanceExtType = child.getInstanceExtType?.();
|
|
22988
|
-
if (instanceExtType) return `G${instanceExtType}
|
|
22989
|
-
return child.propertyType;
|
|
22990
|
-
}
|
|
22991
|
-
function resolveChildSourceComponent(doc, pkg, src) {
|
|
22992
|
-
if (!src) return null;
|
|
22993
|
-
if (src.startsWith("ui://")) {
|
|
22994
|
-
const rest = src.slice(5);
|
|
22995
|
-
const pkgId = rest.slice(0, 8);
|
|
22996
|
-
const resourceId = rest.slice(8);
|
|
22997
|
-
const targetResource = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId)?.getResourceById(resourceId);
|
|
22998
|
-
return targetResource?.propertyType === "Component" ? targetResource : null;
|
|
22999
|
-
}
|
|
23000
|
-
const localResource = pkg.getResourceById(src);
|
|
23001
|
-
return localResource?.propertyType === "Component" ? localResource : null;
|
|
23297
|
+
if (instanceExtType) return { type: `G${instanceExtType}` };
|
|
23298
|
+
return { type: child.propertyType };
|
|
23002
23299
|
}
|
|
23003
23300
|
function resolveComponentBaseType(component) {
|
|
23004
23301
|
const extensionType = component.getExtensionType();
|
|
@@ -23069,21 +23366,21 @@ function renderFguiTypescriptMemberAssignment(member, getMemberByName, variant)
|
|
|
23069
23366
|
return getMemberByName ? `\t\tthis.${member.name} = <${translatedType}><any>(this.getChild("${escapeTypeScriptString(member.originalName)}"));` : `\t\tthis.${member.name} = <${translatedType}><any>(this.getChildAt(${member.index}));`;
|
|
23070
23367
|
}
|
|
23071
23368
|
function resolveCodePath(codePath, basePath, fs) {
|
|
23072
|
-
if (isAbsolutePath(codePath)) return trimTrailingSlashes$
|
|
23369
|
+
if (isAbsolutePath(codePath)) return trimTrailingSlashes$2(codePath);
|
|
23073
23370
|
const projectBasePath = resolveProjectBasePath(basePath);
|
|
23074
|
-
return projectBasePath ? trimTrailingSlashes$
|
|
23371
|
+
return projectBasePath ? trimTrailingSlashes$2(fs.join(projectBasePath, codePath)) : trimTrailingSlashes$2(codePath);
|
|
23075
23372
|
}
|
|
23076
23373
|
function resolveProjectBasePath(basePath) {
|
|
23077
23374
|
if (!basePath) return "";
|
|
23078
|
-
const normalized = trimTrailingSlashes$
|
|
23375
|
+
const normalized = trimTrailingSlashes$2(basePath);
|
|
23079
23376
|
const assetsMatch = normalized.match(/^(.*)[/\\]assets(?:_[^/\\]+)?$/i);
|
|
23080
23377
|
if (assetsMatch?.[1]) return assetsMatch[1];
|
|
23081
23378
|
return dirname$2(normalized);
|
|
23082
23379
|
}
|
|
23083
23380
|
function dirname$2(filePath) {
|
|
23084
|
-
return trimTrailingSlashes$
|
|
23381
|
+
return trimTrailingSlashes$2(filePath).match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
23085
23382
|
}
|
|
23086
|
-
function trimTrailingSlashes$
|
|
23383
|
+
function trimTrailingSlashes$2(value) {
|
|
23087
23384
|
return value.replace(/[/\\]+$/, "");
|
|
23088
23385
|
}
|
|
23089
23386
|
function isAbsolutePath(value) {
|
|
@@ -23092,9 +23389,15 @@ function isAbsolutePath(value) {
|
|
|
23092
23389
|
function isDefaultMemberName(ownerType, kind, name) {
|
|
23093
23390
|
if (kind === "controller") return (ownerType === "GButton" || ownerType === "GComboBox") && name === "button";
|
|
23094
23391
|
if (kind === "transition") return false;
|
|
23095
|
-
if (ownerType === "GButton" || ownerType === "GLabel" || ownerType === "GComboBox")
|
|
23096
|
-
|
|
23097
|
-
|
|
23392
|
+
if (ownerType === "GButton" || ownerType === "GLabel" || ownerType === "GComboBox") {
|
|
23393
|
+
if (name === "title" || name === "icon") return true;
|
|
23394
|
+
}
|
|
23395
|
+
if (ownerType === "GProgressBar") {
|
|
23396
|
+
if (name === "bar" || name === "bar_v" || name === "title" || name === "ani") return true;
|
|
23397
|
+
}
|
|
23398
|
+
if (ownerType === "GSlider") {
|
|
23399
|
+
if (name === "bar" || name === "bar_v" || name === "grip" || name === "title" || name === "ani") return true;
|
|
23400
|
+
}
|
|
23098
23401
|
return /^n\d+(?:_.*)?$/i.test(name);
|
|
23099
23402
|
}
|
|
23100
23403
|
function applyMemberNamePrefix(name, prefix) {
|
|
@@ -23383,11 +23686,11 @@ function inferPackageName(fileName) {
|
|
|
23383
23686
|
if (/\.fui$/i.test(fileName)) return fileName.replace(/\.fui$/i, "");
|
|
23384
23687
|
return fileName.replace(/\.bin$/i, "");
|
|
23385
23688
|
}
|
|
23386
|
-
function trimTrailingSlashes(value) {
|
|
23689
|
+
function trimTrailingSlashes$1(value) {
|
|
23387
23690
|
return value.replace(/[/\\]+$/, "");
|
|
23388
23691
|
}
|
|
23389
23692
|
function normalizeComparablePath(value) {
|
|
23390
|
-
const normalized = trimTrailingSlashes(value).replace(/\\/g, "/");
|
|
23693
|
+
const normalized = trimTrailingSlashes$1(value).replace(/\\/g, "/");
|
|
23391
23694
|
const driveMatch = normalized.match(/^([a-z]:)(?:\/(.*))?$/i);
|
|
23392
23695
|
const drivePrefix = driveMatch?.[1].toLowerCase() ?? "";
|
|
23393
23696
|
const remainder = driveMatch ? driveMatch[2] ?? "" : normalized;
|
|
@@ -23407,14 +23710,14 @@ function normalizeComparablePath(value) {
|
|
|
23407
23710
|
return (drivePrefix ? `${drivePrefix}/${joined}`.replace(/\/$/, "") : hasRoot ? `/${joined}`.replace(/\/$/, "") : joined || ".").toLowerCase();
|
|
23408
23711
|
}
|
|
23409
23712
|
function dirname$1(filePath) {
|
|
23410
|
-
return trimTrailingSlashes(filePath).match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
23713
|
+
return trimTrailingSlashes$1(filePath).match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
23411
23714
|
}
|
|
23412
23715
|
function basename(filePath) {
|
|
23413
|
-
return trimTrailingSlashes(filePath).match(/([^/\\]+)$/)?.[1] ?? "";
|
|
23716
|
+
return trimTrailingSlashes$1(filePath).match(/([^/\\]+)$/)?.[1] ?? "";
|
|
23414
23717
|
}
|
|
23415
23718
|
function resolveOutputProjectPath(output, fs) {
|
|
23416
23719
|
if (/\.fairy$/i.test(output)) return output;
|
|
23417
|
-
const normalizedOutput = trimTrailingSlashes(output);
|
|
23720
|
+
const normalizedOutput = trimTrailingSlashes$1(output);
|
|
23418
23721
|
const projectName = basename(normalizedOutput) || "Restored";
|
|
23419
23722
|
return fs.join(normalizedOutput, `${projectName}.fairy`);
|
|
23420
23723
|
}
|
|
@@ -23460,7 +23763,7 @@ async function prepareRestoreOutputDir(inputDir, outputDir, outputProjectPath, f
|
|
|
23460
23763
|
await fs.mkdir(outputDir);
|
|
23461
23764
|
}
|
|
23462
23765
|
async function restore(options) {
|
|
23463
|
-
const sourceDir = trimTrailingSlashes(options.inputDir);
|
|
23766
|
+
const sourceDir = trimTrailingSlashes$1(options.inputDir);
|
|
23464
23767
|
const outputIsProjectFile = /\.fairy$/i.test(options.output);
|
|
23465
23768
|
const outputProjectPath = resolveOutputProjectPath(options.output, options.fs);
|
|
23466
23769
|
await prepareRestoreOutputDir(sourceDir, dirname$1(outputProjectPath) || ".", outputProjectPath, options.fs, options.force === true, outputIsProjectFile);
|
|
@@ -23602,16 +23905,23 @@ var RestoreWorkflow = class {
|
|
|
23602
23905
|
async _ensureLooseImageResource(doc, pkg, owner, sourceDir, fileName) {
|
|
23603
23906
|
const resources = pkg.listResources();
|
|
23604
23907
|
const existing = this._findResourceByFile(resources, owner, "ImageResource", fileName);
|
|
23605
|
-
if (existing) return existing;
|
|
23606
23908
|
const sourcePath = await this._resolveLooseSourceFile(pkg, sourceDir, fileName);
|
|
23607
|
-
if (!sourcePath) return null;
|
|
23909
|
+
if (!sourcePath) return existing ?? null;
|
|
23910
|
+
if (existing) {
|
|
23911
|
+
existing.setExtras?.({
|
|
23912
|
+
...existing.getExtras?.() ?? {},
|
|
23913
|
+
_publishedFile: fileBaseName(sourcePath),
|
|
23914
|
+
_restoreAsLooseImage: true
|
|
23915
|
+
});
|
|
23916
|
+
return existing;
|
|
23917
|
+
}
|
|
23608
23918
|
const resource = doc.createImageResource(stripExtension(fileName));
|
|
23609
23919
|
resource.setId(generateId()).setPath(owner.getPath?.() ?? "/").setBranch(owner.getBranch?.() ?? "").setBranchItemIds(owner.getBranchItemIds?.() ?? []).setExported(false).setFileName(fileName);
|
|
23610
23920
|
resource.setExtras?.({
|
|
23611
23921
|
...resource.getExtras?.() ?? {},
|
|
23612
23922
|
_publishedFile: fileBaseName(sourcePath),
|
|
23613
23923
|
_suppressPackageSize: true,
|
|
23614
|
-
|
|
23924
|
+
_restoreAsLooseImage: true
|
|
23615
23925
|
});
|
|
23616
23926
|
pkg.addResource(resource);
|
|
23617
23927
|
return resource;
|
|
@@ -23785,13 +24095,13 @@ var RestoreWorkflow = class {
|
|
|
23785
24095
|
}
|
|
23786
24096
|
async _copyLooseResources(pkg, options, warnings) {
|
|
23787
24097
|
for (const resource of pkg.listResources()) {
|
|
23788
|
-
const
|
|
24098
|
+
const restoreAsLooseImage = resource.getExtras?.()?._restoreAsLooseImage === true;
|
|
23789
24099
|
if (![
|
|
23790
24100
|
"SoundResource",
|
|
23791
24101
|
"MiscResource",
|
|
23792
24102
|
"SpineResource",
|
|
23793
24103
|
"DragonBonesResource"
|
|
23794
|
-
].includes(resource.propertyType) && !
|
|
24104
|
+
].includes(resource.propertyType) && !restoreAsLooseImage) continue;
|
|
23795
24105
|
const fileName = resourceFileName(resource);
|
|
23796
24106
|
if (!fileName) continue;
|
|
23797
24107
|
const sourcePath = await this._resolveSourceFile(options.sourceDir, this._sourceFileCandidates(pkg, resourcePublishedFileName(resource), fileName));
|
|
@@ -23961,6 +24271,18 @@ var RestoreWorkflow = class {
|
|
|
23961
24271
|
};
|
|
23962
24272
|
//#endregion
|
|
23963
24273
|
//#region ../functions/src/publish.ts
|
|
24274
|
+
async function runPublishPluginHook(plugins, hook, doc, options) {
|
|
24275
|
+
const logger = doc.getLogger();
|
|
24276
|
+
for (const plugin of plugins) {
|
|
24277
|
+
const fn = plugin.plugin[hook];
|
|
24278
|
+
if (typeof fn !== "function") continue;
|
|
24279
|
+
try {
|
|
24280
|
+
await fn(doc, options);
|
|
24281
|
+
} catch (error) {
|
|
24282
|
+
logger.warn(`publish: Plugin "${plugin.name}" ${hook} failed: ${formatPluginError(error)}`);
|
|
24283
|
+
}
|
|
24284
|
+
}
|
|
24285
|
+
}
|
|
23964
24286
|
const UNITY_PROJECT_TYPE = ProjectType.Unity;
|
|
23965
24287
|
const COCOS_CREATOR_PROJECT_TYPE = ProjectType.CocosCreator;
|
|
23966
24288
|
function resolveDefaultPublishFileExtension(projectType, publishSettings) {
|
|
@@ -24010,6 +24332,19 @@ function resolvePublishOptions(doc, overrides = {}) {
|
|
|
24010
24332
|
atlas: atlasOptions
|
|
24011
24333
|
};
|
|
24012
24334
|
}
|
|
24335
|
+
function trimTrailingSlashes(value) {
|
|
24336
|
+
return value.replace(/[/\\]+$/, "");
|
|
24337
|
+
}
|
|
24338
|
+
function isAbsolutePathLike(value) {
|
|
24339
|
+
return /^(?:[a-zA-Z]:[/\\]|[/\\]{1,2})/u.test(value);
|
|
24340
|
+
}
|
|
24341
|
+
function joinPathSegments(left, right) {
|
|
24342
|
+
const normalizedLeft = trimTrailingSlashes(left);
|
|
24343
|
+
const normalizedRight = right.replace(/^[/\\]+/, "");
|
|
24344
|
+
if (!normalizedLeft) return normalizedRight;
|
|
24345
|
+
if (!normalizedRight) return normalizedLeft;
|
|
24346
|
+
return `${normalizedLeft}${normalizedLeft.includes("\\") ? "\\" : "/"}${normalizedRight}`;
|
|
24347
|
+
}
|
|
24013
24348
|
function dirname(filePath) {
|
|
24014
24349
|
return filePath.replace(/[/\\]+$/, "").match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
24015
24350
|
}
|
|
@@ -24125,13 +24460,14 @@ function extname(fileName) {
|
|
|
24125
24460
|
if (lastDot <= lastSlash) return "";
|
|
24126
24461
|
return normalized.slice(lastDot);
|
|
24127
24462
|
}
|
|
24128
|
-
function resolvePublishedMiscFileName(resource) {
|
|
24463
|
+
function resolvePublishedMiscFileName(resource, projectType) {
|
|
24129
24464
|
const file = resource.getFile();
|
|
24465
|
+
if (projectType !== UNITY_PROJECT_TYPE) return file;
|
|
24130
24466
|
if (file.toLowerCase().endsWith(".atlas")) return `${file}.txt`;
|
|
24131
24467
|
return file;
|
|
24132
24468
|
}
|
|
24133
|
-
function resolvePublishedSkeletonFileName(resource) {
|
|
24134
|
-
if (isSpineResource(resource) && resource.getFile().toLowerCase().endsWith(".skel")) return `${resource.getFile()}.bytes`;
|
|
24469
|
+
function resolvePublishedSkeletonFileName(resource, projectType) {
|
|
24470
|
+
if (projectType === UNITY_PROJECT_TYPE && isSpineResource(resource) && resource.getFile().toLowerCase().endsWith(".skel")) return `${resource.getFile()}.bytes`;
|
|
24135
24471
|
return resource.getFile();
|
|
24136
24472
|
}
|
|
24137
24473
|
function setPublishedFileExtra(resource, fileName) {
|
|
@@ -24234,6 +24570,24 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
24234
24570
|
const referencedIds = /* @__PURE__ */ new Set();
|
|
24235
24571
|
const pixelHitTestImageIds = /* @__PURE__ */ new Set();
|
|
24236
24572
|
const spriteItemIds = /* @__PURE__ */ new Set();
|
|
24573
|
+
const collectExportedResourceIds = (sourceResources, sourcePublishedResourceIds) => {
|
|
24574
|
+
const exportedResourceIds = new Set(sourcePublishedResourceIds);
|
|
24575
|
+
const resourcesById = new Map(sourceResources.map((resource) => [resource.getId(), resource]));
|
|
24576
|
+
let changed = true;
|
|
24577
|
+
while (changed) {
|
|
24578
|
+
changed = false;
|
|
24579
|
+
for (const resourceId of [...exportedResourceIds]) {
|
|
24580
|
+
const resource = resourcesById.get(resourceId);
|
|
24581
|
+
if (!resource || !isSkeletonResource(resource)) continue;
|
|
24582
|
+
for (const requiredId of resource.getRequireIds()) {
|
|
24583
|
+
if (!requiredId || exportedResourceIds.has(requiredId)) continue;
|
|
24584
|
+
exportedResourceIds.add(requiredId);
|
|
24585
|
+
changed = true;
|
|
24586
|
+
}
|
|
24587
|
+
}
|
|
24588
|
+
}
|
|
24589
|
+
return exportedResourceIds;
|
|
24590
|
+
};
|
|
24237
24591
|
for (const atlas of pkg.listAtlases()) for (const sprite of atlas.listSprites()) spriteItemIds.add(sprite.getItemId());
|
|
24238
24592
|
for (const resource of resources) {
|
|
24239
24593
|
if (!isComponentResource(resource)) continue;
|
|
@@ -24260,6 +24614,7 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
24260
24614
|
child.getSelectedIcon?.(),
|
|
24261
24615
|
child.getDropdown?.(),
|
|
24262
24616
|
child.getSound?.(),
|
|
24617
|
+
child.getInstanceSound?.(),
|
|
24263
24618
|
child.getInstanceIcon?.(),
|
|
24264
24619
|
child.getInstanceSelectedIcon?.(),
|
|
24265
24620
|
child.getVtScrollBarRes?.(),
|
|
@@ -24317,19 +24672,7 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
24317
24672
|
}
|
|
24318
24673
|
if (resource.getExported() || referencedIds.has(resourceId)) publishedResourceIds.add(resourceId);
|
|
24319
24674
|
}
|
|
24320
|
-
|
|
24321
|
-
while (changed) {
|
|
24322
|
-
changed = false;
|
|
24323
|
-
for (const resource of resources) {
|
|
24324
|
-
if (!isSkeletonResource(resource)) continue;
|
|
24325
|
-
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
24326
|
-
for (const requiredId of resource.getRequireIds()) {
|
|
24327
|
-
if (!requiredId || publishedResourceIds.has(requiredId)) continue;
|
|
24328
|
-
publishedResourceIds.add(requiredId);
|
|
24329
|
-
changed = true;
|
|
24330
|
-
}
|
|
24331
|
-
}
|
|
24332
|
-
}
|
|
24675
|
+
for (const resourceId of collectExportedResourceIds(resources, publishedResourceIds)) publishedResourceIds.add(resourceId);
|
|
24333
24676
|
const highResolutionItemIds = collectHighResolutionItemIds(resources, publishedResourceIds, options.includeHighResolution);
|
|
24334
24677
|
if (!options.includeBranches) {
|
|
24335
24678
|
const mainByKey = /* @__PURE__ */ new Map();
|
|
@@ -24378,6 +24721,7 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
24378
24721
|
return {
|
|
24379
24722
|
referencedIds,
|
|
24380
24723
|
publishedResourceIds,
|
|
24724
|
+
exportedResourceIds: collectExportedResourceIds(resources, publishedResourceIds),
|
|
24381
24725
|
pixelHitTestImageIds,
|
|
24382
24726
|
highResolutionItemIds,
|
|
24383
24727
|
effectiveResourceIds,
|
|
@@ -24387,6 +24731,7 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
24387
24731
|
return {
|
|
24388
24732
|
referencedIds,
|
|
24389
24733
|
publishedResourceIds,
|
|
24734
|
+
exportedResourceIds: collectExportedResourceIds(resources, publishedResourceIds),
|
|
24390
24735
|
pixelHitTestImageIds,
|
|
24391
24736
|
highResolutionItemIds,
|
|
24392
24737
|
effectiveResourceIds: new Map([...publishedResourceIds].map((resourceId) => [resourceId, resourceId])),
|
|
@@ -24437,7 +24782,7 @@ async function applyPixelHitTests(pkg, imageIds, basePath, encoder) {
|
|
|
24437
24782
|
}
|
|
24438
24783
|
}
|
|
24439
24784
|
async function annotatePackagePublishArtifacts(pkg, basePath, encoder, options) {
|
|
24440
|
-
const { publishedResourceIds, pixelHitTestImageIds, highResolutionItemIds, effectiveResourceIds, includeBranches } = collectPackagePublishContext(pkg, options);
|
|
24785
|
+
const { publishedResourceIds, exportedResourceIds, pixelHitTestImageIds, highResolutionItemIds, effectiveResourceIds, includeBranches } = collectPackagePublishContext(pkg, options);
|
|
24441
24786
|
for (const resource of pkg.listResources()) {
|
|
24442
24787
|
setPublishedIdExtra(resource, effectiveResourceIds.get(resource.getId()) ?? null);
|
|
24443
24788
|
if (isHighResolutionResource(resource)) resource.setHighResolutionItemIds(highResolutionItemIds.get(resource.getId()) ?? []);
|
|
@@ -24447,21 +24792,26 @@ async function annotatePackagePublishArtifacts(pkg, basePath, encoder, options)
|
|
|
24447
24792
|
pkg.setExtras({
|
|
24448
24793
|
...extras,
|
|
24449
24794
|
publishedResourceIds: [...publishedResourceIds].sort((a, b) => a.localeCompare(b)),
|
|
24795
|
+
exportedResourceIds: [...exportedResourceIds].sort((a, b) => a.localeCompare(b)),
|
|
24450
24796
|
publishedIncludeBranches: includeBranches,
|
|
24451
24797
|
publishedEffectiveResourceIds: Object.fromEntries(effectiveResourceIds)
|
|
24452
24798
|
});
|
|
24453
24799
|
for (const resource of pkg.listResources()) {
|
|
24454
24800
|
if (isMiscResource(resource)) {
|
|
24455
|
-
setPublishedFileExtra(resource, resolvePublishedMiscFileName(resource));
|
|
24801
|
+
setPublishedFileExtra(resource, resolvePublishedMiscFileName(resource, options.projectType));
|
|
24456
24802
|
continue;
|
|
24457
24803
|
}
|
|
24458
|
-
if (isSkeletonResource(resource)) setPublishedFileExtra(resource, resolvePublishedSkeletonFileName(resource));
|
|
24804
|
+
if (isSkeletonResource(resource)) setPublishedFileExtra(resource, resolvePublishedSkeletonFileName(resource, options.projectType));
|
|
24459
24805
|
}
|
|
24460
24806
|
}
|
|
24461
24807
|
function getAnnotatedPublishedResourceIds(pkg) {
|
|
24462
24808
|
const extras = pkg.getExtras() ?? {};
|
|
24463
24809
|
return new Set(extras.publishedResourceIds ?? []);
|
|
24464
24810
|
}
|
|
24811
|
+
function getAnnotatedExportedResourceIds(pkg) {
|
|
24812
|
+
const extras = pkg.getExtras() ?? {};
|
|
24813
|
+
return new Set(extras.exportedResourceIds ?? []);
|
|
24814
|
+
}
|
|
24465
24815
|
function getPublishedSkeletonDependencyImageIds(pkg, publishedResourceIds) {
|
|
24466
24816
|
const imageIds = /* @__PURE__ */ new Set();
|
|
24467
24817
|
const resourcesById = new Map(pkg.listResources().map((resource) => [resource.getId(), resource]));
|
|
@@ -24500,18 +24850,18 @@ async function exportPackageSounds(pkg, outputDir, basePath, fs, readFileRaw, lo
|
|
|
24500
24850
|
}
|
|
24501
24851
|
}
|
|
24502
24852
|
async function exportPackageExternalResources(pkg, outputDir, basePath, fs, readFileRaw, logger) {
|
|
24503
|
-
const
|
|
24504
|
-
const skeletonDependencyImageIds = getPublishedSkeletonDependencyImageIds(pkg,
|
|
24505
|
-
if (
|
|
24853
|
+
const exportedResourceIds = getAnnotatedExportedResourceIds(pkg);
|
|
24854
|
+
const skeletonDependencyImageIds = getPublishedSkeletonDependencyImageIds(pkg, exportedResourceIds);
|
|
24855
|
+
if (exportedResourceIds.size === 0) return;
|
|
24506
24856
|
if (!basePath || !readFileRaw) {
|
|
24507
24857
|
if (pkg.listResources().some((resource) => {
|
|
24508
|
-
return (isMiscResource(resource) || isSkeletonResource(resource)) &&
|
|
24858
|
+
return (isMiscResource(resource) || isSkeletonResource(resource)) && exportedResourceIds.has(resource.getId()) || skeletonDependencyImageIds.has(resource.getId());
|
|
24509
24859
|
})) logger.warn(`publish: External resources in package "${pkg.getName()}" were not exported because basePath/readFileRaw is unavailable.`);
|
|
24510
24860
|
return;
|
|
24511
24861
|
}
|
|
24512
24862
|
for (const resource of pkg.listResources()) {
|
|
24513
24863
|
const resourceId = resource.getId();
|
|
24514
|
-
const isSkeletonExternal =
|
|
24864
|
+
const isSkeletonExternal = exportedResourceIds.has(resourceId) && (isMiscResource(resource) || isSkeletonResource(resource));
|
|
24515
24865
|
const isSkeletonImageDependency = skeletonDependencyImageIds.has(resourceId) && isImageResource(resource);
|
|
24516
24866
|
if (!isSkeletonExternal && !isSkeletonImageDependency) continue;
|
|
24517
24867
|
let sourcePath;
|
|
@@ -24536,10 +24886,13 @@ async function exportPackageExternalResources(pkg, outputDir, basePath, fs, read
|
|
|
24536
24886
|
* Publishes a FairyGUI project.
|
|
24537
24887
|
*
|
|
24538
24888
|
* Orchestrates:
|
|
24539
|
-
* 1. Atlas packing (MaxRects layout + optional
|
|
24889
|
+
* 1. Atlas packing (MaxRects layout + optional raster compositing)
|
|
24540
24890
|
* 2. Per-package .fui binary serialization
|
|
24541
24891
|
* 3. File writing to the output directory
|
|
24542
24892
|
*
|
|
24893
|
+
* This is the capability-injected core. Standard hosts should use
|
|
24894
|
+
* `publishNode()` or `publishBrowser()` through their dedicated entries.
|
|
24895
|
+
*
|
|
24543
24896
|
* ```ts
|
|
24544
24897
|
* import sharp from 'sharp';
|
|
24545
24898
|
* const io = new NodeIO();
|
|
@@ -24557,16 +24910,101 @@ async function exportPackageExternalResources(pkg, outputDir, basePath, fs, read
|
|
|
24557
24910
|
*/
|
|
24558
24911
|
function publish(options) {
|
|
24559
24912
|
return createTransform("publish", async (doc) => {
|
|
24913
|
+
const resolveConfiguredOutputPath = (value, projectBasePath) => {
|
|
24914
|
+
const trimmed = value?.trim();
|
|
24915
|
+
if (!trimmed) return void 0;
|
|
24916
|
+
if (isAbsolutePathLike(trimmed) || !projectBasePath) return trimTrailingSlashes(trimmed);
|
|
24917
|
+
return trimTrailingSlashes(options.fs ? options.fs.join(projectBasePath, trimmed) : joinPathSegments(projectBasePath, trimmed));
|
|
24918
|
+
};
|
|
24919
|
+
const resolveProjectPublishConfig = () => {
|
|
24920
|
+
const publishSettings = (doc.getRoot().getSettings?.() ?? {}).publish ?? {};
|
|
24921
|
+
const resolved = resolvePublishOptions(doc, {
|
|
24922
|
+
compressed: options.compressed,
|
|
24923
|
+
fileExtension: options.fileExtension,
|
|
24924
|
+
packages: options.packages,
|
|
24925
|
+
atlas: options.atlas
|
|
24926
|
+
});
|
|
24927
|
+
const includeBranches = (publishSettings.branchProcessing ?? 0) === 0;
|
|
24928
|
+
return {
|
|
24929
|
+
...resolved,
|
|
24930
|
+
projectType: doc.getRoot().getProjectType(),
|
|
24931
|
+
includeBranches,
|
|
24932
|
+
activeBranch: includeBranches ? "" : options.branch ?? "",
|
|
24933
|
+
includeHighResolution: publishSettings.includeHighResolution ?? 0,
|
|
24934
|
+
separatedAtlasForBranch: includeBranches && publishSettings.seperatedAtlasForBranch === true,
|
|
24935
|
+
globalOutputPath: publishSettings.path?.trim() ?? "",
|
|
24936
|
+
globalBranchOutputPath: publishSettings.branchPath?.trim() ?? ""
|
|
24937
|
+
};
|
|
24938
|
+
};
|
|
24939
|
+
const resolvePackagePublishPlan = (pkg, config, projectBasePath) => {
|
|
24940
|
+
let outputDir;
|
|
24941
|
+
if (options.output) outputDir = trimTrailingSlashes(options.output);
|
|
24942
|
+
else {
|
|
24943
|
+
const candidates = [];
|
|
24944
|
+
if (!config.includeBranches && config.activeBranch) candidates.push(pkg.getPublishBranchPath(), config.globalBranchOutputPath);
|
|
24945
|
+
candidates.push(pkg.getPublishPath(), config.globalOutputPath);
|
|
24946
|
+
for (const candidate of candidates) {
|
|
24947
|
+
const resolved = resolveConfiguredOutputPath(candidate, projectBasePath);
|
|
24948
|
+
if (!resolved) continue;
|
|
24949
|
+
outputDir = resolved;
|
|
24950
|
+
break;
|
|
24951
|
+
}
|
|
24952
|
+
}
|
|
24953
|
+
const publishName = pkg.getPublishName() || pkg.getName();
|
|
24954
|
+
return {
|
|
24955
|
+
pkg,
|
|
24956
|
+
outputDir,
|
|
24957
|
+
publishName,
|
|
24958
|
+
fileName: resolvePublishFileName(publishName, config.fileExtension),
|
|
24959
|
+
compressed: config.compressed,
|
|
24960
|
+
fileExtension: config.fileExtension,
|
|
24961
|
+
includeBranches: config.includeBranches,
|
|
24962
|
+
activeBranch: config.activeBranch,
|
|
24963
|
+
includeHighResolution: config.includeHighResolution,
|
|
24964
|
+
separatedAtlasForBranch: config.separatedAtlasForBranch,
|
|
24965
|
+
atlas: config.atlas
|
|
24966
|
+
};
|
|
24967
|
+
};
|
|
24968
|
+
const createNoopPublishFs = () => ({
|
|
24969
|
+
async writeFileRaw() {},
|
|
24970
|
+
async mkdir() {},
|
|
24971
|
+
join(...paths) {
|
|
24972
|
+
return paths.join("/");
|
|
24973
|
+
}
|
|
24974
|
+
});
|
|
24975
|
+
const publishPackage = async (plan, writerFs, packageIndex) => {
|
|
24976
|
+
const atlasRuntimeOptions = resolvePublishAtlasRuntimeOptions(plan.fileExtension);
|
|
24977
|
+
await atlas({
|
|
24978
|
+
...plan.atlas,
|
|
24979
|
+
...options.atlas ?? {},
|
|
24980
|
+
separatedAtlasForBranch: plan.separatedAtlasForBranch,
|
|
24981
|
+
encoder: options.encoder,
|
|
24982
|
+
basePath: options.basePath,
|
|
24983
|
+
outputPath: options.fs ? plan.outputDir : void 0,
|
|
24984
|
+
mkdir: options.fs ? options.fs.mkdir : void 0,
|
|
24985
|
+
readFileRaw: options.atlas?.readFileRaw ?? options.fs?.readFileRaw,
|
|
24986
|
+
packages: [plan.pkg.getName()],
|
|
24987
|
+
...atlasRuntimeOptions
|
|
24988
|
+
})(doc);
|
|
24989
|
+
if (!options.fs) return;
|
|
24990
|
+
if (!plan.outputDir) throw new Error("publish: no output directory resolved. Provide --output, or configure global publish.path / package publishPath.");
|
|
24991
|
+
await options.fs.mkdir(plan.outputDir);
|
|
24992
|
+
const filePath = options.fs.join(plan.outputDir, plan.fileName);
|
|
24993
|
+
const bwOptions = {
|
|
24994
|
+
compressed: plan.compressed,
|
|
24995
|
+
packageIndex
|
|
24996
|
+
};
|
|
24997
|
+
await new BinaryWriter(writerFs).write(doc, filePath, bwOptions);
|
|
24998
|
+
await exportPackageSounds(plan.pkg, plan.outputDir, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
24999
|
+
await exportPackageExternalResources(plan.pkg, plan.outputDir, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
25000
|
+
logger.info(`publish: Written ${plan.fileName}`);
|
|
25001
|
+
};
|
|
24560
25002
|
const root = doc.getRoot();
|
|
24561
25003
|
const logger = doc.getLogger();
|
|
24562
|
-
const
|
|
24563
|
-
const
|
|
24564
|
-
|
|
24565
|
-
|
|
24566
|
-
packages: options.packages,
|
|
24567
|
-
atlas: options.atlas
|
|
24568
|
-
});
|
|
24569
|
-
const ext = resolved.fileExtension;
|
|
25004
|
+
const projectBasePath = resolveProjectBasePath(options.basePath) || doc.getProjectDir?.() || "";
|
|
25005
|
+
const plugins = options.plugins ?? [];
|
|
25006
|
+
await runPublishPluginHook(plugins, "onPublishStart", doc, options);
|
|
25007
|
+
const resolved = resolveProjectPublishConfig();
|
|
24570
25008
|
let allPackages = root.listPackages();
|
|
24571
25009
|
if (resolved.packages && resolved.packages.length > 0) {
|
|
24572
25010
|
const names = new Set(resolved.packages);
|
|
@@ -24574,59 +25012,42 @@ function publish(options) {
|
|
|
24574
25012
|
}
|
|
24575
25013
|
if (allPackages.length === 0) {
|
|
24576
25014
|
logger.warn("publish: No packages to publish.");
|
|
25015
|
+
await runPublishPluginHook(plugins, "onPublishEnd", doc, options);
|
|
24577
25016
|
return;
|
|
24578
25017
|
}
|
|
24579
|
-
const includeBranches = (publishSettings.branchProcessing ?? 0) === 0;
|
|
24580
|
-
const activeBranch = includeBranches ? "" : options.branch ?? "";
|
|
24581
|
-
const includeHighResolution = publishSettings.includeHighResolution ?? 0;
|
|
24582
|
-
const atlasRuntimeOptions = resolvePublishAtlasRuntimeOptions(ext);
|
|
24583
25018
|
const allDocPackages = root.listPackages();
|
|
24584
25019
|
const pkgMap = /* @__PURE__ */ new Map();
|
|
24585
25020
|
for (const p of allDocPackages) pkgMap.set(p.getId(), p);
|
|
24586
25021
|
for (const pkg of allPackages) {
|
|
24587
|
-
_computeDependencies(pkg, pkgMap);
|
|
25022
|
+
_computeDependencies(doc, pkg, pkgMap);
|
|
24588
25023
|
await annotatePackagePublishArtifacts(pkg, options.basePath, options.encoder, {
|
|
24589
|
-
|
|
24590
|
-
|
|
24591
|
-
|
|
25024
|
+
projectType: resolved.projectType,
|
|
25025
|
+
includeBranches: resolved.includeBranches,
|
|
25026
|
+
activeBranch: resolved.activeBranch,
|
|
25027
|
+
includeHighResolution: resolved.includeHighResolution
|
|
24592
25028
|
});
|
|
24593
25029
|
}
|
|
24594
|
-
|
|
24595
|
-
...resolved.atlas,
|
|
24596
|
-
...options.atlas ?? {},
|
|
24597
|
-
separatedAtlasForBranch: includeBranches && publishSettings.seperatedAtlasForBranch === true,
|
|
24598
|
-
encoder: options.encoder,
|
|
24599
|
-
basePath: options.basePath,
|
|
24600
|
-
outputPath: options.fs ? options.output : void 0,
|
|
24601
|
-
mkdir: options.fs ? options.fs.mkdir : void 0,
|
|
24602
|
-
readFileRaw: options.atlas?.readFileRaw ?? options.fs?.readFileRaw,
|
|
24603
|
-
...atlasRuntimeOptions
|
|
24604
|
-
})(doc);
|
|
25030
|
+
const plans = allPackages.map((pkg) => resolvePackagePublishPlan(pkg, resolved, projectBasePath));
|
|
24605
25031
|
if (!options.fs) {
|
|
24606
25032
|
logger.info(`publish: No fs provided — layout computed for ${allPackages.length} package(s), skipping file output.`);
|
|
25033
|
+
const noopWriterFs = toBinaryWriterFileSystem(createNoopPublishFs());
|
|
25034
|
+
for (const plan of plans) await publishPackage(plan, noopWriterFs, allDocPackages.indexOf(plan.pkg));
|
|
25035
|
+
await runPublishPluginHook(plugins, "onPublishEnd", doc, options);
|
|
24607
25036
|
return;
|
|
24608
25037
|
}
|
|
24609
|
-
|
|
25038
|
+
const unresolvedPlan = plans.find((plan) => !plan.outputDir);
|
|
25039
|
+
if (unresolvedPlan) throw new Error(`publish: no output directory resolved for package "${unresolvedPlan.pkg.getName()}". Provide --output, or configure global publish.path / package publishPath.`);
|
|
24610
25040
|
const writerFs = toBinaryWriterFileSystem(options.fs);
|
|
24611
|
-
for (const
|
|
24612
|
-
|
|
24613
|
-
const fileName = resolvePublishFileName(pkg.getPublishName() || pkg.getName(), ext);
|
|
24614
|
-
const filePath = options.fs.join(options.output, fileName);
|
|
24615
|
-
const bwOptions = {
|
|
24616
|
-
compressed: resolved.compressed,
|
|
24617
|
-
packageIndex: pkgIndex
|
|
24618
|
-
};
|
|
24619
|
-
await new BinaryWriter(writerFs).write(doc, filePath, bwOptions);
|
|
24620
|
-
await exportPackageSounds(pkg, options.output, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
24621
|
-
await exportPackageExternalResources(pkg, options.output, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
24622
|
-
logger.info(`publish: Written ${fileName}`);
|
|
24623
|
-
}
|
|
24624
|
-
await publishCodeGeneration(doc, {
|
|
25041
|
+
for (const plan of plans) await publishPackage(plan, writerFs, allDocPackages.indexOf(plan.pkg));
|
|
25042
|
+
if (options.codeGeneration !== false) await publishCodeGeneration(doc, {
|
|
24625
25043
|
basePath: options.basePath,
|
|
24626
25044
|
fs: options.fs,
|
|
24627
|
-
packages: allPackages
|
|
25045
|
+
packages: allPackages,
|
|
25046
|
+
plugins
|
|
24628
25047
|
});
|
|
24629
|
-
|
|
25048
|
+
const publishedTargets = [...new Set(plans.map((plan) => plan.outputDir).filter((value) => Boolean(value)))];
|
|
25049
|
+
logger.info(publishedTargets.length > 0 ? `publish: Published ${allPackages.length} package(s) to ${publishedTargets.join(", ")}` : `publish: Published ${allPackages.length} package(s)`);
|
|
25050
|
+
await runPublishPluginHook(plugins, "onPublishEnd", doc, options);
|
|
24630
25051
|
});
|
|
24631
25052
|
}
|
|
24632
25053
|
/**
|
|
@@ -24634,25 +25055,104 @@ function publish(options) {
|
|
|
24634
25055
|
* The editor only adds dependencies for packages referenced via bitmap font URLs.
|
|
24635
25056
|
* @internal
|
|
24636
25057
|
*/
|
|
24637
|
-
function _computeDependencies(pkg, pkgMap) {
|
|
25058
|
+
function _computeDependencies(doc, pkg, pkgMap) {
|
|
24638
25059
|
const referencedPkgIds = /* @__PURE__ */ new Set();
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
|
|
24644
|
-
|
|
24645
|
-
|
|
24646
|
-
|
|
25060
|
+
const pkgId = pkg.getId();
|
|
25061
|
+
const packageOrder = new Map(doc.getRoot().listPackages().map((entry, index) => [entry.getId(), index]));
|
|
25062
|
+
const addDependencyPackageId = (dependencyPkgId) => {
|
|
25063
|
+
const normalized = dependencyPkgId?.trim() ?? "";
|
|
25064
|
+
if (!normalized || normalized === pkgId) return;
|
|
25065
|
+
referencedPkgIds.add(normalized);
|
|
25066
|
+
};
|
|
25067
|
+
const extractPackageIdFromUiUrl = (value) => {
|
|
25068
|
+
if (!value.startsWith("ui://")) return null;
|
|
25069
|
+
const rest = value.slice(5);
|
|
25070
|
+
if (!rest) return null;
|
|
25071
|
+
const slashIndex = rest.indexOf("/");
|
|
25072
|
+
if (slashIndex >= 0) return rest.slice(0, slashIndex) || null;
|
|
25073
|
+
if (rest.length >= 8) return rest.slice(0, 8);
|
|
25074
|
+
return null;
|
|
25075
|
+
};
|
|
25076
|
+
const addDependencyPackageIdFromUiValue = (value) => {
|
|
25077
|
+
if (!value || typeof value !== "string") return;
|
|
25078
|
+
addDependencyPackageId(extractPackageIdFromUiUrl(value));
|
|
25079
|
+
};
|
|
25080
|
+
const addDependencyPackageIdsFromText = (value) => {
|
|
25081
|
+
if (!value || typeof value !== "string") return;
|
|
25082
|
+
const matches = value.matchAll(/ui:\/\/([0-9a-z]{8})/giu);
|
|
25083
|
+
for (const match of matches) addDependencyPackageId(match[1] ?? "");
|
|
25084
|
+
};
|
|
25085
|
+
const addDependencyPackageIdsFromUnknown = (value) => {
|
|
25086
|
+
if (Array.isArray(value)) {
|
|
25087
|
+
for (const entry of value) addDependencyPackageIdsFromUnknown(entry);
|
|
25088
|
+
return;
|
|
24647
25089
|
}
|
|
24648
|
-
|
|
25090
|
+
if (typeof value === "string") {
|
|
25091
|
+
addDependencyPackageIdFromUiValue(value);
|
|
25092
|
+
addDependencyPackageIdsFromText(value);
|
|
25093
|
+
}
|
|
25094
|
+
};
|
|
25095
|
+
const addDependencyFontRef = (value) => {
|
|
25096
|
+
if (Array.isArray(value)) {
|
|
25097
|
+
for (const entry of value) addDependencyPackageIdFromUiValue(entry);
|
|
25098
|
+
return;
|
|
25099
|
+
}
|
|
25100
|
+
addDependencyPackageIdFromUiValue(value ?? void 0);
|
|
25101
|
+
};
|
|
24649
25102
|
for (const res of pkg.listResources()) {
|
|
24650
25103
|
if (res.propertyType !== "Component") continue;
|
|
24651
|
-
|
|
25104
|
+
const component = res;
|
|
25105
|
+
for (const child of component.listChildren?.() ?? []) {
|
|
25106
|
+
addDependencyPackageId(child.getPackageId?.());
|
|
25107
|
+
addDependencyFontRef(child.getFont?.());
|
|
25108
|
+
addDependencyPackageIdsFromText(child.getText?.());
|
|
25109
|
+
for (const ref of [
|
|
25110
|
+
child.getUrl?.(),
|
|
25111
|
+
child.getDefaultItem?.(),
|
|
25112
|
+
child.getIcon?.(),
|
|
25113
|
+
child.getSelectedIcon?.(),
|
|
25114
|
+
child.getDropdown?.(),
|
|
25115
|
+
child.getSound?.(),
|
|
25116
|
+
child.getInstanceSound?.(),
|
|
25117
|
+
child.getInstanceIcon?.(),
|
|
25118
|
+
child.getInstanceSelectedIcon?.(),
|
|
25119
|
+
child.getVtScrollBarRes?.(),
|
|
25120
|
+
child.getHzScrollBarRes?.(),
|
|
25121
|
+
child.getHeaderRes?.(),
|
|
25122
|
+
child.getFooterRes?.()
|
|
25123
|
+
]) addDependencyPackageIdFromUiValue(ref);
|
|
25124
|
+
for (const item of child.getInstanceComboItems?.() ?? []) addDependencyPackageIdFromUiValue(item.icon ?? void 0);
|
|
25125
|
+
for (const item of child.getListItems?.() ?? []) {
|
|
25126
|
+
addDependencyPackageIdFromUiValue(item.icon ?? void 0);
|
|
25127
|
+
addDependencyPackageIdFromUiValue(item.url ?? void 0);
|
|
25128
|
+
}
|
|
25129
|
+
for (const gear of child.listGears?.() ?? []) {
|
|
25130
|
+
addDependencyPackageIdsFromUnknown(gear.getValues?.());
|
|
25131
|
+
addDependencyPackageIdsFromUnknown(gear.getDefaultValue?.());
|
|
25132
|
+
}
|
|
25133
|
+
}
|
|
25134
|
+
addDependencyFontRef(component.getFont?.());
|
|
25135
|
+
for (const ref of [
|
|
25136
|
+
component.getDropdown?.(),
|
|
25137
|
+
component.getHeaderRes?.(),
|
|
25138
|
+
component.getFooterRes?.(),
|
|
25139
|
+
component.getVtScrollBarRes?.(),
|
|
25140
|
+
component.getHzScrollBarRes?.(),
|
|
25141
|
+
component.getSound?.()
|
|
25142
|
+
]) addDependencyPackageIdFromUiValue(ref);
|
|
25143
|
+
for (const transition of component.listTransitions?.() ?? []) for (const item of transition.listItems?.() ?? []) {
|
|
25144
|
+
addDependencyPackageIdsFromUnknown(item.getStartValue?.());
|
|
25145
|
+
addDependencyPackageIdsFromUnknown(item.getEndValue?.());
|
|
25146
|
+
}
|
|
24652
25147
|
}
|
|
24653
25148
|
for (const dep of pkg.listDependencies()) pkg.removeDependency(dep);
|
|
24654
25149
|
if (referencedPkgIds.size > 0) {
|
|
24655
|
-
const sortedIds = [...referencedPkgIds].sort((a, b) =>
|
|
25150
|
+
const sortedIds = [...referencedPkgIds].sort((a, b) => {
|
|
25151
|
+
const orderA = packageOrder.get(a) ?? Number.MAX_SAFE_INTEGER;
|
|
25152
|
+
const orderB = packageOrder.get(b) ?? Number.MAX_SAFE_INTEGER;
|
|
25153
|
+
if (orderA !== orderB) return orderA - orderB;
|
|
25154
|
+
return a.localeCompare(b);
|
|
25155
|
+
});
|
|
24656
25156
|
for (const refId of sortedIds) {
|
|
24657
25157
|
const depPkg = pkgMap.get(refId);
|
|
24658
25158
|
if (depPkg) pkg.addDependency(depPkg);
|
|
@@ -24660,98 +25160,325 @@ function _computeDependencies(pkg, pkgMap) {
|
|
|
24660
25160
|
}
|
|
24661
25161
|
}
|
|
24662
25162
|
//#endregion
|
|
24663
|
-
//#region src/
|
|
24664
|
-
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24668
|
-
|
|
24669
|
-
|
|
24670
|
-
|
|
24671
|
-
|
|
24672
|
-
|
|
24673
|
-
|
|
24674
|
-
|
|
24675
|
-
|
|
24676
|
-
|
|
24677
|
-
|
|
24678
|
-
|
|
24679
|
-
|
|
24680
|
-
|
|
24681
|
-
|
|
24682
|
-
|
|
24683
|
-
|
|
24684
|
-
|
|
24685
|
-
|
|
24686
|
-
|
|
24687
|
-
|
|
24688
|
-
|
|
24689
|
-
|
|
24690
|
-
|
|
24691
|
-
|
|
24692
|
-
|
|
24693
|
-
|
|
24694
|
-
|
|
24695
|
-
|
|
24696
|
-
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
}
|
|
24701
|
-
|
|
24702
|
-
|
|
24703
|
-
|
|
24704
|
-
|
|
24705
|
-
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
}
|
|
24710
|
-
|
|
25163
|
+
//#region ../core/src/io/node-io.ts
|
|
25164
|
+
/**
|
|
25165
|
+
* Node.js I/O implementation for reading and writing FairyGUI projects.
|
|
25166
|
+
*
|
|
25167
|
+
* Usage:
|
|
25168
|
+
*
|
|
25169
|
+
* ```ts
|
|
25170
|
+
* import { NodeIO } from '@openfairygui/core/node';
|
|
25171
|
+
*
|
|
25172
|
+
* const io = new NodeIO();
|
|
25173
|
+
* const doc = await io.readProject('./path/to/project.fairy');
|
|
25174
|
+
* await io.writeProject(doc, './path/to/output.fairy');
|
|
25175
|
+
* const doc2 = await io.readBinary('./path/to/package_fui.bytes');
|
|
25176
|
+
* ```
|
|
25177
|
+
*
|
|
25178
|
+
* @category I/O
|
|
25179
|
+
*/
|
|
25180
|
+
var NodeIO = class extends PlatformIO {
|
|
25181
|
+
createFileSystem() {
|
|
25182
|
+
return {
|
|
25183
|
+
async readFile(filePath) {
|
|
25184
|
+
return fs$1.readFile(filePath, "utf-8");
|
|
25185
|
+
},
|
|
25186
|
+
async readFileRaw(filePath) {
|
|
25187
|
+
const buf = await fs$1.readFile(filePath);
|
|
25188
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
25189
|
+
},
|
|
25190
|
+
async writeFile(filePath, content) {
|
|
25191
|
+
await fs$1.writeFile(filePath, content, "utf-8");
|
|
25192
|
+
},
|
|
25193
|
+
async writeFileRaw(filePath, data) {
|
|
25194
|
+
await fs$1.writeFile(filePath, data);
|
|
25195
|
+
},
|
|
25196
|
+
async mkdir(dirPath) {
|
|
25197
|
+
await fs$1.mkdir(dirPath, { recursive: true });
|
|
25198
|
+
},
|
|
25199
|
+
async readdir(dirPath) {
|
|
25200
|
+
const entries = await fs$1.readdir(dirPath, { withFileTypes: true });
|
|
25201
|
+
return (await Promise.all(entries.map(async (entry) => {
|
|
25202
|
+
if (entry.isDirectory()) return entry.name;
|
|
25203
|
+
if (!entry.isSymbolicLink()) return null;
|
|
25204
|
+
try {
|
|
25205
|
+
return (await fs$1.stat(path$1.join(dirPath, entry.name))).isDirectory() ? entry.name : null;
|
|
25206
|
+
} catch {
|
|
25207
|
+
return null;
|
|
25208
|
+
}
|
|
25209
|
+
}))).filter((entry) => entry !== null);
|
|
25210
|
+
},
|
|
25211
|
+
async exists(filePath) {
|
|
25212
|
+
try {
|
|
25213
|
+
await fs$1.access(filePath);
|
|
25214
|
+
return true;
|
|
25215
|
+
} catch {
|
|
25216
|
+
return false;
|
|
25217
|
+
}
|
|
25218
|
+
},
|
|
25219
|
+
join(...paths) {
|
|
25220
|
+
return path$1.join(...paths);
|
|
25221
|
+
},
|
|
25222
|
+
dirname(filePath) {
|
|
25223
|
+
return path$1.dirname(filePath);
|
|
25224
|
+
}
|
|
25225
|
+
};
|
|
25226
|
+
}
|
|
25227
|
+
};
|
|
25228
|
+
//#endregion
|
|
25229
|
+
//#region src/utils/project-input.ts
|
|
24711
25230
|
/** Resolve input to a .fairy file path. Accepts a directory or a .fairy file. */
|
|
24712
25231
|
async function resolveFairyPath(input) {
|
|
24713
25232
|
const resolved = path.resolve(input);
|
|
24714
25233
|
const stat = await fs.stat(resolved);
|
|
24715
25234
|
if (stat.isFile() && resolved.endsWith(".fairy")) return resolved;
|
|
24716
25235
|
if (stat.isDirectory()) {
|
|
24717
|
-
const fairyFiles = (await fs.readdir(resolved)).filter((
|
|
25236
|
+
const fairyFiles = (await fs.readdir(resolved)).filter((entry) => entry.endsWith(".fairy"));
|
|
24718
25237
|
if (fairyFiles.length === 1) return path.join(resolved, fairyFiles[0]);
|
|
24719
25238
|
if (fairyFiles.length > 1) throw new Error(`Multiple .fairy files found in ${resolved}: ${fairyFiles.join(", ")}. Please specify one.`);
|
|
24720
25239
|
throw new Error(`No .fairy file found in ${resolved}`);
|
|
24721
25240
|
}
|
|
24722
25241
|
throw new Error(`Input is not a .fairy file or directory: ${resolved}`);
|
|
24723
25242
|
}
|
|
24724
|
-
|
|
24725
|
-
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
25243
|
+
//#endregion
|
|
25244
|
+
//#region src/commands/inspect.ts
|
|
25245
|
+
function registerInspectCommand(program) {
|
|
25246
|
+
program.command("inspect").description("Show project contents report").argument("<project-dir>", "Project root directory or .fairy file").action(async (projectDir) => {
|
|
25247
|
+
const fairyPath = await resolveFairyPath(projectDir);
|
|
25248
|
+
console.log(`Project: ${fairyPath}\n`);
|
|
25249
|
+
printReport(inspect(await new NodeIO().readProject(fairyPath)));
|
|
25250
|
+
});
|
|
25251
|
+
}
|
|
25252
|
+
function printReport(report) {
|
|
25253
|
+
console.log(`ID: ${report.projectId}`);
|
|
25254
|
+
console.log(`Type: ${report.projectType}, Version: ${report.version}`);
|
|
25255
|
+
console.log(`\nPackages: ${report.totals.packages}`);
|
|
25256
|
+
console.log(` Images: ${report.totals.images}`);
|
|
25257
|
+
console.log(` Sounds: ${report.totals.sounds}`);
|
|
25258
|
+
console.log(` Fonts: ${report.totals.fonts}`);
|
|
25259
|
+
console.log(` MovieClips: ${report.totals.movieClips}`);
|
|
25260
|
+
console.log(` Components: ${report.totals.components}`);
|
|
25261
|
+
console.log(` DisplayObjs: ${report.totals.displayObjects}`);
|
|
25262
|
+
console.log(` Gears: ${report.totals.gears}`);
|
|
25263
|
+
console.log(` Controllers: ${report.totals.controllers}`);
|
|
25264
|
+
console.log(` Transitions: ${report.totals.transitions}`);
|
|
25265
|
+
console.log("\nPackage details:");
|
|
25266
|
+
for (const pkg of report.packages) {
|
|
25267
|
+
const res = pkg.resources;
|
|
25268
|
+
console.log(` ${pkg.name} (${pkg.id}): ${res.images.count} img, ${res.sounds.count} snd, ${res.fonts.count} font, ${res.components.count} comp`);
|
|
24729
25269
|
}
|
|
24730
|
-
|
|
24731
|
-
|
|
24732
|
-
|
|
25270
|
+
}
|
|
25271
|
+
//#endregion
|
|
25272
|
+
//#region ../functions/src/adapters/node/plugins.ts
|
|
25273
|
+
const importNative$1 = new Function("id", "return import(id)");
|
|
25274
|
+
async function loadPlugins(doc, pluginsDir) {
|
|
25275
|
+
if (!pluginsDir) return [];
|
|
25276
|
+
const fs = await importNative$1("node:fs/promises");
|
|
25277
|
+
const path = await importNative$1("node:path");
|
|
25278
|
+
let entries;
|
|
25279
|
+
try {
|
|
25280
|
+
entries = await fs.readdir(pluginsDir, { withFileTypes: true });
|
|
25281
|
+
} catch {
|
|
25282
|
+
return [];
|
|
24733
25283
|
}
|
|
24734
|
-
const
|
|
24735
|
-
const
|
|
24736
|
-
|
|
24737
|
-
|
|
24738
|
-
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
await
|
|
24742
|
-
|
|
24743
|
-
|
|
24744
|
-
|
|
24745
|
-
|
|
24746
|
-
|
|
24747
|
-
|
|
24748
|
-
|
|
24749
|
-
|
|
24750
|
-
|
|
24751
|
-
|
|
24752
|
-
|
|
25284
|
+
const plugins = [];
|
|
25285
|
+
for (const entry of entries) {
|
|
25286
|
+
if (!entry.isDirectory()) continue;
|
|
25287
|
+
const pluginDir = path.join(pluginsDir, entry.name);
|
|
25288
|
+
try {
|
|
25289
|
+
const manifest = await readPluginManifest(fs, path, pluginDir);
|
|
25290
|
+
if (!manifest) continue;
|
|
25291
|
+
const plugin = await loadPlugin(resolvePluginMain(path, pluginDir, manifest));
|
|
25292
|
+
plugins.push({
|
|
25293
|
+
name: manifest.name,
|
|
25294
|
+
plugin
|
|
25295
|
+
});
|
|
25296
|
+
} catch (error) {
|
|
25297
|
+
doc.getLogger().warn(`publish: Plugin "${entry.name}" was skipped: ${formatPluginError(error)}`);
|
|
25298
|
+
}
|
|
25299
|
+
}
|
|
25300
|
+
return plugins;
|
|
25301
|
+
}
|
|
25302
|
+
async function readPluginManifest(fs, path, pluginDir) {
|
|
25303
|
+
const manifestPath = path.join(pluginDir, "package.json");
|
|
25304
|
+
const content = await fs.readFile(manifestPath, "utf-8");
|
|
25305
|
+
const manifest = JSON.parse(content);
|
|
25306
|
+
if (!manifest.name) throw new Error(`Codegen plugin at ${pluginDir} is missing package.json name.`);
|
|
25307
|
+
if (!manifest.main) throw new Error(`Codegen plugin "${manifest.name}" is missing package.json main.`);
|
|
25308
|
+
return manifest;
|
|
25309
|
+
}
|
|
25310
|
+
function resolvePluginMain(path, pluginDir, manifest) {
|
|
25311
|
+
const mainPath = path.resolve(pluginDir, manifest.main);
|
|
25312
|
+
const relative = path.relative(pluginDir, mainPath);
|
|
25313
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Codegen plugin "${manifest.name}" main must resolve inside its plugin directory.`);
|
|
25314
|
+
return mainPath;
|
|
25315
|
+
}
|
|
25316
|
+
async function loadPlugin(mainPath) {
|
|
25317
|
+
const { createJiti } = await importNative$1("jiti");
|
|
25318
|
+
const mod = await createJiti(import.meta.url).import(mainPath);
|
|
25319
|
+
const defaultExport = mod.default;
|
|
25320
|
+
return isObject(defaultExport) ? defaultExport : mod;
|
|
25321
|
+
}
|
|
25322
|
+
function isObject(value) {
|
|
25323
|
+
return value !== null && typeof value === "object";
|
|
25324
|
+
}
|
|
25325
|
+
//#endregion
|
|
25326
|
+
//#region ../functions/src/adapters/node/publish.ts
|
|
25327
|
+
const importNative = new Function("id", "return import(id)");
|
|
25328
|
+
async function createNodePublishFileSystem() {
|
|
25329
|
+
const [fs, path] = await Promise.all([importNative("node:fs/promises"), importNative("node:path")]);
|
|
25330
|
+
return {
|
|
25331
|
+
async readFileRaw(filePath) {
|
|
25332
|
+
const data = await fs.readFile(filePath);
|
|
25333
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
25334
|
+
},
|
|
25335
|
+
async writeFileRaw(filePath, data) {
|
|
25336
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
25337
|
+
await fs.writeFile(filePath, data);
|
|
25338
|
+
},
|
|
25339
|
+
async mkdir(dirPath) {
|
|
25340
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
25341
|
+
},
|
|
25342
|
+
async readdir(dirPath) {
|
|
25343
|
+
return fs.readdir(dirPath);
|
|
25344
|
+
},
|
|
25345
|
+
async deleteFile(filePath) {
|
|
25346
|
+
await fs.rm(filePath, { force: true });
|
|
25347
|
+
},
|
|
25348
|
+
join(...paths) {
|
|
25349
|
+
return path.join(...paths);
|
|
25350
|
+
}
|
|
25351
|
+
};
|
|
25352
|
+
}
|
|
25353
|
+
async function resolveNodeAssetsPath(document, assetsPath) {
|
|
25354
|
+
if (assetsPath) return assetsPath;
|
|
25355
|
+
const projectDir = document.getProjectDir?.() ?? "";
|
|
25356
|
+
if (!projectDir) return void 0;
|
|
25357
|
+
return (await importNative("node:path")).join(projectDir, "assets");
|
|
25358
|
+
}
|
|
25359
|
+
async function loadSharpBackend() {
|
|
25360
|
+
try {
|
|
25361
|
+
const sharp = await importNative("sharp");
|
|
25362
|
+
return sharp.default ?? sharp;
|
|
25363
|
+
} catch {
|
|
25364
|
+
return;
|
|
24753
25365
|
}
|
|
24754
25366
|
}
|
|
25367
|
+
async function loadNodePublishPlugins(document, assetsPath) {
|
|
25368
|
+
const projectDir = document.getProjectDir?.() || (assetsPath ? resolveProjectBasePath(assetsPath) : "");
|
|
25369
|
+
if (!projectDir) return [];
|
|
25370
|
+
return loadPlugins(document, (await importNative("node:path")).join(projectDir, "plugins"));
|
|
25371
|
+
}
|
|
25372
|
+
/**
|
|
25373
|
+
* Publish a FairyGUI project through the standard Node host adapter.
|
|
25374
|
+
*
|
|
25375
|
+
* The adapter owns Node filesystem, Sharp, and project plugin discovery.
|
|
25376
|
+
* For custom environments, use the lower-level `publish()` core with explicit
|
|
25377
|
+
* capabilities instead.
|
|
25378
|
+
*/
|
|
25379
|
+
async function publishNode(options) {
|
|
25380
|
+
const { document, assetsPath: configuredAssetsPath, atlas, encoder: configuredEncoder, plugins: configuredPlugins, ...publishOptions } = options;
|
|
25381
|
+
const [fileSystem, assetsPath] = await Promise.all([createNodePublishFileSystem(), resolveNodeAssetsPath(document, configuredAssetsPath)]);
|
|
25382
|
+
const [encoder, plugins] = await Promise.all([configuredEncoder === void 0 ? loadSharpBackend() : Promise.resolve(configuredEncoder), configuredPlugins === void 0 ? loadNodePublishPlugins(document, assetsPath) : Promise.resolve(configuredPlugins)]);
|
|
25383
|
+
if (!encoder) document.getLogger().warn("publish: Sharp is unavailable; atlas layout will be generated without PNG output.");
|
|
25384
|
+
await document.transform(publish({
|
|
25385
|
+
...publishOptions,
|
|
25386
|
+
basePath: assetsPath,
|
|
25387
|
+
encoder,
|
|
25388
|
+
atlas: {
|
|
25389
|
+
...atlas,
|
|
25390
|
+
readFileRaw: fileSystem.readFileRaw
|
|
25391
|
+
},
|
|
25392
|
+
fs: fileSystem,
|
|
25393
|
+
plugins
|
|
25394
|
+
}));
|
|
25395
|
+
}
|
|
25396
|
+
//#endregion
|
|
25397
|
+
//#region src/utils/project-type.ts
|
|
25398
|
+
function parseProjectType(value) {
|
|
25399
|
+
if (!value) return void 0;
|
|
25400
|
+
const trimmed = value.trim();
|
|
25401
|
+
if (trimmed === "") return void 0;
|
|
25402
|
+
if (/^\d+$/u.test(trimmed)) return Number(trimmed);
|
|
25403
|
+
const normalized = trimmed.toLowerCase();
|
|
25404
|
+
const map = {
|
|
25405
|
+
unity: ProjectType.Unity,
|
|
25406
|
+
flash: ProjectType.Flash,
|
|
25407
|
+
starling: ProjectType.Starling,
|
|
25408
|
+
cocoscreator: ProjectType.CocosCreator,
|
|
25409
|
+
cocos: ProjectType.CocosCreator,
|
|
25410
|
+
layabox: ProjectType.LayaBox,
|
|
25411
|
+
laya: ProjectType.LayaBox,
|
|
25412
|
+
egret: ProjectType.Egret,
|
|
25413
|
+
haxe: ProjectType.Haxe,
|
|
25414
|
+
pixi: ProjectType.Pixi,
|
|
25415
|
+
libgdx: ProjectType.LibGDX,
|
|
25416
|
+
unreal: ProjectType.Unreal,
|
|
25417
|
+
cryengine: ProjectType.CryEngine,
|
|
25418
|
+
monogame: ProjectType.MonoGame,
|
|
25419
|
+
vision: ProjectType.Vision
|
|
25420
|
+
};
|
|
25421
|
+
const resolved = map[normalized];
|
|
25422
|
+
if (resolved === void 0) throw new Error(`Unknown project type: ${value}. Use a numeric id or one of: ${Object.keys(map).join(", ")}`);
|
|
25423
|
+
return resolved;
|
|
25424
|
+
}
|
|
25425
|
+
//#endregion
|
|
25426
|
+
//#region src/commands/publish.ts
|
|
25427
|
+
function registerPublishCommand(program) {
|
|
25428
|
+
program.command("publish").description("Publish project to binary outputs and configured generated code").argument("<project-dir>", "Project root directory or .fairy file").option("-o, --output <dir>", "Override project or package publish output directory").option("-c, --compressed", "Compress binary data (overrides project setting)").option("-p, --packages <a,b,c>", "Only publish specific packages (comma-separated)").option("-b, --branch <name>", "Active branch used by \"主干合并活跃分支\"; omit for main branch").option("-t, --project-type <name|id>", "Override project type (for example: unity, layabox, cocoscreator, 0, 4, 3)").action(async (projectDir, options) => {
|
|
25429
|
+
const fairyPath = await resolveFairyPath(projectDir);
|
|
25430
|
+
const projectRootDir = path.dirname(fairyPath);
|
|
25431
|
+
const outputDir = options.output ? path.resolve(options.output) : void 0;
|
|
25432
|
+
console.log(`Reading project: ${fairyPath}`);
|
|
25433
|
+
const doc = await new NodeIO().readProject(fairyPath);
|
|
25434
|
+
const projectType = parseProjectType(options.projectType);
|
|
25435
|
+
if (projectType !== void 0) doc.getRoot().setProjectType(projectType);
|
|
25436
|
+
const pkgFilter = options.packages?.split(",").map((value) => value.trim());
|
|
25437
|
+
const resolved = resolvePublishOptions(doc, {
|
|
25438
|
+
compressed: options.compressed,
|
|
25439
|
+
packages: pkgFilter
|
|
25440
|
+
});
|
|
25441
|
+
console.log(`Settings: ext=${resolved.fileExtension}, compressed=${resolved.compressed}`);
|
|
25442
|
+
if (options.branch) console.log(`Active branch: ${options.branch}`);
|
|
25443
|
+
await publishNode({
|
|
25444
|
+
document: doc,
|
|
25445
|
+
output: outputDir,
|
|
25446
|
+
compressed: resolved.compressed,
|
|
25447
|
+
fileExtension: resolved.fileExtension,
|
|
25448
|
+
packages: resolved.packages,
|
|
25449
|
+
assetsPath: path.join(projectRootDir, "assets"),
|
|
25450
|
+
atlas: resolved.atlas,
|
|
25451
|
+
branch: options.branch
|
|
25452
|
+
});
|
|
25453
|
+
console.log(`\nDone!${outputDir ? ` Output override: ${outputDir}` : ""}`);
|
|
25454
|
+
});
|
|
25455
|
+
}
|
|
25456
|
+
//#endregion
|
|
25457
|
+
//#region src/commands/restore.ts
|
|
25458
|
+
function registerRestoreCommand(program) {
|
|
25459
|
+
program.command("restore").description("Restore a FairyGUI project from published binaries").argument("<release-dir>", "Published release directory").requiredOption("-o, --output <dir>", "Output project directory").option("-p, --packages <a,b,c>", "Only restore specific packages (comma-separated)").option("-f, --force", "Overwrite a non-empty output directory").option("-t, --project-type <name|id>", "Override restored project type; default is unity").action(async (releaseDir, options) => {
|
|
25460
|
+
const inputDir = path.resolve(releaseDir);
|
|
25461
|
+
const outputDir = path.resolve(options.output);
|
|
25462
|
+
const pkgFilter = options.packages ? options.packages.split(",").map((value) => value.trim()).filter(Boolean) : void 0;
|
|
25463
|
+
const projectType = parseProjectType(options.projectType);
|
|
25464
|
+
const { cropImage, extractImage } = await createRestoreImageProcessors();
|
|
25465
|
+
console.log(`Restoring published FairyGUI project: ${inputDir}`);
|
|
25466
|
+
const result = await restore({
|
|
25467
|
+
inputDir,
|
|
25468
|
+
output: outputDir,
|
|
25469
|
+
fs: createNodeRestoreFs(),
|
|
25470
|
+
packages: pkgFilter,
|
|
25471
|
+
force: options.force,
|
|
25472
|
+
projectType,
|
|
25473
|
+
cropImage,
|
|
25474
|
+
extractImage
|
|
25475
|
+
});
|
|
25476
|
+
const packages = result.document.getRoot().listPackages();
|
|
25477
|
+
console.log(`\nDone! Output: ${result.projectPath}`);
|
|
25478
|
+
console.log(`Packages: ${packages.map((pkg) => pkg.getName()).join(", ")}`);
|
|
25479
|
+
for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
|
|
25480
|
+
});
|
|
25481
|
+
}
|
|
24755
25482
|
function createNodeRestoreFs() {
|
|
24756
25483
|
return {
|
|
24757
25484
|
async readFile(filePath) {
|
|
@@ -24860,214 +25587,47 @@ async function createRestoreImageProcessors() {
|
|
|
24860
25587
|
}
|
|
24861
25588
|
};
|
|
24862
25589
|
}
|
|
24863
|
-
|
|
24864
|
-
|
|
24865
|
-
|
|
24866
|
-
|
|
24867
|
-
|
|
24868
|
-
|
|
24869
|
-
console.log(`Project: ${fairyPath}\n`);
|
|
24870
|
-
printReport(inspect(await new NodeIO().readProject(fairyPath)));
|
|
25590
|
+
//#endregion
|
|
25591
|
+
//#region src/utils/package-version.ts
|
|
25592
|
+
const require = createRequire(import.meta.url);
|
|
25593
|
+
function getInjectedPackageVersion() {
|
|
25594
|
+
const version = import.meta.env?.PACKAGE_VERSION;
|
|
25595
|
+
return typeof version === "string" && version.length > 0 ? version : null;
|
|
24871
25596
|
}
|
|
24872
|
-
function
|
|
24873
|
-
|
|
24874
|
-
|
|
24875
|
-
|
|
24876
|
-
|
|
24877
|
-
|
|
24878
|
-
|
|
24879
|
-
|
|
24880
|
-
console.log(` Components: ${report.totals.components}`);
|
|
24881
|
-
console.log(` DisplayObjs: ${report.totals.displayObjects}`);
|
|
24882
|
-
console.log(` Gears: ${report.totals.gears}`);
|
|
24883
|
-
console.log(` Controllers: ${report.totals.controllers}`);
|
|
24884
|
-
console.log(` Transitions: ${report.totals.transitions}`);
|
|
24885
|
-
console.log("\nPackage details:");
|
|
24886
|
-
for (const pkg of report.packages) {
|
|
24887
|
-
const res = pkg.resources;
|
|
24888
|
-
console.log(` ${pkg.name} (${pkg.id}): ${res.images.count} img, ${res.sounds.count} snd, ${res.fonts.count} font, ${res.components.count} comp`);
|
|
24889
|
-
}
|
|
25597
|
+
function readPackageVersion() {
|
|
25598
|
+
const injectedVersion = getInjectedPackageVersion();
|
|
25599
|
+
if (injectedVersion) return injectedVersion;
|
|
25600
|
+
try {
|
|
25601
|
+
const pkg = require("../../package.json");
|
|
25602
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|
|
25603
|
+
} catch {}
|
|
25604
|
+
return "0.0.0-dev";
|
|
24890
25605
|
}
|
|
24891
|
-
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
|
|
24898
|
-
|
|
24899
|
-
|
|
24900
|
-
|
|
24901
|
-
|
|
24902
|
-
|
|
24903
|
-
|
|
24904
|
-
|
|
24905
|
-
|
|
24906
|
-
|
|
24907
|
-
|
|
24908
|
-
|
|
24909
|
-
|
|
24910
|
-
cryengine: ProjectType.CryEngine,
|
|
24911
|
-
monogame: ProjectType.MonoGame,
|
|
24912
|
-
vision: ProjectType.Vision
|
|
24913
|
-
};
|
|
24914
|
-
const resolved = map[normalized];
|
|
24915
|
-
if (resolved === void 0) throw new Error(`Unknown project type: ${value}. Use a numeric id or one of: ${Object.keys(map).join(", ")}`);
|
|
24916
|
-
return resolved;
|
|
25606
|
+
//#endregion
|
|
25607
|
+
//#region src/cli.ts
|
|
25608
|
+
const PACKAGE_VERSION = readPackageVersion();
|
|
25609
|
+
function createProgram() {
|
|
25610
|
+
const program = new Command("ofgui");
|
|
25611
|
+
program.description("FairyGUI Headless Authoring CLI").version(PACKAGE_VERSION).showHelpAfterError();
|
|
25612
|
+
registerInspectCommand(program);
|
|
25613
|
+
registerPublishCommand(program);
|
|
25614
|
+
registerRestoreCommand(program);
|
|
25615
|
+
registerBackendCapabilitiesCommand(program);
|
|
25616
|
+
program.addHelpText("after", [
|
|
25617
|
+
"",
|
|
25618
|
+
"Alias:",
|
|
25619
|
+
" openfairygui",
|
|
25620
|
+
"",
|
|
25621
|
+
"Input can be a .fairy file or a project root directory (auto-discovers .fairy file).",
|
|
25622
|
+
"File extension and binary format are read from project settings."
|
|
25623
|
+
].join("\n"));
|
|
25624
|
+
return program;
|
|
24917
25625
|
}
|
|
24918
|
-
async function
|
|
24919
|
-
|
|
24920
|
-
args,
|
|
24921
|
-
options: {
|
|
24922
|
-
output: {
|
|
24923
|
-
type: "string",
|
|
24924
|
-
short: "o"
|
|
24925
|
-
},
|
|
24926
|
-
packages: { type: "string" },
|
|
24927
|
-
force: { type: "boolean" },
|
|
24928
|
-
"project-type": { type: "string" }
|
|
24929
|
-
},
|
|
24930
|
-
allowPositionals: true
|
|
24931
|
-
});
|
|
24932
|
-
if (positionals.length === 0 || !values.output) {
|
|
24933
|
-
console.error("Usage: ofgui restore <release-dir> --output <dir> [--packages a,b,c] [--force]");
|
|
24934
|
-
process.exit(1);
|
|
24935
|
-
}
|
|
24936
|
-
const releaseDir = path.resolve(positionals[0]);
|
|
24937
|
-
const outputDir = path.resolve(values.output);
|
|
24938
|
-
const pkgFilter = values.packages ? values.packages.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
24939
|
-
const projectType = parseProjectType(values["project-type"]);
|
|
24940
|
-
const { cropImage, extractImage } = await createRestoreImageProcessors();
|
|
24941
|
-
console.log(`Restoring published FairyGUI project: ${releaseDir}`);
|
|
24942
|
-
const result = await restore({
|
|
24943
|
-
inputDir: releaseDir,
|
|
24944
|
-
output: outputDir,
|
|
24945
|
-
fs: createNodeRestoreFs(),
|
|
24946
|
-
packages: pkgFilter,
|
|
24947
|
-
force: values.force,
|
|
24948
|
-
projectType,
|
|
24949
|
-
cropImage,
|
|
24950
|
-
extractImage
|
|
24951
|
-
});
|
|
24952
|
-
const packages = result.document.getRoot().listPackages();
|
|
24953
|
-
console.log(`\nDone! Output: ${result.projectPath}`);
|
|
24954
|
-
console.log(`Packages: ${packages.map((pkg) => pkg.getName()).join(", ")}`);
|
|
24955
|
-
for (const warning of result.warnings) console.warn(`Warning: ${warning}`);
|
|
24956
|
-
}
|
|
24957
|
-
async function cmdPublish(args) {
|
|
24958
|
-
const { values, positionals } = parseArgs({
|
|
24959
|
-
args,
|
|
24960
|
-
options: {
|
|
24961
|
-
output: {
|
|
24962
|
-
type: "string",
|
|
24963
|
-
short: "o"
|
|
24964
|
-
},
|
|
24965
|
-
compressed: { type: "boolean" },
|
|
24966
|
-
packages: { type: "string" },
|
|
24967
|
-
branch: { type: "string" },
|
|
24968
|
-
"project-type": { type: "string" }
|
|
24969
|
-
},
|
|
24970
|
-
allowPositionals: true
|
|
24971
|
-
});
|
|
24972
|
-
if (positionals.length === 0 || !values.output) {
|
|
24973
|
-
console.error("Usage: ofgui publish <project-dir> --output <dir> [--compressed] [--packages a,b,c] [--branch name]");
|
|
24974
|
-
process.exit(1);
|
|
24975
|
-
}
|
|
24976
|
-
const fairyPath = await resolveFairyPath(positionals[0]);
|
|
24977
|
-
const projectDir = path.dirname(fairyPath);
|
|
24978
|
-
const outputDir = path.resolve(values.output);
|
|
24979
|
-
console.log(`Reading project: ${fairyPath}`);
|
|
24980
|
-
const doc = await new NodeIO().readProject(fairyPath);
|
|
24981
|
-
const projectType = parseProjectType(values["project-type"]);
|
|
24982
|
-
if (projectType !== void 0) doc.getRoot().setProjectType(projectType);
|
|
24983
|
-
const pkgFilter = values.packages ? values.packages.split(",").map((s) => s.trim()) : void 0;
|
|
24984
|
-
const resolved = resolvePublishOptions(doc, {
|
|
24985
|
-
compressed: values.compressed,
|
|
24986
|
-
packages: pkgFilter
|
|
24987
|
-
});
|
|
24988
|
-
console.log(`Settings: ext=${resolved.fileExtension}, compressed=${resolved.compressed}`);
|
|
24989
|
-
if (values.branch) console.log(`Active branch: ${values.branch}`);
|
|
24990
|
-
const atlasConfig = {
|
|
24991
|
-
...resolved.atlas,
|
|
24992
|
-
readFileRaw: async (filePath) => {
|
|
24993
|
-
const buf = await fs.readFile(filePath);
|
|
24994
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
24995
|
-
}
|
|
24996
|
-
};
|
|
24997
|
-
let encoder;
|
|
24998
|
-
try {
|
|
24999
|
-
const sharp = await import("sharp");
|
|
25000
|
-
encoder = sharp.default ?? sharp;
|
|
25001
|
-
console.log("Sharp loaded — atlas PNGs will be generated.");
|
|
25002
|
-
} catch {
|
|
25003
|
-
console.log("Sharp not available — atlas PNGs will NOT be generated (layout only).");
|
|
25004
|
-
console.log(" Install sharp to enable: pnpm add sharp");
|
|
25005
|
-
}
|
|
25006
|
-
await doc.transform(publish({
|
|
25007
|
-
output: outputDir,
|
|
25008
|
-
compressed: resolved.compressed,
|
|
25009
|
-
fileExtension: resolved.fileExtension,
|
|
25010
|
-
packages: resolved.packages,
|
|
25011
|
-
fs: {
|
|
25012
|
-
async readFileRaw(filePath) {
|
|
25013
|
-
const buf = await fs.readFile(filePath);
|
|
25014
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
25015
|
-
},
|
|
25016
|
-
async writeFileRaw(filePath, data) {
|
|
25017
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
25018
|
-
await fs.writeFile(filePath, data);
|
|
25019
|
-
},
|
|
25020
|
-
async mkdir(dirPath) {
|
|
25021
|
-
await fs.mkdir(dirPath, { recursive: true });
|
|
25022
|
-
},
|
|
25023
|
-
async readdir(dirPath) {
|
|
25024
|
-
return fs.readdir(dirPath);
|
|
25025
|
-
},
|
|
25026
|
-
async deleteFile(filePath) {
|
|
25027
|
-
await fs.rm(filePath, { force: true });
|
|
25028
|
-
},
|
|
25029
|
-
join(...paths) {
|
|
25030
|
-
return path.join(...paths);
|
|
25031
|
-
}
|
|
25032
|
-
},
|
|
25033
|
-
encoder,
|
|
25034
|
-
basePath: path.join(projectDir, "assets"),
|
|
25035
|
-
atlas: atlasConfig,
|
|
25036
|
-
branch: values.branch
|
|
25037
|
-
}));
|
|
25038
|
-
console.log(`\nDone! Output: ${outputDir}`);
|
|
25039
|
-
}
|
|
25040
|
-
async function cmdBackendCapabilities(args) {
|
|
25041
|
-
if (args.length === 0) {
|
|
25042
|
-
console.error("Usage: ofgui backend-capabilities <project-dir>");
|
|
25043
|
-
process.exit(1);
|
|
25044
|
-
}
|
|
25045
|
-
const runtime = createNodeBackendRuntime();
|
|
25046
|
-
const opened = await runtime.openSession({ projectPath: path.resolve(args[0]) });
|
|
25047
|
-
if (!opened.ok) {
|
|
25048
|
-
console.error(`backend-capabilities: ${opened.error.message}`);
|
|
25049
|
-
process.exit(1);
|
|
25050
|
-
}
|
|
25051
|
-
const capabilities = runtime.getCapabilities();
|
|
25052
|
-
if (!capabilities.ok) {
|
|
25053
|
-
console.error("backend-capabilities: failed to read capabilities");
|
|
25054
|
-
await runtime.closeSession({ sessionId: opened.data.sessionId });
|
|
25055
|
-
process.exit(1);
|
|
25056
|
-
}
|
|
25057
|
-
console.log(`Session: ${opened.data.sessionId}`);
|
|
25058
|
-
console.log(`Project: ${opened.data.canonicalProjectPath}`);
|
|
25059
|
-
console.log(`Revision: ${opened.data.revision}`);
|
|
25060
|
-
console.log(`Runtime owner: ${capabilities.data.runtimeOwner}`);
|
|
25061
|
-
console.log(`Transaction owner: ${capabilities.data.transactionKernelOwner}`);
|
|
25062
|
-
console.log(`App seam owner: ${capabilities.data.appSeamOwner}`);
|
|
25063
|
-
const closed = await runtime.closeSession({ sessionId: opened.data.sessionId });
|
|
25064
|
-
if (!closed.ok) {
|
|
25065
|
-
console.error(`backend-capabilities: ${closed.error.message}`);
|
|
25066
|
-
process.exit(1);
|
|
25067
|
-
}
|
|
25626
|
+
async function main() {
|
|
25627
|
+
await createProgram().parseAsync(process.argv);
|
|
25068
25628
|
}
|
|
25069
25629
|
main().catch((err) => {
|
|
25070
|
-
console.error(err);
|
|
25630
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
25071
25631
|
process.exit(1);
|
|
25072
25632
|
});
|
|
25073
25633
|
//#endregion
|