@openfairygui/functions 0.2.0-alpha.33 → 0.2.0-alpha.35

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/dist/web.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_publish = require("./publish-DCP0AYx2.cjs");
2
+ const require_publish = require("./publish-Bv7E2fZE.cjs");
3
3
  let _openfairygui_core = require("@openfairygui/core");
4
4
  //#region src/adapters/web/raster.ts
5
5
  function getBrowserContext(canvas) {
@@ -223,6 +223,15 @@ function toResult(success, files, diagnostics) {
223
223
  diagnostics
224
224
  };
225
225
  }
226
+ function unsupportedSetting(setting, path, message) {
227
+ return {
228
+ level: "error",
229
+ code: "unsupported_publish_setting",
230
+ setting,
231
+ path,
232
+ message
233
+ };
234
+ }
226
235
  /**
227
236
  * Publish a loaded FairyGUI project to browser-provided storage.
228
237
  *
@@ -238,14 +247,33 @@ async function publishBrowser(options) {
238
247
  options.document.setLogger(createDiagnosticLogger(previousLogger, diagnostics));
239
248
  try {
240
249
  if (options.projectType !== "layabox") throw new Error(`publishBrowser: unsupported project type "${String(options.projectType)}".`);
241
- assertBrowserImageSupport();
242
250
  root.setProjectType(_openfairygui_core.ProjectType.LayaBox);
251
+ const resolved = require_publish.resolvePublishOptions(options.document, {
252
+ compressed: options.compressed,
253
+ packages: options.packages,
254
+ atlas: options.atlas
255
+ });
256
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(resolved.fileExtension)) {
257
+ diagnostics.push(unsupportedSetting("fileExtension", "settings.publish.fileExtension", `publishBrowser: unsupported fileExtension "${resolved.fileExtension}".`));
258
+ return toResult(false, files, diagnostics);
259
+ }
260
+ const selectedPackageNames = options.packages?.length ? new Set(options.packages) : null;
261
+ const selectedPackages = root.listPackages().filter((pkg) => !selectedPackageNames || selectedPackageNames.has(pkg.getName()));
262
+ if (require_publish.resolveCodeGenerationSettings(options.document).allowGenCode) {
263
+ const packageIndex = selectedPackages.findIndex((pkg) => pkg.getGenCode());
264
+ if (packageIndex >= 0) {
265
+ const pkg = selectedPackages[packageIndex];
266
+ diagnostics.push(unsupportedSetting("codeGeneration", `packages[${root.listPackages().indexOf(pkg)}].publish.genCode`, `publishBrowser: code generation requested by package "${pkg.getName()}" is not supported.`));
267
+ return toResult(false, files, diagnostics);
268
+ }
269
+ }
270
+ assertBrowserImageSupport();
243
271
  const outputFileSystem = createTrackingFileSystem(options.outputFileSystem, files);
244
272
  const sourceAssetsPath = options.sourceFileSystem.join(options.document.getProjectDir(), "assets");
245
273
  await options.document.transform(require_publish.publish({
246
274
  output: options.output,
247
- compressed: options.compressed,
248
- fileExtension: "fui",
275
+ compressed: resolved.compressed,
276
+ fileExtension: resolved.fileExtension,
249
277
  packages: options.packages,
250
278
  branch: options.branch,
251
279
  basePath: sourceAssetsPath,
@@ -262,6 +290,7 @@ async function publishBrowser(options) {
262
290
  } catch (error) {
263
291
  diagnostics.push({
264
292
  level: "error",
293
+ code: "publish_failed",
265
294
  message: error instanceof Error ? error.message : String(error)
266
295
  });
267
296
  return toResult(false, files, diagnostics);
package/dist/web.d.cts CHANGED
@@ -20,6 +20,9 @@ interface BrowserPublishOptions {
20
20
  interface BrowserPublishDiagnostic {
21
21
  level: 'debug' | 'info' | 'warning' | 'error';
22
22
  message: string;
23
+ code?: 'unsupported_publish_setting' | 'publish_failed';
24
+ setting?: string;
25
+ path?: string;
23
26
  }
24
27
  interface BrowserPublishedFile {
25
28
  path: string;
package/dist/web.d.ts CHANGED
@@ -20,6 +20,9 @@ interface BrowserPublishOptions {
20
20
  interface BrowserPublishDiagnostic {
21
21
  level: 'debug' | 'info' | 'warning' | 'error';
22
22
  message: string;
23
+ code?: 'unsupported_publish_setting' | 'publish_failed';
24
+ setting?: string;
25
+ path?: string;
23
26
  }
24
27
  interface BrowserPublishedFile {
25
28
  path: string;
package/dist/web.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as publish } from "./publish-BJk8UzRP.js";
1
+ import { c as resolveCodeGenerationSettings, n as resolvePublishOptions, t as publish } from "./publish--8vagaSA.js";
2
2
  import { ProjectType } from "@openfairygui/core";
3
3
  //#region src/adapters/web/raster.ts
4
4
  function getBrowserContext(canvas) {
@@ -222,6 +222,15 @@ function toResult(success, files, diagnostics) {
222
222
  diagnostics
223
223
  };
224
224
  }
225
+ function unsupportedSetting(setting, path, message) {
226
+ return {
227
+ level: "error",
228
+ code: "unsupported_publish_setting",
229
+ setting,
230
+ path,
231
+ message
232
+ };
233
+ }
225
234
  /**
226
235
  * Publish a loaded FairyGUI project to browser-provided storage.
227
236
  *
@@ -237,14 +246,33 @@ async function publishBrowser(options) {
237
246
  options.document.setLogger(createDiagnosticLogger(previousLogger, diagnostics));
238
247
  try {
239
248
  if (options.projectType !== "layabox") throw new Error(`publishBrowser: unsupported project type "${String(options.projectType)}".`);
240
- assertBrowserImageSupport();
241
249
  root.setProjectType(ProjectType.LayaBox);
250
+ const resolved = resolvePublishOptions(options.document, {
251
+ compressed: options.compressed,
252
+ packages: options.packages,
253
+ atlas: options.atlas
254
+ });
255
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(resolved.fileExtension)) {
256
+ diagnostics.push(unsupportedSetting("fileExtension", "settings.publish.fileExtension", `publishBrowser: unsupported fileExtension "${resolved.fileExtension}".`));
257
+ return toResult(false, files, diagnostics);
258
+ }
259
+ const selectedPackageNames = options.packages?.length ? new Set(options.packages) : null;
260
+ const selectedPackages = root.listPackages().filter((pkg) => !selectedPackageNames || selectedPackageNames.has(pkg.getName()));
261
+ if (resolveCodeGenerationSettings(options.document).allowGenCode) {
262
+ const packageIndex = selectedPackages.findIndex((pkg) => pkg.getGenCode());
263
+ if (packageIndex >= 0) {
264
+ const pkg = selectedPackages[packageIndex];
265
+ diagnostics.push(unsupportedSetting("codeGeneration", `packages[${root.listPackages().indexOf(pkg)}].publish.genCode`, `publishBrowser: code generation requested by package "${pkg.getName()}" is not supported.`));
266
+ return toResult(false, files, diagnostics);
267
+ }
268
+ }
269
+ assertBrowserImageSupport();
242
270
  const outputFileSystem = createTrackingFileSystem(options.outputFileSystem, files);
243
271
  const sourceAssetsPath = options.sourceFileSystem.join(options.document.getProjectDir(), "assets");
244
272
  await options.document.transform(publish({
245
273
  output: options.output,
246
- compressed: options.compressed,
247
- fileExtension: "fui",
274
+ compressed: resolved.compressed,
275
+ fileExtension: resolved.fileExtension,
248
276
  packages: options.packages,
249
277
  branch: options.branch,
250
278
  basePath: sourceAssetsPath,
@@ -261,6 +289,7 @@ async function publishBrowser(options) {
261
289
  } catch (error) {
262
290
  diagnostics.push({
263
291
  level: "error",
292
+ code: "publish_failed",
264
293
  message: error instanceof Error ? error.message : String(error)
265
294
  });
266
295
  return toResult(false, files, diagnostics);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfairygui/functions",
3
- "version": "0.2.0-alpha.33",
3
+ "version": "0.2.0-alpha.35",
4
4
  "description": "FairyGUI Headless Authoring SDK — composable transform functions.",
5
5
  "author": "OpenFairyGUI Contributors",
6
6
  "license": "MIT",
@@ -74,7 +74,7 @@
74
74
  ],
75
75
  "dependencies": {
76
76
  "jiti": "^2.6.1",
77
- "@openfairygui/core": "0.2.0-alpha.33"
77
+ "@openfairygui/core": "0.2.0-alpha.35"
78
78
  },
79
79
  "optionalDependencies": {
80
80
  "sharp": ">=0.33.0"
@@ -1,11 +1,13 @@
1
1
  import { type Document, type ILogger, ProjectType } from '@openfairygui/core';
2
2
  import type { AtlasOptions } from '../../atlas.js';
3
+ import { resolveCodeGenerationSettings } from '../../codegen.js';
3
4
  import { publish } from '../../publish.js';
4
5
  import type {
5
6
  PublishFileSystem,
6
7
  PublishOutputFileSystem,
7
8
  PublishSourceFileSystem,
8
9
  } from '../../publish/contracts.js';
10
+ import { resolvePublishOptions } from '../../publish/options.js';
9
11
  import { assertBrowserImageSupport, createBrowserImageEncoder } from './raster.js';
10
12
 
11
13
  export type BrowserPublishProjectType = 'layabox';
@@ -42,6 +44,9 @@ export interface BrowserPublishOptions {
42
44
  export interface BrowserPublishDiagnostic {
43
45
  level: 'debug' | 'info' | 'warning' | 'error';
44
46
  message: string;
47
+ code?: 'unsupported_publish_setting' | 'publish_failed';
48
+ setting?: string;
49
+ path?: string;
45
50
  }
46
51
 
47
52
  export interface BrowserPublishedFile {
@@ -103,6 +108,10 @@ function toResult(
103
108
  };
104
109
  }
105
110
 
111
+ function unsupportedSetting(setting: string, path: string, message: string): BrowserPublishDiagnostic {
112
+ return { level: 'error', code: 'unsupported_publish_setting', setting, path, message };
113
+ }
114
+
106
115
  /**
107
116
  * Publish a loaded FairyGUI project to browser-provided storage.
108
117
  *
@@ -121,16 +130,43 @@ export async function publishBrowser(options: BrowserPublishOptions): Promise<Br
121
130
  if (options.projectType !== 'layabox') {
122
131
  throw new Error(`publishBrowser: unsupported project type "${String(options.projectType)}".`);
123
132
  }
124
- assertBrowserImageSupport();
125
133
  root.setProjectType(ProjectType.LayaBox);
134
+ const resolved = resolvePublishOptions(options.document, {
135
+ compressed: options.compressed,
136
+ packages: options.packages,
137
+ atlas: options.atlas,
138
+ });
139
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(resolved.fileExtension)) {
140
+ diagnostics.push(unsupportedSetting(
141
+ 'fileExtension',
142
+ 'settings.publish.fileExtension',
143
+ `publishBrowser: unsupported fileExtension "${resolved.fileExtension}".`,
144
+ ));
145
+ return toResult(false, files, diagnostics);
146
+ }
147
+ const selectedPackageNames = options.packages?.length ? new Set(options.packages) : null;
148
+ const selectedPackages = root.listPackages().filter((pkg) => !selectedPackageNames || selectedPackageNames.has(pkg.getName()));
149
+ if (resolveCodeGenerationSettings(options.document).allowGenCode) {
150
+ const packageIndex = selectedPackages.findIndex((pkg) => pkg.getGenCode());
151
+ if (packageIndex >= 0) {
152
+ const pkg = selectedPackages[packageIndex]!;
153
+ diagnostics.push(unsupportedSetting(
154
+ 'codeGeneration',
155
+ `packages[${root.listPackages().indexOf(pkg)}].publish.genCode`,
156
+ `publishBrowser: code generation requested by package "${pkg.getName()}" is not supported.`,
157
+ ));
158
+ return toResult(false, files, diagnostics);
159
+ }
160
+ }
161
+ assertBrowserImageSupport();
126
162
  const outputFileSystem = createTrackingFileSystem(options.outputFileSystem, files);
127
163
  const sourceAssetsPath = options.sourceFileSystem.join(options.document.getProjectDir(), 'assets');
128
164
 
129
165
  await options.document.transform(
130
166
  publish({
131
167
  output: options.output,
132
- compressed: options.compressed,
133
- fileExtension: 'fui',
168
+ compressed: resolved.compressed,
169
+ fileExtension: resolved.fileExtension,
134
170
  packages: options.packages,
135
171
  branch: options.branch,
136
172
  basePath: sourceAssetsPath,
@@ -149,6 +185,7 @@ export async function publishBrowser(options: BrowserPublishOptions): Promise<Br
149
185
  } catch (error) {
150
186
  diagnostics.push({
151
187
  level: 'error',
188
+ code: 'publish_failed',
152
189
  message: error instanceof Error ? error.message : String(error),
153
190
  });
154
191
  return toResult(false, files, diagnostics);
@@ -21,7 +21,7 @@ import {
21
21
  } from '../publish/package-context.js';
22
22
  import type { ExtrasMap } from '../shared-types.js';
23
23
  import { parseFnt } from './font.js';
24
- import { extractJtaFrames } from './jta.js';
24
+ import { prepareJtaForPublish, type PreparedJtaData } from './jta.js';
25
25
 
26
26
  /** Trim info for a single image. */
