@expo-harmony/prebuild-config 55.0.0-harmony.6 → 55.0.0-harmony.7

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 (56) hide show
  1. package/README.md +101 -9
  2. package/build/api/template.d.ts +1 -0
  3. package/build/api/template.js +6 -0
  4. package/build/buildDescriptor.js +12 -11
  5. package/build/check.js +5 -16
  6. package/build/getPrebuildConfig.d.ts +6 -0
  7. package/build/getPrebuildConfig.js +15 -0
  8. package/build/index.d.ts +5 -7
  9. package/build/index.js +6 -22
  10. package/build/internal.d.ts +6 -0
  11. package/build/internal.js +14 -0
  12. package/build/manifest.js +19 -10
  13. package/build/mods/withAutolinkingMods.d.ts +2 -1
  14. package/build/mods/withAutolinkingMods.js +14 -4
  15. package/build/mods/withEntryMods.d.ts +1 -1
  16. package/build/mods/withEntryMods.js +21 -19
  17. package/build/mods/withPreparationMod.d.ts +1 -1
  18. package/build/mods/withPreparationMod.js +19 -15
  19. package/build/mods/withProjectMods.d.ts +1 -1
  20. package/build/mods/withProjectMods.js +11 -6
  21. package/build/mods/withSourceMods.d.ts +1 -1
  22. package/build/mods/withSourceMods.js +5 -4
  23. package/build/renderers.d.ts +2 -6
  24. package/build/renderers.js +4 -17
  25. package/build/signing.d.ts +1 -1
  26. package/build/signing.js +22 -16
  27. package/build/stale.d.ts +3 -2
  28. package/build/stale.js +28 -15
  29. package/build/withHarmonyPrebuildConfig.d.ts +2 -3
  30. package/build/withHarmonyPrebuildConfig.js +13 -13
  31. package/package.json +11 -26
  32. package/src/api/template.ts +1 -0
  33. package/src/buildDescriptor.ts +12 -11
  34. package/src/check.ts +6 -18
  35. package/src/getPrebuildConfig.ts +20 -0
  36. package/src/index.ts +5 -24
  37. package/src/internal.ts +6 -0
  38. package/src/manifest.ts +26 -8
  39. package/src/mods/withAutolinkingMods.ts +17 -9
  40. package/src/mods/withEntryMods.ts +25 -39
  41. package/src/mods/withPreparationMod.ts +22 -24
  42. package/src/mods/withProjectMods.ts +11 -10
  43. package/src/mods/withSourceMods.ts +6 -5
  44. package/src/renderers.ts +5 -18
  45. package/src/signing.ts +32 -16
  46. package/src/stale.ts +48 -15
  47. package/src/withHarmonyPrebuildConfig.ts +17 -21
  48. package/build/api/signing.d.ts +0 -1
  49. package/build/api/signing.js +0 -5
  50. package/build/generatedFiles.d.ts +0 -2
  51. package/build/generatedFiles.js +0 -37
  52. package/build/plugin.d.ts +0 -1
  53. package/build/plugin.js +0 -7
  54. package/src/api/signing.ts +0 -4
  55. package/src/generatedFiles.ts +0 -39
  56. package/src/plugin.ts +0 -7
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [**GitHub 仓库**](https://github.com/renbaoshuo/expo-harmony/tree/master/packages/prebuild-config)
4
4
 
5
- 为 Expo 项目提供 HarmonyOS 默认预构建配置,将 `expo.harmony` 转换为可重复生成的原生工程状态。它基于 `@expo-harmony/template` 配置 AppScope、Entry 模块、资源、Hvigor、CMake 和 RNOH 宿主代码,同时完成 Expo 原生模块自动链接并生成 CNG 清单。
5
+ 为 Expo 项目生成 HarmonyOS 原生工程。读取 `expo.harmony` 配置,写入 AppScope、Entry 模块、资源、Hvigor 配置、CMake 和 RNOH 宿主代码,并完成原生模块自动链接。
6
6
 
7
7
  ## 安装
8
8
 
@@ -10,9 +10,11 @@
10
10
  npm install @expo-harmony/prebuild-config
11
11
  ```
12
12
 
13
- ## 基础用法
13
+ 应用还需要 `@react-native-oh/react-native-harmony` 和 `@react-native-oh/react-native-harmony-cli`,以及用来运行和构建的 `@expo-harmony/cli`。
14
14
 
15
- 在 `app.json` 中启用插件并声明 HarmonyOS 配置:
15
+ ## 快速开始
16
+
17
+ 在 `app.json` 里注册插件:
16
18
 
17
19
  ```json
18
20
  {
@@ -20,6 +22,7 @@ npm install @expo-harmony/prebuild-config
20
22
  "name": "Example",
21
23
  "slug": "example",
22
24
  "version": "1.0.0",
25
+ "platforms": ["ios", "android", "harmony"],
23
26
  "plugins": ["@expo-harmony/prebuild-config"],
24
27
  "harmony": {
25
28
  "bundleName": "com.example.app",
@@ -30,13 +33,79 @@ npm install @expo-harmony/prebuild-config
30
33
  }
31
34
  ```
32
35
 
33
- 使用 Expo Harmony CLI 生成或更新原生工程:
36
+ `bundleName` 必填,其余字段有默认值。完整列表见 [@expo-harmony/config-plugins](../config-plugins/README.md)。
37
+
38
+ 生成或更新原生工程:
34
39
 
35
40
  ```sh
36
41
  npx expo-harmony prebuild
37
42
  ```
38
43
 
39
- 需要使用字体、启动屏或其他 HarmonyOS 配置插件时,应将这些插件放在 `@expo-harmony/prebuild-config` 之前,由本包最后注册 Harmony Base Mods:
44
+ 工程写入项目根目录下的 `harmony`。`--clean` 先删除再重新生成,`--check` 只比较差异,不修改文件。
45
+
46
+ ## 生成内容
47
+
48
+ | 文件 | 内容 |
49
+ | -------------------------------------- | --------------------------------------------------- |
50
+ | `AppScope/app.json5` | 包名、版本号、vendor、应用名和图标引用 |
51
+ | `build-profile.json5` | product、module、SDK 版本、ABI 和签名配置 |
52
+ | `entry/build-profile.json5` | Entry 模块的 CMake 路径和 ABI |
53
+ | `entry/src/main/module.json5` | module、Ability、设备类型、权限和 querySchemes |
54
+ | `entry/src/main/resources/` | 字符串、颜色和 media 资源 |
55
+ | `oh-package.json5` | RNOH 运行时依赖 |
56
+ | `hvigor/hvigor-config.json5` | RNOH Hvigor 插件依赖 |
57
+ | `hvigorfile.ts`、`entry/hvigorfile.ts` | Hvigor 构建脚本 |
58
+ | `entry/src/main/ets/` | EntryAbility、Index 页面、Worker 和 PackageProvider |
59
+ | `entry/src/main/cpp/` | PackageProvider.cpp 和 CMakeLists.txt |
60
+ | `react-native.config.js` | RNOH 的 link-harmony 命令 |
61
+
62
+ ## 应用图标
63
+
64
+ `harmony.icon` 指定图标文件,支持 PNG、JPG、SVG 和 WebP。文件写入 AppScope 和 Entry 模块的 media 资源,替换同基本名的 `app_icon`。不设置时用模板自带的图标。
65
+
66
+ ## 权限
67
+
68
+ `harmony.permissions` 里的权限写入 `module.json5` 的 `requestPermissions`,权限名用 `ohos.permission.*`。同名权限合并 `usedScene.abilities`,后写入的 `reason` 覆盖旧值。`reason` 写成 `$string:...` 引用,文案放在字符串资源里。
69
+
70
+ ## 自动链接
71
+
72
+ prebuild 发现项目里支持 Harmony 的 Expo 模块,把模块信息和依赖写进工程,构建时由 Hvigor 和 CMake 链接。`buildType` 选项选择自动链接的构建模式:
73
+
74
+ ```json
75
+ {
76
+ "expo": {
77
+ "plugins": [["@expo-harmony/prebuild-config", { "buildType": "release" }]]
78
+ }
79
+ }
80
+ ```
81
+
82
+ 未指定时读取 `EXPO_HARMONY_BUILD_TYPE`,默认 `debug`。自动链接始终启用。
83
+
84
+ ## 签名配置
85
+
86
+ `harmony.signingConfigFile` 指向一个 JSON5 文件,内容是一个签名配置对象,或一个 `signingConfigs` 数组。数组有多项时,其中一项要命名为 `default`。
87
+
88
+ ```json5
89
+ {
90
+ name: 'default',
91
+ type: 'HarmonyOS',
92
+ material: {
93
+ certpath: './signing/app.cer',
94
+ storePassword: '...',
95
+ keyAlias: '...',
96
+ keyPassword: '...',
97
+ profile: './signing/app.p7b',
98
+ signAlg: 'SHA256withECDSA',
99
+ storeFile: './signing/app.p12',
100
+ },
101
+ }
102
+ ```
103
+
104
+ `material` 的七个字段都是必填的非空字符串,`signAlg` 固定为 `SHA256withECDSA`,`certpath`、`profile` 和 `storeFile` 指向真实文件。这些文件和签名配置文件本身要放在 `harmony` 目录之外,否则 `prebuild --clean` 会删掉它们。配置里的相对路径按签名配置文件所在目录解析。生成的 `build-profile.json5` 引用配置的 `name`,没有配置时不写签名。
105
+
106
+ ## 插件顺序
107
+
108
+ 默认配置在执行阶段读取最终的 app config,其他 Harmony 配置插件可以放在本包前面或后面。要覆盖默认值,把本包放到插件列表最后:
40
109
 
41
110
  ```json
42
111
  {
@@ -52,14 +121,37 @@ npx expo-harmony prebuild
52
121
  ],
53
122
  "@expo-harmony/expo-system-ui",
54
123
  "@expo-harmony/prebuild-config"
55
- ],
56
- "harmony": {
57
- "bundleName": "com.example.app"
58
- }
124
+ ]
59
125
  }
