@openfairygui/functions 0.2.0 → 0.3.0-alpha.2

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 CHANGED
@@ -13,12 +13,13 @@ npm install --save @openfairygui/core @openfairygui/functions
13
13
  ```ts
14
14
  import { NodeIO } from '@openfairygui/core/node';
15
15
  import { inspect } from '@openfairygui/functions';
16
- import { publishNode, restoreNode } from '@openfairygui/functions/node';
16
+ import { publishNode, restoreNode, validateProjectNode } from '@openfairygui/functions/node';
17
17
 
18
18
  const io = new NodeIO();
19
19
  const doc = await io.readProject('./MyProject/MyProject.fairy');
20
20
 
21
21
  const report = inspect(doc);
22
+ const validation = await validateProjectNode('./MyProject/MyProject.fairy');
22
23
  await publishNode({ document: doc, output: './release' });
23
24
 
24
25
  await restoreNode({
@@ -27,17 +28,19 @@ await restoreNode({
27
28
  });
28
29
  ```
29
30
 
30
- `publishNode` owns the standard Node filesystem, Sharp raster backend, and project plugin discovery. `restoreNode` owns the Node filesystem and Sharp image extraction required by trusted-local artifact recovery. The root `publish()` and `restore()` exports remain the lower-level capability-injected workflows for custom hosts.
31
+ `validateProjectNode` combines detailed project reads, UAM integrity checks, source checks, and Sharp image decoding without writing files. `publishNode` owns the standard Node filesystem, Sharp raster backend, and project plugin discovery. `restoreNode` owns the Node filesystem and Sharp image extraction required by trusted-local artifact recovery. The root `validateProject()`, `publish()`, and `restore()` exports remain lower-level workflows for custom hosts.
31
32
 
32
33
  ## Browser LayaBox publish
33
34
 
34
35
  Use `@openfairygui/core/web` to read the raw project, then publish through the browser-only entry. Both filesystems are caller-owned, so they can be File System Access, OPFS, IndexedDB, ZIP, or memory adapters.
35
36
 
36
37
  ```ts
38
+ import { liftDocumentToUamProject } from '@openfairygui/core';
37
39
  import { WebIO } from '@openfairygui/core/web';
38
- import { publishBrowser } from '@openfairygui/functions/web';
40
+ import { publishBrowser, validateProjectWeb } from '@openfairygui/functions/web';
39
41
 
40
- const document = await new WebIO(sourceFileSystem).readProject('Project.fairy');
42
+ const document = await new WebIO(sourceFileSystem).readProject('Project.fairy', { hydrateResourceBytes: true });
43
+ const validation = await validateProjectWeb(liftDocumentToUamProject(document));
41
44
  const result = await publishBrowser({
42
45
  document,
43
46
  sourceFileSystem,
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_publish = require("./publish-CykUJfVa.cjs");
3
- const require_restore = require("./restore-CEywQUHz.cjs");
2
+ const require_publish = require("./publish-C7qHwEiP.cjs");
3
+ const require_restore = require("./restore-LXbDQqmT.cjs");
4
4
  const require_uam_transaction = require("./uam-transaction.cjs");
5
5
  //#region src/inspect.ts
6
6
  function mapResource(resource) {
@@ -104,125 +104,6 @@ function inspect(doc) {
104
104
  };
105
105
  }
106
106
  //#endregion
107
- //#region src/validate.ts
108
- /**
109
- * Severity of a validation issue.
110
- */
111
- let ValidationSeverity = /* @__PURE__ */ function(ValidationSeverity) {
112
- ValidationSeverity["ERROR"] = "error";
113
- ValidationSeverity["WARNING"] = "warning";
114
- ValidationSeverity["INFO"] = "info";
115
- return ValidationSeverity;
116
- }({});
117
- const VALIDATE_DEFAULTS = { throwOnError: false };
118
- /**
119
- * Validates a FairyGUI project for common issues:
120
- * - Missing resource IDs
121
- * - Broken `ui://` references (src pointing to non-existent resources)
122
- * - Empty components (no children)
123
- * - Controllers with no pages
124
- * - Duplicate resource IDs within a package
125
- *
126
- * The validation result is stored in `doc.getRoot().getExtras()._validation`.
127
- *
128
- * ```ts
129
- * await doc.transform(validate({ throwOnError: true }));
130
- * ```
131
- */
132
- function validate(_options = {}) {
133
- const options = {
134
- ...VALIDATE_DEFAULTS,
135
- ..._options
136
- };
137
- return require_publish.createTransform("validate", (doc) => {
138
- const issues = [];
139
- const root = doc.getRoot();
140
- if (!root.getProjectId()) issues.push({
141
- severity: ValidationSeverity.WARNING,
142
- message: "Project has no ID."
143
- });
144
- const globalResources = /* @__PURE__ */ new Map();
145
- for (const pkg of root.listPackages()) {
146
- if (!pkg.getId()) issues.push({
147
- severity: ValidationSeverity.ERROR,
148
- message: `Package "${pkg.getName()}" has no ID.`,
149
- packageName: pkg.getName()
150
- });
151
- const idSet = /* @__PURE__ */ new Set();
152
- for (const res of pkg.listResources()) {
153
- const resId = res.getId();
154
- if (!resId) {
155
- issues.push({
156
- severity: ValidationSeverity.WARNING,
157
- message: `Resource "${res.getName()}" has no ID.`,
158
- packageName: pkg.getName(),
159
- resourceName: res.getName()
160
- });
161
- continue;
162
- }
163
- if (idSet.has(resId)) issues.push({
164
- severity: ValidationSeverity.ERROR,
165
- message: `Duplicate resource ID "${resId}" in package "${pkg.getName()}".`,
166
- packageName: pkg.getName(),
167
- resourceName: res.getName()
168
- });
169
- idSet.add(resId);
170
- globalResources.set(`${pkg.getId()}${resId}`, `${pkg.getName()}/${res.getName()}`);
171
- }
172
- for (const comp of pkg.listComponents()) {
173
- const children = comp.listChildren();
174
- if (children.length === 0) issues.push({
175
- severity: ValidationSeverity.INFO,
176
- message: `Component "${comp.getName()}" has no children.`,
177
- packageName: pkg.getName(),
178
- componentName: comp.getName()
179
- });
180
- for (const ctrl of comp.listControllers()) if (ctrl.listPages().length === 0) issues.push({
181
- severity: ValidationSeverity.WARNING,
182
- message: `Controller "${ctrl.getName()}" in "${comp.getName()}" has no pages.`,
183
- packageName: pkg.getName(),
184
- componentName: comp.getName()
185
- });
186
- for (const child of children) {
187
- const src = child.getSrc?.();
188
- if (!src) continue;
189
- if (src.startsWith("ui://")) {
190
- const idPart = src.slice(5);
191
- if (idPart.length > 8) {
192
- const key = `${idPart.slice(0, 8)}${idPart.slice(8)}`;
193
- if (!globalResources.has(key)) issues.push({
194
- severity: ValidationSeverity.ERROR,
195
- message: `Broken reference "${src}" in "${child.getName()}" (component "${comp.getName()}").`,
196
- packageName: pkg.getName(),
197
- componentName: comp.getName(),
198
- resourceName: child.getName()
199
- });
200
- }
201
- }
202
- }
203
- }
204
- }
205
- const errors = issues.filter((i) => i.severity === ValidationSeverity.ERROR);
206
- const warnings = issues.filter((i) => i.severity === ValidationSeverity.WARNING);
207
- const infos = issues.filter((i) => i.severity === ValidationSeverity.INFO);
208
- const result = {
209
- ok: errors.length === 0,
210
- errors,
211
- warnings,
212
- infos
213
- };
214
- root.setExtras({
215
- ...root.getExtras(),
216
- _validation: result
217
- });
218
- const logger = doc.getLogger();
219
- if (errors.length) logger.warn(`validate: ${errors.length} error(s) found.`);
220
- if (warnings.length) logger.warn(`validate: ${warnings.length} warning(s) found.`);
221
- logger.info(`validate: ${issues.length} issue(s) total.`);
222
- if (options.throwOnError && errors.length > 0) throw new Error(`Validation failed with ${errors.length} error(s):\n${errors.map((e) => ` - ${e.message}`).join("\n")}`);
223
- });
224
- }
225
- //#endregion
226
107
  //#region src/prune.ts
