@expo-harmony/cli 55.0.26-harmony.1 → 55.0.26-harmony.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.
Files changed (73) hide show
  1. package/build/args.d.ts +19 -0
  2. package/build/args.js +27 -0
  3. package/build/bin/expo-harmony.d.ts +2 -0
  4. package/build/buildHap/build.d.ts +25 -0
  5. package/build/buildHap/build.js +96 -0
  6. package/build/buildHap/common.d.ts +24 -0
  7. package/build/buildHap/common.js +92 -0
  8. package/build/buildHap/options.d.ts +7 -0
  9. package/build/buildHap/options.js +30 -0
  10. package/build/cli.d.ts +3 -0
  11. package/build/cli.js +202 -0
  12. package/build/doctor/doctor.d.ts +20 -0
  13. package/build/doctor/doctor.js +217 -0
  14. package/build/doctor/options.d.ts +5 -0
  15. package/build/doctor/options.js +15 -0
  16. package/build/entry.d.ts +2 -0
  17. package/build/entry.js +47 -0
  18. package/build/errors.d.ts +12 -0
  19. package/build/errors.js +16 -0
  20. package/build/expo.d.ts +19 -0
  21. package/build/expo.js +53 -0
  22. package/build/exportEmbed/export.d.ts +16 -0
  23. package/build/exportEmbed/export.js +125 -0
  24. package/build/exportEmbed/manifest.d.ts +44 -0
  25. package/build/exportEmbed/manifest.js +171 -0
  26. package/build/exportEmbed/options.d.ts +7 -0
  27. package/build/exportEmbed/options.js +22 -0
  28. package/build/file.d.ts +9 -0
  29. package/build/file.js +100 -0
  30. package/build/index.d.ts +12 -0
  31. package/build/modules/modules.d.ts +42 -0
  32. package/build/modules/modules.js +84 -0
  33. package/build/modules/options.d.ts +10 -0
  34. package/build/modules/options.js +45 -0
  35. package/build/path.d.ts +4 -0
  36. package/build/path.js +27 -0
  37. package/build/prebuild/check.d.ts +6 -0
  38. package/build/prebuild/check.js +139 -0
  39. package/build/prebuild/clean.d.ts +2 -0
  40. package/build/prebuild/clean.js +50 -0
  41. package/build/prebuild/options.d.ts +10 -0
  42. package/build/prebuild/options.js +50 -0
  43. package/build/prebuild/prebuild.d.ts +6 -0
  44. package/build/prebuild/prebuild.js +62 -0
  45. package/build/prebuild/template.d.ts +8 -0
  46. package/build/prebuild/template.js +86 -0
  47. package/build/process.d.ts +31 -0
  48. package/build/process.js +236 -0
  49. package/build/project.d.ts +2 -0
  50. package/build/project.js +23 -0
  51. package/build/projectLock.d.ts +2 -0
  52. package/build/projectLock.js +180 -0
  53. package/build/run/cache.d.ts +11 -0
  54. package/build/run/cache.js +73 -0
  55. package/build/run/devices.d.ts +29 -0
  56. package/build/run/devices.js +211 -0
  57. package/build/run/emulators.d.ts +13 -0
  58. package/build/run/emulators.js +85 -0
  59. package/build/run/install.d.ts +7 -0
  60. package/build/run/install.js +26 -0
  61. package/build/run/metro.d.ts +17 -0
  62. package/build/run/metro.js +156 -0
  63. package/build/run/options.d.ts +13 -0
  64. package/build/run/options.js +60 -0
  65. package/build/run/run.d.ts +51 -0
  66. package/build/run/run.js +174 -0
  67. package/build/start/options.d.ts +7 -0
  68. package/build/start/options.js +31 -0
  69. package/build/tools.d.ts +39 -0
  70. package/build/tools.js +226 -0
  71. package/build/upstream.d.ts +9 -0
  72. package/build/upstream.js +17 -0
  73. package/package.json +1 -1
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runHarmonyAsync = runHarmonyAsync;
7
+ exports.runHarmonySessionAsync = runHarmonySessionAsync;
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const devices_1 = require("./devices");
10
+ const errors_1 = require("../errors");
11
+ const export_1 = require("../exportEmbed/export");
12
+ const tools_1 = require("../tools");
13
+ const install_1 = require("./install");
14
+ const metro_1 = require("./metro");
15
+ const cache_1 = require("./cache");
16
+ const path_1 = require("../path");
17
+ const projectLock_1 = require("../projectLock");
18
+ const common_1 = require("../buildHap/common");
19
+ const BundleName = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*){2,}$/u;
20
+ function resolveRunIdentity(plan, options) {
21
+ if (options.appId && !BundleName.test(options.appId)) {
22
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_CONFIG_INVALID', '--app-id must contain at least three valid dot-separated segments.', { operation: 'resolve-run' });
23
+ }
24
+ if (options.appId && !options.noInstall && options.appId !== plan.bundleName) {
25
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_APP_ID_MISMATCH', `--app-id can differ from the generated bundle name only with --no-install; expected ${plan.bundleName}.`, { operation: 'resolve-run' });
26
+ }
27
+ return {
28
+ abilityName: plan.abilityName,
29
+ bundleName: options.appId || plan.bundleName,
30
+ };
31
+ }
32
+ async function runHarmonyUnlockedAsync(projectRoot, options = {}) {
33
+ const normalizedOptions = {
34
+ appId: options.appId,
35
+ device: options.device,
36
+ interactiveBundler: Boolean(options.interactiveBundler),
37
+ io: options.io || console,
38
+ noBundler: Boolean(options.noBundler),
39
+ noInstall: Boolean(options.noInstall),
40
+ port: options.port || 8081,
41
+ resetCache: Boolean(options.resetCache),
42
+ sync: Boolean(options.sync),
43
+ variant: options.variant || 'debug',
44
+ };
45
+ const steps = {};
46
+ await (0, common_1.ensureGeneratedProjectAsync)(projectRoot, normalizedOptions, steps);
47
+ const plan = await (0, common_1.timed)(steps, 'buildPlan', () => (0, tools_1.resolveHarmonyBuildPlanAsync)(projectRoot, { buildMode: normalizedOptions.variant }));
48
+ const identity = resolveRunIdentity(plan, normalizedOptions);
49
+ const toolchain = (0, tools_1.resolveHarmonyToolchain)();
50
+ (0, common_1.progress)(normalizedOptions, 'Selecting a Harmony device or emulator');
51
+ const device = await (0, common_1.timed)(steps, 'device', () => (0, devices_1.selectDeviceAsync)(toolchain.hdc, normalizedOptions.device, {
52
+ cwd: plan.harmonyRoot,
53
+ emulator: (0, tools_1.resolveHarmonyEmulator)(toolchain),
54
+ emulatorLogFile: node_path_1.default.join(projectRoot, '.expo', 'harmony', 'emulator.log'),
55
+ onProgress: message => (0, common_1.progress)(normalizedOptions, message),
56
+ }));
57
+ let exportManifest = null;
58
+ if (normalizedOptions.variant === 'release') {
59
+ (0, common_1.progress)(normalizedOptions, 'Exporting the release Hermes bundle');
60
+ exportManifest = await (0, common_1.timed)(steps, 'export', () => (0, export_1.exportEmbedAsync)(projectRoot, { resetCache: normalizedOptions.resetCache, skipDoctor: true }));
61
+ }
62
+ else {
63
+ steps.export = 0;
64
+ }
65
+ (0, common_1.progress)(normalizedOptions, 'Installing Harmony project dependencies');
66
+ await (0, common_1.timed)(steps, 'ohpm', () => (0, install_1.installHarmonyDependenciesAsync)(plan, toolchain));
67
+ let metro = {
68
+ owner: 'disabled',
69
+ port: normalizedOptions.port,
70
+ stop: async () => { },
71
+ waitAsync: async () => { },
72
+ };
73
+ try {
74
+ (0, common_1.progress)(normalizedOptions, 'Checking Harmony native dependency cache');
75
+ const nativeBuildCache = await (0, common_1.timed)(steps, 'nativeCache', () => ((0, cache_1.prepareHarmonyNativeBuildCacheAsync)(projectRoot, plan)));
76
+ if (nativeBuildCache.changed) {
77
+ (0, common_1.progress)(normalizedOptions, 'Invalidated stale Harmony native build objects');
78
+ }
79
+ (0, common_1.progress)(normalizedOptions, `Building the ${normalizedOptions.variant} HAP`);
80
+ const buildEnv = {
81
+ ...process.env,
82
+ EXPO_HARMONY_NODE: process.env.EXPO_HARMONY_NODE || process.execPath,
83
+ EXPO_METRO_TARGET: 'harmony',
84
+ HERMES_V1_ENABLED: 'true',
85
+ ...(normalizedOptions.variant === 'release' ? { EXPO_HARMONY_BUNDLE_PREBUILT: '1' } : {}),
86
+ ...(toolchain.sdkHome && !process.env.DEVECO_SDK_HOME
87
+ ? { DEVECO_SDK_HOME: toolchain.sdkHome }
88
+ : {}),
89
+ };
90
+ await (0, common_1.timed)(steps, 'build', () => (0, common_1.runCheckedAsync)(toolchain.hvigor.command, [
91
+ ...toolchain.hvigor.args,
92
+ ...plan.hvigorArgs,
93
+ ], {
94
+ code: 'ERR_HARMONY_BUILD_FAILED',
95
+ cwd: plan.harmonyRoot,
96
+ env: buildEnv,
97
+ message: 'Hvigor build',
98
+ operation: 'hvigor-build',
99
+ timeoutMs: 15 * 60_000,
100
+ }));
101
+ if (!(0, common_1.isNonEmptyRegularFile)(plan.expectedHap)) {
102
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_HAP_MISSING', 'Hvigor completed without producing the expected non-empty regular HAP.', { operation: 'verify-hap' });
103
+ }
104
+ await (0, common_1.timed)(steps, 'nativeCacheCommit', () => (0, cache_1.commitHarmonyNativeBuildCacheAsync)(nativeBuildCache));
105
+ if (normalizedOptions.variant === 'debug') {
106
+ (0, common_1.progress)(normalizedOptions, normalizedOptions.noBundler
107
+ ? 'Connecting to the existing Expo Metro server'
108
+ : 'Starting Expo Metro');
109
+ metro = await (0, common_1.timed)(steps, 'metro', () => normalizedOptions.noBundler
110
+ ? (0, metro_1.requireExistingMetroAsync)(normalizedOptions.port)
111
+ : (0, metro_1.startExpoMetroAsync)(projectRoot, {
112
+ interactive: normalizedOptions.interactiveBundler,
113
+ port: normalizedOptions.port,
114
+ resetCache: normalizedOptions.resetCache,
115
+ }));
116
+ await (0, common_1.timed)(steps, 'metroPort', () => (0, devices_1.configureMetroPortAsync)(toolchain.hdc, device, normalizedOptions.port, { cwd: plan.harmonyRoot }));
117
+ }
118
+ else {
119
+ steps.metro = 0;
120
+ steps.metroPort = 0;
121
+ }
122
+ if (normalizedOptions.noInstall) {
123
+ steps.install = 0;
124
+ }
125
+ else {
126
+ (0, common_1.progress)(normalizedOptions, `Installing the HAP on ${device.id}`);
127
+ await (0, common_1.timed)(steps, 'install', () => (0, devices_1.installHapAsync)(toolchain.hdc, device, plan.expectedHap, { cwd: plan.harmonyRoot }));
128
+ }
129
+ (0, common_1.progress)(normalizedOptions, `Launching ${identity.bundleName}`);
130
+ await (0, common_1.timed)(steps, 'launch', () => (0, devices_1.launchAppAsync)(toolchain.hdc, device, identity.bundleName, identity.abilityName, { cwd: plan.harmonyRoot }));
131
+ const result = {
132
+ bundleName: identity.bundleName,
133
+ device: {
134
+ id: device.id,
135
+ transport: device.transport,
136
+ },
137
+ export: exportManifest
138
+ ? {
139
+ assetCount: exportManifest.assets.length,
140
+ bundleSha256: exportManifest.bundle.sha256,
141
+ sourceMapSha256: exportManifest.sourceMap.sha256,
142
+ }
143
+ : null,
144
+ hapPath: (0, path_1.toPosixPath)(node_path_1.default.relative(projectRoot, plan.expectedHap)),
145
+ installed: !normalizedOptions.noInstall,
146
+ launched: true,
147
+ metro: {
148
+ owner: metro.owner,
149
+ port: metro.port,
150
+ },
151
+ ok: true,
152
+ schemaVersion: 1,
153
+ steps,
154
+ variant: normalizedOptions.variant,
155
+ };
156
+ return { metro, result };
157
+ }
158
+ catch (error) {
159
+ await metro.stop();
160
+ throw error;
161
+ }
162
+ }
163
+ async function runHarmonySessionAsync(projectRoot, options = {}) {
164
+ return (0, projectLock_1.withHarmonyProjectLockAsync)(projectRoot, 'run', () => runHarmonyUnlockedAsync(projectRoot, options));
165
+ }
166
+ async function runHarmonyAsync(projectRoot, options = {}) {
167
+ const session = await runHarmonySessionAsync(projectRoot, options);
168
+ try {
169
+ return session.result;
170
+ }
171
+ finally {
172
+ await session.metro.stop();
173
+ }
174
+ }
@@ -0,0 +1,7 @@
1
+ declare function parseStartArgs(argv: string[]): {
2
+ help: boolean;
3
+ port: number;
4
+ project: string;
5
+ resetCache: boolean;
6
+ };
7
+ export { parseStartArgs };
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseStartArgs = parseStartArgs;
4
+ const args_1 = require("../args");
5
+ const errors_1 = require("../errors");
6
+ const StartOptions = {
7
+ ...args_1.CommonOptions,
8
+ 'clear': { short: 'c', type: 'boolean' },
9
+ 'port': { type: 'string' },
10
+ 'reset-cache': { type: 'boolean' },
11
+ };
12
+ function parseStartArgs(argv) {
13
+ const { positionals, values } = (0, args_1.parseArgs)(StartOptions, argv);
14
+ if (positionals.length > 1) {
15
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_CONFIG_INVALID', `Unexpected start positional argument: ${positionals[1]}`, {
16
+ operation: 'parse-arguments',
17
+ });
18
+ }
19
+ const port = values.port === undefined ? 8081 : Number(values.port);
20
+ if (!Number.isInteger(port) || port < 1 || port > 65_535) {
21
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_CONFIG_INVALID', '--port must be an integer between 1 and 65535.', {
22
+ operation: 'parse-arguments',
23
+ });
24
+ }
25
+ return {
26
+ help: Boolean(values.help),
27
+ port,
28
+ project: positionals[0],
29
+ resetCache: Boolean(values['reset-cache'] || values.clear),
30
+ };
31
+ }
@@ -0,0 +1,39 @@
1
+ import { type HarmonyBuildDescriptor } from '@expo-harmony/prebuild-config/build-descriptor';
2
+ export interface HarmonyTool {
3
+ args: string[];
4
+ command: string;
5
+ source: 'deveco' | 'override' | 'path';
6
+ }
7
+ export interface HarmonyToolchain {
8
+ hdc: HarmonyTool;
9
+ hvigor: HarmonyTool;
10
+ ohpm: HarmonyTool;
11
+ sdkHome: string | null;
12
+ toolsRoot: string | null;
13
+ }
14
+ export interface HarmonyBuildPlan {
15
+ abilityName: string;
16
+ buildMode: 'debug' | 'release';
17
+ bundleName: string;
18
+ expectedHap: string;
19
+ exportPaths: HarmonyBuildDescriptor['export'];
20
+ harmonyRoot: string;
21
+ hvigorArgs: string[];
22
+ moduleName: string;
23
+ moduleRoot: string;
24
+ nativeCache: HarmonyBuildDescriptor['nativeCache'];
25
+ nativeInputs: HarmonyBuildDescriptor['nativeInputs'];
26
+ projectFiles: HarmonyBuildDescriptor['projectFiles'];
27
+ productName: string;
28
+ targetName: string;
29
+ }
30
+ declare function resolveHarmonyToolchain(): HarmonyToolchain;
31
+ declare function createHarmonyToolchainEnv(toolchain?: HarmonyToolchain): NodeJS.ProcessEnv;
32
+ declare function resolveHarmonyEmulator(toolchain: HarmonyToolchain): HarmonyTool;
33
+ declare function resolveHarmonyBuildPlanIfPresentAsync(projectRoot: string, options?: {
34
+ buildMode?: 'debug' | 'release';
35
+ }): Promise<HarmonyBuildPlan | null>;
36
+ declare function resolveHarmonyBuildPlanAsync(projectRoot: string, options?: {
37
+ buildMode?: 'debug' | 'release';
38
+ }): Promise<HarmonyBuildPlan>;
39
+ export { createHarmonyToolchainEnv, resolveHarmonyBuildPlanAsync, resolveHarmonyBuildPlanIfPresentAsync, resolveHarmonyEmulator, resolveHarmonyToolchain, };
package/build/tools.js ADDED
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createHarmonyToolchainEnv = createHarmonyToolchainEnv;
7
+ exports.resolveHarmonyBuildPlanAsync = resolveHarmonyBuildPlanAsync;
8
+ exports.resolveHarmonyBuildPlanIfPresentAsync = resolveHarmonyBuildPlanIfPresentAsync;
9
+ exports.resolveHarmonyEmulator = resolveHarmonyEmulator;
10
+ exports.resolveHarmonyToolchain = resolveHarmonyToolchain;
11
+ const node_fs_1 = __importDefault(require("node:fs"));
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ const build_descriptor_1 = require("@expo-harmony/prebuild-config/build-descriptor");
14
+ const check_1 = require("@expo-harmony/prebuild-config/check");
15
+ const errors_1 = require("./errors");
16
+ function existingFile(candidates) {
17
+ return candidates.find(candidate => node_fs_1.default.existsSync(candidate)) || null;
18
+ }
19
+ const RequiredSdkComponents = Object.freeze([
20
+ 'default/sdk-pkg.json',
21
+ 'default/hms/ets/uni-package.json',
22
+ 'default/hms/native/uni-package.json',
23
+ 'default/hms/toolchains/uni-package.json',
24
+ 'default/openharmony/ets/oh-uni-package.json',
25
+ 'default/openharmony/native/oh-uni-package.json',
26
+ 'default/openharmony/toolchains/oh-uni-package.json',
27
+ ]);
28
+ function sdkRootsNear(seed) {
29
+ const roots = [];
30
+ let cursor = node_path_1.default.resolve(seed);
31
+ for (let depth = 0; depth < 6; depth += 1) {
32
+ const name = node_path_1.default.basename(cursor).toLowerCase();
33
+ if (name === 'default' && node_path_1.default.basename(node_path_1.default.dirname(cursor)).toLowerCase() === 'sdk') {
34
+ roots.push(node_path_1.default.dirname(cursor));
35
+ }
36
+ if (name === 'sdk')
37
+ roots.push(cursor);
38
+ roots.push(node_path_1.default.join(cursor, 'sdk'));
39
+ const parent = node_path_1.default.dirname(cursor);
40
+ if (parent === cursor)
41
+ break;
42
+ cursor = parent;
43
+ }
44
+ return roots;
45
+ }
46
+ function resolveHarmonySdkRoot(env, platform) {
47
+ const seeds = [
48
+ env.DEVECO_SDK_HOME,
49
+ env.HARMONY_HOME,
50
+ env.OHOS_SDK_HOME,
51
+ env.HARMONY_HVIGORW,
52
+ env.HARMONY_OHPM,
53
+ env.HARMONY_NODE,
54
+ ...(env.PATH || '').split(node_path_1.default.delimiter).filter(Boolean),
55
+ ...(platform === 'darwin' ? ['/Applications/DevEco-Studio.app/Contents'] : []),
56
+ ].filter(Boolean);
57
+ const candidates = [...new Set(seeds.flatMap(sdkRootsNear))];
58
+ return candidates.find(root => RequiredSdkComponents.every(relative => node_fs_1.default.existsSync(node_path_1.default.join(root, ...relative.split('/'))))) || null;
59
+ }
60
+ function devEcoInstallRoots(sdkHome) {
61
+ const ancestors = [sdkHome, node_path_1.default.dirname(sdkHome), node_path_1.default.dirname(node_path_1.default.dirname(sdkHome))];
62
+ const sdkDirectory = ancestors.find(candidate => node_path_1.default.basename(candidate).toLowerCase() === 'sdk');
63
+ const roots = [
64
+ sdkDirectory && node_path_1.default.dirname(sdkDirectory),
65
+ node_path_1.default.dirname(sdkHome),
66
+ node_path_1.default.dirname(node_path_1.default.dirname(sdkHome)),
67
+ ].filter(Boolean);
68
+ return [...new Set(roots)];
69
+ }
70
+ function devEcoLayouts(sdkHome) {
71
+ return devEcoInstallRoots(sdkHome).flatMap(root => [
72
+ {
73
+ nodeRoot: node_path_1.default.join(root, 'tools', 'node'),
74
+ toolsRoot: node_path_1.default.join(root, 'tools'),
75
+ },
76
+ {
77
+ nodeRoot: node_path_1.default.join(root, 'tool', 'node'),
78
+ toolsRoot: root,
79
+ },
80
+ ]);
81
+ }
82
+ function devEcoNode(layout, platform, env) {
83
+ if (env.HARMONY_NODE)
84
+ return { command: env.HARMONY_NODE, source: 'override' };
85
+ const executable = platform === 'win32' ? 'node.exe' : 'node';
86
+ const command = existingFile([
87
+ node_path_1.default.join(layout.nodeRoot, 'bin', executable),
88
+ node_path_1.default.join(layout.nodeRoot, executable),
89
+ ]);
90
+ return command ? { command, source: 'deveco' } : null;
91
+ }
92
+ function resolveHarmonyToolchain() {
93
+ const env = process.env;
94
+ const platform = process.platform;
95
+ // Hvigor expects the SDK root containing default/, not default/ itself.
96
+ // Reject metadata-only candidates so doctor cannot claim an SDK is
97
+ // buildable without its HMS, OpenHarmony, native, ETS, and toolchain parts.
98
+ const sdkHome = resolveHarmonySdkRoot(env, platform);
99
+ const layouts = sdkHome ? devEcoLayouts(sdkHome) : [];
100
+ let ohpm;
101
+ if (env.HARMONY_OHPM) {
102
+ ohpm = { args: [], command: env.HARMONY_OHPM, source: 'override' };
103
+ }
104
+ else {
105
+ const devEcoOhpm = existingFile(layouts.map(layout => node_path_1.default.join(layout.toolsRoot, 'ohpm', 'bin', platform === 'win32' ? 'ohpm.bat' : 'ohpm')));
106
+ ohpm = devEcoOhpm
107
+ ? { args: [], command: devEcoOhpm, source: 'deveco' }
108
+ : { args: [], command: platform === 'win32' ? 'ohpm.bat' : 'ohpm', source: 'path' };
109
+ }
110
+ let hvigor;
111
+ if (env.HARMONY_HVIGORW) {
112
+ if (/\.(?:c|m)?js$/iu.test(env.HARMONY_HVIGORW)) {
113
+ hvigor = {
114
+ args: [env.HARMONY_HVIGORW],
115
+ command: env.HARMONY_NODE || process.execPath,
116
+ source: 'override',
117
+ };
118
+ }
119
+ else {
120
+ hvigor = { args: [], command: env.HARMONY_HVIGORW, source: 'override' };
121
+ }
122
+ }
123
+ else {
124
+ const devEcoHvigor = layouts.map(layout => ({
125
+ layout,
126
+ node: devEcoNode(layout, platform, env),
127
+ script: node_path_1.default.join(layout.toolsRoot, 'hvigor', 'bin', 'hvigorw.js'),
128
+ })).find(candidate => candidate.node && node_fs_1.default.existsSync(candidate.script));
129
+ hvigor = devEcoHvigor
130
+ ? { args: [devEcoHvigor.script], command: devEcoHvigor.node.command, source: 'deveco' }
131
+ : { args: [], command: platform === 'win32' ? 'hvigorw.bat' : 'hvigorw', source: 'path' };
132
+ }
133
+ const toolsRoot = layouts.find(layout => (hvigor.args[0]?.startsWith(`${layout.toolsRoot}${node_path_1.default.sep}`)
134
+ || ohpm.command.startsWith(`${layout.toolsRoot}${node_path_1.default.sep}`)))?.toolsRoot || null;
135
+ let hdc;
136
+ if (env.HARMONY_HDC) {
137
+ hdc = { args: [], command: env.HARMONY_HDC, source: 'override' };
138
+ }
139
+ else {
140
+ const executable = platform === 'win32' ? 'hdc.exe' : 'hdc';
141
+ const sdkHdc = sdkHome && existingFile([
142
+ node_path_1.default.join(sdkHome, 'default', 'openharmony', 'toolchains', executable),
143
+ node_path_1.default.join(sdkHome, 'default', 'hms', 'toolchains', executable),
144
+ ]);
145
+ hdc = sdkHdc
146
+ ? { args: [], command: sdkHdc, source: 'deveco' }
147
+ : { args: [], command: executable, source: 'path' };
148
+ }
149
+ return { hdc, hvigor, ohpm, sdkHome, toolsRoot };
150
+ }
151
+ function createHarmonyToolchainEnv(toolchain = resolveHarmonyToolchain()) {
152
+ return {
153
+ ...process.env,
154
+ HARMONY_OHPM: toolchain.ohpm.command,
155
+ // A script-based Hvigor invocation must retain both its script and Node executable.
156
+ HARMONY_HVIGORW: toolchain.hvigor.args[0] || toolchain.hvigor.command,
157
+ ...(toolchain.hvigor.args.length > 0 ? { HARMONY_NODE: toolchain.hvigor.command } : {}),
158
+ ...(toolchain.sdkHome && !process.env.DEVECO_SDK_HOME
159
+ ? { DEVECO_SDK_HOME: toolchain.sdkHome }
160
+ : {}),
161
+ };
162
+ }
163
+ function resolveHarmonyEmulator(toolchain) {
164
+ if (process.env.HARMONY_EMULATOR) {
165
+ return { args: [], command: process.env.HARMONY_EMULATOR, source: 'override' };
166
+ }
167
+ const executable = process.platform === 'win32' ? 'Emulator.exe' : 'Emulator';
168
+ const roots = [
169
+ toolchain.toolsRoot,
170
+ ...(toolchain.sdkHome ? devEcoLayouts(toolchain.sdkHome).map(layout => layout.toolsRoot) : []),
171
+ ...(process.platform === 'darwin' ? ['/Applications/DevEco-Studio.app/Contents/tools'] : []),
172
+ ].filter(Boolean);
173
+ const command = existingFile(roots.map(root => node_path_1.default.join(root, 'emulator', executable)));
174
+ return command
175
+ ? { args: [], command, source: 'deveco' }
176
+ : { args: [], command: executable, source: 'path' };
177
+ }
178
+ function createHarmonyBuildPlan(projectRoot, build, mode) {
179
+ const resolve = relative => (0, build_descriptor_1.resolveHarmonyBuildPath)(projectRoot, relative);
180
+ const variant = build.variants[mode];
181
+ return {
182
+ abilityName: build.identity.abilityName,
183
+ buildMode: mode,
184
+ bundleName: build.identity.bundleName,
185
+ expectedHap: resolve(variant.expectedHap),
186
+ exportPaths: Object.fromEntries(Object.entries(build.export).map(([name, relative]) => [name, resolve(relative)])),
187
+ harmonyRoot: resolve(build.harmonyRoot),
188
+ hvigorArgs: [...variant.hvigorArgs],
189
+ moduleName: build.identity.moduleName,
190
+ moduleRoot: resolve(build.moduleRoot),
191
+ nativeCache: {
192
+ invalidationRoots: build.nativeCache.invalidationRoots.map(resolve),
193
+ stateFile: resolve(build.nativeCache.stateFile),
194
+ },
195
+ nativeInputs: {
196
+ lockfile: resolve(build.nativeInputs.lockfile),
197
+ manifest: resolve(build.nativeInputs.manifest),
198
+ },
199
+ productName: build.identity.productName,
200
+ projectFiles: Object.fromEntries(Object.entries(build.projectFiles).map(([name, relative]) => [name, resolve(relative)])),
201
+ targetName: build.identity.targetName,
202
+ };
203
+ }
204
+ async function resolveHarmonyBuildPlanIfPresentAsync(projectRoot, options = {}) {
205
+ const mode = options.buildMode || 'debug';
206
+ if (!['debug', 'release'].includes(mode)) {
207
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_CONFIG_INVALID', `Harmony buildMode must be debug or release, received: ${mode}`, { operation: 'resolve-build' });
208
+ }
209
+ let manifest;
210
+ try {
211
+ manifest = await (0, check_1.readManifestIfPresentAsync)(projectRoot);
212
+ }
213
+ catch (cause) {
214
+ throw new errors_1.HarmonyCliError(cause.code || 'ERR_HARMONY_TEMPLATE_INVALID', `Cannot read the generated Harmony build descriptor: ${cause.message}`, { cause, operation: 'resolve-build' });
215
+ }
216
+ if (!manifest)
217
+ return null;
218
+ return createHarmonyBuildPlan(projectRoot, manifest.build, mode);
219
+ }
220
+ async function resolveHarmonyBuildPlanAsync(projectRoot, options = {}) {
221
+ const plan = await resolveHarmonyBuildPlanIfPresentAsync(projectRoot, options);
222
+ if (!plan) {
223
+ throw new errors_1.HarmonyCliError('ERR_HARMONY_MANIFEST_DRIFT', 'Cannot read the generated Harmony build descriptor because the CNG manifest is missing.', { operation: 'resolve-build' });
224
+ }
225
+ return plan;
226
+ }
@@ -0,0 +1,9 @@
1
+ declare const ProjectPackages: Readonly<{
2
+ expo: "expo";
3
+ expoAutolinking: "@expo-harmony/expo-modules-autolinking";
4
+ reactNative: "react-native";
5
+ rnohCli: "@react-native-oh/react-native-harmony-cli";
6
+ rnohRuntime: "@react-native-oh/react-native-harmony";
7
+ }>;
8
+ declare const RequiredProjectPackages: readonly ("@expo-harmony/expo-modules-autolinking" | "@react-native-oh/react-native-harmony-cli" | "@react-native-oh/react-native-harmony")[];
9
+ export { ProjectPackages, RequiredProjectPackages, };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RequiredProjectPackages = exports.ProjectPackages = void 0;
4
+ const ProjectPackages = Object.freeze({
5
+ expo: 'expo',
6
+ expoAutolinking: '@expo-harmony/expo-modules-autolinking',
7
+ reactNative: 'react-native',
8
+ rnohCli: '@react-native-oh/react-native-harmony-cli',
9
+ rnohRuntime: '@react-native-oh/react-native-harmony',
10
+ });
11
+ exports.ProjectPackages = ProjectPackages;
12
+ const RequiredProjectPackages = Object.freeze([
13
+ ProjectPackages.rnohRuntime,
14
+ ProjectPackages.rnohCli,
15
+ ProjectPackages.expoAutolinking,
16
+ ]);
17
+ exports.RequiredProjectPackages = RequiredProjectPackages;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo-harmony/cli",
3
- "version": "55.0.26-harmony.1",
3
+ "version": "55.0.26-harmony.2",
4
4
  "keywords": [
5
5
  "react-native",
6
6
  "expo",