@openfairygui/cli 0.2.0-alpha.8 → 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.
@@ -0,0 +1,67 @@
1
+ import type { Command } from 'commander';
2
+ import { NodeIO } from '@openfairygui/core/node';
3
+ import { resolvePublishOptions } from '@openfairygui/functions';
4
+ import { publishNode } from '@openfairygui/functions/node';
5
+ import path from 'node:path';
6
+ import { resolveFairyPath } from '../utils/project-input.js';
7
+ import { parseProjectType } from '../utils/project-type.js';
8
+
9
+ type PublishCommandOptions = {
10
+ output?: string;
11
+ compressed?: boolean;
12
+ packages?: string;
13
+ branch?: string;
14
+ projectType?: string;
15
+ };
16
+
17
+ export function registerPublishCommand(program: Command): void {
18
+ program
19
+ .command('publish')
20
+ .description('Publish project to binary outputs and configured generated code')
21
+ .argument('<project-dir>', 'Project root directory or .fairy file')
22
+ .option('-o, --output <dir>', 'Override project or package publish output directory')
23
+ .option('-c, --compressed', 'Compress binary data (overrides project setting)')
24
+ .option('-p, --packages <a,b,c>', 'Only publish specific packages (comma-separated)')
25
+ .option('-b, --branch <name>', 'Active branch used by "主干合并活跃分支"; omit for main branch')
26
+ .option(
27
+ '-t, --project-type <name|id>',
28
+ 'Override project type (for example: unity, layabox, cocoscreator, 0, 4, 3)',
29
+ )
30
+ .action(async (projectDir: string, options: PublishCommandOptions) => {
31
+ const fairyPath = await resolveFairyPath(projectDir);
32
+ const projectRootDir = path.dirname(fairyPath);
33
+ const outputDir = options.output ? path.resolve(options.output) : undefined;
34
+
35
+ console.log(`Reading project: ${fairyPath}`);
36
+ const io = new NodeIO();
37
+ const doc = await io.readProject(fairyPath);
38
+ const projectType = parseProjectType(options.projectType);
39
+ if (projectType !== undefined) {
40
+ doc.getRoot().setProjectType(projectType);
41
+ }
42
+
43
+ const pkgFilter = options.packages?.split(',').map((value) => value.trim());
44
+ const resolved = resolvePublishOptions(doc, {
45
+ compressed: options.compressed,
46
+ packages: pkgFilter,
47
+ });
48
+
49
+ console.log(`Settings: ext=${resolved.fileExtension}, compressed=${resolved.compressed}`);
50
+ if (options.branch) {
51
+ console.log(`Active branch: ${options.branch}`);
52
+ }
53
+
54
+ await publishNode({
55
+ document: doc,
56
+ output: outputDir,
57
+ compressed: resolved.compressed,
58
+ fileExtension: resolved.fileExtension,
59
+ packages: resolved.packages,
60
+ assetsPath: path.join(projectRootDir, 'assets'),
61
+ atlas: resolved.atlas,
62
+ branch: options.branch,
63
+ });
64
+
65
+ console.log(`\nDone!${outputDir ? ` Output override: ${outputDir}` : ''}`);
66
+ });
67
+ }
@@ -0,0 +1,49 @@
1
+ import path from 'node:path';
2
+ import { restoreNode } from '@openfairygui/functions/node';
3
+ import type { Command } from 'commander';
4
+ import { parseProjectType } from '../utils/project-type.js';
5
+
6
+ type RestoreCommandOptions = {
7
+ output: string;
8
+ packages?: string;
9
+ force?: boolean;
10
+ projectType?: string;
11
+ };
12
+
13
+ export function registerRestoreCommand(program: Command): void {
14
+ program
15
+ .command('restore')
16
+ .description('Recover a project directory from trusted local published artifacts')
17
+ .argument('<release-dir>', 'Published release directory')
18
+ .requiredOption('-o, --output <dir>', 'Output project directory')
19
+ .option('-p, --packages <a,b,c>', 'Only restore specific packages (comma-separated)')
20
+ .option('-f, --force', 'Replace a non-empty output directory only after a complete staged restore')
21
+ .option('-t, --project-type <name|id>', 'Override restored project type; default is unity')
22
+ .action(async (releaseDir: string, options: RestoreCommandOptions) => {
23
+ const inputDir = path.resolve(releaseDir);
24
+ const outputDir = path.resolve(options.output);
25
+ const pkgFilter = options.packages
26
+ ? options.packages
27
+ .split(',')
28
+ .map((value) => value.trim())
29
+ .filter(Boolean)
30
+ : undefined;
31
+ const projectType = parseProjectType(options.projectType);
32
+
33
+ console.log(`Restoring published FairyGUI project: ${inputDir}`);
34
+ const result = await restoreNode({
35
+ inputDir,
36
+ output: outputDir,
37
+ packages: pkgFilter,
38
+ force: options.force,
39
+ projectType,
40
+ });
41
+
42
+ const packages = result.document.getRoot().listPackages();
43
+ console.log(`\nDone! Output: ${result.projectPath}`);
44
+ console.log(`Packages: ${packages.map((pkg) => pkg.getName()).join(', ')}`);
45
+ for (const warning of result.warnings) {
46
+ console.warn(`Warning: ${warning}`);
47
+ }
48
+ });
49
+ }
@@ -0,0 +1,23 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+ declare const __OPENFAIRYGUI_PACKAGE_VERSION__: string | undefined;
5
+
6
+ function getInjectedPackageVersion(): string | null {
7
+ const version = typeof __OPENFAIRYGUI_PACKAGE_VERSION__ === 'string' ? __OPENFAIRYGUI_PACKAGE_VERSION__ : null;
8
+ return typeof version === 'string' && version.length > 0 ? version : null;
9
+ }
10
+
11
+ export function readPackageVersion(): string {
12
+ const injectedVersion = getInjectedPackageVersion();
13
+ if (injectedVersion) return injectedVersion;
14
+ try {
15
+ const pkg = require('../../package.json') as { version?: unknown };
16
+ if (typeof pkg.version === 'string' && pkg.version.length > 0) {
17
+ return pkg.version;
18
+ }
19
+ } catch {
20
+ // Keep the CLI usable when executed from a bundled artifact missing package.json.
21
+ }
22
+ return '0.0.0-dev';
23
+ }
@@ -0,0 +1,26 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ /** Resolve input to a .fairy file path. Accepts a directory or a .fairy file. */
5
+ export async function resolveFairyPath(input: string): Promise<string> {
6
+ const resolved = path.resolve(input);
7
+ const stat = await fs.stat(resolved);
8
+
9
+ if (stat.isFile() && resolved.endsWith('.fairy')) {
10
+ return resolved;
11
+ }
12
+
13
+ if (stat.isDirectory()) {
14
+ const entries = await fs.readdir(resolved);
15
+ const fairyFiles = entries.filter((entry) => entry.endsWith('.fairy'));
16
+ if (fairyFiles.length === 1) {
17
+ return path.join(resolved, fairyFiles[0]);
18
+ }
19
+ if (fairyFiles.length > 1) {
20
+ throw new Error(`Multiple .fairy files found in ${resolved}: ${fairyFiles.join(', ')}. Please specify one.`);
21
+ }
22
+ throw new Error(`No .fairy file found in ${resolved}`);
23
+ }
24
+
25
+ throw new Error(`Input is not a .fairy file or directory: ${resolved}`);
26
+ }
@@ -0,0 +1,31 @@
1
+ import { ProjectType } from '@openfairygui/core';
2
+
3
+ export function parseProjectType(value: string | undefined): number | undefined {
4
+ if (!value) return undefined;
5
+ const trimmed = value.trim();
6
+ if (trimmed === '') return undefined;
7
+ if (/^\d+$/u.test(trimmed)) return Number(trimmed);
8
+ const normalized = trimmed.toLowerCase();
9
+ const map: Record<string, number> = {
10
+ unity: ProjectType.Unity,
11
+ flash: ProjectType.Flash,
12
+ starling: ProjectType.Starling,
13
+ cocoscreator: ProjectType.CocosCreator,
14
+ cocos: ProjectType.CocosCreator,
15
+ layabox: ProjectType.LayaBox,
16
+ laya: ProjectType.LayaBox,
17
+ egret: ProjectType.Egret,
18
+ haxe: ProjectType.Haxe,
19
+ pixi: ProjectType.Pixi,
20
+ libgdx: ProjectType.LibGDX,
21
+ unreal: ProjectType.Unreal,
22
+ cryengine: ProjectType.CryEngine,
23
+ monogame: ProjectType.MonoGame,
24
+ vision: ProjectType.Vision,
25
+ };
26
+ const resolved = map[normalized];
27
+ if (resolved === undefined) {
28
+ throw new Error(`Unknown project type: ${value}. Use a numeric id or one of: ${Object.keys(map).join(', ')}`);
29
+ }
30
+ return resolved;
31
+ }