@openfairygui/functions 0.2.0-alpha.7 → 0.2.0

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.
Files changed (55) hide show
  1. package/README.md +52 -6
  2. package/dist/atlas-C6tbl7nn.d.ts +193 -0
  3. package/dist/atlas-CHsu2Y8i.d.cts +193 -0
  4. package/dist/index.cjs +17 -3603
  5. package/dist/index.d.cts +5 -294
  6. package/dist/index.d.ts +5 -294
  7. package/dist/index.js +4 -3595
  8. package/dist/node.cjs +256 -0
  9. package/dist/node.d.cts +36 -0
  10. package/dist/node.d.ts +36 -0
  11. package/dist/node.js +254 -0
  12. package/dist/publish-CykUJfVa.cjs +3269 -0
  13. package/dist/publish-DXoaC1Nl.js +3174 -0
  14. package/dist/restore-BQp01WY3.js +914 -0
  15. package/dist/restore-BeWaJNjR.d.cts +288 -0
  16. package/dist/restore-CEywQUHz.cjs +919 -0
  17. package/dist/restore-Dh0-Nvms.d.ts +288 -0
  18. package/dist/uam-transaction.cjs +29 -14
  19. package/dist/uam-transaction.d.cts +2 -1
  20. package/dist/uam-transaction.d.ts +2 -1
  21. package/dist/uam-transaction.js +30 -16
  22. package/dist/web.cjs +440 -0
  23. package/dist/web.d.cts +44 -0
  24. package/dist/web.d.ts +44 -0
  25. package/dist/web.js +439 -0
  26. package/package.json +29 -4
  27. package/src/adapters/node/plugins.ts +82 -0
  28. package/src/adapters/node/publish.ts +130 -0
  29. package/src/adapters/node/restore.ts +187 -0
  30. package/src/adapters/web/publish.ts +196 -0
  31. package/src/adapters/web/raster.ts +421 -0
  32. package/src/atlas/font.ts +95 -0
  33. package/src/atlas/inputs.ts +445 -0
  34. package/src/atlas/jta.ts +157 -0
  35. package/src/atlas/packing.ts +762 -0
  36. package/src/atlas.ts +129 -1221
  37. package/src/codegen.ts +108 -82
  38. package/src/index.ts +43 -3
  39. package/src/node.ts +8 -0
  40. package/src/path-utils.ts +40 -0
  41. package/src/plugins/types.ts +56 -0
  42. package/src/publish/contracts.ts +80 -0
  43. package/src/publish/external-resources.ts +117 -0
  44. package/src/publish/options.ts +180 -0
  45. package/src/publish/package-context.ts +608 -0
  46. package/src/publish/resource-references.ts +210 -0
  47. package/src/publish.ts +327 -975
  48. package/src/restore-internals/font.ts +100 -0
  49. package/src/restore-internals/movie-clip.ts +104 -0
  50. package/src/restore-internals/output-transaction.ts +124 -0
  51. package/src/restore.ts +122 -311
  52. package/src/shared-types.ts +4 -8
  53. package/src/uam-transaction.ts +34 -17
  54. package/src/utils.ts +28 -0
  55. 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,10 @@ import {
12
12
  UNITY_BINDER_TEMPLATE,
13
13
  UNITY_COMPONENT_TEMPLATE,
14
14
  } from './codegen-templates.js';
15
- import type { CliCodeGenerationSettings, PublishFileSystem, RootProjectSettings } from './shared-types.js';
15
+ import { formatPluginError, type LoadedPlugin } from './plugins/types.js';
16
+ import { dirname, isAbsolutePathLike, trimTrailingSlashes } from './path-utils.js';
17
+ import type { PublishFileSystem } from './publish/contracts.js';
18
+ import type { CliCodeGenerationSettings, RootProjectSettings } from './shared-types.js';
16
19
 
17
20
  export const AUTO_GENERATED_CODE_MARK = '/** This is an automatically generated class by FairyGUI. Please do not modify it. **/';
18
21
  const DEFAULT_CLASS_NAME_PREFIX = 'UI_';
@@ -22,25 +25,15 @@ export interface PublishCodeGenerationOptions {
22
25
  basePath?: string;
23
26
  fs: PublishFileSystem;
24
27
  packages: Package[];
28
+ plugins?: LoadedPlugin[];
25
29
  }
26
30
 
