@openfairygui/functions 0.2.0-alpha.2 → 0.2.0-alpha.21
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 +48 -6
- package/dist/atlas-C6tbl7nn.d.ts +193 -0
- package/dist/atlas-CHsu2Y8i.d.cts +193 -0
- package/dist/index.cjs +16 -3603
- package/dist/index.d.cts +5 -294
- package/dist/index.d.ts +5 -294
- package/dist/index.js +3 -3594
- package/dist/node.cjs +256 -0
- package/dist/node.d.cts +36 -0
- package/dist/node.d.ts +36 -0
- package/dist/node.js +254 -0
- package/dist/publish-BJ_eelME.js +3267 -0
- package/dist/publish-xFWT9Slz.cjs +3338 -0
- package/dist/restore-BW2xacB3.cjs +936 -0
- package/dist/restore-BeWaJNjR.d.cts +288 -0
- package/dist/restore-Clk62n0O.js +931 -0
- package/dist/restore-Dh0-Nvms.d.ts +288 -0
- package/dist/uam-transaction.cjs +44 -1
- package/dist/uam-transaction.d.cts +16 -1
- package/dist/uam-transaction.d.ts +16 -1
- package/dist/uam-transaction.js +44 -1
- package/dist/web.cjs +274 -0
- package/dist/web.d.cts +41 -0
- package/dist/web.d.ts +41 -0
- package/dist/web.js +273 -0
- package/package.json +28 -4
- package/src/adapters/node/plugins.ts +82 -0
- package/src/adapters/node/publish.ts +130 -0
- package/src/adapters/node/restore.ts +187 -0
- package/src/adapters/web/publish.ts +159 -0
- package/src/adapters/web/raster.ts +251 -0
- package/src/atlas/font.ts +95 -0
- package/src/atlas/inputs.ts +515 -0
- package/src/atlas/jta.ts +211 -0
- package/src/atlas/packing.ts +767 -0
- package/src/atlas.ts +116 -1221
- package/src/codegen.ts +106 -67
- package/src/index.ts +43 -3
- package/src/node.ts +8 -0
- package/src/plugins/types.ts +56 -0
- package/src/publish/contracts.ts +80 -0
- package/src/publish/external-resources.ts +117 -0
- package/src/publish/options.ts +180 -0
- package/src/publish/package-context.ts +608 -0
- package/src/publish/resource-references.ts +210 -0
- package/src/publish.ts +290 -968
- package/src/restore-internals/font.ts +100 -0
- package/src/restore-internals/movie-clip.ts +104 -0
- package/src/restore-internals/output-transaction.ts +164 -0
- package/src/restore.ts +112 -311
- package/src/shared-types.ts +4 -8
- package/src/uam-transaction.ts +68 -0
- package/src/utils.ts +28 -0
- package/src/web.ts +11 -0
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Component,
|
|
3
|
+
type DragonBonesResource,
|
|
4
|
+
type FontResource,
|
|
5
|
+
type ImageResource,
|
|
6
|
+
type MiscResource,
|
|
7
|
+
type MovieClipResource,
|
|
8
|
+
type Package,
|
|
9
|
+
ProjectType,
|
|
10
|
+
type SoundResource,
|
|
11
|
+
type SpineResource,
|
|
12
|
+
} from '@openfairygui/core';
|
|
13
|
+
import type { AtlasRasterBackend } from './contracts.js';
|
|
14
|
+
import { collectPackageResourceReferences } from './resource-references.js';
|
|
15
|
+
import type { PackagePublishArtifactsExtras } from '../shared-types.js';
|
|
16
|
+
|
|
17
|
+
interface ImageResourceExtras extends Record<string, unknown> {
|
|
18
|
+
_fileName?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PublishFileExtras extends Record<string, unknown> {
|
|
22
|
+
_publishedFile?: string;
|
|
23
|
+
_publishedId?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface BranchAwarePublishedResource {
|
|
27
|
+
getBranch?(): string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface PackagePublishContext {
|
|
31
|
+
referencedIds: Set<string>;
|
|
32
|
+
publishedResourceIds: Set<string>;
|
|
33
|
+
exportedResourceIds: Set<string>;
|
|
34
|
+
pixelHitTestImageIds: Set<string>;
|
|
35
|
+
highResolutionItemIds: Map<string, Array<string | null>>;
|
|
36
|
+
effectiveResourceIds: Map<string, string>;
|
|
37
|
+
includeBranches: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const UNITY_PROJECT_TYPE = ProjectType.Unity;
|
|
41
|
+
|
|
42
|
+
function isComponentResource(resource: ReturnType<Package['listResources']>[number]): resource is Component {
|
|
43
|
+
return resource.propertyType === 'Component';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function isImageResource(resource: ReturnType<Package['listResources']>[number]): resource is ImageResource {
|
|
47
|
+
return resource.propertyType === 'ImageResource';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isMovieClipResource(resource: ReturnType<Package['listResources']>[number]): resource is MovieClipResource {
|
|
51
|
+
return resource.propertyType === 'MovieClipResource';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isHighResolutionResource(
|
|
55
|
+
resource: ReturnType<Package['listResources']>[number],
|
|
56
|
+
): resource is ImageResource | MovieClipResource {
|
|
57
|
+
return isImageResource(resource) || isMovieClipResource(resource);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isMiscResource(resource: ReturnType<Package['listResources']>[number]): resource is MiscResource {
|
|
61
|
+
return resource.propertyType === 'MiscResource';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isFontResource(resource: ReturnType<Package['listResources']>[number]): resource is FontResource {
|
|
65
|
+
return resource.propertyType === 'FontResource';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function isSoundResource(resource: ReturnType<Package['listResources']>[number]): resource is SoundResource {
|
|
69
|
+
return resource.propertyType === 'SoundResource';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isSpineResource(resource: ReturnType<Package['listResources']>[number]): resource is SpineResource {
|
|
73
|
+
return resource.propertyType === 'SpineResource';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isDragonBonesResource(
|
|
77
|
+
resource: ReturnType<Package['listResources']>[number],
|
|
78
|
+
): resource is DragonBonesResource {
|
|
79
|
+
return resource.propertyType === 'DragonBonesResource';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function isSkeletonResource(
|
|
83
|
+
resource: ReturnType<Package['listResources']>[number],
|
|
84
|
+
): resource is SpineResource | DragonBonesResource {
|
|
85
|
+
return isSpineResource(resource) || isDragonBonesResource(resource);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function resolvePackageAssetsBasePath(basePath: string, resource: BranchAwarePublishedResource | undefined): string {
|
|
89
|
+
const branchName = resource?.getBranch?.() ?? '';
|
|
90
|
+
if (!branchName) return basePath;
|
|
91
|
+
const normalized = basePath.replace(/[/\\]+$/, '');
|
|
92
|
+
if (/[\\/]assets$/i.test(normalized)) {
|
|
93
|
+
return normalized.replace(/([\\/])assets$/i, `$1assets_${branchName}`);
|
|
94
|
+
}
|
|
95
|
+
return `${normalized}_${branchName}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function resolveImagePath(resource: ImageResource, pkg: Package, basePath: string): string {
|
|
99
|
+
const fileName = resolveImageFileName(resource);
|
|
100
|
+
const resourcePath = resource.getPath() ?? '/';
|
|
101
|
+
const packageBasePath = resolvePackageAssetsBasePath(basePath, resource);
|
|
102
|
+
return `${packageBasePath}/${pkg.getName()}${resourcePath}${fileName}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function resolveImageFileName(resource: ImageResource): string {
|
|
106
|
+
const extras = (resource.getExtras() as ImageResourceExtras | undefined) ?? {};
|
|
107
|
+
return resource.getFileName() || extras._fileName || resource.getName();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function resolveSoundPath(resource: SoundResource, pkg: Package, basePath: string): string {
|
|
111
|
+
const resourcePath = resource.getPath() ?? '/';
|
|
112
|
+
const packageBasePath = resolvePackageAssetsBasePath(basePath, resource);
|
|
113
|
+
return `${packageBasePath}/${pkg.getName()}${resourcePath}${resource.getFile()}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function resolveGenericResourcePath(
|
|
117
|
+
resource: { getPath(): string; getFile(): string; getBranch?(): string },
|
|
118
|
+
pkg: Package,
|
|
119
|
+
basePath: string,
|
|
120
|
+
): string {
|
|
121
|
+
const resourcePath = resource.getPath() ?? '/';
|
|
122
|
+
const packageBasePath = resolvePackageAssetsBasePath(basePath, resource);
|
|
123
|
+
return `${packageBasePath}/${pkg.getName()}${resourcePath}${resource.getFile()}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function extname(fileName: string): string {
|
|
127
|
+
const normalized = fileName.replace(/\\/g, '/');
|
|
128
|
+
const lastSlash = normalized.lastIndexOf('/');
|
|
129
|
+
const lastDot = normalized.lastIndexOf('.');
|
|
130
|
+
if (lastDot <= lastSlash) return '';
|
|
131
|
+
return normalized.slice(lastDot);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function resolvePublishedMiscFileName(resource: MiscResource, projectType: number): string {
|
|
135
|
+
const file = resource.getFile();
|
|
136
|
+
if (projectType !== UNITY_PROJECT_TYPE) return file;
|
|
137
|
+
if (file.toLowerCase().endsWith('.atlas')) return `${file}.txt`;
|
|
138
|
+
return file;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function resolvePublishedSkeletonFileName(resource: SpineResource | DragonBonesResource, projectType: number): string {
|
|
142
|
+
if (
|
|
143
|
+
projectType === UNITY_PROJECT_TYPE &&
|
|
144
|
+
isSpineResource(resource) &&
|
|
145
|
+
resource.getFile().toLowerCase().endsWith('.skel')
|
|
146
|
+
) {
|
|
147
|
+
return `${resource.getFile()}.bytes`;
|
|
148
|
+
}
|
|
149
|
+
return resource.getFile();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function setPublishedFileExtra(
|
|
153
|
+
resource: { getExtras(): Record<string, unknown> | undefined; setExtras(value: Record<string, unknown>): unknown },
|
|
154
|
+
fileName: string,
|
|
155
|
+
): void {
|
|
156
|
+
const extras = (resource.getExtras() as PublishFileExtras | undefined) ?? {};
|
|
157
|
+
resource.setExtras({
|
|
158
|
+
...extras,
|
|
159
|
+
_publishedFile: fileName,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function setPublishedIdExtra(
|
|
164
|
+
resource: {
|
|
165
|
+
getId(): string;
|
|
166
|
+
getExtras(): Record<string, unknown> | undefined;
|
|
167
|
+
setExtras(value: Record<string, unknown>): unknown;
|
|
168
|
+
},
|
|
169
|
+
effectiveId: string | null,
|
|
170
|
+
): void {
|
|
171
|
+
const extras = (resource.getExtras() as PublishFileExtras | undefined) ?? {};
|
|
172
|
+
if (!effectiveId || effectiveId === resource.getId()) {
|
|
173
|
+
if (!('_publishedId' in extras)) return;
|
|
174
|
+
const { _publishedId: _ignored, ...rest } = extras;
|
|
175
|
+
resource.setExtras(rest);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
resource.setExtras({
|
|
179
|
+
...extras,
|
|
180
|
+
_publishedId: effectiveId,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function getPublishedId(resource: { getId(): string; getExtras(): Record<string, unknown> | undefined }): string {
|
|
185
|
+
const extras = (resource.getExtras() as PublishFileExtras | undefined) ?? {};
|
|
186
|
+
return extras._publishedId ?? resource.getId();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getBranchName(resource: BranchAwarePublishedResource | undefined): string {
|
|
190
|
+
return resource?.getBranch?.() ?? '';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function buildBranchResourceKey(resource: { propertyType: string; getPath(): string; getName(): string }): string {
|
|
194
|
+
return `${resource.propertyType}|${resource.getPath() ?? ''}|${resource.getName() ?? ''}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const HIGH_RESOLUTION_LEVELS = [
|
|
198
|
+
{ scale: 2, bit: 1, slot: 0 },
|
|
199
|
+
{ scale: 3, bit: 2, slot: 1 },
|
|
200
|
+
{ scale: 4, bit: 4, slot: 2 },
|
|
201
|
+
] as const;
|
|
202
|
+
|
|
203
|
+
function buildHighResolutionResourceKey(
|
|
204
|
+
resource: {
|
|
205
|
+
propertyType: string;
|
|
206
|
+
getPath(): string;
|
|
207
|
+
getName(): string;
|
|
208
|
+
getBranch?(): string;
|
|
209
|
+
},
|
|
210
|
+
name = resource.getName(),
|
|
211
|
+
): string {
|
|
212
|
+
return `${resource.propertyType}|${resource.getBranch?.() ?? ''}|${resource.getPath() ?? ''}|${name}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function isHighResolutionVariantName(name: string): boolean {
|
|
216
|
+
return /@(?:2|3|4)x(?:\.[^./\\]+)?$/iu.test(name);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function appendHighResolutionScaleToName(name: string, scale: number): string {
|
|
220
|
+
const extensionIndex = name.lastIndexOf('.');
|
|
221
|
+
if (extensionIndex > 0) {
|
|
222
|
+
return `${name.slice(0, extensionIndex)}@${scale}x${name.slice(extensionIndex)}`;
|
|
223
|
+
}
|
|
224
|
+
return `${name}@${scale}x`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function trimTrailingMissingHighResolutionIds(ids: Array<string | null>): Array<string | null> {
|
|
228
|
+
while (ids.length > 0 && !ids[ids.length - 1]) {
|
|
229
|
+
ids.pop();
|
|
230
|
+
}
|
|
231
|
+
return ids;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function collectHighResolutionItemIds(
|
|
235
|
+
resources: ReturnType<Package['listResources']>,
|
|
236
|
+
publishedResourceIds: Set<string>,
|
|
237
|
+
includeHighResolution: number,
|
|
238
|
+
): Map<string, Array<string | null>> {
|
|
239
|
+
const result = new Map<string, Array<string | null>>();
|
|
240
|
+
if (includeHighResolution <= 0) return result;
|
|
241
|
+
|
|
242
|
+
const highResolutionResourceByKey = new Map<string, ImageResource | MovieClipResource>();
|
|
243
|
+
for (const resource of resources) {
|
|
244
|
+
if (!isHighResolutionResource(resource)) continue;
|
|
245
|
+
highResolutionResourceByKey.set(buildHighResolutionResourceKey(resource), resource);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const resource of resources) {
|
|
249
|
+
if (!isHighResolutionResource(resource)) continue;
|
|
250
|
+
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
251
|
+
if (isHighResolutionVariantName(resource.getName())) continue;
|
|
252
|
+
|
|
253
|
+
const ids: Array<string | null> = [];
|
|
254
|
+
for (const level of HIGH_RESOLUTION_LEVELS) {
|
|
255
|
+
if ((includeHighResolution & level.bit) === 0) {
|
|
256
|
+
ids[level.slot] = null;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const highResolutionResource = highResolutionResourceByKey.get(
|
|
261
|
+
buildHighResolutionResourceKey(
|
|
262
|
+
resource,
|
|
263
|
+
appendHighResolutionScaleToName(resource.getName(), level.scale),
|
|
264
|
+
),
|
|
265
|
+
);
|
|
266
|
+
if (!highResolutionResource) {
|
|
267
|
+
ids[level.slot] = null;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const highResolutionId = highResolutionResource.getId();
|
|
272
|
+
publishedResourceIds.add(highResolutionId);
|
|
273
|
+
ids[level.slot] = highResolutionId;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
trimTrailingMissingHighResolutionIds(ids);
|
|
277
|
+
if (ids.length > 0) result.set(resource.getId(), ids);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function collectPackagePublishContext(
|
|
284
|
+
pkg: Package,
|
|
285
|
+
options: {
|
|
286
|
+
projectType: number;
|
|
287
|
+
includeBranches: boolean;
|
|
288
|
+
activeBranch: string;
|
|
289
|
+
includeHighResolution: number;
|
|
290
|
+
},
|
|
291
|
+
): PackagePublishContext {
|
|
292
|
+
const resources = pkg.listResources();
|
|
293
|
+
const resourceMap = new Map(resources.map((resource) => [resource.getId(), resource]));
|
|
294
|
+
const referencedIds = collectPackageResourceReferences(pkg).localResourceIds;
|
|
295
|
+
const pixelHitTestImageIds = new Set<string>();
|
|
296
|
+
const spriteItemIds = new Set<string>();
|
|
297
|
+
const collectExportedResourceIds = (
|
|
298
|
+
sourceResources: ReturnType<Package['listResources']>,
|
|
299
|
+
sourcePublishedResourceIds: Set<string>,
|
|
300
|
+
): Set<string> => {
|
|
301
|
+
const exportedResourceIds = new Set<string>(sourcePublishedResourceIds);
|
|
302
|
+
const resourcesById = new Map(sourceResources.map((resource) => [resource.getId(), resource] as const));
|
|
303
|
+
let changed = true;
|
|
304
|
+
while (changed) {
|
|
305
|
+
changed = false;
|
|
306
|
+
for (const resourceId of [...exportedResourceIds]) {
|
|
307
|
+
const resource = resourcesById.get(resourceId);
|
|
308
|
+
if (!resource || !isSkeletonResource(resource)) continue;
|
|
309
|
+
for (const requiredId of resource.getRequireIds()) {
|
|
310
|
+
if (!requiredId || exportedResourceIds.has(requiredId)) continue;
|
|
311
|
+
exportedResourceIds.add(requiredId);
|
|
312
|
+
changed = true;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return exportedResourceIds;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
for (const atlas of pkg.listAtlases()) {
|
|
320
|
+
for (const sprite of atlas.listSprites()) {
|
|
321
|
+
spriteItemIds.add(sprite.getItemId());
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
for (const resource of resources) {
|
|
326
|
+
if (!isComponentResource(resource)) continue;
|
|
327
|
+
const component = resource;
|
|
328
|
+
const children = component.listChildren();
|
|
329
|
+
const childMap = new Map(children.map((child) => [child.getId?.() ?? '', child]));
|
|
330
|
+
|
|
331
|
+
const hitTest = component.getHitTest?.()?.trim();
|
|
332
|
+
if (hitTest && !hitTest.includes(',')) {
|
|
333
|
+
const targetChild = childMap.get(hitTest);
|
|
334
|
+
const sourceId = targetChild?.getSrc?.();
|
|
335
|
+
if (sourceId) {
|
|
336
|
+
const sourceResource = resourceMap.get(sourceId);
|
|
337
|
+
if (sourceResource && isImageResource(sourceResource)) {
|
|
338
|
+
pixelHitTestImageIds.add(sourceId);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const publishedResourceIds = new Set<string>(spriteItemIds);
|
|
345
|
+
for (const resource of resources) {
|
|
346
|
+
const resourceId = resource.getId();
|
|
347
|
+
if (!resourceId) continue;
|
|
348
|
+
if (isComponentResource(resource)) {
|
|
349
|
+
if (resource.getExported() || referencedIds.has(resourceId)) {
|
|
350
|
+
publishedResourceIds.add(resourceId);
|
|
351
|
+
}
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
if (isImageResource(resource)) {
|
|
355
|
+
if (
|
|
356
|
+
resource.getExported() ||
|
|
357
|
+
referencedIds.has(resourceId) ||
|
|
358
|
+
spriteItemIds.has(resourceId) ||
|
|
359
|
+
pixelHitTestImageIds.has(resourceId)
|
|
360
|
+
) {
|
|
361
|
+
publishedResourceIds.add(resourceId);
|
|
362
|
+
}
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
if (isMovieClipResource(resource) || isSoundResource(resource)) {
|
|
366
|
+
if (resource.getExported() || referencedIds.has(resourceId)) publishedResourceIds.add(resourceId);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
if (isMiscResource(resource) || isSkeletonResource(resource)) {
|
|
370
|
+
if (resource.getExported() || referencedIds.has(resourceId)) publishedResourceIds.add(resourceId);
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (isFontResource(resource)) {
|
|
374
|
+
if (resource.getExported() || referencedIds.has(resourceId)) {
|
|
375
|
+
publishedResourceIds.add(resourceId);
|
|
376
|
+
}
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
const genericResource = resource as ReturnType<Package['listResources']>[number];
|
|
380
|
+
if (genericResource.getExported() || referencedIds.has(resourceId)) {
|
|
381
|
+
publishedResourceIds.add(resourceId);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (const resourceId of collectExportedResourceIds(resources, publishedResourceIds)) {
|
|
386
|
+
publishedResourceIds.add(resourceId);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const highResolutionItemIds = collectHighResolutionItemIds(
|
|
390
|
+
resources,
|
|
391
|
+
publishedResourceIds,
|
|
392
|
+
options.includeHighResolution,
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
if (!options.includeBranches) {
|
|
396
|
+
const mainByKey = new Map<string, ReturnType<Package['listResources']>[number]>();
|
|
397
|
+
const activeBranchByKey = new Map<string, ReturnType<Package['listResources']>[number]>();
|
|
398
|
+
for (const resource of resources) {
|
|
399
|
+
const branchName = getBranchName(resource);
|
|
400
|
+
const key = buildBranchResourceKey(resource);
|
|
401
|
+
if (!branchName) {
|
|
402
|
+
mainByKey.set(key, resource);
|
|
403
|
+
} else if (branchName === options.activeBranch) {
|
|
404
|
+
activeBranchByKey.set(key, resource);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const mergedPublishedResourceIds = new Set<string>();
|
|
409
|
+
const effectiveResourceIds = new Map<string, string>();
|
|
410
|
+
for (const resource of resources) {
|
|
411
|
+
const resourceId = resource.getId();
|
|
412
|
+
if (!publishedResourceIds.has(resourceId)) continue;
|
|
413
|
+
|
|
414
|
+
const branchName = getBranchName(resource);
|
|
415
|
+
const key = buildBranchResourceKey(resource);
|
|
416
|
+
if (branchName) {
|
|
417
|
+
if (branchName !== options.activeBranch) continue;
|
|
418
|
+
const mainResource = mainByKey.get(key);
|
|
419
|
+
mergedPublishedResourceIds.add(resourceId);
|
|
420
|
+
effectiveResourceIds.set(resourceId, mainResource?.getId() ?? resourceId);
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const override = activeBranchByKey.get(key);
|
|
425
|
+
if (override) {
|
|
426
|
+
mergedPublishedResourceIds.add(override.getId());
|
|
427
|
+
effectiveResourceIds.set(override.getId(), resourceId);
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
mergedPublishedResourceIds.add(resourceId);
|
|
432
|
+
effectiveResourceIds.set(resourceId, resourceId);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
publishedResourceIds.clear();
|
|
436
|
+
for (const resourceId of mergedPublishedResourceIds) {
|
|
437
|
+
publishedResourceIds.add(resourceId);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const mergedPixelHitTestImageIds = new Set<string>();
|
|
441
|
+
for (const resource of resources) {
|
|
442
|
+
if (!isImageResource(resource)) continue;
|
|
443
|
+
const resourceId = resource.getId();
|
|
444
|
+
if (!publishedResourceIds.has(resourceId)) continue;
|
|
445
|
+
const effectiveId = effectiveResourceIds.get(resourceId) ?? resourceId;
|
|
446
|
+
if (pixelHitTestImageIds.has(effectiveId)) {
|
|
447
|
+
mergedPixelHitTestImageIds.add(resourceId);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
pixelHitTestImageIds.clear();
|
|
451
|
+
for (const resourceId of mergedPixelHitTestImageIds) {
|
|
452
|
+
pixelHitTestImageIds.add(resourceId);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return {
|
|
456
|
+
referencedIds,
|
|
457
|
+
publishedResourceIds,
|
|
458
|
+
exportedResourceIds: collectExportedResourceIds(resources, publishedResourceIds),
|
|
459
|
+
pixelHitTestImageIds,
|
|
460
|
+
highResolutionItemIds,
|
|
461
|
+
effectiveResourceIds,
|
|
462
|
+
includeBranches: false,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
referencedIds,
|
|
468
|
+
publishedResourceIds,
|
|
469
|
+
exportedResourceIds: collectExportedResourceIds(resources, publishedResourceIds),
|
|
470
|
+
pixelHitTestImageIds,
|
|
471
|
+
highResolutionItemIds,
|
|
472
|
+
effectiveResourceIds: new Map([...publishedResourceIds].map((resourceId) => [resourceId, resourceId])),
|
|
473
|
+
includeBranches: true,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async function applyPixelHitTests(
|
|
478
|
+
pkg: Package,
|
|
479
|
+
imageIds: Set<string>,
|
|
480
|
+
basePath: string | undefined,
|
|
481
|
+
encoder: AtlasRasterBackend | undefined,
|
|
482
|
+
): Promise<void> {
|
|
483
|
+
const images = pkg.listImageResources();
|
|
484
|
+
for (const image of images) {
|
|
485
|
+
image.setPixelHitTestData(null);
|
|
486
|
+
}
|
|
487
|
+
if (!basePath || !encoder || imageIds.size === 0) return;
|
|
488
|
+
|
|
489
|
+
for (const image of images) {
|
|
490
|
+
const imageId = image.getId();
|
|
491
|
+
if (!imageIds.has(imageId)) continue;
|
|
492
|
+
try {
|
|
493
|
+
const sourcePath = resolveImagePath(image, pkg, basePath);
|
|
494
|
+
const metadata = await encoder(sourcePath).metadata();
|
|
495
|
+
if (!metadata.width || !metadata.height) continue;
|
|
496
|
+
|
|
497
|
+
const resizedWidth = Math.max(1, Math.floor(metadata.width / 2));
|
|
498
|
+
const resizedHeight = Math.max(1, Math.floor(metadata.height / 2));
|
|
499
|
+
const { data, info } = await encoder(sourcePath)
|
|
500
|
+
.ensureAlpha()
|
|
501
|
+
.resize({
|
|
502
|
+
width: resizedWidth,
|
|
503
|
+
height: resizedHeight,
|
|
504
|
+
fit: 'fill',
|
|
505
|
+
})
|
|
506
|
+
.raw()
|
|
507
|
+
.toBuffer({ resolveWithObject: true });
|
|
508
|
+
|
|
509
|
+
const pixelCount = info.width * info.height;
|
|
510
|
+
const maskBytes = new Uint8Array(Math.ceil(pixelCount / 8));
|
|
511
|
+
let byteValue = 0;
|
|
512
|
+
let bitIndex = 0;
|
|
513
|
+
let maskIndex = 0;
|
|
514
|
+
|
|
515
|
+
for (let pixel = 0; pixel < pixelCount; pixel++) {
|
|
516
|
+
const alpha = data[pixel * info.channels + 3];
|
|
517
|
+
if (alpha > 10) byteValue |= 1 << bitIndex;
|
|
518
|
+
bitIndex++;
|
|
519
|
+
if (bitIndex === 8) {
|
|
520
|
+
maskBytes[maskIndex++] = byteValue;
|
|
521
|
+
bitIndex = 0;
|
|
522
|
+
byteValue = 0;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (bitIndex !== 0) {
|
|
526
|
+
maskBytes[maskIndex] = byteValue;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
image.setPixelHitTestData({
|
|
530
|
+
pixelWidth: info.width,
|
|
531
|
+
scaleDenominator: 2,
|
|
532
|
+
pixels: maskBytes,
|
|
533
|
+
});
|
|
534
|
+
} catch {
|
|
535
|
+
image.setPixelHitTestData(null);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export async function annotatePackagePublishArtifacts(
|
|
541
|
+
pkg: Package,
|
|
542
|
+
basePath: string | undefined,
|
|
543
|
+
encoder: AtlasRasterBackend | undefined,
|
|
544
|
+
options: {
|
|
545
|
+
projectType: number;
|
|
546
|
+
includeBranches: boolean;
|
|
547
|
+
activeBranch: string;
|
|
548
|
+
includeHighResolution: number;
|
|
549
|
+
},
|
|
550
|
+
): Promise<void> {
|
|
551
|
+
const {
|
|
552
|
+
publishedResourceIds,
|
|
553
|
+
exportedResourceIds,
|
|
554
|
+
pixelHitTestImageIds,
|
|
555
|
+
highResolutionItemIds,
|
|
556
|
+
effectiveResourceIds,
|
|
557
|
+
includeBranches,
|
|
558
|
+
} = collectPackagePublishContext(pkg, options);
|
|
559
|
+
for (const resource of pkg.listResources()) {
|
|
560
|
+
setPublishedIdExtra(resource, effectiveResourceIds.get(resource.getId()) ?? null);
|
|
561
|
+
if (isHighResolutionResource(resource)) {
|
|
562
|
+
resource.setHighResolutionItemIds(highResolutionItemIds.get(resource.getId()) ?? []);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
await applyPixelHitTests(pkg, pixelHitTestImageIds, basePath, encoder);
|
|
566
|
+
const extras = (pkg.getExtras() as PackagePublishArtifactsExtras | undefined) ?? {};
|
|
567
|
+
pkg.setExtras({
|
|
568
|
+
...extras,
|
|
569
|
+
publishedResourceIds: [...publishedResourceIds].sort((a, b) => a.localeCompare(b)),
|
|
570
|
+
exportedResourceIds: [...exportedResourceIds].sort((a, b) => a.localeCompare(b)),
|
|
571
|
+
publishedIncludeBranches: includeBranches,
|
|
572
|
+
publishedEffectiveResourceIds: Object.fromEntries(effectiveResourceIds),
|
|
573
|
+
});
|
|
574
|
+
for (const resource of pkg.listResources()) {
|
|
575
|
+
if (isMiscResource(resource)) {
|
|
576
|
+
setPublishedFileExtra(resource, resolvePublishedMiscFileName(resource, options.projectType));
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
if (isSkeletonResource(resource)) {
|
|
580
|
+
setPublishedFileExtra(resource, resolvePublishedSkeletonFileName(resource, options.projectType));
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export function getAnnotatedPublishedResourceIds(pkg: Package): Set<string> {
|
|
586
|
+
const extras = (pkg.getExtras() as PackagePublishArtifactsExtras | undefined) ?? {};
|
|
587
|
+
return new Set(extras.publishedResourceIds ?? []);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
export function getAnnotatedExportedResourceIds(pkg: Package): Set<string> {
|
|
591
|
+
const extras = (pkg.getExtras() as PackagePublishArtifactsExtras | undefined) ?? {};
|
|
592
|
+
return new Set(extras.exportedResourceIds ?? []);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
export function getPublishedSkeletonDependencyImageIds(pkg: Package, publishedResourceIds: Set<string>): Set<string> {
|
|
596
|
+
const imageIds = new Set<string>();
|
|
597
|
+
const resourcesById = new Map(pkg.listResources().map((resource) => [resource.getId(), resource] as const));
|
|
598
|
+
for (const resource of pkg.listResources()) {
|
|
599
|
+
if (!isSkeletonResource(resource)) continue;
|
|
600
|
+
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
601
|
+
for (const requiredId of resource.getRequireIds()) {
|
|
602
|
+
if (!requiredId) continue;
|
|
603
|
+
const required = resourcesById.get(requiredId);
|
|
604
|
+
if (required && isImageResource(required)) imageIds.add(requiredId);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return imageIds;
|
|
608
|
+
}
|