227
108
  const PRUNE_DEFAULTS = {
228
109
  emptyComponents: false,
@@ -321,7 +202,6 @@ function rename(options) {
321
202
  }
322
203
  //#endregion
323
204
  exports.AUTO_GENERATED_CODE_MARK = require_publish.AUTO_GENERATED_CODE_MARK;
324
- exports.ValidationSeverity = ValidationSeverity;
325
205
  exports.applyUamTransactionApp = require_uam_transaction.applyUamTransactionApp;
326
206
  exports.applyUamTransactionAppAsync = require_uam_transaction.applyUamTransactionAppAsync;
327
207
  exports.atlas = require_publish.atlas;
@@ -337,4 +217,4 @@ exports.rename = rename;
337
217
  exports.resolvePackageCodegenPlan = require_publish.resolvePackageCodegenPlan;
338
218
  exports.resolvePublishOptions = require_publish.resolvePublishOptions;
339
219
  exports.restore = require_restore.restore;
340
- exports.validate = validate;
220
+ exports.validateProject = require_publish.validateProject;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { a as AtlasRasterInput, c as AtlasRasterResolvedBuffer, d as PublishSourceFileSystem, i as AtlasRasterCompositeInput, l as PublishFileSystem, n as atlas, o as AtlasRasterMetadata, r as AtlasRasterBackend, s as AtlasRasterPipeline, t as AtlasOptions, u as PublishOutputFileSystem } from "./atlas-CHsu2Y8i.cjs";
2
2
  import { A as ExtrasMap, B as ResolvedPublishOptions, C as MaybePromise, D as CliAtlasSettings, E as PluginModule, F as RootProjectSettings, I as publish, L as PublishOptions, M as HasOptionalSrc, N as HasOptionalUrl, O as CliCodeGenerationSettings, P as PublishDependency, R as ResolvePublishOptionsOverrides, S as LoadedPlugin, T as PluginManifest, V as resolvePublishOptions, _ as encodeText, a as RestoreImageExtractor, b as CodeWriter, c as restore, d as CodegenMember, f as CodegenReferencedComponent, g as decodeText, h as buildCodegenClasses, i as RestoreImageExtractInput, j as HasOptionalFont, k as CliPublishSettings, l as AUTO_GENERATED_CODE_MARK, m as ResolvedPackageCodegenPlan, n as RestoreImageCropInput, o as RestoreOptions, p as PublishCodeGenerationOptions, r as RestoreImageCropper, s as RestoreResult, t as RestoreFileSystem, u as CodegenClass, v as publishCodeGeneration, w as Plugin, x as ICodeWriterConfig, y as resolvePackageCodegenPlan, z as ResolvedPublishAtlasOptions } from "./restore-BeWaJNjR.cjs";
3
3
  import { ApplyUamTransactionAppDiagnostic, ApplyUamTransactionAppError, ApplyUamTransactionAppInput, ApplyUamTransactionAppResult, applyUamTransactionApp, applyUamTransactionAppAsync } from "./uam-transaction.cjs";
4
- import { Document, Transform } from "@openfairygui/core";
4
+ import { Document, ProjectDiagnostic, ProjectValidationReport, Transform, UamProject } from "@openfairygui/core";
5
5
 
6
6
  //#region src/inspect.d.ts
7
7
  /**
@@ -69,55 +69,16 @@ interface InspectReport {
69
69
  declare function inspect(doc: Document): InspectReport;
70
70
  //#endregion
71
71
  //#region src/validate.d.ts
72
- /**
73
- * Severity of a validation issue.
74
- */
75
- declare enum ValidationSeverity {
76
- ERROR = "error",
77
- WARNING = "warning",
78
- INFO = "info"
79
- }
80
- /**
81
- * A single validation issue found in the project.
82
- */
83
- interface ValidationIssue {
84
- severity: ValidationSeverity;
85
- message: string;
86
- /** Package name where the issue was found. */
87
- packageName?: string;
88
- /** Component name where the issue was found. */
89
- componentName?: string;
90
- /** Resource/object name related to the issue. */
91
- resourceName?: string;
92
- }
93
- /**
94
- * Result returned by `validate()`.
95
- */
96
- interface ValidationResult {
97
- ok: boolean;
98
- errors: ValidationIssue[];
99
- warnings: ValidationIssue[];
100
- infos: ValidationIssue[];
72
+ interface ValidateProjectOptions {
73
+ /** Diagnostics collected while reading the source project. */
74
+ readDiagnostics?: readonly ProjectDiagnostic[];
75
+ /** Whether the reader and host completed every requested check. */
76
+ complete?: boolean;
77
+ /** Validate hydrated resource bytes in addition to the UAM graph. */
78
+ validateSources?: boolean;
101
79
  }
102
- interface ValidateOptions {
103
- /** If true, the transform throws on errors. Default: false. */
104
- throwOnError?: boolean;
105
- }
106
- /**
107
- * Validates a FairyGUI project for common issues:
108
- * - Missing resource IDs
109
- * - Broken `ui://` references (src pointing to non-existent resources)
110
- * - Empty components (no children)
111
- * - Controllers with no pages
112
- * - Duplicate resource IDs within a package
113
- *
114
- * The validation result is stored in `doc.getRoot().getExtras()._validation`.
115
- *
116
- * ```ts
117
- * await doc.transform(validate({ throwOnError: true }));
118
- * ```
119
- */
120
- declare function validate(_options?: ValidateOptions): Transform;
80
+ /** Validate one authoritative UAM snapshot without mutating it. */
81
+ declare function validateProject(project: UamProject, options?: ValidateProjectOptions): ProjectValidationReport;
121
82
  //#endregion
122
83
  //#region src/prune.d.ts
123
84
  interface PruneOptions {
@@ -174,4 +135,4 @@ declare function rename(options: RenameOptions): Transform;
174
135
  */
175
136
  declare function createTransform(name: string, fn: Transform): Transform;
176
137
  //#endregion
177
- export { AUTO_GENERATED_CODE_MARK, type ApplyUamTransactionAppDiagnostic, type ApplyUamTransactionAppError, type ApplyUamTransactionAppInput, type ApplyUamTransactionAppResult, type AtlasOptions, type AtlasRasterBackend, type AtlasRasterCompositeInput, type AtlasRasterInput, type AtlasRasterMetadata, type AtlasRasterPipeline, type AtlasRasterResolvedBuffer, type CliAtlasSettings, type CliCodeGenerationSettings, type CliPublishSettings, type CodeWriter, type CodegenClass, type CodegenMember, type CodegenReferencedComponent, type ExtrasMap, type HasOptionalFont, type HasOptionalSrc, type HasOptionalUrl, type ICodeWriterConfig, type InspectCategoryReport, type InspectReport, type LoadedPlugin, type MaybePromise, type Plugin, type PluginManifest, type PluginModule, type PruneOptions, type PublishCodeGenerationOptions, type PublishDependency, type PublishFileSystem, type PublishOptions, type PublishOutputFileSystem, type PublishSourceFileSystem, type RenameOptions, type ResolvePublishOptionsOverrides, type ResolvedPackageCodegenPlan, type ResolvedPublishAtlasOptions, type ResolvedPublishOptions, type RestoreFileSystem, type RestoreImageCropInput, type RestoreImageCropper, type RestoreImageExtractInput, type RestoreImageExtractor, type RestoreOptions, type RestoreResult, type RootProjectSettings, type ValidateOptions, type ValidationIssue, type ValidationResult, ValidationSeverity, applyUamTransactionApp, applyUamTransactionAppAsync, atlas, buildCodegenClasses, createTransform, decodeText, encodeText, inspect, prune, publish, publishCodeGeneration, rename, resolvePackageCodegenPlan, resolvePublishOptions, restore, validate };
138
+ export { AUTO_GENERATED_CODE_MARK, type ApplyUamTransactionAppDiagnostic, type ApplyUamTransactionAppError, type ApplyUamTransactionAppInput, type ApplyUamTransactionAppResult, type AtlasOptions, type AtlasRasterBackend, type AtlasRasterCompositeInput, type AtlasRasterInput, type AtlasRasterMetadata, type AtlasRasterPipeline, type AtlasRasterResolvedBuffer, type CliAtlasSettings, type CliCodeGenerationSettings, type CliPublishSettings, type CodeWriter, type CodegenClass, type CodegenMember, type CodegenReferencedComponent, type ExtrasMap, type HasOptionalFont, type HasOptionalSrc, type HasOptionalUrl, type ICodeWriterConfig, type InspectCategoryReport, type InspectReport, type LoadedPlugin, type MaybePromise, type Plugin, type PluginManifest, type PluginModule, type PruneOptions, type PublishCodeGenerationOptions, type PublishDependency, type PublishFileSystem, type PublishOptions, type PublishOutputFileSystem, type PublishSourceFileSystem, type RenameOptions, type ResolvePublishOptionsOverrides, type ResolvedPackageCodegenPlan, type ResolvedPublishAtlasOptions, type ResolvedPublishOptions, type RestoreFileSystem, type RestoreImageCropInput, type RestoreImageCropper, type RestoreImageExtractInput, type RestoreImageExtractor, type RestoreOptions, type RestoreResult, type RootProjectSettings, type ValidateProjectOptions, applyUamTransactionApp, applyUamTransactionAppAsync, atlas, buildCodegenClasses, createTransform, decodeText, encodeText, inspect, prune, publish, publishCodeGeneration, rename, resolvePackageCodegenPlan, resolvePublishOptions, restore, validateProject };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { a as AtlasRasterInput, c as AtlasRasterResolvedBuffer, d as PublishSourceFileSystem, i as AtlasRasterCompositeInput, l as PublishFileSystem, n as atlas, o as AtlasRasterMetadata, r as AtlasRasterBackend, s as AtlasRasterPipeline, t as AtlasOptions, u as PublishOutputFileSystem } from "./atlas-C6tbl7nn.js";
2
2
  import { A as ExtrasMap, B as ResolvedPublishOptions, C as MaybePromise, D as CliAtlasSettings, E as PluginModule, F as RootProjectSettings, I as publish, L as PublishOptions, M as HasOptionalSrc, N as HasOptionalUrl, O as CliCodeGenerationSettings, P as PublishDependency, R as ResolvePublishOptionsOverrides, S as LoadedPlugin, T as PluginManifest, V as resolvePublishOptions, _ as encodeText, a as RestoreImageExtractor, b as CodeWriter, c as restore, d as CodegenMember, f as CodegenReferencedComponent, g as decodeText, h as buildCodegenClasses, i as RestoreImageExtractInput, j as HasOptionalFont, k as CliPublishSettings, l as AUTO_GENERATED_CODE_MARK, m as ResolvedPackageCodegenPlan, n as RestoreImageCropInput, o as RestoreOptions, p as PublishCodeGenerationOptions, r as RestoreImageCropper, s as RestoreResult, t as RestoreFileSystem, u as CodegenClass, v as publishCodeGeneration, w as Plugin, x as ICodeWriterConfig, y as resolvePackageCodegenPlan, z as ResolvedPublishAtlasOptions } from "./restore-Dh0-Nvms.js";
3
3
  import { ApplyUamTransactionAppDiagnostic, ApplyUamTransactionAppError, ApplyUamTransactionAppInput, ApplyUamTransactionAppResult, applyUamTransactionApp, applyUamTransactionAppAsync } from "./uam-transaction.js";
4
- import { Document, Transform } from "@openfairygui/core";
4
+ import { Document, ProjectDiagnostic, ProjectValidationReport, Transform, UamProject } from "@openfairygui/core";
5
5
 
6
6
  //#region src/inspect.d.ts
7
7
  /**
@@ -69,55 +69,16 @@ interface InspectReport {
69
69
  declare function inspect(doc: Document): InspectReport;
70
70
  //#endregion
71
71
  //#region src/validate.d.ts
72
- /**
73
- * Severity of a validation issue.
74
- */
75
- declare enum ValidationSeverity {
76
- ERROR = "error",
77
- WARNING = "warning",
78
- INFO = "info"
79
- }
80
- /**
81
- * A single validation issue found in the project.
82
- */
83
- interface ValidationIssue {
84
- severity: ValidationSeverity;
85
- message: string;
86
- /** Package name where the issue was found. */
87
- packageName?: string;
88
- /** Component name where the issue was found. */
89
- componentName?: string;
90
- /** Resource/object name related to the issue. */
91
- resourceName?: string;
92
- }
93
- /**
94
- * Result returned by `validate()`.
95
- */
96
- interface ValidationResult {
97
- ok: boolean;
98
- errors: ValidationIssue[];
99
- warnings: ValidationIssue[];
100
- infos: ValidationIssue[];
72
+ interface ValidateProjectOptions {
73
+ /** Diagnostics collected while reading the source project. */
74
+ readDiagnostics?: readonly ProjectDiagnostic[];
75
+ /** Whether the reader and host completed every requested check. */
76
+ complete?: boolean;
77
+ /** Validate hydrated resource bytes in addition to the UAM graph. */
78
+ validateSources?: boolean;
101
79
  }
102
- interface ValidateOptions {
103
- /** If true, the transform throws on errors. Default: false. */
104
- throwOnError?: boolean;
105
- }
106
- /**
107
- * Validates a FairyGUI project for common issues:
108
- * - Missing resource IDs
109
- * - Broken `ui://` references (src pointing to non-existent resources)
110
- * - Empty components (no children)
111
- * - Controllers with no pages
112
- * - Duplicate resource IDs within a package
113
- *
114
- * The validation result is stored in `doc.getRoot().getExtras()._validation`.
115
- *
116
- * ```ts
117
- * await doc.transform(validate({ throwOnError: true }));
118
- * ```
119
- */
120
- declare function validate(_options?: ValidateOptions): Transform;
80
+ /** Validate one authoritative UAM snapshot without mutating it. */
81
+ declare function validateProject(project: UamProject, options?: ValidateProjectOptions): ProjectValidationReport;
121
82
  //#endregion
122
83
  //#region src/prune.d.ts
123
84
  interface PruneOptions {
@@ -174,4 +135,4 @@ declare function rename(options: RenameOptions): Transform;
174
135
  */
175
136
  declare function createTransform(name: string, fn: Transform): Transform;
176
137
  //#endregion
177
- export { AUTO_GENERATED_CODE_MARK, type ApplyUamTransactionAppDiagnostic, type ApplyUamTransactionAppError, type ApplyUamTransactionAppInput, type ApplyUamTransactionAppResult, type AtlasOptions, type AtlasRasterBackend, type AtlasRasterCompositeInput, type AtlasRasterInput, type AtlasRasterMetadata, type AtlasRasterPipeline, type AtlasRasterResolvedBuffer, type CliAtlasSettings, type CliCodeGenerationSettings, type CliPublishSettings, type CodeWriter, type CodegenClass, type CodegenMember, type CodegenReferencedComponent, type ExtrasMap, type HasOptionalFont, type HasOptionalSrc, type HasOptionalUrl, type ICodeWriterConfig, type InspectCategoryReport, type InspectReport, type LoadedPlugin, type MaybePromise, type Plugin, type PluginManifest, type PluginModule, type PruneOptions, type PublishCodeGenerationOptions, type PublishDependency, type PublishFileSystem, type PublishOptions, type PublishOutputFileSystem, type PublishSourceFileSystem, type RenameOptions, type ResolvePublishOptionsOverrides, type ResolvedPackageCodegenPlan, type ResolvedPublishAtlasOptions, type ResolvedPublishOptions, type RestoreFileSystem, type RestoreImageCropInput, type RestoreImageCropper, type RestoreImageExtractInput, type RestoreImageExtractor, type RestoreOptions, type RestoreResult, type RootProjectSettings, type ValidateOptions, type ValidationIssue, type ValidationResult, ValidationSeverity, applyUamTransactionApp, applyUamTransactionAppAsync, atlas, buildCodegenClasses, createTransform, decodeText, encodeText, inspect, prune, publish, publishCodeGeneration, rename, resolvePackageCodegenPlan, resolvePublishOptions, restore, validate };
138
+ export { AUTO_GENERATED_CODE_MARK, type ApplyUamTransactionAppDiagnostic, type ApplyUamTransactionAppError, type ApplyUamTransactionAppInput, type ApplyUamTransactionAppResult, type AtlasOptions, type AtlasRasterBackend, type AtlasRasterCompositeInput, type AtlasRasterInput, type AtlasRasterMetadata, type AtlasRasterPipeline, type AtlasRasterResolvedBuffer, type CliAtlasSettings, type CliCodeGenerationSettings, type CliPublishSettings, type CodeWriter, type CodegenClass, type CodegenMember, type CodegenReferencedComponent, type ExtrasMap, type HasOptionalFont, type HasOptionalSrc, type HasOptionalUrl, type ICodeWriterConfig, type InspectCategoryReport, type InspectReport, type LoadedPlugin, type MaybePromise, type Plugin, type PluginManifest, type PluginModule, type PruneOptions, type PublishCodeGenerationOptions, type PublishDependency, type PublishFileSystem, type PublishOptions, type PublishOutputFileSystem, type PublishSourceFileSystem, type RenameOptions, type ResolvePublishOptionsOverrides, type ResolvedPackageCodegenPlan, type ResolvedPublishAtlasOptions, type ResolvedPublishOptions, type RestoreFileSystem, type RestoreImageCropInput, type RestoreImageCropper, type RestoreImageExtractInput, type RestoreImageExtractor, type RestoreOptions, type RestoreResult, type RootProjectSettings, type ValidateProjectOptions, applyUamTransactionApp, applyUamTransactionAppAsync, atlas, buildCodegenClasses, createTransform, decodeText, encodeText, inspect, prune, publish, publishCodeGeneration, rename, resolvePackageCodegenPlan, resolvePublishOptions, restore, validateProject };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as decodeText, g as createTransform, h as atlas, i as buildCodegenClasses, l as resolvePackageCodegenPlan, n as resolvePublishOptions, o as encodeText, r as AUTO_GENERATED_CODE_MARK, s as publishCodeGeneration, t as publish } from "./publish-DXoaC1Nl.js";
2
- import { t as restore } from "./restore-BQp01WY3.js";
1
+ import { _ as validateProject, a as decodeText, g as createTransform, h as atlas, i as buildCodegenClasses, l as resolvePackageCodegenPlan, n as resolvePublishOptions, o as encodeText, r as AUTO_GENERATED_CODE_MARK, s as publishCodeGeneration, t as publish } from "./publish-CyBj2o7n.js";
2
+ import { t as restore } from "./restore-DVo1hXpN.js";
3
3
  import { applyUamTransactionApp, applyUamTransactionAppAsync } from "./uam-transaction.js";
4
4
  //#region src/inspect.ts
5
5
  function mapResource(resource) {
@@ -103,125 +103,6 @@ function inspect(doc) {
103
103
  };
104
104
  }
105
105
  //#endregion
106
- //#region src/validate.ts
107
- /**
108
- * Severity of a validation issue.
109
- */
110
- let ValidationSeverity = /* @__PURE__ */ function(ValidationSeverity) {
111
- ValidationSeverity["ERROR"] = "error";
112
- ValidationSeverity["WARNING"] = "warning";
113
- ValidationSeverity["INFO"] = "info";
114
- return ValidationSeverity;
115
- }({});
116
- const VALIDATE_DEFAULTS = { throwOnError: false };
117
- /**
118
- * Validates a FairyGUI project for common issues:
119
- * - Missing resource IDs
120
- * - Broken `ui://` references (src pointing to non-existent resources)
121
- * - Empty components (no children)
122
- * - Controllers with no pages
123
- * - Duplicate resource IDs within a package
124
- *
125
- * The validation result is stored in `doc.getRoot().getExtras()._validation`.
126
- *
127
- * ```ts
128
- * await doc.transform(validate({ throwOnError: true }));
129
- * ```
130
- */
131
- function validate(_options = {}) {
132
- const options = {
133
- ...VALIDATE_DEFAULTS,
134
- ..._options
135
- };
136
- return createTransform("validate", (doc) => {
137
- const issues = [];
138
- const root = doc.getRoot();
139
- if (!root.getProjectId()) issues.push({
140
- severity: ValidationSeverity.WARNING,
141
- message: "Project has no ID."
142
- });
143
- const globalResources = /* @__PURE__ */ new Map();
144
- for (const pkg of root.listPackages()) {
145
- if (!pkg.getId()) issues.push({
146
- severity: ValidationSeverity.ERROR,
147
- message: `Package "${pkg.getName()}" has no ID.`,
148
- packageName: pkg.getName()
149
- });
150
- const idSet = /* @__PURE__ */ new Set();
151
- for (const res of pkg.listResources()) {
152
- const resId = res.getId();
153
- if (!resId) {
154
- issues.push({
155
- severity: ValidationSeverity.WARNING,
156
- message: `Resource "${res.getName()}" has no ID.`,
157
- packageName: pkg.getName(),
158
- resourceName: res.getName()
159
- });
160
- continue;
161
- }
162
- if (idSet.has(resId)) issues.push({
163
- severity: ValidationSeverity.ERROR,
164
- message: `Duplicate resource ID "${resId}" in package "${pkg.getName()}".`,
165
- packageName: pkg.getName(),
166
- resourceName: res.getName()
167
- });
168
- idSet.add(resId);
169
- globalResources.set(`${pkg.getId()}${resId}`, `${pkg.getName()}/${res.getName()}`);
170
- }
171
- for (const comp of pkg.listComponents()) {
172
- const children = comp.listChildren();
173
- if (children.length === 0) issues.push({
174
- severity: ValidationSeverity.INFO,
175
- message: `Component "${comp.getName()}" has no children.`,
176
- packageName: pkg.getName(),
177
- componentName: comp.getName()
178
- });
179
- for (const ctrl of comp.listControllers()) if (ctrl.listPages().length === 0) issues.push({
180
- severity: ValidationSeverity.WARNING,
181
- message: `Controller "${ctrl.getName()}" in "${comp.getName()}" has no pages.`,
182
- packageName: pkg.getName(),
183
- componentName: comp.getName()
184
- });
185
- for (const child of children) {
186
- const src = child.getSrc?.();
187
- if (!src) continue;
188
- if (src.startsWith("ui://")) {
189
- const idPart = src.slice(5);
190
- if (idPart.length > 8) {
191
- const key = `${idPart.slice(0, 8)}${idPart.slice(8)}`;
192
- if (!globalResources.has(key)) issues.push({
193
- severity: ValidationSeverity.ERROR,
194
- message: `Broken reference "${src}" in "${child.getName()}" (component "${comp.getName()}").`,
195
- packageName: pkg.getName(),
196
- componentName: comp.getName(),
197
- resourceName: child.getName()
198
- });
199
- }
200
- }
201
- }
202
- }
203
- }
204
- const errors = issues.filter((i) => i.severity === ValidationSeverity.ERROR);
205
- const warnings = issues.filter((i) => i.severity === ValidationSeverity.WARNING);
206
- const infos = issues.filter((i) => i.severity === ValidationSeverity.INFO);
207
- const result = {
208
- ok: errors.length === 0,
209
- errors,
210
- warnings,
211
- infos
212
- };
213
- root.setExtras({
214
- ...root.getExtras(),
215
- _validation: result
216
- });
217
- const logger = doc.getLogger();
218
- if (errors.length) logger.warn(`validate: ${errors.length} error(s) found.`);
219
- if (warnings.length) logger.warn(`validate: ${warnings.length} warning(s) found.`);
220
- logger.info(`validate: ${issues.length} issue(s) total.`);
221
- if (options.throwOnError && errors.length > 0) throw new Error(`Validation failed with ${errors.length} error(s):\n${errors.map((e) => ` - ${e.message}`).join("\n")}`);
222
- });
223
- }
224
- //#endregion
225
106
  //#region src/prune.ts
226
107
  const PRUNE_DEFAULTS = {
227
108
  emptyComponents: false,
@@ -319,4 +200,4 @@ function rename(options) {
319
200
  });
320
201
  }
321
202
  //#endregion
322
- export { AUTO_GENERATED_CODE_MARK, ValidationSeverity, applyUamTransactionApp, applyUamTransactionAppAsync, atlas, buildCodegenClasses, createTransform, decodeText, encodeText, inspect, prune, publish, publishCodeGeneration, rename, resolvePackageCodegenPlan, resolvePublishOptions, restore, validate };
203
+ export { AUTO_GENERATED_CODE_MARK, applyUamTransactionApp, applyUamTransactionAppAsync, atlas, buildCodegenClasses, createTransform, decodeText, encodeText, inspect, prune, publish, publishCodeGeneration, rename, resolvePackageCodegenPlan, resolvePublishOptions, restore, validateProject };
package/dist/node.cjs CHANGED
@@ -1,12 +1,14 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_publish = require("./publish-CykUJfVa.cjs");
3
- const require_restore = require("./restore-CEywQUHz.cjs");
2
+ const require_publish = require("./publish-C7qHwEiP.cjs");
3
+ const require_restore = require("./restore-LXbDQqmT.cjs");
4
+ let _openfairygui_core = require("@openfairygui/core");
5
+ let _openfairygui_core_node = require("@openfairygui/core/node");
4
6
  //#region src/adapters/node/plugins.ts
5
- const importNative$2 = new Function("id", "return import(id)");
7
+ const importNative$3 = new Function("id", "return import(id)");
6
8
  async function loadPlugins(doc, pluginsDir) {
7
9
  if (!pluginsDir) return [];
8
- const fs = await importNative$2("node:fs/promises");
9
- const path = await importNative$2("node:path");
10
+ const fs = await importNative$3("node:fs/promises");
11
+ const path = await importNative$3("node:path");
10
12
  let entries;
11
13
  try {
12
14
  entries = await fs.readdir(pluginsDir, { withFileTypes: true });
@@ -46,7 +48,7 @@ function resolvePluginMain(path, pluginDir, manifest) {
46
48
  return mainPath;
47
49
  }
48
50
  async function loadPlugin(mainPath) {
49
- const { createJiti } = await importNative$2("jiti");
51
+ const { createJiti } = await importNative$3("jiti");
50
52
  const mod = await createJiti(require("url").pathToFileURL(__filename).href).import(mainPath);
51
53
  const defaultExport = mod.default;
52
54
  return isObject(defaultExport) ? defaultExport : mod;
@@ -56,9 +58,9 @@ function isObject(value) {
56
58
  }
57
59
  //#endregion
58
60
  //#region src/adapters/node/publish.ts
59
- const importNative$1 = new Function("id", "return import(id)");
61
+ const importNative$2 = new Function("id", "return import(id)");
60
62
  async function createNodePublishFileSystem() {
61
- const [fs, path] = await Promise.all([importNative$1("node:fs/promises"), importNative$1("node:path")]);
63
+ const [fs, path] = await Promise.all([importNative$2("node:fs/promises"), importNative$2("node:path")]);
62
64
  return {
63
65
  async readFileRaw(filePath) {
64
66
  const data = await fs.readFile(filePath);
@@ -86,11 +88,11 @@ async function resolveNodeAssetsPath(document, assetsPath) {
86
88
  if (assetsPath) return assetsPath;
87
89
  const projectDir = document.getProjectDir?.() ?? "";
88
90
  if (!projectDir) return void 0;
89
- return (await importNative$1("node:path")).join(projectDir, "assets");
91
+ return (await importNative$2("node:path")).join(projectDir, "assets");
90
92
  }
91
93
  async function loadSharpBackend() {
92
94
  try {
93
- const loaded = await importNative$1("sharp");
95
+ const loaded = await importNative$2("sharp");
94
96
  return loaded.default ?? loaded;
95
97
  } catch {
96
98
  return;
@@ -99,7 +101,7 @@ async function loadSharpBackend() {
99
101
  async function loadNodePublishPlugins(document, assetsPath) {
100
102
  const projectDir = document.getProjectDir?.() || (assetsPath ? require_publish.resolveProjectBasePath(assetsPath) : "");
101
103
  if (!projectDir) return [];
102
- return loadPlugins(document, (await importNative$1("node:path")).join(projectDir, "plugins"));
104
+ return loadPlugins(document, (await importNative$2("node:path")).join(projectDir, "plugins"));
103
105
  }
104
106
  /**
105
107
  * Publish a FairyGUI project through the standard Node host adapter.
@@ -127,9 +129,9 @@ async function publishNode(options) {
127
129
  }
128
130
  //#endregion
129
131
  //#region src/adapters/node/restore.ts
130
- const importNative = new Function("id", "return import(id)");
132
+ const importNative$1 = new Function("id", "return import(id)");
131
133
  async function createNodeRestoreFileSystem() {
132
- const [fs, path] = await Promise.all([importNative("node:fs/promises"), importNative("node:path")]);
134
+ const [fs, path] = await Promise.all([importNative$1("node:fs/promises"), importNative$1("node:path")]);
133
135
  return {
134
136
  async readFile(filePath) {
135
137
  return fs.readFile(filePath, "utf-8");
@@ -194,7 +196,7 @@ async function createNodeRestoreFileSystem() {
194
196
  async function createRestoreImageProcessors() {
195
197
  let sharp;
196
198
  try {
197
- const loaded = await importNative("sharp");
199
+ const loaded = await importNative$1("sharp");
198
200
  sharp = loaded.default ?? loaded;
199
201
  } catch {
200
202
  throw new Error("restoreNode: Sharp is required to crop atlas images. Install sharp before restoring.");
@@ -232,8 +234,8 @@ async function createRestoreImageProcessors() {
232
234
  if (input.expectedWidth > 0 && input.expectedHeight > 0 && (info.width !== input.expectedWidth || info.height !== input.expectedHeight)) throw new Error(`restore: Cropped image size mismatch for ${targetPath}: expected ${input.expectedWidth}x${input.expectedHeight}, got ${info.width}x${info.height}`);
233
235
  return data;
234
236
  }
235
- const fs = await importNative("node:fs/promises");
236
- const path = await importNative("node:path");
237
+ const fs = await importNative$1("node:fs/promises");
238
+ const path = await importNative$1("node:path");
237
239
  return {
238
240
  extractImage,
239
241
  cropImage: async (input) => {
@@ -252,5 +254,70 @@ async function restoreNode(options) {
252
254
  });
253
255
  }
254
256
  //#endregion
257
+ //#region src/adapters/node/validate.ts
258
+ const importNative = new Function("id", "return import(id)");
259
+ function sourceName(resource) {
260
+ return resource.sourcePath ?? resource.fileName ?? resource.file ?? resource.name;
261
+ }
262
+ async function validateProjectNode(projectPath) {
263
+ const read = await new _openfairygui_core_node.NodeIO().readProjectDetailed(projectPath, { hydrateResourceBytes: true });
264
+ if (!read.document) return (0, _openfairygui_core.createProjectValidationReport)(read.diagnostics, false);
265
+ let project;
266
+ try {
267
+ project = (0, _openfairygui_core.liftDocumentToUamProject)(read.document);
268
+ } catch (error) {
269
+ return (0, _openfairygui_core.createProjectValidationReport)([...read.diagnostics, {
270
+ severity: "error",
271
+ code: "invalid_uam",
272
+ path: "project",
273
+ message: `Project cannot be represented as UAM: ${error instanceof Error ? error.message : String(error)}`,
274
+ sourcePath: projectPath
275
+ }], false);
276
+ }
277
+ const base = require_publish.validateProject(project, {
278
+ readDiagnostics: read.diagnostics,
279
+ complete: read.complete,
280
+ validateSources: true
281
+ });
282
+ let diagnostics = base.diagnostics;
283
+ const knownCorruptPaths = new Set(base.diagnostics.filter((diagnostic) => diagnostic.code === "corrupt_source").map((diagnostic) => diagnostic.path));
284
+ const images = project.packages.flatMap((pkg, packageIndex) => pkg.resources.map((resource, resourceIndex) => ({
285
+ pkg,
286
+ packageIndex,
287
+ resource,
288
+ resourceIndex
289
+ })).filter(({ resource, packageIndex, resourceIndex }) => resource.kind === "image" && resource.sourceBytes instanceof Uint8Array && !knownCorruptPaths.has(`packages[${packageIndex}].resources[${resourceIndex}]`)));
290
+ if (images.length === 0) return base;
291
+ let sharp;
292
+ try {
293
+ const loaded = await importNative("sharp");
294
+ sharp = loaded.default ?? loaded;
295
+ } catch {
296
+ return (0, _openfairygui_core.createProjectValidationReport)([...base.diagnostics, {
297
+ severity: "warning",
298
+ code: "decode_capability_unavailable",
299
+ path: "project",
300
+ message: "Sharp is unavailable, so Node image decoding could not be completed."
301
+ }], false);
302
+ }
303
+ const decodedPaths = new Set(images.map(({ packageIndex, resourceIndex }) => `packages[${packageIndex}].resources[${resourceIndex}]`));
304
+ diagnostics = diagnostics.filter((diagnostic) => diagnostic.code !== "decode_capability_unavailable" || !decodedPaths.has(diagnostic.path));
305
+ for (const { pkg, packageIndex, resource, resourceIndex } of images) try {
306
+ await sharp(resource.sourceBytes).raw().toBuffer();
307
+ } catch (error) {
308
+ diagnostics.push({
309
+ severity: "error",
310
+ code: "corrupt_source",
311
+ path: `packages[${packageIndex}].resources[${resourceIndex}]`,
312
+ message: `Image source cannot be decoded: ${error instanceof Error ? error.message : String(error)}`,
313
+ packageId: pkg.id,
314
+ resourceId: resource.id,
315
+ sourcePath: sourceName(resource)
316
+ });
317
+ }
318
+ return (0, _openfairygui_core.createProjectValidationReport)(diagnostics, read.complete && !diagnostics.some((diagnostic) => diagnostic.code === "decode_capability_unavailable"));
319
+ }
320
+ //#endregion
255
321
  exports.publishNode = publishNode;
256
322
  exports.restoreNode = restoreNode;
323
+ exports.validateProjectNode = validateProjectNode;