@openfairygui/functions 0.2.0-alpha.1 → 0.2.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.cjs +872 -282
- package/dist/index.d.cts +143 -79
- package/dist/index.d.ts +143 -79
- package/dist/index.js +869 -283
- package/dist/uam-transaction.cjs +79 -0
- package/dist/uam-transaction.d.cts +42 -0
- package/dist/uam-transaction.d.ts +42 -0
- package/dist/uam-transaction.js +78 -0
- package/package.json +66 -53
- package/src/atlas.ts +502 -146
- package/src/codegen.ts +104 -66
- package/src/index.ts +25 -1
- package/src/plugins/loader.ts +85 -0
- package/src/plugins/types.ts +47 -0
- package/src/publish.ts +499 -105
- package/src/restore.ts +12 -5
- package/src/shared-types.ts +1 -0
- package/src/uam-transaction.ts +69 -1
- package/src/utils.ts +28 -0
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_uam_transaction = require("./uam-transaction.cjs");
|
|
2
3
|
let _openfairygui_core = require("@openfairygui/core");
|
|
4
|
+
let jiti = require("jiti");
|
|
3
5
|
//#region src/inspect.ts
|
|
4
6
|
function mapResource(resource) {
|
|
5
7
|
return {
|
|
@@ -110,6 +112,40 @@ function createTransform(name, fn) {
|
|
|
110
112
|
Object.defineProperty(fn, "name", { value: name });
|
|
111
113
|
return fn;
|
|
112
114
|
}
|
|
115
|
+
function parseTextureSetMode(value) {
|
|
116
|
+
const raw = value?.trim() ?? "";
|
|
117
|
+
if (!raw) return {
|
|
118
|
+
kind: "auto",
|
|
119
|
+
raw: ""
|
|
120
|
+
};
|
|
121
|
+
if (raw === "alone") return {
|
|
122
|
+
kind: "standalone",
|
|
123
|
+
raw,
|
|
124
|
+
sizeMode: "default"
|
|
125
|
+
};
|
|
126
|
+
if (raw === "alone_npot") return {
|
|
127
|
+
kind: "standalone",
|
|
128
|
+
raw,
|
|
129
|
+
sizeMode: "npot"
|
|
130
|
+
};
|
|
131
|
+
if (raw === "alone_mof") return {
|
|
132
|
+
kind: "standalone",
|
|
133
|
+
raw,
|
|
134
|
+
sizeMode: "multipleOf4"
|
|
135
|
+
};
|
|
136
|
+
if (/^\d+$/.test(raw)) {
|
|
137
|
+
const pageIndex = Number(raw);
|
|
138
|
+
if (pageIndex >= 0 && pageIndex <= 10) return {
|
|
139
|
+
kind: "page",
|
|
140
|
+
raw,
|
|
141
|
+
pageIndex
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
kind: "auto",
|
|
146
|
+
raw
|
|
147
|
+
};
|
|
148
|
+
}
|
|
113
149
|
//#endregion
|
|
114
150
|
//#region src/validate.ts
|
|
115
151
|
/**
|
|
@@ -1041,6 +1077,19 @@ const ATLAS_DEFAULTS = {
|
|
|
1041
1077
|
function getPublishedItemId(resource) {
|
|
1042
1078
|
return (resource.getExtras() ?? {})._publishedId ?? resource.getId();
|
|
1043
1079
|
}
|
|
1080
|
+
function getSelectedSkeletonDependencyImageIds(resources) {
|
|
1081
|
+
const imageIds = /* @__PURE__ */ new Set();
|
|
1082
|
+
const resourcesById = new Map(resources.map((resource) => [resource.getId(), resource]));
|
|
1083
|
+
for (const resource of resources) {
|
|
1084
|
+
if (!isSkeletonResource$1(resource)) continue;
|
|
1085
|
+
for (const requiredId of resource.getRequireIds()) {
|
|
1086
|
+
if (!requiredId) continue;
|
|
1087
|
+
const required = resourcesById.get(requiredId);
|
|
1088
|
+
if (required && isImageResource$1(required)) imageIds.add(requiredId);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return imageIds;
|
|
1092
|
+
}
|
|
1044
1093
|
function resolveFontFileName(fontName) {
|
|
1045
1094
|
return /\.fnt$/i.test(fontName) ? fontName : `${fontName}.fnt`;
|
|
1046
1095
|
}
|
|
@@ -1177,12 +1226,18 @@ function atlas(_options = {}) {
|
|
|
1177
1226
|
const logger = doc.getLogger();
|
|
1178
1227
|
const encoder = options.encoder;
|
|
1179
1228
|
const doTrim = options.trimImage && !!encoder && !!options.basePath;
|
|
1229
|
+
const packageFilter = options.packages ? new Set(options.packages) : null;
|
|
1180
1230
|
for (const pkg of root.listPackages()) {
|
|
1231
|
+
if (packageFilter && !packageFilter.has(pkg.getName())) continue;
|
|
1181
1232
|
const selectedPublishIds = new Set((pkg.getExtras() ?? {}).publishedResourceIds ?? []);
|
|
1182
1233
|
const allResources = selectedPublishIds.size > 0 ? pkg.listResources().filter((resource) => selectedPublishIds.has(resource.getId())) : pkg.listResources();
|
|
1234
|
+
const skeletonDependencyImageIds = getSelectedSkeletonDependencyImageIds(allResources);
|
|
1183
1235
|
const orderedResources = await resolveEditorCompatibleResourceOrder(pkg, allResources, options);
|
|
1184
1236
|
const orderedAllResources = sortResourcesByOrder(allResources, new Map(orderedResources.map((resource, index) => [resource.getId(), index])), new Map(allResources.map((resource, index) => [resource.getId(), index])));
|
|
1185
|
-
if (!allResources.some((resource) =>
|
|
1237
|
+
if (!allResources.some((resource) => {
|
|
1238
|
+
if (isImageResource$1(resource) && skeletonDependencyImageIds.has(resource.getId())) return false;
|
|
1239
|
+
return isPackableResource(resource);
|
|
1240
|
+
})) continue;
|
|
1186
1241
|
const inputs = [];
|
|
1187
1242
|
const referencedIds = /* @__PURE__ */ new Set();
|
|
1188
1243
|
const resourceMap = /* @__PURE__ */ new Map();
|
|
@@ -1251,148 +1306,72 @@ function atlas(_options = {}) {
|
|
|
1251
1306
|
}
|
|
1252
1307
|
for (const res of orderedAllResources) if (isImageResource$1(res)) {
|
|
1253
1308
|
const resId = res.getId();
|
|
1254
|
-
if (
|
|
1309
|
+
if (skeletonDependencyImageIds.has(resId)) continue;
|
|
1310
|
+
if (selectedPublishIds.size === 0 && !res.getExported() && referencedIds.size > 0 && !referencedIds.has(resId)) continue;
|
|
1255
1311
|
await _collectImage(res, pkg, inputs, encoder, options, doTrim, logger);
|
|
1256
1312
|
} else if (isMovieClipResource$1(res)) {
|
|
1257
1313
|
const resId = res.getId();
|
|
1258
|
-
if (!res.getExported() && referencedIds.size > 0 && !referencedIds.has(resId)) continue;
|
|
1314
|
+
if (selectedPublishIds.size === 0 && !res.getExported() && referencedIds.size > 0 && !referencedIds.has(resId)) continue;
|
|
1259
1315
|
await _collectMovieClipFrames(doc, res, pkg, inputs, encoder, options, logger);
|
|
1260
1316
|
} else if (isFontResource$1(res)) {
|
|
1261
1317
|
const resId = res.getId();
|
|
1262
|
-
if (!res.getExported() && referencedIds.size > 0 && !referencedIds.has(resId)) continue;
|
|
1318
|
+
if (selectedPublishIds.size === 0 && !res.getExported() && referencedIds.size > 0 && !referencedIds.has(resId)) continue;
|
|
1263
1319
|
await _collectFontTexture(doc, res, pkg, options);
|
|
1264
1320
|
}
|
|
1265
1321
|
if (inputs.length === 0) continue;
|
|
1266
|
-
const branchGroups = buildBranchAtlasGroups(doc, inputs, options);
|
|
1267
1322
|
let totalPageCount = 0;
|
|
1268
1323
|
let usedDirectOutput = false;
|
|
1324
|
+
const { autoInputs, fixedPageGroups, standaloneGroups, reservedPageIndexes } = groupStandaloneInputs(doc, inputs, options);
|
|
1325
|
+
const branchGroups = buildBranchAtlasGroups(doc, autoInputs, options);
|
|
1326
|
+
const branchPageOffsets = /* @__PURE__ */ new Map();
|
|
1269
1327
|
for (const group of branchGroups) {
|
|
1270
|
-
const directOutput = resolveDirectImageOutput(group.inputs, options);
|
|
1328
|
+
const directOutput = fixedPageGroups.length === 0 && standaloneGroups.length === 0 ? resolveDirectImageOutput(group.inputs, options) : null;
|
|
1271
1329
|
if (directOutput) {
|
|
1272
1330
|
await emitDirectImageOutput(doc, pkg, directOutput, encoder, options, logger, group.branchName, group.branchOrdinal);
|
|
1273
1331
|
usedDirectOutput = true;
|
|
1274
1332
|
totalPageCount += 1;
|
|
1275
1333
|
continue;
|
|
1276
1334
|
}
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1335
|
+
const pageStart = reserveAutoPageStart(branchPageOffsets, group.branchOrdinal, reservedPageIndexes);
|
|
1336
|
+
const emittedPageCount = await emitPagedAtlasGroup(doc, pkg, allResources, group.inputs, {
|
|
1337
|
+
branchName: group.branchName,
|
|
1338
|
+
branchOrdinal: group.branchOrdinal,
|
|
1339
|
+
pageStart,
|
|
1340
|
+
fileNameAt: (pageIndex) => resolveAtlasOutputFileName(pkg, pageIndex, group.branchName),
|
|
1341
|
+
options,
|
|
1342
|
+
encoder,
|
|
1343
|
+
logger
|
|
1279
1344
|
});
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
const rotated = pr.rotated;
|
|
1311
|
-
const sprite = doc.createSprite();
|
|
1312
|
-
sprite.setItemId(input.id);
|
|
1313
|
-
sprite.setRectX(pr.x);
|
|
1314
|
-
sprite.setRectY(pr.y);
|
|
1315
|
-
sprite.setRectWidth(packedSize.width);
|
|
1316
|
-
sprite.setRectHeight(packedSize.height);
|
|
1317
|
-
sprite.setRotated(rotated);
|
|
1318
|
-
sprite.setOffsetX(input.offsetX);
|
|
1319
|
-
sprite.setOffsetY(input.offsetY);
|
|
1320
|
-
sprite.setOriginalWidth(input.originalWidth);
|
|
1321
|
-
sprite.setOriginalHeight(input.originalHeight);
|
|
1322
|
-
sprite.setAtlas(atlasNode);
|
|
1323
|
-
atlasNode.addSprite(sprite);
|
|
1324
|
-
}
|
|
1325
|
-
for (const res of allResources) {
|
|
1326
|
-
if (!isFontResource$1(res)) continue;
|
|
1327
|
-
const alias = res.getExtras()?._fontSpriteAlias;
|
|
1328
|
-
if (!alias) continue;
|
|
1329
|
-
const imgSprite = page.outputRects.find((result) => group.inputs[result.index]?.id === alias.textureId);
|
|
1330
|
-
if (!imgSprite) continue;
|
|
1331
|
-
const imgInput = group.inputs[imgSprite.index];
|
|
1332
|
-
const fontSprite = doc.createSprite();
|
|
1333
|
-
fontSprite.setItemId(alias.fontId);
|
|
1334
|
-
fontSprite.setRectX(imgSprite.x);
|
|
1335
|
-
fontSprite.setRectY(imgSprite.y);
|
|
1336
|
-
fontSprite.setRectWidth(imgSprite.width);
|
|
1337
|
-
fontSprite.setRectHeight(imgSprite.height);
|
|
1338
|
-
fontSprite.setRotated(imgSprite.rotated);
|
|
1339
|
-
if (imgInput) {
|
|
1340
|
-
fontSprite.setOffsetX(imgInput.offsetX);
|
|
1341
|
-
fontSprite.setOffsetY(imgInput.offsetY);
|
|
1342
|
-
fontSprite.setOriginalWidth(imgInput.originalWidth);
|
|
1343
|
-
fontSprite.setOriginalHeight(imgInput.originalHeight);
|
|
1344
|
-
}
|
|
1345
|
-
fontSprite.setAtlas(atlasNode);
|
|
1346
|
-
atlasNode.addSprite(fontSprite);
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
if (encoder && options.outputPath) {
|
|
1350
|
-
if (options.mkdir) await options.mkdir(options.outputPath);
|
|
1351
|
-
for (let p = 0; p < pages.length; p++) {
|
|
1352
|
-
const page = pages[p];
|
|
1353
|
-
const compositeInputs = [];
|
|
1354
|
-
for (const pr of page.outputRects) {
|
|
1355
|
-
const input = group.inputs[pr.index];
|
|
1356
|
-
if (!input) continue;
|
|
1357
|
-
if (pr.width <= 0 || pr.height <= 0 || input.width <= 0 || input.height <= 0) continue;
|
|
1358
|
-
try {
|
|
1359
|
-
let imgBuffer;
|
|
1360
|
-
if (input.trimBuffer) {
|
|
1361
|
-
imgBuffer = input.trimBuffer;
|
|
1362
|
-
if (imgBuffer.length === 0) continue;
|
|
1363
|
-
} else {
|
|
1364
|
-
if (!isImageResource$1(input.resource)) {
|
|
1365
|
-
logger.warn(`atlas: Non-image input "${input.id}" is missing inline buffer, skipping compositing.`);
|
|
1366
|
-
continue;
|
|
1367
|
-
}
|
|
1368
|
-
imgBuffer = await encoder(_resolveImagePath(input.resource, pkg, options.basePath)).toBuffer();
|
|
1369
|
-
}
|
|
1370
|
-
if (pr.rotated) imgBuffer = await encoder(imgBuffer).rotate(270).toBuffer();
|
|
1371
|
-
compositeInputs.push({
|
|
1372
|
-
input: imgBuffer,
|
|
1373
|
-
left: pr.x,
|
|
1374
|
-
top: pr.y
|
|
1375
|
-
});
|
|
1376
|
-
} catch {
|
|
1377
|
-
logger.warn(`atlas: Could not read image "${input.id}" for compositing.`);
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
const atlasFileName = resolveAtlasOutputFileName(pkg, p, group.branchName);
|
|
1381
|
-
const outputFile = `${options.outputPath}/${atlasFileName}`;
|
|
1382
|
-
await encoder({ create: {
|
|
1383
|
-
width: page.width,
|
|
1384
|
-
height: page.height,
|
|
1385
|
-
channels: 4,
|
|
1386
|
-
background: {
|
|
1387
|
-
r: 0,
|
|
1388
|
-
g: 0,
|
|
1389
|
-
b: 0,
|
|
1390
|
-
alpha: 0
|
|
1391
|
-
}
|
|
1392
|
-
} }).composite(compositeInputs).png().toFile(outputFile);
|
|
1393
|
-
logger.info(`atlas: Generated ${atlasFileName} (${page.width}x${page.height}, ${page.outputRects.length} sprites)`);
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1345
|
+
totalPageCount += emittedPageCount;
|
|
1346
|
+
branchPageOffsets.set(group.branchOrdinal, pageStart + emittedPageCount);
|
|
1347
|
+
}
|
|
1348
|
+
for (const group of fixedPageGroups) {
|
|
1349
|
+
const emittedPageCount = await emitPagedAtlasGroup(doc, pkg, allResources, group.inputs, {
|
|
1350
|
+
branchName: group.branchName,
|
|
1351
|
+
branchOrdinal: group.branchOrdinal,
|
|
1352
|
+
pageStart: group.pageIndex,
|
|
1353
|
+
forceSinglePage: true,
|
|
1354
|
+
fileNameAt: () => resolveAtlasOutputFileName(pkg, group.pageIndex, group.branchName),
|
|
1355
|
+
options,
|
|
1356
|
+
encoder,
|
|
1357
|
+
logger
|
|
1358
|
+
});
|
|
1359
|
+
totalPageCount += emittedPageCount;
|
|
1360
|
+
}
|
|
1361
|
+
const standalonePageOffsets = new Map(branchPageOffsets);
|
|
1362
|
+
for (const group of fixedPageGroups) {
|
|
1363
|
+
const nextPageIndex = group.pageIndex + 1;
|
|
1364
|
+
if (nextPageIndex > (standalonePageOffsets.get(group.branchOrdinal) ?? 0)) standalonePageOffsets.set(group.branchOrdinal, nextPageIndex);
|
|
1365
|
+
}
|
|
1366
|
+
for (const group of standaloneGroups) {
|
|
1367
|
+
const emittedPageCount = await emitStandaloneAtlasGroup(doc, pkg, group, {
|
|
1368
|
+
atlasIndexStart: standalonePageOffsets.get(group.branchOrdinal) ?? 0,
|
|
1369
|
+
options,
|
|
1370
|
+
encoder,
|
|
1371
|
+
logger
|
|
1372
|
+
});
|
|
1373
|
+
totalPageCount += emittedPageCount;
|
|
1374
|
+
standalonePageOffsets.set(group.branchOrdinal, (standalonePageOffsets.get(group.branchOrdinal) ?? 0) + emittedPageCount);
|
|
1396
1375
|
}
|
|
1397
1376
|
if (usedDirectOutput) logger.info(`atlas: Direct output for single image package "${pkg.getName()}".`);
|
|
1398
1377
|
logger.info(`atlas: Packed ${inputs.length} images into ${totalPageCount} atlas(es) for package "${pkg.getName()}".`);
|
|
@@ -1429,6 +1408,171 @@ function buildBranchAtlasGroups(doc, inputs, options) {
|
|
|
1429
1408
|
inputs: groups.get(branchName) ?? []
|
|
1430
1409
|
}));
|
|
1431
1410
|
}
|
|
1411
|
+
function reserveAutoPageStart(branchPageOffsets, branchOrdinal, reservedPageIndexes) {
|
|
1412
|
+
let pageIndex = branchPageOffsets.get(branchOrdinal) ?? 0;
|
|
1413
|
+
while (branchOrdinal === 0 && reservedPageIndexes.has(pageIndex)) pageIndex += 1;
|
|
1414
|
+
return pageIndex;
|
|
1415
|
+
}
|
|
1416
|
+
async function emitPagedAtlasGroup(doc, pkg, allResources, inputs, context) {
|
|
1417
|
+
if (inputs.length === 0) return 0;
|
|
1418
|
+
const pages = packAtlasPages(inputs, context.options, context.forceSinglePage === true);
|
|
1419
|
+
if (pages.length === 0) return 0;
|
|
1420
|
+
for (let pageOffset = 0; pageOffset < pages.length; pageOffset += 1) {
|
|
1421
|
+
const page = pages[pageOffset];
|
|
1422
|
+
const pageIndex = context.pageStart + pageOffset;
|
|
1423
|
+
const atlasNode = doc.createAtlas(`atlas${resolveAtlasIndex(context.branchOrdinal, pageIndex)}`);
|
|
1424
|
+
atlasNode.setIndex(resolveAtlasIndex(context.branchOrdinal, pageIndex));
|
|
1425
|
+
atlasNode.setFile(context.fileNameAt(pageIndex));
|
|
1426
|
+
atlasNode.setWidth(page.width);
|
|
1427
|
+
atlasNode.setHeight(page.height);
|
|
1428
|
+
pkg.addAtlas(atlasNode);
|
|
1429
|
+
attachSpritesToAtlas(doc, allResources, inputs, page.outputRects, atlasNode);
|
|
1430
|
+
await writeAtlasPageImage(pkg, inputs, page, atlasNode.getFile(), context.encoder, context.options, context.logger);
|
|
1431
|
+
}
|
|
1432
|
+
return pages.length;
|
|
1433
|
+
}
|
|
1434
|
+
async function emitStandaloneAtlasGroup(doc, pkg, group, context) {
|
|
1435
|
+
if (group.inputs.length === 0) return 0;
|
|
1436
|
+
const pages = packAtlasPages(group.inputs, context.options, true, group.sizeMode === "npot" ? {
|
|
1437
|
+
powerOfTwo: false,
|
|
1438
|
+
multipleOfFour: false,
|
|
1439
|
+
square: false
|
|
1440
|
+
} : group.sizeMode === "multipleOf4" ? {
|
|
1441
|
+
powerOfTwo: false,
|
|
1442
|
+
multipleOfFour: true,
|
|
1443
|
+
square: false
|
|
1444
|
+
} : void 0);
|
|
1445
|
+
if (pages.length === 0) return 0;
|
|
1446
|
+
for (let pageOffset = 0; pageOffset < pages.length; pageOffset += 1) {
|
|
1447
|
+
const page = pages[pageOffset];
|
|
1448
|
+
const baseFileName = resolveStandaloneAtlasOutputFileName(pkg, group.resource, group.branchName);
|
|
1449
|
+
const atlasFileName = pages.length <= 1 ? baseFileName : insertFileNameSuffix(baseFileName, `_${pageOffset}`);
|
|
1450
|
+
const atlasIndex = context.atlasIndexStart + pageOffset;
|
|
1451
|
+
const atlasNode = doc.createAtlas(`atlas${resolveAtlasIndex(group.branchOrdinal, atlasIndex)}`);
|
|
1452
|
+
atlasNode.setIndex(resolveAtlasIndex(group.branchOrdinal, atlasIndex));
|
|
1453
|
+
atlasNode.setFile(atlasFileName);
|
|
1454
|
+
const standaloneSize = resolveStandaloneAtlasSize(page.width, page.height, group.sizeMode, context.options);
|
|
1455
|
+
atlasNode.setWidth(standaloneSize.width);
|
|
1456
|
+
atlasNode.setHeight(standaloneSize.height);
|
|
1457
|
+
pkg.addAtlas(atlasNode);
|
|
1458
|
+
attachSpritesToAtlas(doc, [], group.inputs, page.outputRects, atlasNode);
|
|
1459
|
+
await writeAtlasPageImage(pkg, group.inputs, {
|
|
1460
|
+
...page,
|
|
1461
|
+
width: standaloneSize.width,
|
|
1462
|
+
height: standaloneSize.height
|
|
1463
|
+
}, atlasFileName, context.encoder, context.options, context.logger);
|
|
1464
|
+
}
|
|
1465
|
+
return pages.length;
|
|
1466
|
+
}
|
|
1467
|
+
function packAtlasPages(inputs, options, forceSinglePage, sizeOverrides) {
|
|
1468
|
+
const hasDuplicatePadding = inputs.some((input) => {
|
|
1469
|
+
return isImageResource$1(input.resource) && input.resource.getDuplicatePadding?.() === true;
|
|
1470
|
+
});
|
|
1471
|
+
return new MaxRectsPackerCompat({
|
|
1472
|
+
pot: sizeOverrides?.powerOfTwo ?? options.powerOfTwo,
|
|
1473
|
+
mof: sizeOverrides?.multipleOfFour ?? !options.powerOfTwo,
|
|
1474
|
+
padding: options.padding,
|
|
1475
|
+
rotation: options.allowRotation,
|
|
1476
|
+
minWidth: 16,
|
|
1477
|
+
minHeight: 16,
|
|
1478
|
+
maxWidth: options.maxSize,
|
|
1479
|
+
maxHeight: options.maxSize,
|
|
1480
|
+
square: sizeOverrides?.square ?? options.square,
|
|
1481
|
+
fast: options.fast,
|
|
1482
|
+
edgePadding: false,
|
|
1483
|
+
duplicatePadding: hasDuplicatePadding,
|
|
1484
|
+
multiPage: forceSinglePage ? false : options.multiPage,
|
|
1485
|
+
preserveInputOrderOnTie: options.preserveInputOrderOnTie
|
|
1486
|
+
}).pack(inputs.map((input, index) => inputToCompatRect(input, index))) ?? [];
|
|
1487
|
+
}
|
|
1488
|
+
function attachSpritesToAtlas(doc, allResources, inputs, outputRects, atlasNode) {
|
|
1489
|
+
for (const packedRect of outputRects) {
|
|
1490
|
+
const input = inputs[packedRect.index];
|
|
1491
|
+
if (!input) continue;
|
|
1492
|
+
const packedSize = resolvePackedRectSize(input, packedRect.width, packedRect.height, packedRect.rotated);
|
|
1493
|
+
const sprite = doc.createSprite();
|
|
1494
|
+
sprite.setItemId(input.id);
|
|
1495
|
+
sprite.setRectX(packedRect.x);
|
|
1496
|
+
sprite.setRectY(packedRect.y);
|
|
1497
|
+
sprite.setRectWidth(packedSize.width);
|
|
1498
|
+
sprite.setRectHeight(packedSize.height);
|
|
1499
|
+
sprite.setRotated(packedRect.rotated);
|
|
1500
|
+
sprite.setOffsetX(input.offsetX);
|
|
1501
|
+
sprite.setOffsetY(input.offsetY);
|
|
1502
|
+
sprite.setOriginalWidth(input.originalWidth);
|
|
1503
|
+
sprite.setOriginalHeight(input.originalHeight);
|
|
1504
|
+
sprite.setAtlas(atlasNode);
|
|
1505
|
+
atlasNode.addSprite(sprite);
|
|
1506
|
+
}
|
|
1507
|
+
for (const resource of allResources) {
|
|
1508
|
+
if (!isFontResource$1(resource)) continue;
|
|
1509
|
+
const alias = resource.getExtras()?._fontSpriteAlias;
|
|
1510
|
+
if (!alias) continue;
|
|
1511
|
+
const imageSprite = outputRects.find((result) => inputs[result.index]?.id === alias.textureId);
|
|
1512
|
+
if (!imageSprite) continue;
|
|
1513
|
+
const imageInput = inputs[imageSprite.index];
|
|
1514
|
+
const fontSprite = doc.createSprite();
|
|
1515
|
+
fontSprite.setItemId(alias.fontId);
|
|
1516
|
+
fontSprite.setRectX(imageSprite.x);
|
|
1517
|
+
fontSprite.setRectY(imageSprite.y);
|
|
1518
|
+
fontSprite.setRectWidth(imageSprite.width);
|
|
1519
|
+
fontSprite.setRectHeight(imageSprite.height);
|
|
1520
|
+
fontSprite.setRotated(imageSprite.rotated);
|
|
1521
|
+
if (imageInput) {
|
|
1522
|
+
fontSprite.setOffsetX(imageInput.offsetX);
|
|
1523
|
+
fontSprite.setOffsetY(imageInput.offsetY);
|
|
1524
|
+
fontSprite.setOriginalWidth(imageInput.originalWidth);
|
|
1525
|
+
fontSprite.setOriginalHeight(imageInput.originalHeight);
|
|
1526
|
+
}
|
|
1527
|
+
fontSprite.setAtlas(atlasNode);
|
|
1528
|
+
atlasNode.addSprite(fontSprite);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
async function writeAtlasPageImage(pkg, inputs, page, atlasFileName, encoder, options, logger) {
|
|
1532
|
+
if (!encoder || !options.outputPath) return;
|
|
1533
|
+
if (options.mkdir) await options.mkdir(options.outputPath);
|
|
1534
|
+
const compositeInputs = [];
|
|
1535
|
+
for (const packedRect of page.outputRects) {
|
|
1536
|
+
const input = inputs[packedRect.index];
|
|
1537
|
+
if (!input) continue;
|
|
1538
|
+
if (packedRect.width <= 0 || packedRect.height <= 0 || input.width <= 0 || input.height <= 0) continue;
|
|
1539
|
+
try {
|
|
1540
|
+
let imageBuffer;
|
|
1541
|
+
if (input.trimBuffer) {
|
|
1542
|
+
imageBuffer = input.trimBuffer;
|
|
1543
|
+
if (imageBuffer.length === 0) continue;
|
|
1544
|
+
} else if (input.rasterizedBuffer) imageBuffer = input.rasterizedBuffer;
|
|
1545
|
+
else {
|
|
1546
|
+
if (!isImageResource$1(input.resource)) {
|
|
1547
|
+
logger.warn(`atlas: Non-image input "${input.id}" is missing inline buffer, skipping compositing.`);
|
|
1548
|
+
continue;
|
|
1549
|
+
}
|
|
1550
|
+
imageBuffer = await encoder(_resolveImagePath(input.resource, pkg, options.basePath)).toBuffer();
|
|
1551
|
+
}
|
|
1552
|
+
if (packedRect.rotated) imageBuffer = await encoder(imageBuffer).rotate(270).toBuffer();
|
|
1553
|
+
compositeInputs.push({
|
|
1554
|
+
input: imageBuffer,
|
|
1555
|
+
left: packedRect.x,
|
|
1556
|
+
top: packedRect.y
|
|
1557
|
+
});
|
|
1558
|
+
} catch {
|
|
1559
|
+
logger.warn(`atlas: Could not read image "${input.id}" for compositing.`);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
const outputFile = `${options.outputPath}/${atlasFileName}`;
|
|
1563
|
+
await encoder({ create: {
|
|
1564
|
+
width: page.width,
|
|
1565
|
+
height: page.height,
|
|
1566
|
+
channels: 4,
|
|
1567
|
+
background: {
|
|
1568
|
+
r: 0,
|
|
1569
|
+
g: 0,
|
|
1570
|
+
b: 0,
|
|
1571
|
+
alpha: 0
|
|
1572
|
+
}
|
|
1573
|
+
} }).composite(compositeInputs).toFile(outputFile);
|
|
1574
|
+
logger.info(`atlas: Generated ${atlasFileName} (${page.width}x${page.height}, ${page.outputRects.length} sprites)`);
|
|
1575
|
+
}
|
|
1432
1576
|
function inputToCompatRect(input, index) {
|
|
1433
1577
|
const duplicatePadding = isImageResource$1(input.resource) && input.resource.getDuplicatePadding?.() === true;
|
|
1434
1578
|
return {
|
|
@@ -1543,14 +1687,47 @@ function resolveAtlasOutputFileName(pkg, pageIndex, branchName) {
|
|
|
1543
1687
|
const suffix = branchName ? `_${branchName}` : "";
|
|
1544
1688
|
return `${pkg.getPublishName() || pkg.getName()}_atlas${pageIndex}${suffix}.png`;
|
|
1545
1689
|
}
|
|
1690
|
+
function resolveStandaloneAtlasOutputFileName(pkg, resource, branchName) {
|
|
1691
|
+
const baseName = `${pkg.getPublishName() || pkg.getName()}_atlas_${getPublishedItemId(resource)}`;
|
|
1692
|
+
const suffix = branchName ? `_${branchName}` : "";
|
|
1693
|
+
if (isImageResource$1(resource)) return `${baseName}${suffix}${extname$1(resolveImageFileName$1(resource)) || ".png"}`;
|
|
1694
|
+
return `${baseName}${suffix}.png`;
|
|
1695
|
+
}
|
|
1696
|
+
function resolveStandaloneAtlasSize(width, height, sizeMode, options) {
|
|
1697
|
+
if (sizeMode === "npot") return {
|
|
1698
|
+
width,
|
|
1699
|
+
height
|
|
1700
|
+
};
|
|
1701
|
+
if (sizeMode === "multipleOf4") return {
|
|
1702
|
+
width: roundUpToMultiple(width, 4),
|
|
1703
|
+
height: roundUpToMultiple(height, 4)
|
|
1704
|
+
};
|
|
1705
|
+
return resolveDirectOutputAtlasSize(width, height, options);
|
|
1706
|
+
}
|
|
1546
1707
|
function resolveImageFileName$1(resource) {
|
|
1547
1708
|
const extras = resource.getExtras();
|
|
1548
1709
|
return resource.getFileName() || extras._fileName || resource.getName();
|
|
1549
1710
|
}
|
|
1711
|
+
function extname$1(fileName) {
|
|
1712
|
+
const normalized = fileName.replace(/\\/g, "/");
|
|
1713
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
1714
|
+
const lastDot = normalized.lastIndexOf(".");
|
|
1715
|
+
if (lastDot <= lastSlash) return "";
|
|
1716
|
+
return normalized.slice(lastDot);
|
|
1717
|
+
}
|
|
1718
|
+
function insertFileNameSuffix(fileName, suffix) {
|
|
1719
|
+
const extension = extname$1(fileName);
|
|
1720
|
+
if (!extension) return `${fileName}${suffix}`;
|
|
1721
|
+
return `${fileName.slice(0, -extension.length)}${suffix}${extension}`;
|
|
1722
|
+
}
|
|
1550
1723
|
function nextPow2(value) {
|
|
1551
1724
|
if (value <= 1) return 1;
|
|
1552
1725
|
return 2 ** Math.ceil(Math.log2(value));
|
|
1553
1726
|
}
|
|
1727
|
+
function roundUpToMultiple(value, base) {
|
|
1728
|
+
if (value <= 0) return 0;
|
|
1729
|
+
return Math.ceil(value / base) * base;
|
|
1730
|
+
}
|
|
1554
1731
|
function sortResourcesByOrder(resources, orderMap, inputOrderMap) {
|
|
1555
1732
|
const ordered = [...resources];
|
|
1556
1733
|
ordered.sort((left, right) => {
|
|
@@ -1566,14 +1743,71 @@ function sortResourcesByOrder(resources, orderMap, inputOrderMap) {
|
|
|
1566
1743
|
});
|
|
1567
1744
|
return ordered;
|
|
1568
1745
|
}
|
|
1746
|
+
function getResourceTextureSetMode(resource) {
|
|
1747
|
+
if (isImageResource$1(resource)) return parseTextureSetMode(resource.getTextureSetMode?.());
|
|
1748
|
+
return parseTextureSetMode(resource.getTextureSetMode?.());
|
|
1749
|
+
}
|
|
1750
|
+
function groupStandaloneInputs(doc, inputs, options) {
|
|
1751
|
+
const autoInputs = [];
|
|
1752
|
+
const fixedInputsByPage = /* @__PURE__ */ new Map();
|
|
1753
|
+
const standaloneGroups = /* @__PURE__ */ new Map();
|
|
1754
|
+
const reservedPageIndexes = /* @__PURE__ */ new Set();
|
|
1755
|
+
const discoveredBranchNames = [...new Set(inputs.map((input) => getInputBranchName(input)).filter((branchName) => !!branchName))];
|
|
1756
|
+
const orderedBranchNames = doc.getRoot().listBranches().filter((branchName) => discoveredBranchNames.includes(branchName));
|
|
1757
|
+
for (const branchName of discoveredBranchNames) if (!orderedBranchNames.includes(branchName)) orderedBranchNames.push(branchName);
|
|
1758
|
+
const branchOrdinalByName = /* @__PURE__ */ new Map();
|
|
1759
|
+
branchOrdinalByName.set("", 0);
|
|
1760
|
+
if (options.separatedAtlasForBranch) {
|
|
1761
|
+
let ordinal = 1;
|
|
1762
|
+
for (const branchName of orderedBranchNames) branchOrdinalByName.set(branchName, ordinal++);
|
|
1763
|
+
} else for (const branchName of orderedBranchNames) branchOrdinalByName.set(branchName, 0);
|
|
1764
|
+
for (const input of inputs) {
|
|
1765
|
+
const branchName = getInputBranchName(input);
|
|
1766
|
+
const branchOrdinal = branchOrdinalByName.get(branchName) ?? 0;
|
|
1767
|
+
const mode = getResourceTextureSetMode(input.resource);
|
|
1768
|
+
if (mode.kind === "standalone") {
|
|
1769
|
+
const key = `${branchName}\u0000${getPublishedItemId(input.resource)}`;
|
|
1770
|
+
const existing = standaloneGroups.get(key);
|
|
1771
|
+
if (existing) existing.inputs.push(input);
|
|
1772
|
+
else standaloneGroups.set(key, {
|
|
1773
|
+
resource: input.resource,
|
|
1774
|
+
branchName,
|
|
1775
|
+
branchOrdinal,
|
|
1776
|
+
sizeMode: mode.sizeMode,
|
|
1777
|
+
inputs: [input]
|
|
1778
|
+
});
|
|
1779
|
+
continue;
|
|
1780
|
+
}
|
|
1781
|
+
if (mode.kind === "page") {
|
|
1782
|
+
reservedPageIndexes.add(mode.pageIndex);
|
|
1783
|
+
const key = `${branchName}\u0000${mode.pageIndex}`;
|
|
1784
|
+
const existing = fixedInputsByPage.get(key);
|
|
1785
|
+
if (existing) existing.inputs.push(input);
|
|
1786
|
+
else fixedInputsByPage.set(key, {
|
|
1787
|
+
pageIndex: mode.pageIndex,
|
|
1788
|
+
branchName,
|
|
1789
|
+
branchOrdinal,
|
|
1790
|
+
inputs: [input]
|
|
1791
|
+
});
|
|
1792
|
+
continue;
|
|
1793
|
+
}
|
|
1794
|
+
autoInputs.push(input);
|
|
1795
|
+
}
|
|
1796
|
+
return {
|
|
1797
|
+
autoInputs,
|
|
1798
|
+
fixedPageGroups: [...fixedInputsByPage.values()].sort((left, right) => left.branchOrdinal - right.branchOrdinal || left.pageIndex - right.pageIndex),
|
|
1799
|
+
standaloneGroups: [...standaloneGroups.values()].sort((left, right) => left.branchOrdinal - right.branchOrdinal || getPublishedItemId(left.resource).localeCompare(getPublishedItemId(right.resource))),
|
|
1800
|
+
reservedPageIndexes
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1569
1803
|
/**
|
|
1570
1804
|
* Trim transparent edges from an image using sharp.
|
|
1571
1805
|
* Returns the trimmed buffer, dimensions, and offsets.
|
|
1572
1806
|
* Falls back to the original image if trim fails (e.g. no alpha channel, no transparent edges).
|
|
1573
1807
|
*/
|
|
1574
|
-
async function _trimImage(encoder,
|
|
1808
|
+
async function _trimImage(encoder, input, originalWidth, originalHeight) {
|
|
1575
1809
|
try {
|
|
1576
|
-
const trimResult = await encoder(
|
|
1810
|
+
const trimResult = await encoder(input).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
1577
1811
|
if (!isResolvedBuffer(trimResult)) throw new Error("atlas: encoder raw alpha trim did not return resolved metadata.");
|
|
1578
1812
|
const { data, info } = trimResult;
|
|
1579
1813
|
const width = info.width;
|
|
@@ -1602,7 +1836,7 @@ async function _trimImage(encoder, filePath, originalWidth, originalHeight) {
|
|
|
1602
1836
|
const trimmedWidth = maxX - minX + 1;
|
|
1603
1837
|
const trimmedHeight = maxY - minY + 1;
|
|
1604
1838
|
return {
|
|
1605
|
-
buffer: await encoder(
|
|
1839
|
+
buffer: await encoder(input).extract({
|
|
1606
1840
|
left: minX,
|
|
1607
1841
|
top: minY,
|
|
1608
1842
|
width: trimmedWidth,
|
|
@@ -1617,7 +1851,7 @@ async function _trimImage(encoder, filePath, originalWidth, originalHeight) {
|
|
|
1617
1851
|
};
|
|
1618
1852
|
} catch {
|
|
1619
1853
|
return {
|
|
1620
|
-
buffer: await encoder(
|
|
1854
|
+
buffer: await encoder(input).png().toBuffer(),
|
|
1621
1855
|
width: originalWidth,
|
|
1622
1856
|
height: originalHeight,
|
|
1623
1857
|
offsetX: 0,
|
|
@@ -1641,7 +1875,10 @@ function _resolveImagePath(resource, pkg, basePath) {
|
|
|
1641
1875
|
async function _collectImage(resource, pkg, inputs, encoder, options, doTrim, logger) {
|
|
1642
1876
|
let origW = resource.getWidth() ?? 0;
|
|
1643
1877
|
let origH = resource.getHeight() ?? 0;
|
|
1878
|
+
const declaredWidth = origW;
|
|
1879
|
+
const declaredHeight = origH;
|
|
1644
1880
|
let sourceHasAlpha = false;
|
|
1881
|
+
let rasterizedBuffer;
|
|
1645
1882
|
if (encoder && options.basePath) {
|
|
1646
1883
|
const filePath = _resolveImagePath(resource, pkg, options.basePath);
|
|
1647
1884
|
try {
|
|
@@ -1653,6 +1890,10 @@ async function _collectImage(resource, pkg, inputs, encoder, options, doTrim, lo
|
|
|
1653
1890
|
resource.setHeight(origH);
|
|
1654
1891
|
}
|
|
1655
1892
|
sourceHasAlpha = metadata.hasAlpha === true || metadata.channels === 4;
|
|
1893
|
+
if (/\.svg$/i.test(resolveImageFileName$1(resource)) && declaredWidth > 0 && declaredHeight > 0) {
|
|
1894
|
+
rasterizedBuffer = await encoder(filePath).resize(declaredWidth, declaredHeight, { fit: "fill" }).png().toBuffer();
|
|
1895
|
+
sourceHasAlpha = true;
|
|
1896
|
+
}
|
|
1656
1897
|
} catch {
|
|
1657
1898
|
if (origW === 0 || origH === 0) {
|
|
1658
1899
|
logger.warn(`atlas: Could not read image "${filePath}", skipping.`);
|
|
@@ -1666,7 +1907,7 @@ async function _collectImage(resource, pkg, inputs, encoder, options, doTrim, lo
|
|
|
1666
1907
|
if (doTrim && sourceHasAlpha && options.basePath && encoder) {
|
|
1667
1908
|
const filePath = _resolveImagePath(resource, pkg, options.basePath);
|
|
1668
1909
|
try {
|
|
1669
|
-
const trimResult = await _trimImage(encoder, filePath, origW, origH);
|
|
1910
|
+
const trimResult = await _trimImage(encoder, rasterizedBuffer ?? filePath, origW, origH);
|
|
1670
1911
|
packW = trimResult.width;
|
|
1671
1912
|
packH = trimResult.height;
|
|
1672
1913
|
offX = trimResult.offsetX;
|
|
@@ -1686,6 +1927,7 @@ async function _collectImage(resource, pkg, inputs, encoder, options, doTrim, lo
|
|
|
1686
1927
|
offsetY: offY,
|
|
1687
1928
|
resource,
|
|
1688
1929
|
trimBuffer: trimBuf,
|
|
1930
|
+
rasterizedBuffer,
|
|
1689
1931
|
sourceKind: "image"
|
|
1690
1932
|
});
|
|
1691
1933
|
}
|
|
@@ -2118,6 +2360,62 @@ const FGUI_TYPESCRIPT_BINDER_TEMPLATE = `{{generatedMark}}
|
|
|
2118
2360
|
}
|
|
2119
2361
|
`;
|
|
2120
2362
|
//#endregion
|
|
2363
|
+
//#region src/plugins/loader.ts
|
|
2364
|
+
const importNative = new Function("id", "return import(id)");
|
|
2365
|
+
async function loadPlugins(doc, pluginsDir) {
|
|
2366
|
+
if (!pluginsDir) return [];
|
|
2367
|
+
const fs = await importNative("node:fs/promises");
|
|
2368
|
+
const path = await importNative("node:path");
|
|
2369
|
+
let entries;
|
|
2370
|
+
try {
|
|
2371
|
+
entries = await fs.readdir(pluginsDir, { withFileTypes: true });
|
|
2372
|
+
} catch {
|
|
2373
|
+
return [];
|
|
2374
|
+
}
|
|
2375
|
+
const plugins = [];
|
|
2376
|
+
for (const entry of entries) {
|
|
2377
|
+
if (!entry.isDirectory()) continue;
|
|
2378
|
+
const pluginDir = path.join(pluginsDir, entry.name);
|
|
2379
|
+
try {
|
|
2380
|
+
const manifest = await readPluginManifest(fs, path, pluginDir);
|
|
2381
|
+
if (!manifest) continue;
|
|
2382
|
+
const plugin = await loadPlugin(resolvePluginMain(path, pluginDir, manifest));
|
|
2383
|
+
plugins.push({
|
|
2384
|
+
name: manifest.name,
|
|
2385
|
+
plugin
|
|
2386
|
+
});
|
|
2387
|
+
} catch (error) {
|
|
2388
|
+
doc.getLogger().warn(`publish: Plugin "${entry.name}" was skipped: ${formatPluginError(error)}`);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
return plugins;
|
|
2392
|
+
}
|
|
2393
|
+
function formatPluginError(error) {
|
|
2394
|
+
return error instanceof Error ? error.message : String(error);
|
|
2395
|
+
}
|
|
2396
|
+
async function readPluginManifest(fs, path, pluginDir) {
|
|
2397
|
+
const manifestPath = path.join(pluginDir, "package.json");
|
|
2398
|
+
const content = await fs.readFile(manifestPath, "utf-8");
|
|
2399
|
+
const manifest = JSON.parse(content);
|
|
2400
|
+
if (!manifest.name) throw new Error(`Codegen plugin at ${pluginDir} is missing package.json name.`);
|
|
2401
|
+
if (!manifest.main) throw new Error(`Codegen plugin "${manifest.name}" is missing package.json main.`);
|
|
2402
|
+
return manifest;
|
|
2403
|
+
}
|
|
2404
|
+
function resolvePluginMain(path, pluginDir, manifest) {
|
|
2405
|
+
const mainPath = path.resolve(pluginDir, manifest.main);
|
|
2406
|
+
const relative = path.relative(pluginDir, mainPath);
|
|
2407
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Codegen plugin "${manifest.name}" main must resolve inside its plugin directory.`);
|
|
2408
|
+
return mainPath;
|
|
2409
|
+
}
|
|
2410
|
+
async function loadPlugin(mainPath) {
|
|
2411
|
+
const mod = await (0, jiti.createJiti)(require("url").pathToFileURL(__filename).href).import(mainPath);
|
|
2412
|
+
const defaultExport = mod.default;
|
|
2413
|
+
return isObject(defaultExport) ? defaultExport : mod;
|
|
2414
|
+
}
|
|
2415
|
+
function isObject(value) {
|
|
2416
|
+
return value !== null && typeof value === "object";
|
|
2417
|
+
}
|
|
2418
|
+
//#endregion
|
|
2121
2419
|
//#region src/codegen.ts
|
|
2122
2420
|
const AUTO_GENERATED_CODE_MARK = "/** This is an automatically generated class by FairyGUI. Please do not modify it. **/";
|
|
2123
2421
|
const DEFAULT_CLASS_NAME_PREFIX = "UI_";
|
|
@@ -2153,6 +2451,18 @@ async function publishCodeGeneration(doc, options) {
|
|
|
2153
2451
|
const logger = doc.getLogger();
|
|
2154
2452
|
const settings = resolveCodeGenerationSettings(doc);
|
|
2155
2453
|
if (!settings.allowGenCode) return;
|
|
2454
|
+
const plugins = options.plugins?.filter((plugin) => typeof plugin.plugin.genCode === "function") ?? [];
|
|
2455
|
+
if (plugins.length > 0) {
|
|
2456
|
+
let handled = false;
|
|
2457
|
+
for (const plugin of plugins) try {
|
|
2458
|
+
await plugin.plugin.genCode(doc, settings, options);
|
|
2459
|
+
handled = true;
|
|
2460
|
+
logger.info(`publish: Generated code using plugin "${plugin.name}"`);
|
|
2461
|
+
} catch (error) {
|
|
2462
|
+
logger.warn(`publish: Code generation plugin "${plugin.name}" failed: ${formatPluginError(error)}`);
|
|
2463
|
+
}
|
|
2464
|
+
if (handled) return;
|
|
2465
|
+
}
|
|
2156
2466
|
for (const pkg of options.packages) {
|
|
2157
2467
|
if (!pkg.getGenCode()) continue;
|
|
2158
2468
|
const plan = resolvePackageCodegenPlan(pkg, settings, options);
|
|
@@ -2251,9 +2561,9 @@ async function cleanupGeneratedFiles(directory, fs, extension = ".cs") {
|
|
|
2251
2561
|
}
|
|
2252
2562
|
}
|
|
2253
2563
|
function buildCodegenClasses(doc, pkg, plan) {
|
|
2254
|
-
const
|
|
2564
|
+
const codegenComponents = pkg.listComponents().sort((left, right) => left.getId().localeCompare(right.getId()));
|
|
2255
2565
|
const generatedById = /* @__PURE__ */ new Map();
|
|
2256
|
-
for (const component of
|
|
2566
|
+
for (const component of codegenComponents) {
|
|
2257
2567
|
const encodedClassName = `${plan.settings.classNamePrefix}${normalizeTypeName(component.getName()) || "Component"}`;
|
|
2258
2568
|
generatedById.set(component.getId(), {
|
|
2259
2569
|
classId: component.getId(),
|
|
@@ -2266,7 +2576,13 @@ function buildCodegenClasses(doc, pkg, plan) {
|
|
|
2266
2576
|
members: []
|
|
2267
2577
|
});
|
|
2268
2578
|
}
|
|
2269
|
-
for (const component of
|
|
2579
|
+
for (const component of codegenComponents) {
|
|
2580
|
+
const classInfo = generatedById.get(component.getId());
|
|
2581
|
+
if (!classInfo) continue;
|
|
2582
|
+
classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
|
|
2583
|
+
}
|
|
2584
|
+
for (const [componentId, classInfo] of generatedById) if (classInfo.members.every((member) => member.ignored)) generatedById.delete(componentId);
|
|
2585
|
+
for (const component of codegenComponents) {
|
|
2270
2586
|
const classInfo = generatedById.get(component.getId());
|
|
2271
2587
|
if (!classInfo) continue;
|
|
2272
2588
|
classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
|
|
@@ -2280,7 +2596,12 @@ function buildCodegenMembers(doc, pkg, component, plan, generatedById) {
|
|
|
2280
2596
|
let childIndex = 0;
|
|
2281
2597
|
let transitionIndex = 0;
|
|
2282
2598
|
for (const controller of component.listControllers()) members.push(createMember(ownerType, "controller", "Controller", controller.getName(), controllerIndex++, plan));
|
|
2283
|
-
for (const child of component.listChildren())
|
|
2599
|
+
for (const child of component.listChildren()) {
|
|
2600
|
+
if (!isRuntimeChild(child)) continue;
|
|
2601
|
+
const index = childIndex++;
|
|
2602
|
+
const resolvedChild = resolveChildType(doc, pkg, child, generatedById);
|
|
2603
|
+
members.push(createMember(ownerType, "child", resolvedChild.type, child.getName(), index, plan, resolvedChild.referencedComponent));
|
|
2604
|
+
}
|
|
2284
2605
|
for (const transition of component.listTransitions()) members.push(createMember(ownerType, "transition", "Transition", transition.getName(), transitionIndex++, plan));
|
|
2285
2606
|
const usedNames = /* @__PURE__ */ new Map();
|
|
2286
2607
|
for (const member of members) {
|
|
@@ -2292,7 +2613,10 @@ function buildCodegenMembers(doc, pkg, component, plan, generatedById) {
|
|
|
2292
2613
|
}
|
|
2293
2614
|
return members;
|
|
2294
2615
|
}
|
|
2295
|
-
function
|
|
2616
|
+
function isRuntimeChild(child) {
|
|
2617
|
+
return child.propertyType !== "GGroup" || child.getAdvanced?.() === true;
|
|
2618
|
+
}
|
|
2619
|
+
function createMember(ownerType, kind, type, originalName, index, plan, referencedComponent) {
|
|
2296
2620
|
const ignored = plan.settings.ignoreNoname && isDefaultMemberName(ownerType, kind, originalName);
|
|
2297
2621
|
return {
|
|
2298
2622
|
index,
|
|
@@ -2300,30 +2624,41 @@ function createMember(ownerType, kind, type, originalName, index, plan) {
|
|
|
2300
2624
|
name: applyMemberNamePrefix(originalName, plan.settings.memberNamePrefix),
|
|
2301
2625
|
originalName,
|
|
2302
2626
|
type,
|
|
2303
|
-
ignored
|
|
2627
|
+
ignored,
|
|
2628
|
+
referencedComponent
|
|
2304
2629
|
};
|
|
2305
2630
|
}
|
|
2306
2631
|
function resolveChildType(doc, pkg, child, generatedById) {
|
|
2307
2632
|
const src = child.getSrc?.();
|
|
2308
2633
|
if (src) {
|
|
2309
|
-
|
|
2310
|
-
if (
|
|
2634
|
+
let referencedComponent = null;
|
|
2635
|
+
if (src.startsWith("ui://")) {
|
|
2636
|
+
const rest = src.slice(5);
|
|
2637
|
+
const pkgId = rest.slice(0, 8);
|
|
2638
|
+
const resourceId = rest.slice(8);
|
|
2639
|
+
const targetPackage = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId);
|
|
2640
|
+
const targetResource = targetPackage?.getResourceById(resourceId);
|
|
2641
|
+
if (targetPackage && targetResource?.propertyType === "Component") referencedComponent = {
|
|
2642
|
+
component: targetResource,
|
|
2643
|
+
package: targetPackage
|
|
2644
|
+
};
|
|
2645
|
+
} else {
|
|
2646
|
+
const packageId = child.getPackageId?.();
|
|
2647
|
+
const targetPackage = packageId ? doc.getRoot().listPackages().find((candidate) => candidate.getId() === packageId) : pkg;
|
|
2648
|
+
const targetResource = targetPackage?.getResourceById(src);
|
|
2649
|
+
if (targetPackage && targetResource?.propertyType === "Component") referencedComponent = {
|
|
2650
|
+
component: targetResource,
|
|
2651
|
+
package: targetPackage
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
if (referencedComponent) return {
|
|
2655
|
+
type: (referencedComponent.package === pkg ? generatedById.get(referencedComponent.component.getId()) : void 0)?.encodedClassName ?? resolveComponentBaseType(referencedComponent.component),
|
|
2656
|
+
referencedComponent
|
|
2657
|
+
};
|
|
2311
2658
|
}
|
|
2312
2659
|
const instanceExtType = child.getInstanceExtType?.();
|
|
2313
|
-
if (instanceExtType) return `G${instanceExtType}
|
|
2314
|
-
return child.propertyType;
|
|
2315
|
-
}
|
|
2316
|
-
function resolveChildSourceComponent(doc, pkg, src) {
|
|
2317
|
-
if (!src) return null;
|
|
2318
|
-
if (src.startsWith("ui://")) {
|
|
2319
|
-
const rest = src.slice(5);
|
|
2320
|
-
const pkgId = rest.slice(0, 8);
|
|
2321
|
-
const resourceId = rest.slice(8);
|
|
2322
|
-
const targetResource = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId)?.getResourceById(resourceId);
|
|
2323
|
-
return targetResource?.propertyType === "Component" ? targetResource : null;
|
|
2324
|
-
}
|
|
2325
|
-
const localResource = pkg.getResourceById(src);
|
|
2326
|
-
return localResource?.propertyType === "Component" ? localResource : null;
|
|
2660
|
+
if (instanceExtType) return { type: `G${instanceExtType}` };
|
|
2661
|
+
return { type: child.propertyType };
|
|
2327
2662
|
}
|
|
2328
2663
|
function resolveComponentBaseType(component) {
|
|
2329
2664
|
const extensionType = component.getExtensionType();
|
|
@@ -2394,21 +2729,21 @@ function renderFguiTypescriptMemberAssignment(member, getMemberByName, variant)
|
|
|
2394
2729
|
return getMemberByName ? `\t\tthis.${member.name} = <${translatedType}><any>(this.getChild("${escapeTypeScriptString(member.originalName)}"));` : `\t\tthis.${member.name} = <${translatedType}><any>(this.getChildAt(${member.index}));`;
|
|
2395
2730
|
}
|
|
2396
2731
|
function resolveCodePath(codePath, basePath, fs) {
|
|
2397
|
-
if (isAbsolutePath(codePath)) return trimTrailingSlashes$
|
|
2732
|
+
if (isAbsolutePath(codePath)) return trimTrailingSlashes$2(codePath);
|
|
2398
2733
|
const projectBasePath = resolveProjectBasePath(basePath);
|
|
2399
|
-
return projectBasePath ? trimTrailingSlashes$
|
|
2734
|
+
return projectBasePath ? trimTrailingSlashes$2(fs.join(projectBasePath, codePath)) : trimTrailingSlashes$2(codePath);
|
|
2400
2735
|
}
|
|
2401
2736
|
function resolveProjectBasePath(basePath) {
|
|
2402
2737
|
if (!basePath) return "";
|
|
2403
|
-
const normalized = trimTrailingSlashes$
|
|
2738
|
+
const normalized = trimTrailingSlashes$2(basePath);
|
|
2404
2739
|
const assetsMatch = normalized.match(/^(.*)[/\\]assets(?:_[^/\\]+)?$/i);
|
|
2405
2740
|
if (assetsMatch?.[1]) return assetsMatch[1];
|
|
2406
2741
|
return dirname$2(normalized);
|
|
2407
2742
|
}
|
|
2408
2743
|
function dirname$2(filePath) {
|
|
2409
|
-
return trimTrailingSlashes$
|
|
2744
|
+
return trimTrailingSlashes$2(filePath).match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
2410
2745
|
}
|
|
2411
|
-
function trimTrailingSlashes$
|
|
2746
|
+
function trimTrailingSlashes$2(value) {
|
|
2412
2747
|
return value.replace(/[/\\]+$/, "");
|
|
2413
2748
|
}
|
|
2414
2749
|
function isAbsolutePath(value) {
|
|
@@ -2417,9 +2752,15 @@ function isAbsolutePath(value) {
|
|
|
2417
2752
|
function isDefaultMemberName(ownerType, kind, name) {
|
|
2418
2753
|
if (kind === "controller") return (ownerType === "GButton" || ownerType === "GComboBox") && name === "button";
|
|
2419
2754
|
if (kind === "transition") return false;
|
|
2420
|
-
if (ownerType === "GButton" || ownerType === "GLabel" || ownerType === "GComboBox")
|
|
2421
|
-
|
|
2422
|
-
|
|
2755
|
+
if (ownerType === "GButton" || ownerType === "GLabel" || ownerType === "GComboBox") {
|
|
2756
|
+
if (name === "title" || name === "icon") return true;
|
|
2757
|
+
}
|
|
2758
|
+
if (ownerType === "GProgressBar") {
|
|
2759
|
+
if (name === "bar" || name === "bar_v" || name === "title" || name === "ani") return true;
|
|
2760
|
+
}
|
|
2761
|
+
if (ownerType === "GSlider") {
|
|
2762
|
+
if (name === "bar" || name === "bar_v" || name === "grip" || name === "title" || name === "ani") return true;
|
|
2763
|
+
}
|
|
2423
2764
|
return /^n\d+(?:_.*)?$/i.test(name);
|
|
2424
2765
|
}
|
|
2425
2766
|
function applyMemberNamePrefix(name, prefix) {
|
|
@@ -2708,11 +3049,11 @@ function inferPackageName(fileName) {
|
|
|
2708
3049
|
if (/\.fui$/i.test(fileName)) return fileName.replace(/\.fui$/i, "");
|
|
2709
3050
|
return fileName.replace(/\.bin$/i, "");
|
|
2710
3051
|
}
|
|
2711
|
-
function trimTrailingSlashes(value) {
|
|
3052
|
+
function trimTrailingSlashes$1(value) {
|
|
2712
3053
|
return value.replace(/[/\\]+$/, "");
|
|
2713
3054
|
}
|
|
2714
3055
|
function normalizeComparablePath(value) {
|
|
2715
|
-
const normalized = trimTrailingSlashes(value).replace(/\\/g, "/");
|
|
3056
|
+
const normalized = trimTrailingSlashes$1(value).replace(/\\/g, "/");
|
|
2716
3057
|
const driveMatch = normalized.match(/^([a-z]:)(?:\/(.*))?$/i);
|
|
2717
3058
|
const drivePrefix = driveMatch?.[1].toLowerCase() ?? "";
|
|
2718
3059
|
const remainder = driveMatch ? driveMatch[2] ?? "" : normalized;
|
|
@@ -2732,14 +3073,14 @@ function normalizeComparablePath(value) {
|
|
|
2732
3073
|
return (drivePrefix ? `${drivePrefix}/${joined}`.replace(/\/$/, "") : hasRoot ? `/${joined}`.replace(/\/$/, "") : joined || ".").toLowerCase();
|
|
2733
3074
|
}
|
|
2734
3075
|
function dirname$1(filePath) {
|
|
2735
|
-
return trimTrailingSlashes(filePath).match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
3076
|
+
return trimTrailingSlashes$1(filePath).match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
2736
3077
|
}
|
|
2737
3078
|
function basename(filePath) {
|
|
2738
|
-
return trimTrailingSlashes(filePath).match(/([^/\\]+)$/)?.[1] ?? "";
|
|
3079
|
+
return trimTrailingSlashes$1(filePath).match(/([^/\\]+)$/)?.[1] ?? "";
|
|
2739
3080
|
}
|
|
2740
3081
|
function resolveOutputProjectPath(output, fs) {
|
|
2741
3082
|
if (/\.fairy$/i.test(output)) return output;
|
|
2742
|
-
const normalizedOutput = trimTrailingSlashes(output);
|
|
3083
|
+
const normalizedOutput = trimTrailingSlashes$1(output);
|
|
2743
3084
|
const projectName = basename(normalizedOutput) || "Restored";
|
|
2744
3085
|
return fs.join(normalizedOutput, `${projectName}.fairy`);
|
|
2745
3086
|
}
|
|
@@ -2785,7 +3126,7 @@ async function prepareRestoreOutputDir(inputDir, outputDir, outputProjectPath, f
|
|
|
2785
3126
|
await fs.mkdir(outputDir);
|
|
2786
3127
|
}
|
|
2787
3128
|
async function restore(options) {
|
|
2788
|
-
const sourceDir = trimTrailingSlashes(options.inputDir);
|
|
3129
|
+
const sourceDir = trimTrailingSlashes$1(options.inputDir);
|
|
2789
3130
|
const outputIsProjectFile = /\.fairy$/i.test(options.output);
|
|
2790
3131
|
const outputProjectPath = resolveOutputProjectPath(options.output, options.fs);
|
|
2791
3132
|
await prepareRestoreOutputDir(sourceDir, dirname$1(outputProjectPath) || ".", outputProjectPath, options.fs, options.force === true, outputIsProjectFile);
|
|
@@ -2927,16 +3268,23 @@ var RestoreWorkflow = class {
|
|
|
2927
3268
|
async _ensureLooseImageResource(doc, pkg, owner, sourceDir, fileName) {
|
|
2928
3269
|
const resources = pkg.listResources();
|
|
2929
3270
|
const existing = this._findResourceByFile(resources, owner, "ImageResource", fileName);
|
|
2930
|
-
if (existing) return existing;
|
|
2931
3271
|
const sourcePath = await this._resolveLooseSourceFile(pkg, sourceDir, fileName);
|
|
2932
|
-
if (!sourcePath) return null;
|
|
3272
|
+
if (!sourcePath) return existing ?? null;
|
|
3273
|
+
if (existing) {
|
|
3274
|
+
existing.setExtras?.({
|
|
3275
|
+
...existing.getExtras?.() ?? {},
|
|
3276
|
+
_publishedFile: fileBaseName(sourcePath),
|
|
3277
|
+
_restoreAsLooseImage: true
|
|
3278
|
+
});
|
|
3279
|
+
return existing;
|
|
3280
|
+
}
|
|
2933
3281
|
const resource = doc.createImageResource(stripExtension(fileName));
|
|
2934
3282
|
resource.setId((0, _openfairygui_core.generateId)()).setPath(owner.getPath?.() ?? "/").setBranch(owner.getBranch?.() ?? "").setBranchItemIds(owner.getBranchItemIds?.() ?? []).setExported(false).setFileName(fileName);
|
|
2935
3283
|
resource.setExtras?.({
|
|
2936
3284
|
...resource.getExtras?.() ?? {},
|
|
2937
3285
|
_publishedFile: fileBaseName(sourcePath),
|
|
2938
3286
|
_suppressPackageSize: true,
|
|
2939
|
-
|
|
3287
|
+
_restoreAsLooseImage: true
|
|
2940
3288
|
});
|
|
2941
3289
|
pkg.addResource(resource);
|
|
2942
3290
|
return resource;
|
|
@@ -3110,13 +3458,13 @@ var RestoreWorkflow = class {
|
|
|
3110
3458
|
}
|
|
3111
3459
|
async _copyLooseResources(pkg, options, warnings) {
|
|
3112
3460
|
for (const resource of pkg.listResources()) {
|
|
3113
|
-
const
|
|
3461
|
+
const restoreAsLooseImage = resource.getExtras?.()?._restoreAsLooseImage === true;
|
|
3114
3462
|
if (![
|
|
3115
3463
|
"SoundResource",
|
|
3116
3464
|
"MiscResource",
|
|
3117
3465
|
"SpineResource",
|
|
3118
3466
|
"DragonBonesResource"
|
|
3119
|
-
].includes(resource.propertyType) && !
|
|
3467
|
+
].includes(resource.propertyType) && !restoreAsLooseImage) continue;
|
|
3120
3468
|
const fileName = resourceFileName(resource);
|
|
3121
3469
|
if (!fileName) continue;
|
|
3122
3470
|
const sourcePath = await this._resolveSourceFile(options.sourceDir, this._sourceFileCandidates(pkg, resourcePublishedFileName(resource), fileName));
|
|
@@ -3286,6 +3634,26 @@ var RestoreWorkflow = class {
|
|
|
3286
3634
|
};
|
|
3287
3635
|
//#endregion
|
|
3288
3636
|
//#region src/publish.ts
|
|
3637
|
+
async function runPublishPluginHook(plugins, hook, doc, options) {
|
|
3638
|
+
const logger = doc.getLogger();
|
|
3639
|
+
for (const plugin of plugins) {
|
|
3640
|
+
const fn = plugin.plugin[hook];
|
|
3641
|
+
if (typeof fn !== "function") continue;
|
|
3642
|
+
try {
|
|
3643
|
+
await fn(doc, options);
|
|
3644
|
+
} catch (error) {
|
|
3645
|
+
logger.warn(`publish: Plugin "${plugin.name}" ${hook} failed: ${formatPluginError(error)}`);
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
function resolvePublishPluginsDir(doc, options) {
|
|
3650
|
+
const fs = options.fs;
|
|
3651
|
+
const projectDir = doc.getProjectDir?.() ?? "";
|
|
3652
|
+
if (projectDir) return fs?.join ? fs.join(projectDir, "plugins") : `${projectDir.replace(/[/\\]+$/, "")}/plugins`;
|
|
3653
|
+
const projectBasePath = resolveProjectBasePath(options.basePath);
|
|
3654
|
+
if (!projectBasePath) return "";
|
|
3655
|
+
return fs?.join ? fs.join(projectBasePath, "plugins") : `${projectBasePath.replace(/[/\\]+$/, "")}/plugins`;
|
|
3656
|
+
}
|
|
3289
3657
|
const UNITY_PROJECT_TYPE = _openfairygui_core.ProjectType.Unity;
|
|
3290
3658
|
const COCOS_CREATOR_PROJECT_TYPE = _openfairygui_core.ProjectType.CocosCreator;
|
|
3291
3659
|
function resolveDefaultPublishFileExtension(projectType, publishSettings) {
|
|
@@ -3335,6 +3703,19 @@ function resolvePublishOptions(doc, overrides = {}) {
|
|
|
3335
3703
|
atlas: atlasOptions
|
|
3336
3704
|
};
|
|
3337
3705
|
}
|
|
3706
|
+
function trimTrailingSlashes(value) {
|
|
3707
|
+
return value.replace(/[/\\]+$/, "");
|
|
3708
|
+
}
|
|
3709
|
+
function isAbsolutePathLike(value) {
|
|
3710
|
+
return /^(?:[a-zA-Z]:[/\\]|[/\\]{1,2})/u.test(value);
|
|
3711
|
+
}
|
|
3712
|
+
function joinPathSegments(left, right) {
|
|
3713
|
+
const normalizedLeft = trimTrailingSlashes(left);
|
|
3714
|
+
const normalizedRight = right.replace(/^[/\\]+/, "");
|
|
3715
|
+
if (!normalizedLeft) return normalizedRight;
|
|
3716
|
+
if (!normalizedRight) return normalizedLeft;
|
|
3717
|
+
return `${normalizedLeft}${normalizedLeft.includes("\\") ? "\\" : "/"}${normalizedRight}`;
|
|
3718
|
+
}
|
|
3338
3719
|
function dirname(filePath) {
|
|
3339
3720
|
return filePath.replace(/[/\\]+$/, "").match(/^(.*)[/\\][^/\\]+$/)?.[1] ?? "";
|
|
3340
3721
|
}
|
|
@@ -3365,6 +3746,9 @@ function isImageResource(resource) {
|
|
|
3365
3746
|
function isMovieClipResource(resource) {
|
|
3366
3747
|
return resource.propertyType === "MovieClipResource";
|
|
3367
3748
|
}
|
|
3749
|
+
function isHighResolutionResource(resource) {
|
|
3750
|
+
return isImageResource(resource) || isMovieClipResource(resource);
|
|
3751
|
+
}
|
|
3368
3752
|
function isMiscResource(resource) {
|
|
3369
3753
|
return resource.propertyType === "MiscResource";
|
|
3370
3754
|
}
|
|
@@ -3447,13 +3831,14 @@ function extname(fileName) {
|
|
|
3447
3831
|
if (lastDot <= lastSlash) return "";
|
|
3448
3832
|
return normalized.slice(lastDot);
|
|
3449
3833
|
}
|
|
3450
|
-
function resolvePublishedMiscFileName(resource) {
|
|
3834
|
+
function resolvePublishedMiscFileName(resource, projectType) {
|
|
3451
3835
|
const file = resource.getFile();
|
|
3836
|
+
if (projectType !== UNITY_PROJECT_TYPE) return file;
|
|
3452
3837
|
if (file.toLowerCase().endsWith(".atlas")) return `${file}.txt`;
|
|
3453
3838
|
return file;
|
|
3454
3839
|
}
|
|
3455
|
-
function resolvePublishedSkeletonFileName(resource) {
|
|
3456
|
-
if (isSpineResource(resource) && resource.getFile().toLowerCase().endsWith(".skel")) return `${resource.getFile()}.bytes`;
|
|
3840
|
+
function resolvePublishedSkeletonFileName(resource, projectType) {
|
|
3841
|
+
if (projectType === UNITY_PROJECT_TYPE && isSpineResource(resource) && resource.getFile().toLowerCase().endsWith(".skel")) return `${resource.getFile()}.bytes`;
|
|
3457
3842
|
return resource.getFile();
|
|
3458
3843
|
}
|
|
3459
3844
|
function setPublishedFileExtra(resource, fileName) {
|
|
@@ -3485,6 +3870,70 @@ function getBranchName(resource) {
|
|
|
3485
3870
|
function buildBranchResourceKey(resource) {
|
|
3486
3871
|
return `${resource.propertyType}|${resource.getPath() ?? ""}|${resource.getName() ?? ""}`;
|
|
3487
3872
|
}
|
|
3873
|
+
const HIGH_RESOLUTION_LEVELS = [
|
|
3874
|
+
{
|
|
3875
|
+
scale: 2,
|
|
3876
|
+
bit: 1,
|
|
3877
|
+
slot: 0
|
|
3878
|
+
},
|
|
3879
|
+
{
|
|
3880
|
+
scale: 3,
|
|
3881
|
+
bit: 2,
|
|
3882
|
+
slot: 1
|
|
3883
|
+
},
|
|
3884
|
+
{
|
|
3885
|
+
scale: 4,
|
|
3886
|
+
bit: 4,
|
|
3887
|
+
slot: 2
|
|
3888
|
+
}
|
|
3889
|
+
];
|
|
3890
|
+
function buildHighResolutionResourceKey(resource, name = resource.getName()) {
|
|
3891
|
+
return `${resource.propertyType}|${resource.getBranch?.() ?? ""}|${resource.getPath() ?? ""}|${name}`;
|
|
3892
|
+
}
|
|
3893
|
+
function isHighResolutionVariantName(name) {
|
|
3894
|
+
return /@(?:2|3|4)x(?:\.[^./\\]+)?$/iu.test(name);
|
|
3895
|
+
}
|
|
3896
|
+
function appendHighResolutionScaleToName(name, scale) {
|
|
3897
|
+
const extensionIndex = name.lastIndexOf(".");
|
|
3898
|
+
if (extensionIndex > 0) return `${name.slice(0, extensionIndex)}@${scale}x${name.slice(extensionIndex)}`;
|
|
3899
|
+
return `${name}@${scale}x`;
|
|
3900
|
+
}
|
|
3901
|
+
function trimTrailingMissingHighResolutionIds(ids) {
|
|
3902
|
+
while (ids.length > 0 && !ids[ids.length - 1]) ids.pop();
|
|
3903
|
+
return ids;
|
|
3904
|
+
}
|
|
3905
|
+
function collectHighResolutionItemIds(resources, publishedResourceIds, includeHighResolution) {
|
|
3906
|
+
const result = /* @__PURE__ */ new Map();
|
|
3907
|
+
if (includeHighResolution <= 0) return result;
|
|
3908
|
+
const highResolutionResourceByKey = /* @__PURE__ */ new Map();
|
|
3909
|
+
for (const resource of resources) {
|
|
3910
|
+
if (!isHighResolutionResource(resource)) continue;
|
|
3911
|
+
highResolutionResourceByKey.set(buildHighResolutionResourceKey(resource), resource);
|
|
3912
|
+
}
|
|
3913
|
+
for (const resource of resources) {
|
|
3914
|
+
if (!isHighResolutionResource(resource)) continue;
|
|
3915
|
+
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
3916
|
+
if (isHighResolutionVariantName(resource.getName())) continue;
|
|
3917
|
+
const ids = [];
|
|
3918
|
+
for (const level of HIGH_RESOLUTION_LEVELS) {
|
|
3919
|
+
if ((includeHighResolution & level.bit) === 0) {
|
|
3920
|
+
ids[level.slot] = null;
|
|
3921
|
+
continue;
|
|
3922
|
+
}
|
|
3923
|
+
const highResolutionResource = highResolutionResourceByKey.get(buildHighResolutionResourceKey(resource, appendHighResolutionScaleToName(resource.getName(), level.scale)));
|
|
3924
|
+
if (!highResolutionResource) {
|
|
3925
|
+
ids[level.slot] = null;
|
|
3926
|
+
continue;
|
|
3927
|
+
}
|
|
3928
|
+
const highResolutionId = highResolutionResource.getId();
|
|
3929
|
+
publishedResourceIds.add(highResolutionId);
|
|
3930
|
+
ids[level.slot] = highResolutionId;
|
|
3931
|
+
}
|
|
3932
|
+
trimTrailingMissingHighResolutionIds(ids);
|
|
3933
|
+
if (ids.length > 0) result.set(resource.getId(), ids);
|
|
3934
|
+
}
|
|
3935
|
+
return result;
|
|
3936
|
+
}
|
|
3488
3937
|
function collectPackagePublishContext(pkg, options) {
|
|
3489
3938
|
const pkgId = pkg.getId();
|
|
3490
3939
|
const resources = pkg.listResources();
|
|
@@ -3492,6 +3941,24 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
3492
3941
|
const referencedIds = /* @__PURE__ */ new Set();
|
|
3493
3942
|
const pixelHitTestImageIds = /* @__PURE__ */ new Set();
|
|
3494
3943
|
const spriteItemIds = /* @__PURE__ */ new Set();
|
|
3944
|
+
const collectExportedResourceIds = (sourceResources, sourcePublishedResourceIds) => {
|
|
3945
|
+
const exportedResourceIds = new Set(sourcePublishedResourceIds);
|
|
3946
|
+
const resourcesById = new Map(sourceResources.map((resource) => [resource.getId(), resource]));
|
|
3947
|
+
let changed = true;
|
|
3948
|
+
while (changed) {
|
|
3949
|
+
changed = false;
|
|
3950
|
+
for (const resourceId of [...exportedResourceIds]) {
|
|
3951
|
+
const resource = resourcesById.get(resourceId);
|
|
3952
|
+
if (!resource || !isSkeletonResource(resource)) continue;
|
|
3953
|
+
for (const requiredId of resource.getRequireIds()) {
|
|
3954
|
+
if (!requiredId || exportedResourceIds.has(requiredId)) continue;
|
|
3955
|
+
exportedResourceIds.add(requiredId);
|
|
3956
|
+
changed = true;
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
return exportedResourceIds;
|
|
3961
|
+
};
|
|
3495
3962
|
for (const atlas of pkg.listAtlases()) for (const sprite of atlas.listSprites()) spriteItemIds.add(sprite.getItemId());
|
|
3496
3963
|
for (const resource of resources) {
|
|
3497
3964
|
if (!isComponentResource(resource)) continue;
|
|
@@ -3518,6 +3985,7 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
3518
3985
|
child.getSelectedIcon?.(),
|
|
3519
3986
|
child.getDropdown?.(),
|
|
3520
3987
|
child.getSound?.(),
|
|
3988
|
+
child.getInstanceSound?.(),
|
|
3521
3989
|
child.getInstanceIcon?.(),
|
|
3522
3990
|
child.getInstanceSelectedIcon?.(),
|
|
3523
3991
|
child.getVtScrollBarRes?.(),
|
|
@@ -3575,19 +4043,8 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
3575
4043
|
}
|
|
3576
4044
|
if (resource.getExported() || referencedIds.has(resourceId)) publishedResourceIds.add(resourceId);
|
|
3577
4045
|
}
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
changed = false;
|
|
3581
|
-
for (const resource of resources) {
|
|
3582
|
-
if (!isSkeletonResource(resource)) continue;
|
|
3583
|
-
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
3584
|
-
for (const requiredId of resource.getRequireIds()) {
|
|
3585
|
-
if (!requiredId || publishedResourceIds.has(requiredId)) continue;
|
|
3586
|
-
publishedResourceIds.add(requiredId);
|
|
3587
|
-
changed = true;
|
|
3588
|
-
}
|
|
3589
|
-
}
|
|
3590
|
-
}
|
|
4046
|
+
for (const resourceId of collectExportedResourceIds(resources, publishedResourceIds)) publishedResourceIds.add(resourceId);
|
|
4047
|
+
const highResolutionItemIds = collectHighResolutionItemIds(resources, publishedResourceIds, options.includeHighResolution);
|
|
3591
4048
|
if (!options.includeBranches) {
|
|
3592
4049
|
const mainByKey = /* @__PURE__ */ new Map();
|
|
3593
4050
|
const activeBranchByKey = /* @__PURE__ */ new Map();
|
|
@@ -3635,7 +4092,9 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
3635
4092
|
return {
|
|
3636
4093
|
referencedIds,
|
|
3637
4094
|
publishedResourceIds,
|
|
4095
|
+
exportedResourceIds: collectExportedResourceIds(resources, publishedResourceIds),
|
|
3638
4096
|
pixelHitTestImageIds,
|
|
4097
|
+
highResolutionItemIds,
|
|
3639
4098
|
effectiveResourceIds,
|
|
3640
4099
|
includeBranches: false
|
|
3641
4100
|
};
|
|
@@ -3643,7 +4102,9 @@ function collectPackagePublishContext(pkg, options) {
|
|
|
3643
4102
|
return {
|
|
3644
4103
|
referencedIds,
|
|
3645
4104
|
publishedResourceIds,
|
|
4105
|
+
exportedResourceIds: collectExportedResourceIds(resources, publishedResourceIds),
|
|
3646
4106
|
pixelHitTestImageIds,
|
|
4107
|
+
highResolutionItemIds,
|
|
3647
4108
|
effectiveResourceIds: new Map([...publishedResourceIds].map((resourceId) => [resourceId, resourceId])),
|
|
3648
4109
|
includeBranches: true
|
|
3649
4110
|
};
|
|
@@ -3692,28 +4153,36 @@ async function applyPixelHitTests(pkg, imageIds, basePath, encoder) {
|
|
|
3692
4153
|
}
|
|
3693
4154
|
}
|
|
3694
4155
|
async function annotatePackagePublishArtifacts(pkg, basePath, encoder, options) {
|
|
3695
|
-
const { publishedResourceIds, pixelHitTestImageIds, effectiveResourceIds, includeBranches } = collectPackagePublishContext(pkg, options);
|
|
3696
|
-
for (const resource of pkg.listResources())
|
|
4156
|
+
const { publishedResourceIds, exportedResourceIds, pixelHitTestImageIds, highResolutionItemIds, effectiveResourceIds, includeBranches } = collectPackagePublishContext(pkg, options);
|
|
4157
|
+
for (const resource of pkg.listResources()) {
|
|
4158
|
+
setPublishedIdExtra(resource, effectiveResourceIds.get(resource.getId()) ?? null);
|
|
4159
|
+
if (isHighResolutionResource(resource)) resource.setHighResolutionItemIds(highResolutionItemIds.get(resource.getId()) ?? []);
|
|
4160
|
+
}
|
|
3697
4161
|
await applyPixelHitTests(pkg, pixelHitTestImageIds, basePath, encoder);
|
|
3698
4162
|
const extras = pkg.getExtras() ?? {};
|
|
3699
4163
|
pkg.setExtras({
|
|
3700
4164
|
...extras,
|
|
3701
4165
|
publishedResourceIds: [...publishedResourceIds].sort((a, b) => a.localeCompare(b)),
|
|
4166
|
+
exportedResourceIds: [...exportedResourceIds].sort((a, b) => a.localeCompare(b)),
|
|
3702
4167
|
publishedIncludeBranches: includeBranches,
|
|
3703
4168
|
publishedEffectiveResourceIds: Object.fromEntries(effectiveResourceIds)
|
|
3704
4169
|
});
|
|
3705
4170
|
for (const resource of pkg.listResources()) {
|
|
3706
4171
|
if (isMiscResource(resource)) {
|
|
3707
|
-
setPublishedFileExtra(resource, resolvePublishedMiscFileName(resource));
|
|
4172
|
+
setPublishedFileExtra(resource, resolvePublishedMiscFileName(resource, options.projectType));
|
|
3708
4173
|
continue;
|
|
3709
4174
|
}
|
|
3710
|
-
if (isSkeletonResource(resource)) setPublishedFileExtra(resource, resolvePublishedSkeletonFileName(resource));
|
|
4175
|
+
if (isSkeletonResource(resource)) setPublishedFileExtra(resource, resolvePublishedSkeletonFileName(resource, options.projectType));
|
|
3711
4176
|
}
|
|
3712
4177
|
}
|
|
3713
4178
|
function getAnnotatedPublishedResourceIds(pkg) {
|
|
3714
4179
|
const extras = pkg.getExtras() ?? {};
|
|
3715
4180
|
return new Set(extras.publishedResourceIds ?? []);
|
|
3716
4181
|
}
|
|
4182
|
+
function getAnnotatedExportedResourceIds(pkg) {
|
|
4183
|
+
const extras = pkg.getExtras() ?? {};
|
|
4184
|
+
return new Set(extras.exportedResourceIds ?? []);
|
|
4185
|
+
}
|
|
3717
4186
|
function getPublishedSkeletonDependencyImageIds(pkg, publishedResourceIds) {
|
|
3718
4187
|
const imageIds = /* @__PURE__ */ new Set();
|
|
3719
4188
|
const resourcesById = new Map(pkg.listResources().map((resource) => [resource.getId(), resource]));
|
|
@@ -3752,18 +4221,18 @@ async function exportPackageSounds(pkg, outputDir, basePath, fs, readFileRaw, lo
|
|
|
3752
4221
|
}
|
|
3753
4222
|
}
|
|
3754
4223
|
async function exportPackageExternalResources(pkg, outputDir, basePath, fs, readFileRaw, logger) {
|
|
3755
|
-
const
|
|
3756
|
-
const skeletonDependencyImageIds = getPublishedSkeletonDependencyImageIds(pkg,
|
|
3757
|
-
if (
|
|
4224
|
+
const exportedResourceIds = getAnnotatedExportedResourceIds(pkg);
|
|
4225
|
+
const skeletonDependencyImageIds = getPublishedSkeletonDependencyImageIds(pkg, exportedResourceIds);
|
|
4226
|
+
if (exportedResourceIds.size === 0) return;
|
|
3758
4227
|
if (!basePath || !readFileRaw) {
|
|
3759
4228
|
if (pkg.listResources().some((resource) => {
|
|
3760
|
-
return (isMiscResource(resource) || isSkeletonResource(resource)) &&
|
|
4229
|
+
return (isMiscResource(resource) || isSkeletonResource(resource)) && exportedResourceIds.has(resource.getId()) || skeletonDependencyImageIds.has(resource.getId());
|
|
3761
4230
|
})) logger.warn(`publish: External resources in package "${pkg.getName()}" were not exported because basePath/readFileRaw is unavailable.`);
|
|
3762
4231
|
return;
|
|
3763
4232
|
}
|
|
3764
4233
|
for (const resource of pkg.listResources()) {
|
|
3765
4234
|
const resourceId = resource.getId();
|
|
3766
|
-
const isSkeletonExternal =
|
|
4235
|
+
const isSkeletonExternal = exportedResourceIds.has(resourceId) && (isMiscResource(resource) || isSkeletonResource(resource));
|
|
3767
4236
|
const isSkeletonImageDependency = skeletonDependencyImageIds.has(resourceId) && isImageResource(resource);
|
|
3768
4237
|
if (!isSkeletonExternal && !isSkeletonImageDependency) continue;
|
|
3769
4238
|
let sourcePath;
|
|
@@ -3809,16 +4278,102 @@ async function exportPackageExternalResources(pkg, outputDir, basePath, fs, read
|
|
|
3809
4278
|
*/
|
|
3810
4279
|
function publish(options) {
|
|
3811
4280
|
return createTransform("publish", async (doc) => {
|
|
4281
|
+
const resolveConfiguredOutputPath = (value, projectBasePath) => {
|
|
4282
|
+
const trimmed = value?.trim();
|
|
4283
|
+
if (!trimmed) return void 0;
|
|
4284
|
+
if (isAbsolutePathLike(trimmed) || !projectBasePath) return trimTrailingSlashes(trimmed);
|
|
4285
|
+
return trimTrailingSlashes(options.fs ? options.fs.join(projectBasePath, trimmed) : joinPathSegments(projectBasePath, trimmed));
|
|
4286
|
+
};
|
|
4287
|
+
const resolveProjectPublishConfig = () => {
|
|
4288
|
+
const publishSettings = (doc.getRoot().getSettings?.() ?? {}).publish ?? {};
|
|
4289
|
+
const resolved = resolvePublishOptions(doc, {
|
|
4290
|
+
compressed: options.compressed,
|
|
4291
|
+
fileExtension: options.fileExtension,
|
|
4292
|
+
packages: options.packages,
|
|
4293
|
+
atlas: options.atlas
|
|
4294
|
+
});
|
|
4295
|
+
const includeBranches = (publishSettings.branchProcessing ?? 0) === 0;
|
|
4296
|
+
return {
|
|
4297
|
+
...resolved,
|
|
4298
|
+
projectType: doc.getRoot().getProjectType(),
|
|
4299
|
+
includeBranches,
|
|
4300
|
+
activeBranch: includeBranches ? "" : options.branch ?? "",
|
|
4301
|
+
includeHighResolution: publishSettings.includeHighResolution ?? 0,
|
|
4302
|
+
separatedAtlasForBranch: includeBranches && publishSettings.seperatedAtlasForBranch === true,
|
|
4303
|
+
globalOutputPath: publishSettings.path?.trim() ?? "",
|
|
4304
|
+
globalBranchOutputPath: publishSettings.branchPath?.trim() ?? ""
|
|
4305
|
+
};
|
|
4306
|
+
};
|
|
4307
|
+
const resolvePackagePublishPlan = (pkg, config, projectBasePath) => {
|
|
4308
|
+
let outputDir;
|
|
4309
|
+
if (options.output) outputDir = trimTrailingSlashes(options.output);
|
|
4310
|
+
else {
|
|
4311
|
+
const candidates = [];
|
|
4312
|
+
if (!config.includeBranches && config.activeBranch) candidates.push(pkg.getPublishBranchPath(), config.globalBranchOutputPath);
|
|
4313
|
+
candidates.push(pkg.getPublishPath(), config.globalOutputPath);
|
|
4314
|
+
for (const candidate of candidates) {
|
|
4315
|
+
const resolved = resolveConfiguredOutputPath(candidate, projectBasePath);
|
|
4316
|
+
if (!resolved) continue;
|
|
4317
|
+
outputDir = resolved;
|
|
4318
|
+
break;
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
const publishName = pkg.getPublishName() || pkg.getName();
|
|
4322
|
+
return {
|
|
4323
|
+
pkg,
|
|
4324
|
+
outputDir,
|
|
4325
|
+
publishName,
|
|
4326
|
+
fileName: resolvePublishFileName(publishName, config.fileExtension),
|
|
4327
|
+
compressed: config.compressed,
|
|
4328
|
+
fileExtension: config.fileExtension,
|
|
4329
|
+
includeBranches: config.includeBranches,
|
|
4330
|
+
activeBranch: config.activeBranch,
|
|
4331
|
+
includeHighResolution: config.includeHighResolution,
|
|
4332
|
+
separatedAtlasForBranch: config.separatedAtlasForBranch,
|
|
4333
|
+
atlas: config.atlas
|
|
4334
|
+
};
|
|
4335
|
+
};
|
|
4336
|
+
const createNoopPublishFs = () => ({
|
|
4337
|
+
async writeFileRaw() {},
|
|
4338
|
+
async mkdir() {},
|
|
4339
|
+
join(...paths) {
|
|
4340
|
+
return paths.join("/");
|
|
4341
|
+
}
|
|
4342
|
+
});
|
|
4343
|
+
const publishPackage = async (plan, writerFs, packageIndex) => {
|
|
4344
|
+
const atlasRuntimeOptions = resolvePublishAtlasRuntimeOptions(plan.fileExtension);
|
|
4345
|
+
await atlas({
|
|
4346
|
+
...plan.atlas,
|
|
4347
|
+
...options.atlas ?? {},
|
|
4348
|
+
separatedAtlasForBranch: plan.separatedAtlasForBranch,
|
|
4349
|
+
encoder: options.encoder,
|
|
4350
|
+
basePath: options.basePath,
|
|
4351
|
+
outputPath: options.fs ? plan.outputDir : void 0,
|
|
4352
|
+
mkdir: options.fs ? options.fs.mkdir : void 0,
|
|
4353
|
+
readFileRaw: options.atlas?.readFileRaw ?? options.fs?.readFileRaw,
|
|
4354
|
+
packages: [plan.pkg.getName()],
|
|
4355
|
+
...atlasRuntimeOptions
|
|
4356
|
+
})(doc);
|
|
4357
|
+
if (!options.fs) return;
|
|
4358
|
+
if (!plan.outputDir) throw new Error("publish: no output directory resolved. Provide --output, or configure global publish.path / package publishPath.");
|
|
4359
|
+
await options.fs.mkdir(plan.outputDir);
|
|
4360
|
+
const filePath = options.fs.join(plan.outputDir, plan.fileName);
|
|
4361
|
+
const bwOptions = {
|
|
4362
|
+
compressed: plan.compressed,
|
|
4363
|
+
packageIndex
|
|
4364
|
+
};
|
|
4365
|
+
await new _openfairygui_core.BinaryWriter(writerFs).write(doc, filePath, bwOptions);
|
|
4366
|
+
await exportPackageSounds(plan.pkg, plan.outputDir, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
4367
|
+
await exportPackageExternalResources(plan.pkg, plan.outputDir, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
4368
|
+
logger.info(`publish: Written ${plan.fileName}`);
|
|
4369
|
+
};
|
|
3812
4370
|
const root = doc.getRoot();
|
|
3813
4371
|
const logger = doc.getLogger();
|
|
3814
|
-
const
|
|
3815
|
-
const
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
atlas: options.atlas
|
|
3820
|
-
});
|
|
3821
|
-
const ext = resolved.fileExtension;
|
|
4372
|
+
const projectBasePath = resolveProjectBasePath(options.basePath) || doc.getProjectDir?.() || "";
|
|
4373
|
+
const pluginsDir = resolvePublishPluginsDir(doc, options);
|
|
4374
|
+
const plugins = pluginsDir ? await loadPlugins(doc, pluginsDir) : [];
|
|
4375
|
+
await runPublishPluginHook(plugins, "onPublishStart", doc, options);
|
|
4376
|
+
const resolved = resolveProjectPublishConfig();
|
|
3822
4377
|
let allPackages = root.listPackages();
|
|
3823
4378
|
if (resolved.packages && resolved.packages.length > 0) {
|
|
3824
4379
|
const names = new Set(resolved.packages);
|
|
@@ -3826,57 +4381,42 @@ function publish(options) {
|
|
|
3826
4381
|
}
|
|
3827
4382
|
if (allPackages.length === 0) {
|
|
3828
4383
|
logger.warn("publish: No packages to publish.");
|
|
4384
|
+
await runPublishPluginHook(plugins, "onPublishEnd", doc, options);
|
|
3829
4385
|
return;
|
|
3830
4386
|
}
|
|
3831
|
-
const includeBranches = (publishSettings.branchProcessing ?? 0) === 0;
|
|
3832
|
-
const activeBranch = includeBranches ? "" : options.branch ?? "";
|
|
3833
|
-
const atlasRuntimeOptions = resolvePublishAtlasRuntimeOptions(ext);
|
|
3834
4387
|
const allDocPackages = root.listPackages();
|
|
3835
4388
|
const pkgMap = /* @__PURE__ */ new Map();
|
|
3836
4389
|
for (const p of allDocPackages) pkgMap.set(p.getId(), p);
|
|
3837
4390
|
for (const pkg of allPackages) {
|
|
3838
|
-
_computeDependencies(pkg, pkgMap);
|
|
4391
|
+
_computeDependencies(doc, pkg, pkgMap);
|
|
3839
4392
|
await annotatePackagePublishArtifacts(pkg, options.basePath, options.encoder, {
|
|
3840
|
-
|
|
3841
|
-
|
|
4393
|
+
projectType: resolved.projectType,
|
|
4394
|
+
includeBranches: resolved.includeBranches,
|
|
4395
|
+
activeBranch: resolved.activeBranch,
|
|
4396
|
+
includeHighResolution: resolved.includeHighResolution
|
|
3842
4397
|
});
|
|
3843
4398
|
}
|
|
3844
|
-
|
|
3845
|
-
...resolved.atlas,
|
|
3846
|
-
...options.atlas ?? {},
|
|
3847
|
-
separatedAtlasForBranch: includeBranches && publishSettings.seperatedAtlasForBranch === true,
|
|
3848
|
-
encoder: options.encoder,
|
|
3849
|
-
basePath: options.basePath,
|
|
3850
|
-
outputPath: options.fs ? options.output : void 0,
|
|
3851
|
-
mkdir: options.fs ? options.fs.mkdir : void 0,
|
|
3852
|
-
readFileRaw: options.atlas?.readFileRaw ?? options.fs?.readFileRaw,
|
|
3853
|
-
...atlasRuntimeOptions
|
|
3854
|
-
})(doc);
|
|
4399
|
+
const plans = allPackages.map((pkg) => resolvePackagePublishPlan(pkg, resolved, projectBasePath));
|
|
3855
4400
|
if (!options.fs) {
|
|
3856
4401
|
logger.info(`publish: No fs provided — layout computed for ${allPackages.length} package(s), skipping file output.`);
|
|
4402
|
+
const noopWriterFs = toBinaryWriterFileSystem(createNoopPublishFs());
|
|
4403
|
+
for (const plan of plans) await publishPackage(plan, noopWriterFs, allDocPackages.indexOf(plan.pkg));
|
|
4404
|
+
await runPublishPluginHook(plugins, "onPublishEnd", doc, options);
|
|
3857
4405
|
return;
|
|
3858
4406
|
}
|
|
3859
|
-
|
|
4407
|
+
const unresolvedPlan = plans.find((plan) => !plan.outputDir);
|
|
4408
|
+
if (unresolvedPlan) throw new Error(`publish: no output directory resolved for package "${unresolvedPlan.pkg.getName()}". Provide --output, or configure global publish.path / package publishPath.`);
|
|
3860
4409
|
const writerFs = toBinaryWriterFileSystem(options.fs);
|
|
3861
|
-
for (const
|
|
3862
|
-
const pkgIndex = allDocPackages.indexOf(pkg);
|
|
3863
|
-
const fileName = resolvePublishFileName(pkg.getPublishName() || pkg.getName(), ext);
|
|
3864
|
-
const filePath = options.fs.join(options.output, fileName);
|
|
3865
|
-
const bwOptions = {
|
|
3866
|
-
compressed: resolved.compressed,
|
|
3867
|
-
packageIndex: pkgIndex
|
|
3868
|
-
};
|
|
3869
|
-
await new _openfairygui_core.BinaryWriter(writerFs).write(doc, filePath, bwOptions);
|
|
3870
|
-
await exportPackageSounds(pkg, options.output, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
3871
|
-
await exportPackageExternalResources(pkg, options.output, options.basePath, options.fs, options.atlas?.readFileRaw ?? options.fs.readFileRaw, logger);
|
|
3872
|
-
logger.info(`publish: Written ${fileName}`);
|
|
3873
|
-
}
|
|
4410
|
+
for (const plan of plans) await publishPackage(plan, writerFs, allDocPackages.indexOf(plan.pkg));
|
|
3874
4411
|
await publishCodeGeneration(doc, {
|
|
3875
4412
|
basePath: options.basePath,
|
|
3876
4413
|
fs: options.fs,
|
|
3877
|
-
packages: allPackages
|
|
4414
|
+
packages: allPackages,
|
|
4415
|
+
plugins
|
|
3878
4416
|
});
|
|
3879
|
-
|
|
4417
|
+
const publishedTargets = [...new Set(plans.map((plan) => plan.outputDir).filter((value) => Boolean(value)))];
|
|
4418
|
+
logger.info(publishedTargets.length > 0 ? `publish: Published ${allPackages.length} package(s) to ${publishedTargets.join(", ")}` : `publish: Published ${allPackages.length} package(s)`);
|
|
4419
|
+
await runPublishPluginHook(plugins, "onPublishEnd", doc, options);
|
|
3880
4420
|
});
|
|
3881
4421
|
}
|
|
3882
4422
|
/**
|
|
@@ -3884,25 +4424,104 @@ function publish(options) {
|
|
|
3884
4424
|
* The editor only adds dependencies for packages referenced via bitmap font URLs.
|
|
3885
4425
|
* @internal
|
|
3886
4426
|
*/
|
|
3887
|
-
function _computeDependencies(pkg, pkgMap) {
|
|
4427
|
+
function _computeDependencies(doc, pkg, pkgMap) {
|
|
3888
4428
|
const referencedPkgIds = /* @__PURE__ */ new Set();
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4429
|
+
const pkgId = pkg.getId();
|
|
4430
|
+
const packageOrder = new Map(doc.getRoot().listPackages().map((entry, index) => [entry.getId(), index]));
|
|
4431
|
+
const addDependencyPackageId = (dependencyPkgId) => {
|
|
4432
|
+
const normalized = dependencyPkgId?.trim() ?? "";
|
|
4433
|
+
if (!normalized || normalized === pkgId) return;
|
|
4434
|
+
referencedPkgIds.add(normalized);
|
|
4435
|
+
};
|
|
4436
|
+
const extractPackageIdFromUiUrl = (value) => {
|
|
4437
|
+
if (!value.startsWith("ui://")) return null;
|
|
4438
|
+
const rest = value.slice(5);
|
|
4439
|
+
if (!rest) return null;
|
|
4440
|
+
const slashIndex = rest.indexOf("/");
|
|
4441
|
+
if (slashIndex >= 0) return rest.slice(0, slashIndex) || null;
|
|
4442
|
+
if (rest.length >= 8) return rest.slice(0, 8);
|
|
4443
|
+
return null;
|
|
4444
|
+
};
|
|
4445
|
+
const addDependencyPackageIdFromUiValue = (value) => {
|
|
4446
|
+
if (!value || typeof value !== "string") return;
|
|
4447
|
+
addDependencyPackageId(extractPackageIdFromUiUrl(value));
|
|
4448
|
+
};
|
|
4449
|
+
const addDependencyPackageIdsFromText = (value) => {
|
|
4450
|
+
if (!value || typeof value !== "string") return;
|
|
4451
|
+
const matches = value.matchAll(/ui:\/\/([0-9a-z]{8})/giu);
|
|
4452
|
+
for (const match of matches) addDependencyPackageId(match[1] ?? "");
|
|
4453
|
+
};
|
|
4454
|
+
const addDependencyPackageIdsFromUnknown = (value) => {
|
|
4455
|
+
if (Array.isArray(value)) {
|
|
4456
|
+
for (const entry of value) addDependencyPackageIdsFromUnknown(entry);
|
|
4457
|
+
return;
|
|
3897
4458
|
}
|
|
3898
|
-
|
|
4459
|
+
if (typeof value === "string") {
|
|
4460
|
+
addDependencyPackageIdFromUiValue(value);
|
|
4461
|
+
addDependencyPackageIdsFromText(value);
|
|
4462
|
+
}
|
|
4463
|
+
};
|
|
4464
|
+
const addDependencyFontRef = (value) => {
|
|
4465
|
+
if (Array.isArray(value)) {
|
|
4466
|
+
for (const entry of value) addDependencyPackageIdFromUiValue(entry);
|
|
4467
|
+
return;
|
|
4468
|
+
}
|
|
4469
|
+
addDependencyPackageIdFromUiValue(value ?? void 0);
|
|
4470
|
+
};
|
|
3899
4471
|
for (const res of pkg.listResources()) {
|
|
3900
4472
|
if (res.propertyType !== "Component") continue;
|
|
3901
|
-
|
|
4473
|
+
const component = res;
|
|
4474
|
+
for (const child of component.listChildren?.() ?? []) {
|
|
4475
|
+
addDependencyPackageId(child.getPackageId?.());
|
|
4476
|
+
addDependencyFontRef(child.getFont?.());
|
|
4477
|
+
addDependencyPackageIdsFromText(child.getText?.());
|
|
4478
|
+
for (const ref of [
|
|
4479
|
+
child.getUrl?.(),
|
|
4480
|
+
child.getDefaultItem?.(),
|
|
4481
|
+
child.getIcon?.(),
|
|
4482
|
+
child.getSelectedIcon?.(),
|
|
4483
|
+
child.getDropdown?.(),
|
|
4484
|
+
child.getSound?.(),
|
|
4485
|
+
child.getInstanceSound?.(),
|
|
4486
|
+
child.getInstanceIcon?.(),
|
|
4487
|
+
child.getInstanceSelectedIcon?.(),
|
|
4488
|
+
child.getVtScrollBarRes?.(),
|
|
4489
|
+
child.getHzScrollBarRes?.(),
|
|
4490
|
+
child.getHeaderRes?.(),
|
|
4491
|
+
child.getFooterRes?.()
|
|
4492
|
+
]) addDependencyPackageIdFromUiValue(ref);
|
|
4493
|
+
for (const item of child.getInstanceComboItems?.() ?? []) addDependencyPackageIdFromUiValue(item.icon ?? void 0);
|
|
4494
|
+
for (const item of child.getListItems?.() ?? []) {
|
|
4495
|
+
addDependencyPackageIdFromUiValue(item.icon ?? void 0);
|
|
4496
|
+
addDependencyPackageIdFromUiValue(item.url ?? void 0);
|
|
4497
|
+
}
|
|
4498
|
+
for (const gear of child.listGears?.() ?? []) {
|
|
4499
|
+
addDependencyPackageIdsFromUnknown(gear.getValues?.());
|
|
4500
|
+
addDependencyPackageIdsFromUnknown(gear.getDefaultValue?.());
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
addDependencyFontRef(component.getFont?.());
|
|
4504
|
+
for (const ref of [
|
|
4505
|
+
component.getDropdown?.(),
|
|
4506
|
+
component.getHeaderRes?.(),
|
|
4507
|
+
component.getFooterRes?.(),
|
|
4508
|
+
component.getVtScrollBarRes?.(),
|
|
4509
|
+
component.getHzScrollBarRes?.(),
|
|
4510
|
+
component.getSound?.()
|
|
4511
|
+
]) addDependencyPackageIdFromUiValue(ref);
|
|
4512
|
+
for (const transition of component.listTransitions?.() ?? []) for (const item of transition.listItems?.() ?? []) {
|
|
4513
|
+
addDependencyPackageIdsFromUnknown(item.getStartValue?.());
|
|
4514
|
+
addDependencyPackageIdsFromUnknown(item.getEndValue?.());
|
|
4515
|
+
}
|
|
3902
4516
|
}
|
|
3903
4517
|
for (const dep of pkg.listDependencies()) pkg.removeDependency(dep);
|
|
3904
4518
|
if (referencedPkgIds.size > 0) {
|
|
3905
|
-
const sortedIds = [...referencedPkgIds].sort((a, b) =>
|
|
4519
|
+
const sortedIds = [...referencedPkgIds].sort((a, b) => {
|
|
4520
|
+
const orderA = packageOrder.get(a) ?? Number.MAX_SAFE_INTEGER;
|
|
4521
|
+
const orderB = packageOrder.get(b) ?? Number.MAX_SAFE_INTEGER;
|
|
4522
|
+
if (orderA !== orderB) return orderA - orderB;
|
|
4523
|
+
return a.localeCompare(b);
|
|
4524
|
+
});
|
|
3906
4525
|
for (const refId of sortedIds) {
|
|
3907
4526
|
const depPkg = pkgMap.get(refId);
|
|
3908
4527
|
if (depPkg) pkg.addDependency(depPkg);
|
|
@@ -3910,49 +4529,20 @@ function _computeDependencies(pkg, pkgMap) {
|
|
|
3910
4529
|
}
|
|
3911
4530
|
}
|
|
3912
4531
|
//#endregion
|
|
3913
|
-
//#region src/uam-transaction.ts
|
|
3914
|
-
function mapTransactionErrorStage(error) {
|
|
3915
|
-
switch (error.code) {
|
|
3916
|
-
case "transaction_unsupported": return "preflight";
|
|
3917
|
-
case "invalid_uam": return "preflight";
|
|
3918
|
-
case "execution_failure": return error.opIndex === void 0 && error.issues !== void 0 ? "postflight" : "execution";
|
|
3919
|
-
case "selector_ambiguity": return error.opIndex === void 0 ? "preflight" : "execution";
|
|
3920
|
-
}
|
|
3921
|
-
}
|
|
3922
|
-
function applyUamTransactionApp(input) {
|
|
3923
|
-
try {
|
|
3924
|
-
return {
|
|
3925
|
-
ok: true,
|
|
3926
|
-
project: (0, _openfairygui_core.applyUamTransaction)(input.project, input.operations)
|
|
3927
|
-
};
|
|
3928
|
-
} catch (error) {
|
|
3929
|
-
if (error instanceof _openfairygui_core.UamTransactionError) return {
|
|
3930
|
-
ok: false,
|
|
3931
|
-
error: {
|
|
3932
|
-
code: error.code,
|
|
3933
|
-
stage: mapTransactionErrorStage(error),
|
|
3934
|
-
message: error.message,
|
|
3935
|
-
opIndex: error.opIndex,
|
|
3936
|
-
opId: error.opId,
|
|
3937
|
-
opKind: error.opKind,
|
|
3938
|
-
selector: error.selector,
|
|
3939
|
-
issues: error.issues
|
|
3940
|
-
}
|
|
3941
|
-
};
|
|
3942
|
-
throw error;
|
|
3943
|
-
}
|
|
3944
|
-
}
|
|
3945
|
-
//#endregion
|
|
3946
4532
|
exports.AUTO_GENERATED_CODE_MARK = AUTO_GENERATED_CODE_MARK;
|
|
3947
4533
|
exports.ValidationSeverity = ValidationSeverity;
|
|
3948
|
-
exports.applyUamTransactionApp = applyUamTransactionApp;
|
|
4534
|
+
exports.applyUamTransactionApp = require_uam_transaction.applyUamTransactionApp;
|
|
3949
4535
|
exports.atlas = atlas;
|
|
4536
|
+
exports.buildCodegenClasses = buildCodegenClasses;
|
|
3950
4537
|
exports.createTransform = createTransform;
|
|
4538
|
+
exports.decodeText = decodeText;
|
|
4539
|
+
exports.encodeText = encodeText;
|
|
3951
4540
|
exports.inspect = inspect;
|
|
3952
4541
|
exports.prune = prune;
|
|
3953
4542
|
exports.publish = publish;
|
|
3954
4543
|
exports.publishCodeGeneration = publishCodeGeneration;
|
|
3955
4544
|
exports.rename = rename;
|
|
4545
|
+
exports.resolvePackageCodegenPlan = resolvePackageCodegenPlan;
|
|
3956
4546
|
exports.resolvePublishOptions = resolvePublishOptions;
|
|
3957
4547
|
exports.restore = restore;
|
|
3958
4548
|
exports.validate = validate;
|