60
126
  }
61
127
  ```
62
128
 
129
+ 默认导出和具名导出 `withHarmonyPrebuildConfig` 是同一个插件,重复注册只生效一次。
130
+
131
+ ## 文件清理
132
+
133
+ 再次 prebuild 时,插件不再声明的文件会被删除;卸载插件后,它管理的文件也会清理。
134
+
135
+ ## 原生补丁
136
+
137
+ 用 [`@expo-harmony/patch-project`](https://github.com/renbaoshuo/expo-harmony/tree/master/packages/patch-project) 保存原生修改,并在 prebuild 时自动恢复。
138
+
139
+ ## 读取配置
140
+
141
+ `getPrebuildConfigAsync(projectRoot)` 读取静态或动态 app config,执行已声明的配置插件,返回 `HarmonyProjectConfig`。它不生成原生工程。
142
+
143
+ ```ts
144
+ import { getPrebuildConfigAsync } from '@expo-harmony/prebuild-config';
145
+
146
+ const project = await getPrebuildConfigAsync(projectRoot);
147
+ ```
148
+
149
+ `withHarmonyPrebuildConfig` 是插件本身,可以带 `HarmonyPrebuildOptions` 手动组合。`HarmonyPrebuildError` 带有 `code`、`operation` 和 `file`,用于识别预构建失败的原因。
150
+
151
+ ## 与上游 Expo 的分工
152
+
153
+ HarmonyOS 的工程生成由本包负责,iOS 和 Android 仍使用 Expo 上游的预构建。此外,上游面向旧版应用的自动插件列表不适用于 HarmonyOS,模块插件要在应用里显式声明。
154
+
63
155
  ## Author
64
156
 
65
157
  **expo-harmony** © [Baoshuo](https://github.com/renbaoshuo), Released under the MIT License.<br>
@@ -0,0 +1 @@
1
+ export { ROOT_ENV, resolveBundled } from '../template';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveBundled = exports.ROOT_ENV = void 0;
4
+ var template_1 = require("../template");
5
+ Object.defineProperty(exports, "ROOT_ENV", { enumerable: true, get: function () { return template_1.ROOT_ENV; } });
6
+ Object.defineProperty(exports, "resolveBundled", { enumerable: true, get: function () { return template_1.resolveBundled; } });
@@ -10,6 +10,7 @@ exports.resolveHarmonyBuildPath = resolveHarmonyBuildPath;
10
10
  exports.validateHarmonyBuildDescriptor = validateHarmonyBuildDescriptor;
11
11
  const node_path_1 = __importDefault(require("node:path"));
12
12
  const config_plugins_1 = require("@expo-harmony/config-plugins");
13
+ const internal_1 = require("@expo-harmony/config-plugins/internal");
13
14
  const BuildDescriptorSchemaVersion = 2;
14
15
  exports.BuildDescriptorSchemaVersion = BuildDescriptorSchemaVersion;
15
16
  const BuildModes = Object.freeze(['debug', 'release']);
@@ -61,8 +62,8 @@ function validateHarmonyBuildDescriptor(value) {
61
62
  || !isStrictDescendant(value.harmonyRoot, value.moduleRoot)) {
62
63
  throw new TypeError('Harmony build descriptor contains invalid project roots.');
63
64
  }
64
- const harmonyRoot = value.harmonyRoot;
65
- const moduleRoot = value.moduleRoot;
65
+ const harmony = value.harmonyRoot;
66
+ const module = value.moduleRoot;
66
67
  const identity = value.identity;
67
68
  if (!isRecord(identity)
68
69
  || ['abilityName', 'bundleName', 'moduleName', 'productName', 'targetName']
@@ -73,17 +74,17 @@ function validateHarmonyBuildDescriptor(value) {
73
74
  if (!isRecord(inputs)
74
75
  || !isSafeRelativePath(inputs.manifest)
75
76
  || !isSafeRelativePath(inputs.lockfile)
76
- || !isStrictDescendant(harmonyRoot, inputs.manifest)
77
- || !isStrictDescendant(harmonyRoot, inputs.lockfile)) {
77
+ || !isStrictDescendant(harmony, inputs.manifest)
78
+ || !isStrictDescendant(harmony, inputs.lockfile)) {
78
79
  throw new TypeError('Harmony build descriptor contains invalid native input paths.');
79
80
  }
80
81
  const cache = value.nativeCache;
81
82
  if (!isRecord(cache)
82
83
  || !isSafeRelativePath(cache.stateFile)
83
- || !isStrictDescendant(moduleRoot, cache.stateFile)
84
+ || !isStrictDescendant(module, cache.stateFile)
84
85
  || !Array.isArray(cache.invalidationRoots)
85
86
  || cache.invalidationRoots.length === 0
86
- || cache.invalidationRoots.some(item => (!isSafeRelativePath(item) || !isStrictDescendant(moduleRoot, item)))) {
87
+ || cache.invalidationRoots.some(item => (!isSafeRelativePath(item) || !isStrictDescendant(module, item)))) {
87
88
  throw new TypeError('Harmony build descriptor contains invalid native cache paths.');
88
89
  }
89
90
  const files = value.projectFiles;
@@ -97,8 +98,8 @@ function validateHarmonyBuildDescriptor(value) {
97
98
  const modules = ['moduleHvigor', 'moduleJson'];
98
99
  if (!isRecord(files)
99
100
  || [...roots, ...modules].some(field => !isSafeRelativePath(files[field]))
100
- || roots.some(field => !isStrictDescendant(harmonyRoot, files[field]))
101
- || modules.some(field => !isStrictDescendant(moduleRoot, files[field]))) {
101
+ || roots.some(field => !isStrictDescendant(harmony, files[field]))
102
+ || modules.some(field => !isStrictDescendant(module, files[field]))) {
102
103
  throw new TypeError('Harmony build descriptor contains invalid project file paths.');
103
104
  }
104
105
  const output = value.export;
@@ -108,7 +109,7 @@ function validateHarmonyBuildDescriptor(value) {
108
109
  const invalid = ['bundle', 'manifest', 'metadataRoot', 'rawfileRoot', 'sourceMap']
109
110
  .some(field => !isSafeRelativePath(output[field]));
110
111
  if (invalid
111
- || !isStrictDescendant(moduleRoot, output.rawfileRoot)
112
+ || !isStrictDescendant(module, output.rawfileRoot)
112
113
  || !isStrictDescendant(output.rawfileRoot, output.bundle)
113
114
  || !isStrictDescendant(output.metadataRoot, output.sourceMap)) {
114
115
  throw new TypeError('Harmony build descriptor contains invalid export paths.');
@@ -120,7 +121,7 @@ function validateHarmonyBuildDescriptor(value) {
120
121
  }
121
122
  for (const mode of BuildModes) {
122
123
  const variant = validateVariant(value.variants[mode]);
123
- if (!isStrictDescendant(moduleRoot, variant.expectedHap)) {
124
+ if (!isStrictDescendant(module, variant.expectedHap)) {
124
125
  throw new TypeError(`Harmony ${mode} HAP output must be inside the module root.`);
125
126
  }
126
127
  }
@@ -173,7 +174,7 @@ function createHarmonyBuildDescriptor(config, signing) {
173
174
  hvigorConfig: `${harmony}/${paths.hvigorConfig}`,
174
175
  moduleHvigor: `${harmony}/${paths.entryHvigor}`,
175
176
  moduleJson: `${harmony}/${paths.moduleJson}`,
176
- nativeInputsStamp: `${harmony}/${paths.nativeInputsStamp}`,
177
+ nativeInputsStamp: `${harmony}/${internal_1.NativeInputsStampPath}`,
177
178
  projectBuildProfile: `${harmony}/${paths.projectBuildProfile}`,
178
179
  rootHvigor: `${harmony}/${paths.rootHvigor}`,
179
180
  templateMarker: `${harmony}/${HarmonyTemplateMarker}`,
package/build/check.js CHANGED
@@ -10,19 +10,14 @@ exports.stageAsync = stageAsync;
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const node_path_1 = __importDefault(require("node:path"));
12
12
  const node_util_1 = require("node:util");
13
- const config_1 = require("@expo/config");
14
13
  const config_plugins_1 = require("@expo-harmony/config-plugins");
15
14
  const expo_modules_autolinking_1 = require("@expo-harmony/expo-modules-autolinking");
16
15
  const json5_1 = __importDefault(require("json5"));
17
16
  const errors_1 = require("./errors");
17
+ const getPrebuildConfig_1 = require("./getPrebuildConfig");
18
18
  const buildDescriptor_1 = require("./buildDescriptor");
19
19
  const manifest_1 = require("./manifest");
20
20
  const signing_1 = require("./signing");
21
- function isInside(root, target) {
22
- const relative = node_path_1.default.relative(root, target);
23
- return relative === ''
24
- || (!relative.startsWith(`..${node_path_1.default.sep}`) && relative !== '..' && !node_path_1.default.isAbsolute(relative));
25
- }
26
21
  function mirrorPath(temp, source) {
27
22
  const absolute = node_path_1.default.resolve(source);
28
23
  const parsed = node_path_1.default.parse(absolute);
@@ -126,10 +121,7 @@ async function stageManifestAsync(project, target) {
126
121
  catch (cause) {
127
122
  throw new errors_1.HarmonyPrebuildError('ERR_HARMONY_MANIFEST_DRIFT', `Cannot stage the CNG manifest for isolated --check: ${source}`, { cause, file: source, operation: 'check' });
128
123
  }
129
- const config = (0, config_1.getConfig)(project, {
130
- isModdedConfig: true,
131
- skipSDKVersionRequirement: true,
132
- }).exp;
124
+ const { exp: config } = await (0, getPrebuildConfig_1.getPrebuildConfigAsync)(project);
133
125
  const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(config);
134
126
  const hash = (0, manifest_1.hashSha256)((0, config_plugins_1.stableHarmonyJson)(harmony));
135
127
  let identity = cng.managedIdentity;
@@ -162,20 +154,17 @@ async function stageManifestAsync(project, target) {
162
154
  }));
163
155
  }
164
156
  async function stageSigningAsync(project, temp) {
165
- const config = (0, config_1.getConfig)(project, {
166
- isModdedConfig: true,
167
- skipSDKVersionRequirement: true,
168
- }).exp;
157
+ const { exp: config } = await (0, getPrebuildConfig_1.getPrebuildConfigAsync)(project);
169
158
  const reference = config.harmony?.signingConfigFile;
170
159
  if (!reference)
171
160
  return;
172
161
  const signing = await (0, signing_1.validateHarmonySigningConfigFile)(project, reference);
173
162
  const inputs = [signing.file, ...Object.values(signing.materialFiles)];
174
163
  for (const source of inputs) {
175
- if (isInside(project, source))
164
+ if (config_plugins_1.HarmonyPaths.isInside(project, source))
176
165
  continue;
177
166
  const target = mirrorPath(temp, source);
178
- if (!isInside(temp, target)) {
167
+ if (!config_plugins_1.HarmonyPaths.isInside(temp, target)) {
179
168
  throw new errors_1.HarmonyPrebuildError('ERR_HARMONY_SIGNING_INVALID', `External Harmony signing input escapes the isolated --check workspace: ${source}`, { operation: 'check-signing' });
180
169
  }
181
170
  await node_fs_1.default.promises.mkdir(node_path_1.default.dirname(target), { recursive: true });
@@ -0,0 +1,6 @@
1
+ import { type ProjectConfig } from '@expo/config';
2
+ import { type ExpoConfigWithHarmony } from '@expo-harmony/config-plugins';
3
+ export type HarmonyProjectConfig = Omit<ProjectConfig, 'exp'> & {
4
+ exp: ExpoConfigWithHarmony;
5
+ };
6
+ export declare function getPrebuildConfigAsync(root: string): Promise<HarmonyProjectConfig>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPrebuildConfigAsync = getPrebuildConfigAsync;
4
+ const config_1 = require("@expo/config");
5
+ const config_plugins_1 = require("@expo-harmony/config-plugins");
6
+ const withHarmonyPrebuildConfig_1 = require("./withHarmonyPrebuildConfig");
7
+ async function getPrebuildConfigAsync(root) {
8
+ const project = (0, config_1.getConfig)(root, {
9
+ skipSDKVersionRequirement: true,
10
+ isModdedConfig: true,
11
+ });
12
+ const config = (0, withHarmonyPrebuildConfig_1.withHarmonyPrebuildConfig)(project.exp);
13
+ (0, config_plugins_1.normalizeHarmonyConfig)(config);
14
+ return { ...project, exp: config };
15
+ }
package/build/index.d.ts CHANGED
@@ -1,8 +1,6 @@
1
- export { HarmonyPrebuildPlugin as default } from './plugin';
2
- export { BuildDescriptorSchemaVersion, BuildModes, HarmonyPlatformDirectory, HarmonyTemplateMarker, createHarmonyBuildDescriptor, harmonyModuleSourcePath, resolveHarmonyBuildPath, validateHarmonyBuildDescriptor, type HarmonyBuildDescriptor, type HarmonyBuildMode, type HarmonyBuildVariantDescriptor, } from './buildDescriptor';
3
- export { HarmonyPrebuildError } from './errors';
4
- export { CngManifestPath, createCngManifest, validateCngManifest, type CngManifest, } from './manifest';
5
- export { isRnohAutolinkingDisabled } from './native';
6
- export { validateHarmonySigningConfigFile, type HarmonySigningConfig } from './signing';
7
- export { withHarmonyPrebuildConfig } from './withHarmonyPrebuildConfig';
1
+ export { withHarmonyPrebuildConfig as default, withHarmonyPrebuildConfig } from './withHarmonyPrebuildConfig';
8
2
  export type { HarmonyPrebuildOptions } from './withHarmonyPrebuildConfig';
3
+ export { getPrebuildConfigAsync } from './getPrebuildConfig';
4
+ export type { HarmonyProjectConfig } from './getPrebuildConfig';
5
+ export { HarmonyPrebuildError } from './errors';
6
+ export type { HarmonyPrebuildErrorOptions } from './errors';
package/build/index.js CHANGED
@@ -1,26 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withHarmonyPrebuildConfig = exports.validateHarmonySigningConfigFile = exports.isRnohAutolinkingDisabled = exports.validateCngManifest = exports.createCngManifest = exports.CngManifestPath = exports.HarmonyPrebuildError = exports.validateHarmonyBuildDescriptor = exports.resolveHarmonyBuildPath = exports.harmonyModuleSourcePath = exports.createHarmonyBuildDescriptor = exports.HarmonyTemplateMarker = exports.HarmonyPlatformDirectory = exports.BuildModes = exports.BuildDescriptorSchemaVersion = exports.default = void 0;
4
- var plugin_1 = require("./plugin");
5
- Object.defineProperty(exports, "default", { enumerable: true, get: function () { return plugin_1.HarmonyPrebuildPlugin; } });
6
- var buildDescriptor_1 = require("./buildDescriptor");
7
- Object.defineProperty(exports, "BuildDescriptorSchemaVersion", { enumerable: true, get: function () { return buildDescriptor_1.BuildDescriptorSchemaVersion; } });
8
- Object.defineProperty(exports, "BuildModes", { enumerable: true, get: function () { return buildDescriptor_1.BuildModes; } });
9
- Object.defineProperty(exports, "HarmonyPlatformDirectory", { enumerable: true, get: function () { return buildDescriptor_1.HarmonyPlatformDirectory; } });
10
- Object.defineProperty(exports, "HarmonyTemplateMarker", { enumerable: true, get: function () { return buildDescriptor_1.HarmonyTemplateMarker; } });
11
- Object.defineProperty(exports, "createHarmonyBuildDescriptor", { enumerable: true, get: function () { return buildDescriptor_1.createHarmonyBuildDescriptor; } });
12
- Object.defineProperty(exports, "harmonyModuleSourcePath", { enumerable: true, get: function () { return buildDescriptor_1.harmonyModuleSourcePath; } });
13
- Object.defineProperty(exports, "resolveHarmonyBuildPath", { enumerable: true, get: function () { return buildDescriptor_1.resolveHarmonyBuildPath; } });
14
- Object.defineProperty(exports, "validateHarmonyBuildDescriptor", { enumerable: true, get: function () { return buildDescriptor_1.validateHarmonyBuildDescriptor; } });
15
- var errors_1 = require("./errors");
16
- Object.defineProperty(exports, "HarmonyPrebuildError", { enumerable: true, get: function () { return errors_1.HarmonyPrebuildError; } });
17
- var manifest_1 = require("./manifest");
18
- Object.defineProperty(exports, "CngManifestPath", { enumerable: true, get: function () { return manifest_1.CngManifestPath; } });
19
- Object.defineProperty(exports, "createCngManifest", { enumerable: true, get: function () { return manifest_1.createCngManifest; } });
20
- Object.defineProperty(exports, "validateCngManifest", { enumerable: true, get: function () { return manifest_1.validateCngManifest; } });
21
- var native_1 = require("./native");
22
- Object.defineProperty(exports, "isRnohAutolinkingDisabled", { enumerable: true, get: function () { return native_1.isRnohAutolinkingDisabled; } });
23
- var signing_1 = require("./signing");
24
- Object.defineProperty(exports, "validateHarmonySigningConfigFile", { enumerable: true, get: function () { return signing_1.validateHarmonySigningConfigFile; } });
3
+ exports.HarmonyPrebuildError = exports.getPrebuildConfigAsync = exports.withHarmonyPrebuildConfig = exports.default = void 0;
25
4
  var withHarmonyPrebuildConfig_1 = require("./withHarmonyPrebuildConfig");
5
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return withHarmonyPrebuildConfig_1.withHarmonyPrebuildConfig; } });
26
6
  Object.defineProperty(exports, "withHarmonyPrebuildConfig", { enumerable: true, get: function () { return withHarmonyPrebuildConfig_1.withHarmonyPrebuildConfig; } });
7
+ var getPrebuildConfig_1 = require("./getPrebuildConfig");
8
+ Object.defineProperty(exports, "getPrebuildConfigAsync", { enumerable: true, get: function () { return getPrebuildConfig_1.getPrebuildConfigAsync; } });
9
+ var errors_1 = require("./errors");
10
+ Object.defineProperty(exports, "HarmonyPrebuildError", { enumerable: true, get: function () { return errors_1.HarmonyPrebuildError; } });
@@ -0,0 +1,6 @@
1
+ export { compareAsync, readManifestIfPresentAsync, stageAsync } from './check';
2
+ export type { Change, Result } from './check';
3
+ export { HarmonyPlatformDirectory, resolveHarmonyBuildPath } from './buildDescriptor';
4
+ export type { HarmonyBuildDescriptor } from './buildDescriptor';
5
+ export { isRnohAutolinkingDisabled } from './native';
6
+ export { validateHarmonySigningConfigFile } from './signing';
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateHarmonySigningConfigFile = exports.isRnohAutolinkingDisabled = exports.resolveHarmonyBuildPath = exports.HarmonyPlatformDirectory = exports.stageAsync = exports.readManifestIfPresentAsync = exports.compareAsync = void 0;
4
+ var check_1 = require("./check");
5
+ Object.defineProperty(exports, "compareAsync", { enumerable: true, get: function () { return check_1.compareAsync; } });
6
+ Object.defineProperty(exports, "readManifestIfPresentAsync", { enumerable: true, get: function () { return check_1.readManifestIfPresentAsync; } });
7
+ Object.defineProperty(exports, "stageAsync", { enumerable: true, get: function () { return check_1.stageAsync; } });
8
+ var buildDescriptor_1 = require("./buildDescriptor");
9
+ Object.defineProperty(exports, "HarmonyPlatformDirectory", { enumerable: true, get: function () { return buildDescriptor_1.HarmonyPlatformDirectory; } });
10
+ Object.defineProperty(exports, "resolveHarmonyBuildPath", { enumerable: true, get: function () { return buildDescriptor_1.resolveHarmonyBuildPath; } });
11
+ var native_1 = require("./native");
12
+ Object.defineProperty(exports, "isRnohAutolinkingDisabled", { enumerable: true, get: function () { return native_1.isRnohAutolinkingDisabled; } });
13
+ var signing_1 = require("./signing");
14
+ Object.defineProperty(exports, "validateHarmonySigningConfigFile", { enumerable: true, get: function () { return signing_1.validateHarmonySigningConfigFile; } });
package/build/manifest.js CHANGED
@@ -12,6 +12,8 @@ const node_crypto_1 = require("node:crypto");
12
12
  const node_fs_1 = require("node:fs");
13
13
  const node_path_1 = __importDefault(require("node:path"));
14
14
  const config_plugins_1 = require("@expo-harmony/config-plugins");
15
+ const internal_1 = require("@expo-harmony/config-plugins/internal");
16
+ const json5_1 = __importDefault(require("json5"));
15
17
  const errors_1 = require("./errors");
16
18
  const buildDescriptor_1 = require("./buildDescriptor");
17
19
  const packageMetadata_1 = require("./packageMetadata");
@@ -62,7 +64,7 @@ function validateCngManifest(manifest, options = {}) {
62
64
  throw new errors_1.HarmonyPrebuildError('ERR_HARMONY_MANIFEST_INVALID', 'Harmony CNG manifest managedFiles must be an array.', { file, operation: 'validate-manifest' });
63
65
  }
64
66
  try {
65
- manifest.configPlugins = (0, config_plugins_1.normalizeHarmonyConfigPlugins)(manifest.configPlugins);
67
+ manifest.configPlugins = (0, internal_1.normalizeHarmonyConfigPlugins)(manifest.configPlugins);
66
68
  }
67
69
  catch (cause) {
68
70
  throw new errors_1.HarmonyPrebuildError('ERR_HARMONY_MANIFEST_INVALID', `Harmony CNG manifest has invalid config-plugin ownership: ${cause.message}`, { cause, file, operation: 'validate-manifest' });
@@ -127,29 +129,36 @@ async function hashFile(file) {
127
129
  return hashSha256(Uint8Array.from(await node_fs_1.promises.readFile(file)));
128
130
  }
129
131
  async function createCngManifest(root, config, managed, modules = [], signing = null, plugins = []) {
130
- const build = (0, buildDescriptor_1.createHarmonyBuildDescriptor)(config, signing);
132
+ const file = node_path_1.default.join(root, 'harmony', config_plugins_1.HarmonyPaths.HARMONY_PATHS.projectBuildProfile);
133
+ const profile = json5_1.default.parse(await node_fs_1.promises.readFile(file, 'utf8'));
134
+ const product = profile.app?.products?.find(item => item.name === config.productName);
135
+ const build = (0, buildDescriptor_1.createHarmonyBuildDescriptor)(config, product?.signingConfig ?? null);
131
136
  const files = [];
132
137
  for (const item of managed) {
133
138
  const target = node_path_1.default.join(root, ...item.path.split('/'));
134
139
  try {
135
140
  files.push({ owner: item.owner, path: item.path, sha256: await hashFile(target) });
136
141
  }
137
- catch (error) {
138
- if (error.code !== 'ENOENT')
139
- return Promise.reject(error);
142
+ catch (cause) {
143
+ if (cause.code !== 'ENOENT') {
144
+ throw new errors_1.HarmonyPrebuildError(cause.code || 'ERR_HARMONY_MANIFEST_INVALID', cause.message || `Cannot hash managed file ${target}.`, { cause, file: target, operation: 'create-manifest' });
145
+ }
140
146
  }
141
147
  }
142
148
  files.sort((left, right) => left.path.localeCompare(right.path, 'en'));
143
- const autolinkingFile = node_path_1.default.join(root, '.expo/harmony/autolinking.json');
144
- const autolinkingHash = await hashFile(autolinkingFile)
145
- .catch(error => error.code === 'ENOENT' ? hashSha256('') : Promise.reject(error));
149
+ const autolinking = node_path_1.default.join(root, '.expo/harmony/autolinking.json');
150
+ const hash = await hashFile(autolinking).catch((cause) => {
151
+ if (cause.code === 'ENOENT')
152
+ return hashSha256('');
153
+ throw new errors_1.HarmonyPrebuildError(cause.code || 'ERR_HARMONY_MANIFEST_INVALID', cause.message || `Cannot hash autolinking manifest ${autolinking}.`, { cause, file: autolinking, operation: 'create-manifest' });
154
+ });
146
155
  return validateCngManifest({
147
156
  build,
148
157
  generatedAt: null,
149
- configPlugins: (0, config_plugins_1.normalizeHarmonyConfigPlugins)(plugins),
158
+ configPlugins: (0, internal_1.normalizeHarmonyConfigPlugins)(plugins),
150
159
  generator: { package: '@expo-harmony/prebuild-config', version: GeneratorVersion },
151
160
  inputs: {
152
- autolinkingHash,
161
+ autolinkingHash: hash,
153
162
  configHash: hashSha256((0, config_plugins_1.stableHarmonyJson)(config)),
154
163
  },
155
164
  managedFiles: files,
@@ -1 +1,2 @@
1
- export declare function withAutolinkingMods(config: any, harmony: any, options: any): any;
1
+ import type { HarmonyPrebuildOptions } from '../withHarmonyPrebuildConfig';
2
+ export declare function withAutolinkingMods(config: any, options: HarmonyPrebuildOptions): any;
@@ -8,6 +8,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const expo_modules_autolinking_1 = require("@expo-harmony/expo-modules-autolinking");
10
10
  const config_plugins_1 = require("@expo-harmony/config-plugins");
11
+ const internal_1 = require("@expo-harmony/config-plugins/internal");
11
12
  const errors_1 = require("../errors");
12
13
  const buildDescriptor_1 = require("../buildDescriptor");
13
14
  const manifest_1 = require("../manifest");
@@ -16,14 +17,20 @@ function formatAutolinkingDiagnostics(cause) {
16
17
  ? ` ${cause.diagnostics.map(item => `[${item.code}] ${item.message}`).join(' ')}`
17
18
  : '';
18
19
  }
19
- function withAutolinkingMods(config, harmony, options) {
20
+ function withAutolinkingMods(config, options) {
20
21
  config = (0, config_plugins_1.withHarmonyAutolinking)(config, async (mod) => {
22
+ if (mod.modRequest.introspect)
23
+ return mod;
24
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
25
+ const mode = options.buildType ?? process.env.EXPO_HARMONY_BUILD_TYPE ?? 'debug';
26
+ if (mode !== 'debug' && mode !== 'release') {
27
+ throw new errors_1.HarmonyPrebuildError('ERR_HARMONY_CONFIG_INVALID', 'EXPO_HARMONY_BUILD_TYPE must be debug or release.', { operation: 'autolinking' });
28
+ }
21
29
  try {
22
30
  const root = mod.modRequest.projectRoot;
23
31
  const project = await node_fs_1.default.promises.realpath(root);
24
32
  const build = (0, buildDescriptor_1.createHarmonyBuildDescriptor)(harmony, mod._internal?.harmonySigningConfig?.name ?? null);
25
33
  const platform = (0, buildDescriptor_1.resolveHarmonyBuildPath)(project, build.harmonyRoot);
26
- const mode = (options.buildType || process.env.EXPO_HARMONY_BUILD_TYPE || 'debug');
27
34
  const result = await (0, expo_modules_autolinking_1.linkModulesAsync)({
28
35
  projectRoot: project,
29
36
  harmonyProjectPath: platform,
@@ -44,9 +51,12 @@ function withAutolinkingMods(config, harmony, options) {
44
51
  throw new errors_1.HarmonyPrebuildError('ERR_HARMONY_AUTOLINK_FAILED', `Harmony autolinking failed: ${cause.message}${formatAutolinkingDiagnostics(cause)}`, { cause, operation: 'autolinking' });
45
52
  }
46
53
  });
47
- config = (0, config_plugins_1.withCngManifest)(config, async (mod) => {
54
+ config = (0, internal_1.withCngManifest)(config, async (mod) => {
55
+ if (mod.modRequest.introspect)
56
+ return mod;
57
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
48
58
  const managed = mod._internal?.harmonyManagedFiles || [];
49
- const manifest = await (0, manifest_1.createCngManifest)(mod.modRequest.projectRoot, harmony, managed, mod._internal?.harmonyAutolinkingModules || [], mod._internal?.harmonySigningConfig?.name ?? null, (0, config_plugins_1.getHarmonyConfigPlugins)(mod));
59
+ const manifest = await (0, manifest_1.createCngManifest)(mod.modRequest.projectRoot, harmony, managed, mod._internal?.harmonyAutolinkingModules || [], mod._internal?.harmonySigningConfig?.name ?? null, (0, internal_1.getHarmonyConfigPlugins)(mod));
50
60
  const file = (0, buildDescriptor_1.resolveHarmonyBuildPath)(mod.modRequest.projectRoot, manifest_1.CngManifestPath);
51
61
  await node_fs_1.default.promises.mkdir(node_path_1.default.dirname(file), { recursive: true });
52
62
  await node_fs_1.default.promises.writeFile(file, (0, config_plugins_1.stableHarmonyJson)(manifest));
@@ -1,2 +1,2 @@
1
- declare function withEntryMods(config: any, harmony: any): any;
1
+ declare function withEntryMods(config: any): any;
2
2
  export { withEntryMods };
@@ -40,19 +40,13 @@ exports.withEntryMods = withEntryMods;
40
40
  const node_fs_1 = __importDefault(require("node:fs"));
41
41
  const node_path_1 = __importDefault(require("node:path"));
42
42
  const config_plugins_1 = require("@expo-harmony/config-plugins");
43
+ const internal_1 = require("@expo-harmony/config-plugins/internal");
43
44
  const buildDescriptor_1 = require("../buildDescriptor");
44
45
  const dependencies_1 = require("../dependencies");
45
46
  const errors_1 = require("../errors");
46
47
  const reconcile_1 = require("../reconcile");
47
48
  const render = __importStar(require("../renderers"));
48
49
  const stale_1 = require("../stale");
49
- function setResource(items, name, value) {
50
- const resources = (Array.isArray(items) ? items : [])
51
- .filter(item => item?.name !== name);
52
- resources.push({ name, value });
53
- resources.sort((left, right) => left.name.localeCompare(right.name, 'en'));
54
- return resources;
55
- }
56
50
  function replaceMediaBase(files, base, descriptor) {
57
51
  for (const name of Object.keys(files)) {
58
52
  if (node_path_1.default.parse(name).name === base)
@@ -100,8 +94,9 @@ function resolveInputFile(root, value) {
100
94
  }
101
95
  return file;
102
96
  }
103
- function withEntryMods(config, harmony) {
97
+ function withEntryMods(config) {
104
98
  config = (0, config_plugins_1.withEntryBuildProfile)(config, (mod) => {
99
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
105
100
  const build = (0, reconcile_1.readRecord)(mod.modResults.buildOption);
106
101
  const native = (0, reconcile_1.readRecord)(build.externalNativeOptions);
107
102
  mod.modResults = {
@@ -124,6 +119,7 @@ function withEntryMods(config, harmony) {
124
119
  return mod;
125
120
  });
126
121
  config = (0, config_plugins_1.withEntryOhPackage)(config, (mod) => {
122
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
127
123
  mod.modResults = {
128
124
  ...mod.modResults,
129
125
  name: harmony.moduleName,
@@ -135,19 +131,21 @@ function withEntryMods(config, harmony) {
135
131
  return mod;
136
132
  });
137
133
  config = (0, config_plugins_1.withEntryHvigor)(config, async (mod) => {
134
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
138
135
  const build = (0, buildDescriptor_1.createHarmonyBuildDescriptor)(harmony, mod._internal?.harmonySigningConfig?.name ?? null);
139
136
  const relative = node_path_1.default.posix.relative(build.harmonyRoot, build.projectFiles.moduleHvigor);
140
137
  mod.modResults = render.renderCanonical(await (0, dependencies_1.readTemplateSource)(relative), build.projectFiles.moduleHvigor);
141
138
  return mod;
142
139
  });
143
140
  config = (0, config_plugins_1.withModuleJson)(config, (mod) => {
141
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
144
142
  const home = {
145
143
  entities: ['entity.system.home'],
146
144
  actions: ['action.system.home'],
147
145
  };
148
146
  const module = (0, stale_1.removeStaleExtensionAbilities)((0, reconcile_1.readRecord)(mod.modResults.module), config_plugins_1.HarmonyPaths.toPosixRelative(mod.modRequest.projectRoot, node_path_1.default.join(mod.modRequest.platformProjectRoot, config_plugins_1.HarmonyPaths.HARMONY_PATHS.moduleJson)), mod._internal?.harmonyStalePluginFiles || []);
149
147
  const previous = mod._internal?.harmonyPreviousManagedIdentity;
150
- const plugins = (0, config_plugins_1.getHarmonyConfigPlugins)(mod);
148
+ const plugins = (0, internal_1.getHarmonyConfigPlugins)(mod);
151
149
  const abilities = (0, reconcile_1.upsertManagedNamed)(module.abilities, harmony.abilityName, previous?.abilityName, 'EntryAbility', existing => ({
152
150
  ...existing,
153
151
  name: harmony.abilityName,
@@ -188,25 +186,29 @@ function withEntryMods(config, harmony) {
188
186
  return mod;
189
187
  });
190
188
  config = (0, config_plugins_1.withStrings)(config, (mod) => {
189
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
191
190
  mod.modResults = (0, stale_1.removeStaleResources)(mod.modResults, 'strings', mod._internal?.harmonyStaleConfigPlugins || []);
192
- mod.modResults.app ??= {};
193
- mod.modResults.entry ??= {};
194
- mod.modResults.app.string = setResource(mod.modResults.app.string, 'app_name', harmony.label);
195
- let strings = mod.modResults.entry.string || [];
196
- strings = setResource(strings, 'expo_harmony_ability_desc', `${harmony.label} main ability`);
197
- strings = setResource(strings, 'expo_harmony_ability_label', harmony.label);
198
- strings = setResource(strings, 'expo_harmony_module_desc', `${harmony.label} entry module`);
199
- mod.modResults.entry.string = strings;
191
+ const app = mod.modResults.app ??= {};
192
+ const entry = mod.modResults.entry ??= {};
193
+ config_plugins_1.HarmonyResources.setString(app, { name: 'app_name', value: harmony.label });
194
+ config_plugins_1.HarmonyResources.setString(entry, { name: 'expo_harmony_ability_desc', value: `${harmony.label} main ability` });
195
+ config_plugins_1.HarmonyResources.setString(entry, { name: 'expo_harmony_ability_label', value: harmony.label });
196
+ config_plugins_1.HarmonyResources.setString(entry, { name: 'expo_harmony_module_desc', value: `${harmony.label} entry module` });
197
+ for (const file of [app, entry])
198
+ file.string.sort((left, right) => left.name.localeCompare(right.name, 'en'));
200
199
  return mod;
201
200
  });
202
201
  config = (0, config_plugins_1.withColors)(config, (mod) => {
202
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
203
203
  mod.modResults = (0, stale_1.removeStaleResources)(mod.modResults, 'colors', mod._internal?.harmonyStaleConfigPlugins || []);
204
- mod.modResults.entry ??= {};
204
+ const entry = mod.modResults.entry ??= {};
205
205
  mod.modResults.entryDark ??= {};
206
- mod.modResults.entry.color = setResource(mod.modResults.entry.color, 'expo_harmony_start_window_background', harmony.backgroundColor);
206
+ config_plugins_1.HarmonyResources.setColor(entry, { name: 'expo_harmony_start_window_background', value: harmony.backgroundColor });
207
+ entry.color.sort((left, right) => left.name.localeCompare(right.name, 'en'));
207
208
  return mod;
208
209
  });
209
210
  config = (0, config_plugins_1.withMedia)(config, (mod) => {
211
+ const harmony = (0, config_plugins_1.normalizeHarmonyConfig)(mod.modRawConfig);
210
212
  mod.modResults = (0, stale_1.removeStaleResources)(mod.modResults, 'media', mod._internal?.harmonyStaleConfigPlugins || []);
211
213
  const icon = harmony.icon
212
214
  ? resolveInputFile(mod.modRequest.projectRoot, harmony.icon)
@@ -1,2 +1,2 @@
1
- declare function withPreparationMod(config: any, harmony: any): import("@expo/config-types").ExpoConfig;
1
+ declare function withPreparationMod(config: any): any;
2
2
  export { withPreparationMod };