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