@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
package/src/codegen.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type Component,
|
|
3
|
-
type GComponent,
|
|
4
3
|
type Document,
|
|
4
|
+
type GComponent,
|
|
5
5
|
type GObject,
|
|
6
6
|
type Package,
|
|
7
7
|
ProjectType,
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
UNITY_BINDER_TEMPLATE,
|
|
13
13
|
UNITY_COMPONENT_TEMPLATE,
|
|
14
14
|
} from './codegen-templates.js';
|
|
15
|
-
import
|
|
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';
|
|
16
18
|
|
|
17
19
|
export const AUTO_GENERATED_CODE_MARK = '/** This is an automatically generated class by FairyGUI. Please do not modify it. **/';
|
|
18
20
|
const DEFAULT_CLASS_NAME_PREFIX = 'UI_';
|
|
@@ -22,25 +24,15 @@ export interface PublishCodeGenerationOptions {
|
|
|
22
24
|
basePath?: string;
|
|
23
25
|
fs: PublishFileSystem;
|
|
24
26
|
packages: Package[];
|
|
27
|
+
plugins?: LoadedPlugin[];
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
interface
|
|
28
|
-
allowGenCode: boolean;
|
|
29
|
-
classNamePrefix: string;
|
|
30
|
-
memberNamePrefix: string;
|
|
31
|
-
packageName: string;
|
|
32
|
-
ignoreNoname: boolean;
|
|
33
|
-
getMemberByName: boolean;
|
|
34
|
-
codePath: string;
|
|
35
|
-
codeType: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface ResolvedPackageCodegenPlan {
|
|
30
|
+
export interface ResolvedPackageCodegenPlan {
|
|
39
31
|
outputDir: string;
|
|
40
32
|
packageFolderName: string;
|
|
41
33
|
packageNamespace: string;
|
|
42
34
|
binderClassName: string;
|
|
43
|
-
settings:
|
|
35
|
+
settings: CliCodeGenerationSettings;
|
|
44
36
|
}
|
|
45
37
|
|
|
46
38
|
interface FguiTypescriptVariant {
|
|
@@ -77,16 +69,22 @@ const SHARED_FGUI_TYPESCRIPT_VARIANT: FguiTypescriptVariant = {
|
|
|
77
69
|
runtimeNamespace: 'fgui',
|
|
78
70
|
};
|
|
79
71
|
|
|
80
|
-
interface CodegenMember {
|
|
72
|
+
export interface CodegenMember {
|
|
81
73
|
index: number;
|
|
82
74
|
kind: 'child' | 'controller' | 'transition';
|
|
83
75
|
name: string;
|
|
84
76
|
originalName: string;
|
|
85
77
|
type: string;
|
|
86
78
|
ignored: boolean;
|
|
79
|
+
referencedComponent?: CodegenReferencedComponent;
|
|
87
80
|
}
|
|
88
81
|
|
|
89
|
-
interface
|
|
82
|
+
export interface CodegenReferencedComponent {
|
|
83
|
+
component: Component;
|
|
84
|
+
package: Package;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface CodegenClass {
|
|
90
88
|
classId: string;
|
|
91
89
|
className: string;
|
|
92
90
|
encodedClassName: string;
|
|
@@ -97,14 +95,28 @@ interface CodegenClass {
|
|
|
97
95
|
members: CodegenMember[];
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
export async function publishCodeGeneration(
|
|
101
|
-
doc: Document,
|
|
102
|
-
options: PublishCodeGenerationOptions,
|
|
103
|
-
): Promise<void> {
|
|
98
|
+
export async function publishCodeGeneration(doc: Document, options: PublishCodeGenerationOptions): Promise<void> {
|
|
104
99
|
const logger = doc.getLogger();
|
|
105
100
|
const settings = resolveCodeGenerationSettings(doc);
|
|
106
101
|
if (!settings.allowGenCode) return;
|
|
107
102
|
|
|
103
|
+
const plugins = options.plugins?.filter((plugin) => typeof plugin.plugin.genCode === 'function') ?? [];
|
|
104
|
+
if (plugins.length > 0) {
|
|
105
|
+
let handled = false;
|
|
106
|
+
for (const plugin of plugins) {
|
|
107
|
+
try {
|
|
108
|
+
await plugin.plugin.genCode(doc, settings, options);
|
|
109
|
+
handled = true;
|
|
110
|
+
logger.info(`publish: Generated code using plugin "${plugin.name}"`);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
logger.warn(`publish: Code generation plugin "${plugin.name}" failed: ${formatPluginError(error)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (handled) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
108
120
|
for (const pkg of options.packages) {
|
|
109
121
|
if (!pkg.getGenCode()) continue;
|
|
110
122
|
|
|
@@ -129,7 +141,7 @@ export async function publishCodeGeneration(
|
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
143
|
|
|
132
|
-
function resolveCodeGenerationSettings(doc: Document):
|
|
144
|
+
export function resolveCodeGenerationSettings(doc: Document): Required<CliCodeGenerationSettings> {
|
|
133
145
|
const settings = (doc.getRoot().getSettings?.() ?? {}) as RootProjectSettings;
|
|
134
146
|
const publish = settings.publish ?? {};
|
|
135
147
|
const codeGeneration = publish.codeGeneration as CliCodeGenerationSettings | undefined;
|
|
@@ -159,11 +171,7 @@ function resolveCodeGenerationSettings(doc: Document): ResolvedCodeGenerationSet
|
|
|
159
171
|
};
|
|
160
172
|
}
|
|
161
173
|
|
|
162
|
-
function resolvePackageCodegenPlan(
|
|
163
|
-
pkg: Package,
|
|
164
|
-
settings: ResolvedCodeGenerationSettings,
|
|
165
|
-
options: PublishCodeGenerationOptions,
|
|
166
|
-
): ResolvedPackageCodegenPlan | null {
|
|
174
|
+
export function resolvePackageCodegenPlan(pkg: Package, settings: CliCodeGenerationSettings, options: PublishCodeGenerationOptions): ResolvedPackageCodegenPlan | null {
|
|
167
175
|
const rawCodePath = (pkg.getCodePath() || settings.codePath || '').trim();
|
|
168
176
|
if (!rawCodePath) return null;
|
|
169
177
|
|
|
@@ -276,17 +284,11 @@ async function cleanupGeneratedFiles(directory: string, fs: PublishFileSystem, e
|
|
|
276
284
|
}
|
|
277
285
|
}
|
|
278
286
|
|
|
279
|
-
function buildCodegenClasses(
|
|
280
|
-
|
|
281
|
-
pkg: Package,
|
|
282
|
-
plan: ResolvedPackageCodegenPlan,
|
|
283
|
-
): CodegenClass[] {
|
|
284
|
-
const exportedComponents = pkg.listComponents()
|
|
285
|
-
.filter((component) => component.getExported())
|
|
286
|
-
.sort((left, right) => left.getId().localeCompare(right.getId()));
|
|
287
|
+
export function buildCodegenClasses(doc: Document, pkg: Package, plan: ResolvedPackageCodegenPlan): CodegenClass[] {
|
|
288
|
+
const codegenComponents = pkg.listComponents().sort((left, right) => left.getId().localeCompare(right.getId()));
|
|
287
289
|
const generatedById = new Map<string, CodegenClass>();
|
|
288
290
|
|
|
289
|
-
for (const component of
|
|
291
|
+
for (const component of codegenComponents) {
|
|
290
292
|
const encodedClassName = `${plan.settings.classNamePrefix}${normalizeTypeName(component.getName()) || 'Component'}`;
|
|
291
293
|
generatedById.set(component.getId(), {
|
|
292
294
|
classId: component.getId(),
|
|
@@ -300,7 +302,19 @@ function buildCodegenClasses(
|
|
|
300
302
|
});
|
|
301
303
|
}
|
|
302
304
|
|
|
303
|
-
for (const component of
|
|
305
|
+
for (const component of codegenComponents) {
|
|
306
|
+
const classInfo = generatedById.get(component.getId());
|
|
307
|
+
if (!classInfo) continue;
|
|
308
|
+
classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
for (const [componentId, classInfo] of generatedById) {
|
|
312
|
+
if (classInfo.members.every((member) => member.ignored)) {
|
|
313
|
+
generatedById.delete(componentId);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
for (const component of codegenComponents) {
|
|
304
318
|
const classInfo = generatedById.get(component.getId());
|
|
305
319
|
if (!classInfo) continue;
|
|
306
320
|
classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
|
|
@@ -327,13 +341,17 @@ function buildCodegenMembers(
|
|
|
327
341
|
}
|
|
328
342
|
|
|
329
343
|
for (const child of component.listChildren()) {
|
|
344
|
+
if (!isRuntimeChild(child)) continue;
|
|
345
|
+
const index = childIndex++;
|
|
346
|
+
const resolvedChild = resolveChildType(doc, pkg, child, generatedById);
|
|
330
347
|
members.push(createMember(
|
|
331
348
|
ownerType,
|
|
332
349
|
'child',
|
|
333
|
-
|
|
350
|
+
resolvedChild.type,
|
|
334
351
|
child.getName(),
|
|
335
|
-
|
|
352
|
+
index,
|
|
336
353
|
plan,
|
|
354
|
+
resolvedChild.referencedComponent,
|
|
337
355
|
));
|
|
338
356
|
}
|
|
339
357
|
|
|
@@ -355,6 +373,10 @@ function buildCodegenMembers(
|
|
|
355
373
|
return members;
|
|
356
374
|
}
|
|
357
375
|
|
|
376
|
+
function isRuntimeChild(child: GObject): boolean {
|
|
377
|
+
return child.propertyType !== 'GGroup' || (child as GObject & { getAdvanced?(): boolean }).getAdvanced?.() === true;
|
|
378
|
+
}
|
|
379
|
+
|
|
358
380
|
function createMember(
|
|
359
381
|
ownerType: string,
|
|
360
382
|
kind: CodegenMember['kind'],
|
|
@@ -362,6 +384,7 @@ function createMember(
|
|
|
362
384
|
originalName: string,
|
|
363
385
|
index: number,
|
|
364
386
|
plan: ResolvedPackageCodegenPlan,
|
|
387
|
+
referencedComponent?: CodegenReferencedComponent,
|
|
365
388
|
): CodegenMember {
|
|
366
389
|
const ignored = plan.settings.ignoreNoname && isDefaultMemberName(ownerType, kind, originalName);
|
|
367
390
|
return {
|
|
@@ -371,43 +394,59 @@ function createMember(
|
|
|
371
394
|
originalName,
|
|
372
395
|
type,
|
|
373
396
|
ignored,
|
|
397
|
+
referencedComponent,
|
|
374
398
|
};
|
|
375
399
|
}
|
|
376
400
|
|
|
401
|
+
interface ResolvedChildCodegenType {
|
|
402
|
+
type: string;
|
|
403
|
+
referencedComponent?: CodegenReferencedComponent;
|
|
404
|
+
}
|
|
405
|
+
|
|
377
406
|
function resolveChildType(
|
|
378
407
|
doc: Document,
|
|
379
408
|
pkg: Package,
|
|
380
409
|
child: GObject,
|
|
381
410
|
generatedById: Map<string, CodegenClass>,
|
|
382
|
-
):
|
|
411
|
+
): ResolvedChildCodegenType {
|
|
383
412
|
const src = (child as GObject & { getSrc?(): string }).getSrc?.();
|
|
384
413
|
if (src) {
|
|
385
|
-
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
|
|
414
|
+
let referencedComponent: CodegenReferencedComponent | null = null;
|
|
415
|
+
if (src.startsWith('ui://')) {
|
|
416
|
+
const rest = src.slice(5);
|
|
417
|
+
const pkgId = rest.slice(0, 8);
|
|
418
|
+
const resourceId = rest.slice(8);
|
|
419
|
+
const targetPackage = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId);
|
|
420
|
+
const targetResource = targetPackage?.getResourceById(resourceId);
|
|
421
|
+
if (targetPackage && targetResource?.propertyType === 'Component') {
|
|
422
|
+
referencedComponent = { component: targetResource, package: targetPackage };
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
const packageId = (child as GComponent & { getPackageId?(): string }).getPackageId?.();
|
|
426
|
+
const targetPackage = packageId
|
|
427
|
+
? doc.getRoot().listPackages().find((candidate) => candidate.getId() === packageId)
|
|
428
|
+
: pkg;
|
|
429
|
+
const targetResource = targetPackage?.getResourceById(src);
|
|
430
|
+
if (targetPackage && targetResource?.propertyType === 'Component') {
|
|
431
|
+
referencedComponent = { component: targetResource, package: targetPackage };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (referencedComponent) {
|
|
436
|
+
const localGeneratedClass = referencedComponent.package === pkg
|
|
437
|
+
? generatedById.get(referencedComponent.component.getId())
|
|
438
|
+
: undefined;
|
|
439
|
+
return {
|
|
440
|
+
type: localGeneratedClass?.encodedClassName ?? resolveComponentBaseType(referencedComponent.component),
|
|
441
|
+
referencedComponent,
|
|
442
|
+
};
|
|
389
443
|
}
|
|
390
444
|
}
|
|
391
445
|
|
|
392
446
|
const instanceExtType = (child as GComponent & { getInstanceExtType?(): string }).getInstanceExtType?.();
|
|
393
|
-
if (instanceExtType) return `G${instanceExtType}
|
|
394
|
-
|
|
395
|
-
return child.propertyType;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function resolveChildSourceComponent(doc: Document, pkg: Package, src: string): Component | null {
|
|
399
|
-
if (!src) return null;
|
|
400
|
-
if (src.startsWith('ui://')) {
|
|
401
|
-
const rest = src.slice(5);
|
|
402
|
-
const pkgId = rest.slice(0, 8);
|
|
403
|
-
const resourceId = rest.slice(8);
|
|
404
|
-
const targetPackage = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId);
|
|
405
|
-
const targetResource = targetPackage?.getResourceById(resourceId);
|
|
406
|
-
return targetResource?.propertyType === 'Component' ? targetResource : null;
|
|
407
|
-
}
|
|
447
|
+
if (instanceExtType) return { type: `G${instanceExtType}` };
|
|
408
448
|
|
|
409
|
-
|
|
410
|
-
return localResource?.propertyType === 'Component' ? localResource : null;
|
|
449
|
+
return { type: child.propertyType };
|
|
411
450
|
}
|
|
412
451
|
|
|
413
452
|
function resolveComponentBaseType(component: Component): string {
|
|
@@ -549,7 +588,7 @@ function resolveCodePath(
|
|
|
549
588
|
return projectBasePath ? trimTrailingSlashes(fs.join(projectBasePath, codePath)) : trimTrailingSlashes(codePath);
|
|
550
589
|
}
|
|
551
590
|
|
|
552
|
-
function resolveProjectBasePath(basePath: string | undefined): string {
|
|
591
|
+
export function resolveProjectBasePath(basePath: string | undefined): string {
|
|
553
592
|
if (!basePath) return '';
|
|
554
593
|
const normalized = trimTrailingSlashes(basePath);
|
|
555
594
|
const assetsMatch = normalized.match(/^(.*)[/\\]assets(?:_[^/\\]+)?$/i);
|
|
@@ -578,13 +617,13 @@ function isDefaultMemberName(ownerType: string, kind: CodegenMember['kind'], nam
|
|
|
578
617
|
if (kind === 'transition') return false;
|
|
579
618
|
|
|
580
619
|
if (ownerType === 'GButton' || ownerType === 'GLabel' || ownerType === 'GComboBox') {
|
|
581
|
-
|
|
620
|
+
if (name === 'title' || name === 'icon') return true;
|
|
582
621
|
}
|
|
583
622
|
if (ownerType === 'GProgressBar') {
|
|
584
|
-
|
|
623
|
+
if (name === 'bar' || name === 'bar_v' || name === 'title' || name === 'ani') return true;
|
|
585
624
|
}
|
|
586
625
|
if (ownerType === 'GSlider') {
|
|
587
|
-
|
|
626
|
+
if (name === 'bar' || name === 'bar_v' || name === 'grip' || name === 'title' || name === 'ani') return true;
|
|
588
627
|
}
|
|
589
628
|
return /^n\d+(?:_.*)?$/i.test(name);
|
|
590
629
|
}
|
|
@@ -647,10 +686,10 @@ async function writeTextFile(fs: PublishFileSystem, filePath: string, content: s
|
|
|
647
686
|
await fs.writeFileRaw(filePath, encodeText(content));
|
|
648
687
|
}
|
|
649
688
|
|
|
650
|
-
function encodeText(value: string): Uint8Array {
|
|
689
|
+
export function encodeText(value: string): Uint8Array {
|
|
651
690
|
return new TextEncoder().encode(value);
|
|
652
691
|
}
|
|
653
692
|
|
|
654
|
-
function decodeText(value: Uint8Array): string {
|
|
693
|
+
export function decodeText(value: Uint8Array): string {
|
|
655
694
|
return new TextDecoder().decode(value);
|
|
656
695
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,48 @@
|
|
|
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';
|
|
6
|
-
export {
|
|
12
|
+
export {
|
|
13
|
+
publishCodeGeneration,
|
|
14
|
+
AUTO_GENERATED_CODE_MARK,
|
|
15
|
+
type PublishCodeGenerationOptions,
|
|
16
|
+
type ResolvedPackageCodegenPlan,
|
|
17
|
+
resolvePackageCodegenPlan,
|
|
18
|
+
buildCodegenClasses,
|
|
19
|
+
type CodegenClass,
|
|
20
|
+
type CodegenMember,
|
|
21
|
+
type CodegenReferencedComponent,
|
|
22
|
+
encodeText,
|
|
23
|
+
decodeText,
|
|
24
|
+
} from './codegen.js';
|
|
25
|
+
|
|
26
|
+
export type {
|
|
27
|
+
CodeWriter,
|
|
28
|
+
ICodeWriterConfig,
|
|
29
|
+
MaybePromise,
|
|
30
|
+
LoadedPlugin,
|
|
31
|
+
Plugin,
|
|
32
|
+
PluginManifest,
|
|
33
|
+
PluginModule,
|
|
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';
|
|
7
46
|
export {
|
|
8
47
|
restore,
|
|
9
48
|
type RestoreFileSystem,
|
|
@@ -24,6 +63,7 @@ export {
|
|
|
24
63
|
} from './publish.js';
|
|
25
64
|
export {
|
|
26
65
|
applyUamTransactionApp,
|
|
66
|
+
type ApplyUamTransactionAppDiagnostic,
|
|
27
67
|
type ApplyUamTransactionAppError,
|
|
28
68
|
type ApplyUamTransactionAppInput,
|
|
29
69
|
type ApplyUamTransactionAppResult,
|
|
@@ -37,6 +77,6 @@ export type {
|
|
|
37
77
|
HasOptionalSrc,
|
|
38
78
|
HasOptionalUrl,
|
|
39
79
|
PublishDependency,
|
|
40
|
-
PublishFileSystem,
|
|
41
80
|
RootProjectSettings,
|
|
81
|
+
CliCodeGenerationSettings,
|
|
42
82
|
} from './shared-types.js';
|
package/src/node.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Document } from '@openfairygui/core';
|
|
2
|
+
import type { PublishCodeGenerationOptions } from '../codegen.js';
|
|
3
|
+
import type { PublishOptions } from '../publish.js';
|
|
4
|
+
import type { CliCodeGenerationSettings } from '../shared-types.js';
|
|
5
|
+
|
|
6
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
7
|
+
|
|
8
|
+
export interface PluginManifest {
|
|
9
|
+
name: string;
|
|
10
|
+
displayName?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
version?: string;
|
|
13
|
+
author?: {
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
icon?: string;
|
|
17
|
+
main: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ICodeWriterConfig {
|
|
21
|
+
blockStart?: string;
|
|
22
|
+
blockEnd?: string;
|
|
23
|
+
blockFromNewLine?: boolean;
|
|
24
|
+
usingTabs?: boolean;
|
|
25
|
+
endOfLine?: string;
|
|
26
|
+
fileMark?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface CodeWriter {
|
|
30
|
+
writeMark(): void;
|
|
31
|
+
writeln(fmt?: string, ...args: any[]): CodeWriter;
|
|
32
|
+
startBlock(): CodeWriter;
|
|
33
|
+
endBlock(): CodeWriter;
|
|
34
|
+
incIndent(): CodeWriter;
|
|
35
|
+
decIndent(): CodeWriter;
|
|
36
|
+
reset(): void;
|
|
37
|
+
toString(): string;
|
|
38
|
+
save(filePath: string): void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Plugin {
|
|
42
|
+
genCode?: (doc: Document, settings: Required<CliCodeGenerationSettings>, options: PublishCodeGenerationOptions) => MaybePromise<void>;
|
|
43
|
+
onPublishStart?: (doc: Document, options: PublishOptions) => MaybePromise<void>;
|
|
44
|
+
onPublishEnd?: (doc: Document, options: PublishOptions) => MaybePromise<void>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface LoadedPlugin {
|
|
48
|
+
name: string;
|
|
49
|
+
plugin: Plugin;
|
|
50
|
+
}
|
|
51
|
+
|
|
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;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { Package } from '@openfairygui/core';
|
|
2
|
+
import type { PublishFileSystem } from './contracts.js';
|
|
3
|
+
import {
|
|
4
|
+
extname,
|
|
5
|
+
getAnnotatedExportedResourceIds,
|
|
6
|
+
getAnnotatedPublishedResourceIds,
|
|
7
|
+
getPublishedId,
|
|
8
|
+
getPublishedSkeletonDependencyImageIds,
|
|
9
|
+
isImageResource,
|
|
10
|
+
isMiscResource,
|
|
11
|
+
isSkeletonResource,
|
|
12
|
+
isSoundResource,
|
|
13
|
+
resolveGenericResourcePath,
|
|
14
|
+
resolveImageFileName,
|
|
15
|
+
resolveImagePath,
|
|
16
|
+
resolveSoundPath,
|
|
17
|
+
} from './package-context.js';
|
|
18
|
+
|
|
19
|
+
interface PublishFileExtras extends Record<string, unknown> {
|
|
20
|
+
_publishedFile?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function exportPackageSounds(
|
|
24
|
+
pkg: Package,
|
|
25
|
+
outputDir: string,
|
|
26
|
+
basePath: string | undefined,
|
|
27
|
+
fs: PublishFileSystem,
|
|
28
|
+
readFileRaw: PublishFileSystem['readFileRaw'] | undefined,
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
const publishedResourceIds = getAnnotatedPublishedResourceIds(pkg);
|
|
31
|
+
if (publishedResourceIds.size === 0) return;
|
|
32
|
+
if (!basePath || !readFileRaw) {
|
|
33
|
+
const hasPublishedSound = pkg.listResources().some((resource) => {
|
|
34
|
+
return isSoundResource(resource) && publishedResourceIds.has(resource.getId());
|
|
35
|
+
});
|
|
36
|
+
if (hasPublishedSound) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`publish: Sound resources in package "${pkg.getName()}" require basePath and readFileRaw for output.`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const resource of pkg.listResources()) {
|
|
45
|
+
if (!isSoundResource(resource)) continue;
|
|
46
|
+
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
47
|
+
|
|
48
|
+
const sourcePath = resolveSoundPath(resource, pkg, basePath);
|
|
49
|
+
const targetName = `${pkg.getPublishName() || pkg.getName()}_${getPublishedId(resource)}${extname(resource.getFile() || '')}`;
|
|
50
|
+
const targetPath = fs.join(outputDir, targetName);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const data = await readFileRaw(sourcePath);
|
|
54
|
+
await fs.writeFileRaw(targetPath, data);
|
|
55
|
+
} catch {
|
|
56
|
+
throw new Error(`publish: Could not export sound "${resource.getId()}" from package "${pkg.getName()}".`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function exportPackageExternalResources(
|
|
62
|
+
pkg: Package,
|
|
63
|
+
outputDir: string,
|
|
64
|
+
basePath: string | undefined,
|
|
65
|
+
fs: PublishFileSystem,
|
|
66
|
+
readFileRaw: PublishFileSystem['readFileRaw'] | undefined,
|
|
67
|
+
): Promise<void> {
|
|
68
|
+
const exportedResourceIds = getAnnotatedExportedResourceIds(pkg);
|
|
69
|
+
const skeletonDependencyImageIds = getPublishedSkeletonDependencyImageIds(pkg, exportedResourceIds);
|
|
70
|
+
if (exportedResourceIds.size === 0) return;
|
|
71
|
+
if (!basePath || !readFileRaw) {
|
|
72
|
+
const hasPublishedExternal = pkg.listResources().some((resource) => {
|
|
73
|
+
return (
|
|
74
|
+
((isMiscResource(resource) || isSkeletonResource(resource)) &&
|
|
75
|
+
exportedResourceIds.has(resource.getId())) ||
|
|
76
|
+
skeletonDependencyImageIds.has(resource.getId())
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
if (hasPublishedExternal) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`publish: External resources in package "${pkg.getName()}" require basePath and readFileRaw for output.`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const resource of pkg.listResources()) {
|
|
88
|
+
const resourceId = resource.getId();
|
|
89
|
+
const isSkeletonExternal =
|
|
90
|
+
exportedResourceIds.has(resourceId) && (isMiscResource(resource) || isSkeletonResource(resource));
|
|
91
|
+
const isSkeletonImageDependency = skeletonDependencyImageIds.has(resourceId) && isImageResource(resource);
|
|
92
|
+
if (!isSkeletonExternal && !isSkeletonImageDependency) continue;
|
|
93
|
+
|
|
94
|
+
let sourcePath: string;
|
|
95
|
+
let targetName: string;
|
|
96
|
+
if (isSkeletonImageDependency) {
|
|
97
|
+
sourcePath = resolveImagePath(resource, pkg, basePath);
|
|
98
|
+
targetName = resolveImageFileName(resource);
|
|
99
|
+
} else if (isMiscResource(resource) || isSkeletonResource(resource)) {
|
|
100
|
+
sourcePath = resolveGenericResourcePath(resource, pkg, basePath);
|
|
101
|
+
targetName =
|
|
102
|
+
((resource.getExtras() as PublishFileExtras | undefined) ?? {})._publishedFile ?? resource.getFile();
|
|
103
|
+
} else {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const targetPath = fs.join(outputDir, targetName);
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const data = await readFileRaw(sourcePath);
|
|
110
|
+
await fs.writeFileRaw(targetPath, data);
|
|
111
|
+
} catch {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`publish: Could not export external resource "${resource.getId()}" from package "${pkg.getName()}".`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|