27
- interface ResolvedCodeGenerationSettings {
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 {
31
+ export interface ResolvedPackageCodegenPlan {
39
32
  outputDir: string;
40
33
  packageFolderName: string;
41
34
  packageNamespace: string;
42
35
  binderClassName: string;
43
- settings: ResolvedCodeGenerationSettings;
36
+ settings: CliCodeGenerationSettings;
44
37
  }
45
38
 
46
39
  interface FguiTypescriptVariant {
@@ -77,16 +70,22 @@ const SHARED_FGUI_TYPESCRIPT_VARIANT: FguiTypescriptVariant = {
77
70
  runtimeNamespace: 'fgui',
78
71
  };
79
72
 
80
- interface CodegenMember {
73
+ export interface CodegenMember {
81
74
  index: number;
82
75
  kind: 'child' | 'controller' | 'transition';
83
76
  name: string;
84
77
  originalName: string;
85
78
  type: string;
86
79
  ignored: boolean;
80
+ referencedComponent?: CodegenReferencedComponent;
81
+ }
82
+
83
+ export interface CodegenReferencedComponent {
84
+ component: Component;
85
+ package: Package;
87
86
  }
88
87
 
89
- interface CodegenClass {
88
+ export interface CodegenClass {
90
89
  classId: string;
91
90
  className: string;
92
91
  encodedClassName: string;
@@ -97,14 +96,28 @@ interface CodegenClass {
97
96
  members: CodegenMember[];
98
97
  }
99
98
 
100
- export async function publishCodeGeneration(
101
- doc: Document,
102
- options: PublishCodeGenerationOptions,
103
- ): Promise<void> {
99
+ export async function publishCodeGeneration(doc: Document, options: PublishCodeGenerationOptions): Promise<void> {
104
100
  const logger = doc.getLogger();
105
101
  const settings = resolveCodeGenerationSettings(doc);
106
102
  if (!settings.allowGenCode) return;
107
103
 
104
+ const plugins = options.plugins?.filter((plugin) => typeof plugin.plugin.genCode === 'function') ?? [];
105
+ if (plugins.length > 0) {
106
+ let handled = false;
107
+ for (const plugin of plugins) {
108
+ try {
109
+ await plugin.plugin.genCode(doc, settings, options);
110
+ handled = true;
111
+ logger.info(`publish: Generated code using plugin "${plugin.name}"`);
112
+ } catch (error) {
113
+ logger.warn(`publish: Code generation plugin "${plugin.name}" failed: ${formatPluginError(error)}`);
114
+ }
115
+ }
116
+ if (handled) {
117
+ return;
118
+ }
119
+ }
120
+
108
121
  for (const pkg of options.packages) {
109
122
  if (!pkg.getGenCode()) continue;
110
123
 
@@ -129,7 +142,7 @@ export async function publishCodeGeneration(
129
142
  }
130
143
  }
131
144
 
132
- function resolveCodeGenerationSettings(doc: Document): ResolvedCodeGenerationSettings {
145
+ export function resolveCodeGenerationSettings(doc: Document): Required<CliCodeGenerationSettings> {
133
146
  const settings = (doc.getRoot().getSettings?.() ?? {}) as RootProjectSettings;
134
147
  const publish = settings.publish ?? {};
135
148
  const codeGeneration = publish.codeGeneration as CliCodeGenerationSettings | undefined;
@@ -159,11 +172,7 @@ function resolveCodeGenerationSettings(doc: Document): ResolvedCodeGenerationSet
159
172
  };
160
173
  }
161
174
 
162
- function resolvePackageCodegenPlan(
163
- pkg: Package,
164
- settings: ResolvedCodeGenerationSettings,
165
- options: PublishCodeGenerationOptions,
166
- ): ResolvedPackageCodegenPlan | null {
175
+ export function resolvePackageCodegenPlan(pkg: Package, settings: CliCodeGenerationSettings, options: PublishCodeGenerationOptions): ResolvedPackageCodegenPlan | null {
167
176
  const rawCodePath = (pkg.getCodePath() || settings.codePath || '').trim();
168
177
  if (!rawCodePath) return null;
169
178
 
@@ -276,17 +285,11 @@ async function cleanupGeneratedFiles(directory: string, fs: PublishFileSystem, e
276
285
  }
277
286
  }
278
287
 
279
- function buildCodegenClasses(
280
- doc: Document,
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()));
288
+ export function buildCodegenClasses(doc: Document, pkg: Package, plan: ResolvedPackageCodegenPlan): CodegenClass[] {
289
+ const codegenComponents = pkg.listComponents().sort((left, right) => left.getId().localeCompare(right.getId()));
287
290
  const generatedById = new Map<string, CodegenClass>();
288
291
 
289
- for (const component of exportedComponents) {
292
+ for (const component of codegenComponents) {
290
293
  const encodedClassName = `${plan.settings.classNamePrefix}${normalizeTypeName(component.getName()) || 'Component'}`;
291
294
  generatedById.set(component.getId(), {
292
295
  classId: component.getId(),
@@ -300,7 +303,19 @@ function buildCodegenClasses(
300
303
  });
301
304
  }
302
305
 
303
- for (const component of exportedComponents) {
306
+ for (const component of codegenComponents) {
307
+ const classInfo = generatedById.get(component.getId());
308
+ if (!classInfo) continue;
309
+ classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
310
+ }
311
+
312
+ for (const [componentId, classInfo] of generatedById) {
313
+ if (classInfo.members.every((member) => member.ignored)) {
314
+ generatedById.delete(componentId);
315
+ }
316
+ }
317
+
318
+ for (const component of codegenComponents) {
304
319
  const classInfo = generatedById.get(component.getId());
305
320
  if (!classInfo) continue;
306
321
  classInfo.members = buildCodegenMembers(doc, pkg, component, plan, generatedById);
@@ -327,13 +342,17 @@ function buildCodegenMembers(
327
342
  }
328
343
 
329
344
  for (const child of component.listChildren()) {
345
+ if (!isRuntimeChild(child)) continue;
346
+ const index = childIndex++;
347
+ const resolvedChild = resolveChildType(doc, pkg, child, generatedById);
330
348
  members.push(createMember(
331
349
  ownerType,
332
350
  'child',
333
- resolveChildType(doc, pkg, child, generatedById),
351
+ resolvedChild.type,
334
352
  child.getName(),
335
- childIndex++,
353
+ index,
336
354
  plan,
355
+ resolvedChild.referencedComponent,
337
356
  ));
338
357
  }
339
358
 
@@ -355,6 +374,10 @@ function buildCodegenMembers(
355
374
  return members;
356
375
  }
357
376
 
377
+ function isRuntimeChild(child: GObject): boolean {
378
+ return child.propertyType !== 'GGroup' || (child as GObject & { getAdvanced?(): boolean }).getAdvanced?.() === true;
379
+ }
380
+
358
381
  function createMember(
359
382
  ownerType: string,
360
383
  kind: CodegenMember['kind'],
@@ -362,6 +385,7 @@ function createMember(
362
385
  originalName: string,
363
386
  index: number,
364
387
  plan: ResolvedPackageCodegenPlan,
388
+ referencedComponent?: CodegenReferencedComponent,
365
389
  ): CodegenMember {
366
390
  const ignored = plan.settings.ignoreNoname && isDefaultMemberName(ownerType, kind, originalName);
367
391
  return {
@@ -371,43 +395,59 @@ function createMember(
371
395
  originalName,
372
396
  type,
373
397
  ignored,
398
+ referencedComponent,
374
399
  };
375
400
  }
376
401
 
402
+ interface ResolvedChildCodegenType {
403
+ type: string;
404
+ referencedComponent?: CodegenReferencedComponent;
405
+ }
406
+
377
407
  function resolveChildType(
378
408
  doc: Document,
379
409
  pkg: Package,
380
410
  child: GObject,
381
411
  generatedById: Map<string, CodegenClass>,
382
- ): string {
412
+ ): ResolvedChildCodegenType {
383
413
  const src = (child as GObject & { getSrc?(): string }).getSrc?.();
384
414
  if (src) {
385
- const localResource = resolveChildSourceComponent(doc, pkg, src);
386
- if (localResource) {
387
- return generatedById.get(localResource.getId())?.encodedClassName
388
- ?? resolveComponentBaseType(localResource);
415
+ let referencedComponent: CodegenReferencedComponent | null = null;
416
+ if (src.startsWith('ui://')) {
417
+ const rest = src.slice(5);
418
+ const pkgId = rest.slice(0, 8);
419
+ const resourceId = rest.slice(8);
420
+ const targetPackage = doc.getRoot().listPackages().find((candidate) => candidate.getId() === pkgId);
421
+ const targetResource = targetPackage?.getResourceById(resourceId);
422
+ if (targetPackage && targetResource?.propertyType === 'Component') {
423
+ referencedComponent = { component: targetResource, package: targetPackage };
424
+ }
425
+ } else {
426
+ const packageId = (child as GComponent & { getPackageId?(): string }).getPackageId?.();
427
+ const targetPackage = packageId
428
+ ? doc.getRoot().listPackages().find((candidate) => candidate.getId() === packageId)
429
+ : pkg;
430
+ const targetResource = targetPackage?.getResourceById(src);
431
+ if (targetPackage && targetResource?.propertyType === 'Component') {
432
+ referencedComponent = { component: targetResource, package: targetPackage };
433
+ }
434
+ }
435
+
436
+ if (referencedComponent) {
437
+ const localGeneratedClass = referencedComponent.package === pkg
438
+ ? generatedById.get(referencedComponent.component.getId())
439
+ : undefined;
440
+ return {
441
+ type: localGeneratedClass?.encodedClassName ?? resolveComponentBaseType(referencedComponent.component),
442
+ referencedComponent,
443
+ };
389
444
  }
390
445
  }
391
446
 
392
447
  const instanceExtType = (child as GComponent & { getInstanceExtType?(): string }).getInstanceExtType?.();
393
- if (instanceExtType) return `G${instanceExtType}`;
394
-
395
- return child.propertyType;
396
- }
448
+ if (instanceExtType) return { type: `G${instanceExtType}` };
397
449
 
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
- }
408
-
409
- const localResource = pkg.getResourceById(src);
410
- return localResource?.propertyType === 'Component' ? localResource : null;
450
+ return { type: child.propertyType };
411
451
  }
412
452
 
413
453
  function resolveComponentBaseType(component: Component): string {
@@ -544,12 +584,12 @@ function resolveCodePath(
544
584
  basePath: string | undefined,
545
585
  fs: Pick<PublishFileSystem, 'join'>,
546
586
  ): string {
547
- if (isAbsolutePath(codePath)) return trimTrailingSlashes(codePath);
587
+ if (isAbsolutePathLike(codePath)) return trimTrailingSlashes(codePath);
548
588
  const projectBasePath = resolveProjectBasePath(basePath);
549
589
  return projectBasePath ? trimTrailingSlashes(fs.join(projectBasePath, codePath)) : trimTrailingSlashes(codePath);
550
590
  }
551
591
 
552
- function resolveProjectBasePath(basePath: string | undefined): string {
592
+ export function resolveProjectBasePath(basePath: string | undefined): string {
553
593
  if (!basePath) return '';
554
594
  const normalized = trimTrailingSlashes(basePath);
555
595
  const assetsMatch = normalized.match(/^(.*)[/\\]assets(?:_[^/\\]+)?$/i);
@@ -557,20 +597,6 @@ function resolveProjectBasePath(basePath: string | undefined): string {
557
597
  return dirname(normalized);
558
598
  }
559
599
 
560
- function dirname(filePath: string): string {
561
- const trimmed = trimTrailingSlashes(filePath);
562
- const match = trimmed.match(/^(.*)[/\\][^/\\]+$/);
563
- return match?.[1] ?? '';
564
- }
565
-
566
- function trimTrailingSlashes(value: string): string {
567
- return value.replace(/[/\\]+$/, '');
568
- }
569
-
570
- function isAbsolutePath(value: string): boolean {
571
- return /^[a-z]:[/\\]/i.test(value) || value.startsWith('/') || value.startsWith('\\\\');
572
- }
573
-
574
600
  function isDefaultMemberName(ownerType: string, kind: CodegenMember['kind'], name: string): boolean {
575
601
  if (kind === 'controller') {
576
602
  return (ownerType === 'GButton' || ownerType === 'GComboBox') && name === 'button';
@@ -578,13 +604,13 @@ function isDefaultMemberName(ownerType: string, kind: CodegenMember['kind'], nam
578
604
  if (kind === 'transition') return false;
579
605
 
580
606
  if (ownerType === 'GButton' || ownerType === 'GLabel' || ownerType === 'GComboBox') {
581
- return name === 'title' || name === 'icon';
607
+ if (name === 'title' || name === 'icon') return true;
582
608
  }
583
609
  if (ownerType === 'GProgressBar') {
584
- return name === 'bar' || name === 'bar_v' || name === 'title' || name === 'ani';
610
+ if (name === 'bar' || name === 'bar_v' || name === 'title' || name === 'ani') return true;
585
611
  }
586
612
  if (ownerType === 'GSlider') {
587
- return name === 'bar' || name === 'bar_v' || name === 'grip' || name === 'title' || name === 'ani';
613
+ if (name === 'bar' || name === 'bar_v' || name === 'grip' || name === 'title' || name === 'ani') return true;
588
614
  }
589
615
  return /^n\d+(?:_.*)?$/i.test(name);
590
616
  }
@@ -647,10 +673,10 @@ async function writeTextFile(fs: PublishFileSystem, filePath: string, content: s
647
673
  await fs.writeFileRaw(filePath, encodeText(content));
648
674
  }
649
675
 
650
- function encodeText(value: string): Uint8Array {
676
+ export function encodeText(value: string): Uint8Array {
651
677
  return new TextEncoder().encode(value);
652
678
  }
653
679
 
654
- function decodeText(value: Uint8Array): string {
680
+ export function decodeText(value: Uint8Array): string {
655
681
  return new TextDecoder().decode(value);
656
682
  }
package/src/index.ts CHANGED
@@ -1,9 +1,48 @@
1
1
  export { inspect, type InspectReport, type InspectCategoryReport } from './inspect.js';
2
- export { validate, type ValidateOptions, type ValidationResult, type ValidationIssue, ValidationSeverity } from './validate.js';
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 { publishCodeGeneration, AUTO_GENERATED_CODE_MARK, type PublishCodeGenerationOptions } from './codegen.js';
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
+ applyUamTransactionAppAsync,
27
67
  type ApplyUamTransactionAppDiagnostic,
28
68
  type ApplyUamTransactionAppError,
29
69
  type ApplyUamTransactionAppInput,
@@ -38,6 +78,6 @@ export type {
38
78
  HasOptionalSrc,
39
79
  HasOptionalUrl,
40
80
  PublishDependency,
41
- PublishFileSystem,
42
81
  RootProjectSettings,
82
+ CliCodeGenerationSettings,
43
83
  } from './shared-types.js';
package/src/node.ts ADDED
@@ -0,0 +1,8 @@
1
+ export {
2
+ publishNode,
3
+ type PublishNodeOptions,
4
+ } from './adapters/node/publish.js';
5
+ export {
6
+ restoreNode,
7
+ type RestoreNodeOptions,
8
+ } from './adapters/node/restore.js';
@@ -0,0 +1,40 @@
1
+ export function trimTrailingSlashes(value: string): string {
2
+ return value.replace(/[/\\]+$/, '');
3
+ }
4
+
5
+ export function dirname(filePath: string): string {
6
+ const match = trimTrailingSlashes(filePath).match(/^(.*)[/\\][^/\\]+$/);
7
+ return match?.[1] ?? '';
8
+ }
9
+
10
+ export function basename(filePath: string): string {
11
+ const match = trimTrailingSlashes(filePath).match(/([^/\\]+)$/);
12
+ return match?.[1] ?? '';
13
+ }
14
+
15
+ export function isAbsolutePathLike(value: string): boolean {
16
+ return /^(?:[a-zA-Z]:[/\\]|[/\\]{1,2})/u.test(value);
17
+ }
18
+
19
+ export function normalizeComparablePath(value: string): string {
20
+ const normalized = trimTrailingSlashes(value).replace(/\\/g, '/');
21
+ const driveMatch = normalized.match(/^([a-z]:)(?:\/(.*))?$/i);
22
+ const drivePrefix = driveMatch?.[1].toLowerCase() ?? '';
23
+ const remainder = driveMatch ? (driveMatch[2] ?? '') : normalized;
24
+ const hasRoot = driveMatch ? true : remainder.startsWith('/');
25
+ const segments: string[] = [];
26
+
27
+ for (const segment of remainder.split('/').filter(Boolean)) {
28
+ if (segment === '.') continue;
29
+ if (segment === '..') {
30
+ if (segments.length > 0 && segments.at(-1) !== '..') segments.pop();
31
+ else if (!hasRoot) segments.push('..');
32
+ continue;
33
+ }
34
+ segments.push(segment);
35
+ }
36
+
37
+ const joined = segments.join('/');
38
+ const comparable = drivePrefix ? `${drivePrefix}/${joined}` : hasRoot ? `/${joined}` : joined || '.';
39
+ return comparable.replace(/\/$/, '').toLowerCase();
40
+ }
@@ -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;