27
27
  interface TrimInfo {
@@ -181,6 +181,36 @@ export interface PagedAtlasGroup {
181
181
  inputs: InputItem[];
182
182
  }
183
183
 
184
+ export function resolveMovieClipSourcePath(resource: MovieClipResource, pkg: Package, basePath: string): string {
185
+ const fileName = `${resource.getName()}.jta`;
186
+ const resourcePath = resource.getPath() ?? '/';
187
+ return `${basePath}/${pkg.getName()}${resourcePath}${fileName}`;
188
+ }
189
+
190
+ export async function prepareMovieClipResource(
191
+ resource: MovieClipResource,
192
+ pkg: Package,
193
+ encoder: AtlasRasterBackend | undefined,
194
+ basePath: string,
195
+ readFileRaw: (path: string) => Promise<Uint8Array>,
196
+ ): Promise<PreparedJtaData> {
197
+ const filePath = resolveMovieClipSourcePath(resource, pkg, basePath);
198
+ let raw: Uint8Array;
199
+ try {
200
+ raw = await readFileRaw(filePath);
201
+ } catch {
202
+ throw new Error(`atlas: Could not read MovieClip "${filePath}".`);
203
+ }
204
+
205
+ try {
206
+ return await prepareJtaForPublish(raw, encoder, filePath);
207
+ } catch (error) {
208
+ if (error instanceof Error && error.message.startsWith('atlas:')) throw error;
209
+ const detail = error instanceof Error ? ` ${error.message}` : '';
210
+ throw new Error(`atlas: Could not parse MovieClip "${filePath}".${detail}`);
211
+ }
212
+ }
213
+
184
214
  /** Collect a single ImageResource into the inputs array. */
185
215
  export async function collectImage(
186
216
  resource: ImageResource,
@@ -285,130 +315,62 @@ export async function collectMovieClipFrames(
285
315
  }
286
316
 
287
317
  const mcId = resource.getId();
288
- const mcName = resource.getName() + '.jta';
289
- const mcPath = resource.getPath() ?? '/';
290
- const filePath = `${options.basePath}/${pkg.getName()}${mcPath}${mcName}`;
318
+ const filePath = resolveMovieClipSourcePath(resource, pkg, options.basePath);
291
319
 
292
320
  try {
293
- const raw = await options.readFileRaw(filePath);
294
- const jta = extractJtaFrames(raw);
295
- if (jta.frames.length === 0) return;
296
-
297
- const frameMetas = jta.meta?.frames ?? [];
321
+ const jta =
322
+ options.preparedMovieClips?.get(resource) ??
323
+ (await prepareMovieClipResource(resource, pkg, encoder, options.basePath, options.readFileRaw));
298
324
  for (const frame of resource.listFrames()) {
299
325
  resource.removeFrame(frame);
300
326
  }
301
327
  resource
302
- .setInterval(jta.meta?.interval ?? 100)
303
- .setSwing(jta.meta?.swing ?? false)
304
- .setRepeatDelay(jta.meta?.repeatDelay ?? 0);
305
-
306
- if (frameMetas.length > 0) {
307
- const firstFrameIndexByTextureIndex = new Map<number, number>();
308
- for (let frameIndex = 0; frameIndex < frameMetas.length; frameIndex += 1) {
309
- const meta = frameMetas[frameIndex];
310
- const textureIndex = Number.isFinite(meta.textureIndex) ? meta.textureIndex : frameIndex;
311
- if (!firstFrameIndexByTextureIndex.has(textureIndex)) {
312
- firstFrameIndexByTextureIndex.set(textureIndex, frameIndex);
313
- }
314
- }
315
-
316
- const spriteIdByTextureIndex = new Map<number, string>();
317
- for (let textureIndex = 0; textureIndex < jta.frames.length; textureIndex += 1) {
318
- const exportFrameIndex = firstFrameIndexByTextureIndex.get(textureIndex);
319
- if (exportFrameIndex === undefined) continue;
320
- const itemId = `${mcId}_${exportFrameIndex}`;
321
- const input = await createMovieClipFrameInput(
322
- jta.frames[textureIndex],
323
- itemId,
328
+ .setInterval(jta.meta.interval)
329
+ .setSwing(jta.meta.swing)
330
+ .setRepeatDelay(jta.meta.repeatDelay);
331
+ const spriteIdByTextureIndex = new Map<number, string>();
332
+ for (const texture of jta.referencedTextures) {
333
+ if (texture.width <= 0 || texture.height <= 0) continue;
334
+ const itemId = `${mcId}_${texture.firstFrameIndex}`;
335
+ inputs.push({
336
+ id: itemId,
337
+ width: texture.width,
338
+ height: texture.height,
339
+ originalWidth: texture.width,
340
+ originalHeight: texture.height,
341
+ offsetX: 0,
342
+ offsetY: 0,
324
343
  resource,
325
- encoder,
326
- options.strictOutput,
327
- );
328
- if (!input) continue;
329
- inputs.push(input);
330
- spriteIdByTextureIndex.set(textureIndex, itemId);
331
- }
344
+ trimBuffer: texture.buffer,
345
+ sourceKind: 'movieclip-frame',
346
+ });
347
+ spriteIdByTextureIndex.set(texture.textureIndex, itemId);
348
+ }
332
349
 
333
- for (let frameIndex = 0; frameIndex < frameMetas.length; frameIndex += 1) {
334
- const meta = frameMetas[frameIndex];
335
- const textureIndex = Number.isFinite(meta.textureIndex) ? meta.textureIndex : frameIndex;
336
- const frame = doc.createMovieFrame(`${mcId}_${frameIndex}`);
337
- frame
338
- .setRectX(meta.offsetX)
339
- .setRectY(meta.offsetY)
340
- .setRectWidth(meta.width)
341
- .setRectHeight(meta.height)
342
- .setAddDelay(meta.addDelay)
343
- .setSpriteId(spriteIdByTextureIndex.get(textureIndex) ?? '');
344
- resource.addFrame(frame);
345
- }
346
- } else {
347
- for (let frameIndex = 0; frameIndex < jta.frames.length; frameIndex += 1) {
348
- const itemId = `${mcId}_${frameIndex}`;
349
- const input = await createMovieClipFrameInput(
350
- jta.frames[frameIndex],
351
- itemId,
352
- resource,
353
- encoder,
354
- options.strictOutput,
355
- );
356
- if (!input) continue;
357
- inputs.push(input);
358
- const frame = doc.createMovieFrame(itemId);
359
- frame
360
- .setRectX(0)
361
- .setRectY(0)
362
- .setRectWidth(input.originalWidth)
363
- .setRectHeight(input.originalHeight)
364
- .setAddDelay(0)
365
- .setSpriteId(itemId);
366
- resource.addFrame(frame);
367
- }
350
+ for (let frameIndex = 0; frameIndex < jta.meta.frames.length; frameIndex += 1) {
351
+ const meta = jta.meta.frames[frameIndex]!;
352
+ const frame = doc.createMovieFrame(`${mcId}_${frameIndex}`);
353
+ frame
354
+ .setRectX(meta.offsetX)
355
+ .setRectY(meta.offsetY)
356
+ .setRectWidth(meta.width)
357
+ .setRectHeight(meta.height)
358
+ .setAddDelay(meta.addDelay)
359
+ .setSpriteId(meta.textureIndex === -1 ? '' : (spriteIdByTextureIndex.get(meta.textureIndex) ?? ''));
360
+ resource.addFrame(frame);
368
361
  }
369
362
 
370
- if ((jta.meta?.width ?? 0) > 0 && (jta.meta?.height ?? 0) > 0) {
371
- resource.setWidth(jta.meta?.width ?? 0);
372
- resource.setHeight(jta.meta?.height ?? 0);
363
+ if (jta.meta.width > 0 && jta.meta.height > 0) {
364
+ resource.setWidth(jta.meta.width);
365
+ resource.setHeight(jta.meta.height);
373
366
  }
374
- } catch {
375
- const message = `atlas: Could not parse MovieClip "${filePath}".`;
376
- if (options.strictOutput) throw new Error(message);
367
+ } catch (error) {
368
+ const message = error instanceof Error ? error.message : `atlas: Could not parse MovieClip "${filePath}".`;
369
+ if (options.strictOutput) throw error;
377
370
  logger.warn(`${message} Skipping frames.`);
378
371
  }
379
372
  }
380
373
 
381
- async function createMovieClipFrameInput(
382
- buffer: Uint8Array,
383
- itemId: string,
384
- resource: MovieClipResource,
385
- encoder: AtlasRasterBackend | undefined,
386
- strictOutput: boolean,
387
- ): Promise<InputItem | null> {
388
- if (!encoder || buffer.length === 0) return null;
389
- try {
390
- const meta = await encoder(buffer).metadata();
391
- const width = meta.width ?? 0;
392
- const height = meta.height ?? 0;
393
- if (width <= 0 || height <= 0) return null;
394
- return {
395
- id: itemId,
396
- width,
397
- height,
398
- originalWidth: width,
399
- originalHeight: height,
400
- offsetX: 0,
401
- offsetY: 0,
402
- resource,
403
- trimBuffer: buffer,
404
- sourceKind: 'movieclip-frame',
405
- };
406
- } catch {
407
- if (strictOutput) throw new Error(`atlas: Could not decode MovieClip frame "${itemId}".`);
408
- return null;
409
- }
410
- }
411
-
412
374
  /** Collect a Bitmap Font's texture image, packed under the font's ID. */
413
375
  export async function collectFontTexture(
414
376
  doc: Document,