@openfairygui/functions 0.2.0-alpha.11 → 0.2.0-alpha.13
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 +28 -3
- package/dist/atlas-CDn6TirX.d.ts +193 -0
- package/dist/atlas-CHsu2Y8i.d.cts +193 -0
- package/dist/codegen-C7PPZrB3.d.cts +241 -0
- package/dist/codegen-CEnmtjBP.d.ts +241 -0
- package/dist/index.cjs +41 -3429
- package/dist/index.d.cts +4 -337
- package/dist/index.d.ts +4 -337
- package/dist/index.js +29 -3417
- package/dist/node.cjs +128 -0
- package/dist/node.d.cts +31 -0
- package/dist/node.d.ts +31 -0
- package/dist/node.js +127 -0
- package/dist/publish-Bl-GK9kt.js +3337 -0
- package/dist/publish-CtCXsMdj.cjs +3408 -0
- package/dist/web.cjs +272 -0
- package/dist/web.d.cts +41 -0
- package/dist/web.d.ts +41 -0
- package/dist/web.js +271 -0
- package/package.json +24 -4
- package/src/{plugins/loader.ts → adapters/node/plugins.ts} +8 -11
- package/src/adapters/node/publish.ts +129 -0
- package/src/adapters/web/publish.ts +404 -0
- package/src/atlas.ts +236 -144
- package/src/codegen.ts +3 -2
- package/src/index.ts +19 -3
- package/src/node.ts +4 -0
- package/src/plugins/types.ts +9 -0
- package/src/publish/contracts.ts +80 -0
- package/src/publish.ts +131 -102
- package/src/shared-types.ts +3 -8
- package/src/web.ts +11 -0
package/src/codegen.ts
CHANGED
|
@@ -12,8 +12,9 @@ import {
|
|
|
12
12
|
UNITY_BINDER_TEMPLATE,
|
|
13
13
|
UNITY_COMPONENT_TEMPLATE,
|
|
14
14
|
} from './codegen-templates.js';
|
|
15
|
-
import { formatPluginError, type LoadedPlugin } from './plugins/
|
|
16
|
-
import type {
|
|
15
|
+
import { formatPluginError, type LoadedPlugin } from './plugins/types.js';
|
|
16
|
+
import type { PublishFileSystem } from './publish/contracts.js';
|
|
17
|
+
import type { CliCodeGenerationSettings, RootProjectSettings } from './shared-types.js';
|
|
17
18
|
|
|
18
19
|
export const AUTO_GENERATED_CODE_MARK = '/** This is an automatically generated class by FairyGUI. Please do not modify it. **/';
|
|
19
20
|
const DEFAULT_CLASS_NAME_PREFIX = 'UI_';
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export { inspect, type InspectReport, type InspectCategoryReport } from './inspect.js';
|
|
2
|
-
export {
|
|
2
|
+
export {
|
|
3
|
+
validate,
|
|
4
|
+
type ValidateOptions,
|
|
5
|
+
type ValidationResult,
|
|
6
|
+
type ValidationIssue,
|
|
7
|
+
ValidationSeverity,
|
|
8
|
+
} from './validate.js';
|
|
3
9
|
export { prune, type PruneOptions } from './prune.js';
|
|
4
10
|
export { rename, type RenameOptions } from './rename.js';
|
|
5
11
|
export { atlas, type AtlasOptions } from './atlas.js';
|
|
@@ -17,15 +23,26 @@ export {
|
|
|
17
23
|
decodeText,
|
|
18
24
|
} from './codegen.js';
|
|
19
25
|
|
|
20
|
-
|
|
21
26
|
export type {
|
|
22
27
|
CodeWriter,
|
|
23
28
|
ICodeWriterConfig,
|
|
24
29
|
MaybePromise,
|
|
30
|
+
LoadedPlugin,
|
|
25
31
|
Plugin,
|
|
26
32
|
PluginManifest,
|
|
27
33
|
PluginModule,
|
|
28
34
|
} from './plugins/types.js';
|
|
35
|
+
export type {
|
|
36
|
+
AtlasRasterBackend,
|
|
37
|
+
AtlasRasterCompositeInput,
|
|
38
|
+
AtlasRasterInput,
|
|
39
|
+
AtlasRasterMetadata,
|
|
40
|
+
AtlasRasterPipeline,
|
|
41
|
+
AtlasRasterResolvedBuffer,
|
|
42
|
+
PublishFileSystem,
|
|
43
|
+
PublishOutputFileSystem,
|
|
44
|
+
PublishSourceFileSystem,
|
|
45
|
+
} from './publish/contracts.js';
|
|
29
46
|
export {
|
|
30
47
|
restore,
|
|
31
48
|
type RestoreFileSystem,
|
|
@@ -60,7 +77,6 @@ export type {
|
|
|
60
77
|
HasOptionalSrc,
|
|
61
78
|
HasOptionalUrl,
|
|
62
79
|
PublishDependency,
|
|
63
|
-
PublishFileSystem,
|
|
64
80
|
RootProjectSettings,
|
|
65
81
|
CliCodeGenerationSettings,
|
|
66
82
|
} from './shared-types.js';
|
package/src/node.ts
ADDED
package/src/plugins/types.ts
CHANGED
|
@@ -44,4 +44,13 @@ export interface Plugin {
|
|
|
44
44
|
onPublishEnd?: (doc: Document, options: PublishOptions) => MaybePromise<void>;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
export interface LoadedPlugin {
|
|
48
|
+
name: string;
|
|
49
|
+
plugin: Plugin;
|
|
50
|
+
}
|
|
51
|
+
|
|
47
52
|
export type PluginModule = Plugin & { default?: Plugin };
|
|
53
|
+
|
|
54
|
+
export function formatPluginError(error: unknown): string {
|
|
55
|
+
return error instanceof Error ? error.message : String(error);
|
|
56
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { FileSystem } from '@openfairygui/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Source files required by a publish adapter.
|
|
5
|
+
*
|
|
6
|
+
* The host owns this filesystem: Node adapters use native paths while web
|
|
7
|
+
* adapters can use File System Access, OPFS, IndexedDB, ZIP, or memory.
|
|
8
|
+
*/
|
|
9
|
+
export type PublishSourceFileSystem = Pick<FileSystem, 'readFileRaw' | 'join'>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Output files required by a publish adapter.
|
|
13
|
+
*/
|
|
14
|
+
export type PublishOutputFileSystem = Pick<FileSystem, 'writeFileRaw' | 'mkdir' | 'join'>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Full filesystem contract consumed by the capability-injected publish core.
|
|
18
|
+
*
|
|
19
|
+
* Read, enumeration, and delete operations are optional because individual
|
|
20
|
+
* publish lanes only request them when needed.
|
|
21
|
+
*/
|
|
22
|
+
export type PublishFileSystem = PublishOutputFileSystem & {
|
|
23
|
+
deleteFile?: (path: string) => Promise<void>;
|
|
24
|
+
exists?: FileSystem['exists'];
|
|
25
|
+
readdir?: FileSystem['readdir'];
|
|
26
|
+
readFileRaw?: FileSystem['readFileRaw'];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export interface AtlasRasterMetadata {
|
|
30
|
+
width?: number;
|
|
31
|
+
height?: number;
|
|
32
|
+
channels?: number;
|
|
33
|
+
hasAlpha?: boolean;
|
|
34
|
+
trimOffsetLeft?: number;
|
|
35
|
+
trimOffsetTop?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface AtlasRasterResolvedBuffer {
|
|
39
|
+
data: Uint8Array;
|
|
40
|
+
info: Required<Pick<AtlasRasterMetadata, 'width' | 'height' | 'channels'>> & AtlasRasterMetadata;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AtlasRasterCompositeInput {
|
|
44
|
+
input: Uint8Array;
|
|
45
|
+
left: number;
|
|
46
|
+
top: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type AtlasRasterInput =
|
|
50
|
+
| string
|
|
51
|
+
| Uint8Array
|
|
52
|
+
| {
|
|
53
|
+
create: {
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
channels: 4;
|
|
57
|
+
background: { r: number; g: number; b: number; alpha: number };
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Host-provided raster pipeline used by atlas packing.
|
|
63
|
+
*
|
|
64
|
+
* Sharp and the browser Canvas adapter both satisfy this contract.
|
|
65
|
+
*/
|
|
66
|
+
export interface AtlasRasterPipeline {
|
|
67
|
+
ensureAlpha(): AtlasRasterPipeline;
|
|
68
|
+
resize(options: { width: number; height: number; fit?: 'fill' }): AtlasRasterPipeline;
|
|
69
|
+
raw(): AtlasRasterPipeline;
|
|
70
|
+
extract(options: { left: number; top: number; width: number; height: number }): AtlasRasterPipeline;
|
|
71
|
+
png(): AtlasRasterPipeline;
|
|
72
|
+
rotate(angle: number): AtlasRasterPipeline;
|
|
73
|
+
composite(inputs: AtlasRasterCompositeInput[]): AtlasRasterPipeline;
|
|
74
|
+
metadata(): Promise<AtlasRasterMetadata>;
|
|
75
|
+
toBuffer(options: { resolveWithObject: true }): Promise<AtlasRasterResolvedBuffer>;
|
|
76
|
+
toBuffer(options?: { resolveWithObject?: false }): Promise<Uint8Array>;
|
|
77
|
+
toFile(path: string): Promise<unknown>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type AtlasRasterBackend = (input: AtlasRasterInput) => AtlasRasterPipeline;
|
package/src/publish.ts
CHANGED
|
@@ -18,12 +18,12 @@ import {
|
|
|
18
18
|
import { createTransform } from './utils.js';
|
|
19
19
|
import { atlas, type AtlasOptions } from './atlas.js';
|
|
20
20
|
import { publishCodeGeneration, resolveProjectBasePath } from './codegen.js';
|
|
21
|
-
import { formatPluginError,
|
|
21
|
+
import { formatPluginError, type LoadedPlugin } from './plugins/types.js';
|
|
22
|
+
import type { AtlasRasterBackend, PublishFileSystem } from './publish/contracts.js';
|
|
22
23
|
import type {
|
|
23
24
|
CliPublishSettings,
|
|
24
25
|
HasOptionalFont,
|
|
25
26
|
PackagePublishArtifactsExtras,
|
|
26
|
-
PublishFileSystem,
|
|
27
27
|
RootProjectSettings,
|
|
28
28
|
} from './shared-types.js';
|
|
29
29
|
|
|
@@ -46,10 +46,10 @@ export interface PublishOptions {
|
|
|
46
46
|
fileExtension?: string;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* Raster backend for atlas image compositing.
|
|
50
50
|
* If not provided, atlas packing only computes layout (no PNGs generated).
|
|
51
51
|
*/
|
|
52
|
-
encoder?:
|
|
52
|
+
encoder?: AtlasRasterBackend;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Base path for reading source images (project assets root).
|
|
@@ -79,9 +79,33 @@ export interface PublishOptions {
|
|
|
79
79
|
* Empty or omitted means publishing the main branch.
|
|
80
80
|
*/
|
|
81
81
|
branch?: string;
|
|
82
|
-
}
|
|
83
82
|
|
|
84
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Publish hooks supplied by the host adapter.
|
|
85
|
+
*
|
|
86
|
+
* Node adapters load project plugins. Browser adapters pass an empty list.
|
|
87
|
+
*/
|
|
88
|
+
plugins?: LoadedPlugin[];
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Run generic code generation after runtime artifacts. Default: true.
|
|
92
|
+
*/
|
|
93
|
+
codeGeneration?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ResolvedPublishAtlasOptions
|
|
97
|
+
extends Pick<
|
|
98
|
+
AtlasOptions,
|
|
99
|
+
| 'maxSize'
|
|
100
|
+
| 'fast'
|
|
101
|
+
| 'allowRotation'
|
|
102
|
+
| 'padding'
|
|
103
|
+
| 'powerOfTwo'
|
|
104
|
+
| 'square'
|
|
105
|
+
| 'multiPage'
|
|
106
|
+
| 'trimImage'
|
|
107
|
+
| 'extractAlpha'
|
|
108
|
+
> {}
|
|
85
109
|
|
|
86
110
|
export interface ResolvePublishOptionsOverrides {
|
|
87
111
|
compressed?: boolean;
|
|
@@ -139,16 +163,6 @@ async function runPublishPluginHook(
|
|
|
139
163
|
}
|
|
140
164
|
}
|
|
141
165
|
|
|
142
|
-
function resolvePublishPluginsDir(doc: Document, options: PublishOptions): string {
|
|
143
|
-
const fs = options.fs;
|
|
144
|
-
const projectDir = doc.getProjectDir?.() ?? '';
|
|
145
|
-
if (projectDir) return fs?.join ? fs.join(projectDir, 'plugins') : `${projectDir.replace(/[/\\]+$/, '')}/plugins`;
|
|
146
|
-
|
|
147
|
-
const projectBasePath = resolveProjectBasePath(options.basePath);
|
|
148
|
-
if (!projectBasePath) return '';
|
|
149
|
-
return fs?.join ? fs.join(projectBasePath, 'plugins') : `${projectBasePath.replace(/[/\\]+$/, '')}/plugins`;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
166
|
interface ImageResourceExtras extends Record<string, unknown> {
|
|
153
167
|
_fileName?: string;
|
|
154
168
|
}
|
|
@@ -229,27 +243,6 @@ interface ComponentWithPublishRefs {
|
|
|
229
243
|
listTransitions?(): TransitionWithPublishRefs[];
|
|
230
244
|
}
|
|
231
245
|
|
|
232
|
-
interface PublishEncoderMetadata {
|
|
233
|
-
width?: number;
|
|
234
|
-
height?: number;
|
|
235
|
-
channels?: number;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
interface PublishEncoderResolvedBuffer {
|
|
239
|
-
data: Uint8Array;
|
|
240
|
-
info: Required<Pick<PublishEncoderMetadata, 'width' | 'height' | 'channels'>> & PublishEncoderMetadata;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
interface PublishEncoderPipeline {
|
|
244
|
-
ensureAlpha(): PublishEncoderPipeline;
|
|
245
|
-
resize(options: { width: number; height: number; fit: 'fill' }): PublishEncoderPipeline;
|
|
246
|
-
raw(): PublishEncoderPipeline;
|
|
247
|
-
toBuffer(options: { resolveWithObject: true }): Promise<PublishEncoderResolvedBuffer>;
|
|
248
|
-
metadata(): Promise<PublishEncoderMetadata>;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
type PublishEncoder = (input: string | Uint8Array) => PublishEncoderPipeline;
|
|
252
|
-
|
|
253
246
|
const UNITY_PROJECT_TYPE = ProjectType.Unity;
|
|
254
247
|
const COCOS_CREATOR_PROJECT_TYPE = ProjectType.CocosCreator;
|
|
255
248
|
|
|
@@ -302,8 +295,7 @@ export function resolvePublishOptions(
|
|
|
302
295
|
const atlasSetting = publishSettings.atlasSetting ?? {};
|
|
303
296
|
const projectType = root.getProjectType();
|
|
304
297
|
|
|
305
|
-
const fileExtension = overrides.fileExtension
|
|
306
|
-
?? resolveDefaultPublishFileExtension(projectType, publishSettings);
|
|
298
|
+
const fileExtension = overrides.fileExtension ?? resolveDefaultPublishFileExtension(projectType, publishSettings);
|
|
307
299
|
|
|
308
300
|
let compressed = overrides.compressed ?? publishSettings.compressDesc ?? false;
|
|
309
301
|
if (projectType === UNITY_PROJECT_TYPE) {
|
|
@@ -347,7 +339,6 @@ function joinPathSegments(left: string, right: string): string {
|
|
|
347
339
|
return `${normalizedLeft}${separator}${normalizedRight}`;
|
|
348
340
|
}
|
|
349
341
|
|
|
350
|
-
|
|
351
342
|
function dirname(filePath: string): string {
|
|
352
343
|
const trimmed = filePath.replace(/[/\\]+$/, '');
|
|
353
344
|
const match = trimmed.match(/^(.*)[/\\][^/\\]+$/);
|
|
@@ -386,7 +377,9 @@ function isMovieClipResource(resource: ReturnType<Package['listResources']>[numb
|
|
|
386
377
|
return resource.propertyType === 'MovieClipResource';
|
|
387
378
|
}
|
|
388
379
|
|
|
389
|
-
function isHighResolutionResource(
|
|
380
|
+
function isHighResolutionResource(
|
|
381
|
+
resource: ReturnType<Package['listResources']>[number],
|
|
382
|
+
): resource is ImageResource | MovieClipResource {
|
|
390
383
|
return isImageResource(resource) || isMovieClipResource(resource);
|
|
391
384
|
}
|
|
392
385
|
|
|
@@ -406,7 +399,9 @@ function isSpineResource(resource: ReturnType<Package['listResources']>[number])
|
|
|
406
399
|
return resource.propertyType === 'SpineResource';
|
|
407
400
|
}
|
|
408
401
|
|
|
409
|
-
function isDragonBonesResource(
|
|
402
|
+
function isDragonBonesResource(
|
|
403
|
+
resource: ReturnType<Package['listResources']>[number],
|
|
404
|
+
): resource is DragonBonesResource {
|
|
410
405
|
return resource.propertyType === 'DragonBonesResource';
|
|
411
406
|
}
|
|
412
407
|
|
|
@@ -453,10 +448,7 @@ function addLocalFontRef(target: Set<string>, pkgId: string, value: string | str
|
|
|
453
448
|
addLocalUiResourceRef(target, pkgId, value ?? undefined);
|
|
454
449
|
}
|
|
455
450
|
|
|
456
|
-
function resolvePackageAssetsBasePath(
|
|
457
|
-
basePath: string,
|
|
458
|
-
resource: BranchAwarePublishedResource | undefined,
|
|
459
|
-
): string {
|
|
451
|
+
function resolvePackageAssetsBasePath(basePath: string, resource: BranchAwarePublishedResource | undefined): string {
|
|
460
452
|
const branchName = resource?.getBranch?.() ?? '';
|
|
461
453
|
if (!branchName) return basePath;
|
|
462
454
|
const normalized = basePath.replace(/[/\\]+$/, '');
|
|
@@ -510,7 +502,11 @@ function resolvePublishedMiscFileName(resource: MiscResource, projectType: numbe
|
|
|
510
502
|
}
|
|
511
503
|
|
|
512
504
|
function resolvePublishedSkeletonFileName(resource: SpineResource | DragonBonesResource, projectType: number): string {
|
|
513
|
-
if (
|
|
505
|
+
if (
|
|
506
|
+
projectType === UNITY_PROJECT_TYPE &&
|
|
507
|
+
isSpineResource(resource) &&
|
|
508
|
+
resource.getFile().toLowerCase().endsWith('.skel')
|
|
509
|
+
) {
|
|
514
510
|
return `${resource.getFile()}.bytes`;
|
|
515
511
|
}
|
|
516
512
|
return resource.getFile();
|
|
@@ -528,7 +524,11 @@ function setPublishedFileExtra(
|
|
|
528
524
|
}
|
|
529
525
|
|
|
530
526
|
function setPublishedIdExtra(
|
|
531
|
-
resource: {
|
|
527
|
+
resource: {
|
|
528
|
+
getId(): string;
|
|
529
|
+
getExtras(): Record<string, unknown> | undefined;
|
|
530
|
+
setExtras(value: Record<string, unknown>): unknown;
|
|
531
|
+
},
|
|
532
532
|
effectiveId: string | null,
|
|
533
533
|
): void {
|
|
534
534
|
const extras = (resource.getExtras() as PublishFileExtras | undefined) ?? {};
|
|
@@ -553,11 +553,7 @@ function getBranchName(resource: BranchAwarePublishedResource | undefined): stri
|
|
|
553
553
|
return resource?.getBranch?.() ?? '';
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
-
function buildBranchResourceKey(resource: {
|
|
557
|
-
propertyType: string;
|
|
558
|
-
getPath(): string;
|
|
559
|
-
getName(): string;
|
|
560
|
-
}): string {
|
|
556
|
+
function buildBranchResourceKey(resource: { propertyType: string; getPath(): string; getName(): string }): string {
|
|
561
557
|
return `${resource.propertyType}|${resource.getPath() ?? ''}|${resource.getName() ?? ''}`;
|
|
562
558
|
}
|
|
563
559
|
|
|
@@ -567,12 +563,15 @@ const HIGH_RESOLUTION_LEVELS = [
|
|
|
567
563
|
{ scale: 4, bit: 4, slot: 2 },
|
|
568
564
|
] as const;
|
|
569
565
|
|
|
570
|
-
function buildHighResolutionResourceKey(
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
566
|
+
function buildHighResolutionResourceKey(
|
|
567
|
+
resource: {
|
|
568
|
+
propertyType: string;
|
|
569
|
+
getPath(): string;
|
|
570
|
+
getName(): string;
|
|
571
|
+
getBranch?(): string;
|
|
572
|
+
},
|
|
573
|
+
name = resource.getName(),
|
|
574
|
+
): string {
|
|
576
575
|
return `${resource.propertyType}|${resource.getBranch?.() ?? ''}|${resource.getPath() ?? ''}|${name}`;
|
|
577
576
|
}
|
|
578
577
|
|
|
@@ -622,7 +621,10 @@ function collectHighResolutionItemIds(
|
|
|
622
621
|
}
|
|
623
622
|
|
|
624
623
|
const highResolutionResource = highResolutionResourceByKey.get(
|
|
625
|
-
buildHighResolutionResourceKey(
|
|
624
|
+
buildHighResolutionResourceKey(
|
|
625
|
+
resource,
|
|
626
|
+
appendHighResolutionScaleToName(resource.getName(), level.scale),
|
|
627
|
+
),
|
|
626
628
|
);
|
|
627
629
|
if (!highResolutionResource) {
|
|
628
630
|
ids[level.slot] = null;
|
|
@@ -767,7 +769,12 @@ function collectPackagePublishContext(
|
|
|
767
769
|
continue;
|
|
768
770
|
}
|
|
769
771
|
if (isImageResource(resource)) {
|
|
770
|
-
if (
|
|
772
|
+
if (
|
|
773
|
+
resource.getExported() ||
|
|
774
|
+
referencedIds.has(resourceId) ||
|
|
775
|
+
spriteItemIds.has(resourceId) ||
|
|
776
|
+
pixelHitTestImageIds.has(resourceId)
|
|
777
|
+
) {
|
|
771
778
|
publishedResourceIds.add(resourceId);
|
|
772
779
|
}
|
|
773
780
|
continue;
|
|
@@ -888,7 +895,7 @@ async function applyPixelHitTests(
|
|
|
888
895
|
pkg: Package,
|
|
889
896
|
imageIds: Set<string>,
|
|
890
897
|
basePath: string | undefined,
|
|
891
|
-
encoder:
|
|
898
|
+
encoder: AtlasRasterBackend | undefined,
|
|
892
899
|
): Promise<void> {
|
|
893
900
|
const images = pkg.listImageResources();
|
|
894
901
|
for (const image of images) {
|
|
@@ -950,7 +957,7 @@ async function applyPixelHitTests(
|
|
|
950
957
|
async function annotatePackagePublishArtifacts(
|
|
951
958
|
pkg: Package,
|
|
952
959
|
basePath: string | undefined,
|
|
953
|
-
encoder:
|
|
960
|
+
encoder: AtlasRasterBackend | undefined,
|
|
954
961
|
options: {
|
|
955
962
|
projectType: number;
|
|
956
963
|
includeBranches: boolean;
|
|
@@ -1002,10 +1009,7 @@ function getAnnotatedExportedResourceIds(pkg: Package): Set<string> {
|
|
|
1002
1009
|
return new Set(extras.exportedResourceIds ?? []);
|
|
1003
1010
|
}
|
|
1004
1011
|
|
|
1005
|
-
function getPublishedSkeletonDependencyImageIds(
|
|
1006
|
-
pkg: Package,
|
|
1007
|
-
publishedResourceIds: Set<string>,
|
|
1008
|
-
): Set<string> {
|
|
1012
|
+
function getPublishedSkeletonDependencyImageIds(pkg: Package, publishedResourceIds: Set<string>): Set<string> {
|
|
1009
1013
|
const imageIds = new Set<string>();
|
|
1010
1014
|
const resourcesById = new Map(pkg.listResources().map((resource) => [resource.getId(), resource] as const));
|
|
1011
1015
|
for (const resource of pkg.listResources()) {
|
|
@@ -1035,7 +1039,9 @@ async function exportPackageSounds(
|
|
|
1035
1039
|
return isSoundResource(resource) && publishedResourceIds.has(resource.getId());
|
|
1036
1040
|
});
|
|
1037
1041
|
if (hasPublishedSound) {
|
|
1038
|
-
logger.warn(
|
|
1042
|
+
logger.warn(
|
|
1043
|
+
`publish: Sound resources in package "${pkg.getName()}" were not exported because basePath/readFileRaw is unavailable.`,
|
|
1044
|
+
);
|
|
1039
1045
|
}
|
|
1040
1046
|
return;
|
|
1041
1047
|
}
|
|
@@ -1071,19 +1077,23 @@ async function exportPackageExternalResources(
|
|
|
1071
1077
|
if (!basePath || !readFileRaw) {
|
|
1072
1078
|
const hasPublishedExternal = pkg.listResources().some((resource) => {
|
|
1073
1079
|
return (
|
|
1074
|
-
(isMiscResource(resource) || isSkeletonResource(resource))
|
|
1075
|
-
|
|
1076
|
-
|
|
1080
|
+
((isMiscResource(resource) || isSkeletonResource(resource)) &&
|
|
1081
|
+
exportedResourceIds.has(resource.getId())) ||
|
|
1082
|
+
skeletonDependencyImageIds.has(resource.getId())
|
|
1083
|
+
);
|
|
1077
1084
|
});
|
|
1078
1085
|
if (hasPublishedExternal) {
|
|
1079
|
-
logger.warn(
|
|
1086
|
+
logger.warn(
|
|
1087
|
+
`publish: External resources in package "${pkg.getName()}" were not exported because basePath/readFileRaw is unavailable.`,
|
|
1088
|
+
);
|
|
1080
1089
|
}
|
|
1081
1090
|
return;
|
|
1082
1091
|
}
|
|
1083
1092
|
|
|
1084
1093
|
for (const resource of pkg.listResources()) {
|
|
1085
1094
|
const resourceId = resource.getId();
|
|
1086
|
-
const isSkeletonExternal =
|
|
1095
|
+
const isSkeletonExternal =
|
|
1096
|
+
exportedResourceIds.has(resourceId) && (isMiscResource(resource) || isSkeletonResource(resource));
|
|
1087
1097
|
const isSkeletonImageDependency = skeletonDependencyImageIds.has(resourceId) && isImageResource(resource);
|
|
1088
1098
|
if (!isSkeletonExternal && !isSkeletonImageDependency) continue;
|
|
1089
1099
|
|
|
@@ -1094,7 +1104,8 @@ async function exportPackageExternalResources(
|
|
|
1094
1104
|
targetName = resolveImageFileName(resource);
|
|
1095
1105
|
} else if (isMiscResource(resource) || isSkeletonResource(resource)) {
|
|
1096
1106
|
sourcePath = resolveGenericResourcePath(resource, pkg, basePath);
|
|
1097
|
-
targetName =
|
|
1107
|
+
targetName =
|
|
1108
|
+
((resource.getExtras() as PublishFileExtras | undefined) ?? {})._publishedFile ?? resource.getFile();
|
|
1098
1109
|
} else {
|
|
1099
1110
|
continue;
|
|
1100
1111
|
}
|
|
@@ -1104,7 +1115,9 @@ async function exportPackageExternalResources(
|
|
|
1104
1115
|
const data = await readFileRaw(sourcePath);
|
|
1105
1116
|
await fs.writeFileRaw(targetPath, data);
|
|
1106
1117
|
} catch {
|
|
1107
|
-
logger.warn(
|
|
1118
|
+
logger.warn(
|
|
1119
|
+
`publish: Could not export external resource "${resource.getId()}" from package "${pkg.getName()}".`,
|
|
1120
|
+
);
|
|
1108
1121
|
}
|
|
1109
1122
|
}
|
|
1110
1123
|
}
|
|
@@ -1113,10 +1126,13 @@ async function exportPackageExternalResources(
|
|
|
1113
1126
|
* Publishes a FairyGUI project.
|
|
1114
1127
|
*
|
|
1115
1128
|
* Orchestrates:
|
|
1116
|
-
* 1. Atlas packing (MaxRects layout + optional
|
|
1129
|
+
* 1. Atlas packing (MaxRects layout + optional raster compositing)
|
|
1117
1130
|
* 2. Per-package .fui binary serialization
|
|
1118
1131
|
* 3. File writing to the output directory
|
|
1119
1132
|
*
|
|
1133
|
+
* This is the capability-injected core. Standard hosts should use
|
|
1134
|
+
* `publishNode()` or `publishBrowser()` through their dedicated entries.
|
|
1135
|
+
*
|
|
1120
1136
|
* ```ts
|
|
1121
1137
|
* import sharp from 'sharp';
|
|
1122
1138
|
* const io = new NodeIO();
|
|
@@ -1140,7 +1156,9 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1140
1156
|
if (isAbsolutePathLike(trimmed) || !projectBasePath) {
|
|
1141
1157
|
return trimTrailingSlashes(trimmed);
|
|
1142
1158
|
}
|
|
1143
|
-
return trimTrailingSlashes(
|
|
1159
|
+
return trimTrailingSlashes(
|
|
1160
|
+
options.fs ? options.fs.join(projectBasePath, trimmed) : joinPathSegments(projectBasePath, trimmed),
|
|
1161
|
+
);
|
|
1144
1162
|
};
|
|
1145
1163
|
|
|
1146
1164
|
const resolveProjectPublishConfig = (): ResolvedProjectPublishConfig => {
|
|
@@ -1167,7 +1185,11 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1167
1185
|
};
|
|
1168
1186
|
};
|
|
1169
1187
|
|
|
1170
|
-
const resolvePackagePublishPlan = (
|
|
1188
|
+
const resolvePackagePublishPlan = (
|
|
1189
|
+
pkg: Package,
|
|
1190
|
+
config: ResolvedProjectPublishConfig,
|
|
1191
|
+
projectBasePath?: string,
|
|
1192
|
+
): ResolvedPackagePublishPlan => {
|
|
1171
1193
|
let outputDir: string | undefined;
|
|
1172
1194
|
|
|
1173
1195
|
if (options.output) {
|
|
@@ -1215,7 +1237,7 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1215
1237
|
},
|
|
1216
1238
|
});
|
|
1217
1239
|
|
|
1218
|
-
const publishPackage = async (
|
|
1240
|
+
const publishPackage = async (plan: ResolvedPackagePublishPlan, writerFs: FileSystem, packageIndex: number) => {
|
|
1219
1241
|
const atlasRuntimeOptions = resolvePublishAtlasRuntimeOptions(plan.fileExtension);
|
|
1220
1242
|
await atlas({
|
|
1221
1243
|
...plan.atlas,
|
|
@@ -1232,7 +1254,9 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1232
1254
|
|
|
1233
1255
|
if (!options.fs) return;
|
|
1234
1256
|
if (!plan.outputDir) {
|
|
1235
|
-
throw new Error(
|
|
1257
|
+
throw new Error(
|
|
1258
|
+
'publish: no output directory resolved. Provide --output, or configure global publish.path / package publishPath.',
|
|
1259
|
+
);
|
|
1236
1260
|
}
|
|
1237
1261
|
|
|
1238
1262
|
await options.fs.mkdir(plan.outputDir);
|
|
@@ -1268,8 +1292,7 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1268
1292
|
const root = doc.getRoot();
|
|
1269
1293
|
const logger = doc.getLogger();
|
|
1270
1294
|
const projectBasePath = resolveProjectBasePath(options.basePath) || doc.getProjectDir?.() || '';
|
|
1271
|
-
const
|
|
1272
|
-
const plugins = pluginsDir ? await loadPlugins(doc, pluginsDir) : [];
|
|
1295
|
+
const plugins = options.plugins ?? [];
|
|
1273
1296
|
await runPublishPluginHook(plugins, 'onPublishStart', doc, options);
|
|
1274
1297
|
|
|
1275
1298
|
const resolved = resolveProjectPublishConfig();
|
|
@@ -1298,23 +1321,20 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1298
1321
|
// Compute dependency list and selected publish artifacts before atlas packing,
|
|
1299
1322
|
// so merged-branch publishes can pack the overridden resources with main IDs.
|
|
1300
1323
|
_computeDependencies(doc, pkg, pkgMap);
|
|
1301
|
-
await annotatePackagePublishArtifacts(
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
includeBranches: resolved.includeBranches,
|
|
1308
|
-
activeBranch: resolved.activeBranch,
|
|
1309
|
-
includeHighResolution: resolved.includeHighResolution,
|
|
1310
|
-
},
|
|
1311
|
-
);
|
|
1324
|
+
await annotatePackagePublishArtifacts(pkg, options.basePath, options.encoder, {
|
|
1325
|
+
projectType: resolved.projectType,
|
|
1326
|
+
includeBranches: resolved.includeBranches,
|
|
1327
|
+
activeBranch: resolved.activeBranch,
|
|
1328
|
+
includeHighResolution: resolved.includeHighResolution,
|
|
1329
|
+
});
|
|
1312
1330
|
}
|
|
1313
1331
|
|
|
1314
1332
|
const plans = allPackages.map((pkg) => resolvePackagePublishPlan(pkg, resolved, projectBasePath));
|
|
1315
1333
|
|
|
1316
1334
|
if (!options.fs) {
|
|
1317
|
-
logger.info(
|
|
1335
|
+
logger.info(
|
|
1336
|
+
`publish: No fs provided — layout computed for ${allPackages.length} package(s), skipping file output.`,
|
|
1337
|
+
);
|
|
1318
1338
|
const noopWriterFs = toBinaryWriterFileSystem(createNoopPublishFs());
|
|
1319
1339
|
for (const plan of plans) {
|
|
1320
1340
|
await publishPackage(plan, noopWriterFs, allDocPackages.indexOf(plan.pkg));
|
|
@@ -1338,14 +1358,18 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1338
1358
|
await publishPackage(plan, writerFs, pkgIndex);
|
|
1339
1359
|
}
|
|
1340
1360
|
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1361
|
+
if (options.codeGeneration !== false) {
|
|
1362
|
+
await publishCodeGeneration(doc, {
|
|
1363
|
+
basePath: options.basePath,
|
|
1364
|
+
fs: options.fs,
|
|
1365
|
+
packages: allPackages,
|
|
1366
|
+
plugins,
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1347
1369
|
|
|
1348
|
-
const publishedTargets = [
|
|
1370
|
+
const publishedTargets = [
|
|
1371
|
+
...new Set(plans.map((plan) => plan.outputDir).filter((value): value is string => Boolean(value))),
|
|
1372
|
+
];
|
|
1349
1373
|
logger.info(
|
|
1350
1374
|
publishedTargets.length > 0
|
|
1351
1375
|
? `publish: Published ${allPackages.length} package(s) to ${publishedTargets.join(', ')}`
|
|
@@ -1363,7 +1387,12 @@ export function publish(options: PublishOptions): Transform {
|
|
|
1363
1387
|
function _computeDependencies(doc: Document, pkg: Package, pkgMap: Map<string, Package>): void {
|
|
1364
1388
|
const referencedPkgIds = new Set<string>();
|
|
1365
1389
|
const pkgId = pkg.getId();
|
|
1366
|
-
const packageOrder = new Map(
|
|
1390
|
+
const packageOrder = new Map(
|
|
1391
|
+
doc
|
|
1392
|
+
.getRoot()
|
|
1393
|
+
.listPackages()
|
|
1394
|
+
.map((entry, index) => [entry.getId(), index] as const),
|
|
1395
|
+
);
|
|
1367
1396
|
const addDependencyPackageId = (dependencyPkgId: string | null | undefined): void => {
|
|
1368
1397
|
const normalized = dependencyPkgId?.trim() ?? '';
|
|
1369
1398
|
if (!normalized || normalized === pkgId) return;
|
package/src/shared-types.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ProjectSettings, PublishSettings } from '@openfairygui/core';
|
|
2
|
+
|
|
3
|
+
export type { PublishFileSystem } from './publish/contracts.js';
|
|
2
4
|
|
|
3
5
|
export type ExtrasMap = Record<string, unknown>;
|
|
4
6
|
|
|
@@ -57,10 +59,3 @@ export interface HasOptionalSrc {
|
|
|
57
59
|
export interface HasOptionalUrl {
|
|
58
60
|
getUrl?(): string | undefined;
|
|
59
61
|
}
|
|
60
|
-
|
|
61
|
-
export type PublishFileSystem = Pick<FileSystem, 'join' | 'mkdir' | 'writeFileRaw'> & {
|
|
62
|
-
deleteFile?: (path: string) => Promise<void>;
|
|
63
|
-
exists?: FileSystem['exists'];
|
|
64
|
-
readdir?: FileSystem['readdir'];
|
|
65
|
-
readFileRaw?: FileSystem['readFileRaw'];
|
|
66
|
-
};
|
package/src/web.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export {
|
|
2
|
+
publishBrowser,
|
|
3
|
+
type BrowserPublishedFile,
|
|
4
|
+
type BrowserPublishAtlasOptions,
|
|
5
|
+
type BrowserPublishDiagnostic,
|
|
6
|
+
type BrowserPublishOptions,
|
|
7
|
+
type BrowserPublishProjectType,
|
|
8
|
+
type BrowserPublishResult,
|
|
9
|
+
type BrowserPublishOutputFileSystem,
|
|
10
|
+
type BrowserPublishSourceFileSystem,
|
|
11
|
+
} from './adapters/web/publish.js';
|