@expo-harmony/prebuild-config 55.0.0-harmony.1

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,332 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import {
5
+ getHarmonyConfigPlugins,
6
+ HarmonyPaths,
7
+ withColors,
8
+ withEntryBuildProfile,
9
+ withEntryHvigor,
10
+ withEntryOhPackage,
11
+ withMedia,
12
+ withModuleJson,
13
+ withProfiles,
14
+ withStrings,
15
+ } from '@expo-harmony/config-plugins';
16
+
17
+ import {
18
+ createHarmonyBuildDescriptor,
19
+ HarmonyPlatformDirectory,
20
+ } from '../buildDescriptor';
21
+ import { readTemplateSource, resolveTemplateFile } from '../dependencies';
22
+ import { HarmonyPrebuildError } from '../errors';
23
+ import {
24
+ appendUnique,
25
+ readRecord,
26
+ upsertManagedNamed,
27
+ upsertNamed,
28
+ } from '../reconcile';
29
+ import * as render from '../renderers';
30
+ import { removeStaleExtensionAbilities, removeStaleResources } from '../stale';
31
+
32
+ function setResource(items, name, value) {
33
+ const resources = (Array.isArray(items) ? items : [])
34
+ .filter(item => item?.name !== name);
35
+
36
+ resources.push({ name, value });
37
+ resources.sort((left, right) => left.name.localeCompare(right.name, 'en'));
38
+
39
+ return resources;
40
+ }
41
+
42
+ function replaceMediaBase(files, base, descriptor?) {
43
+ for (const name of Object.keys(files)) {
44
+ if (path.parse(name).name === base) delete files[name];
45
+ }
46
+
47
+ if (descriptor) {
48
+ files[descriptor.name] = { source: descriptor.source, replaceBase: true };
49
+ }
50
+ }
51
+
52
+ function reconcileRuntimeMetadata(items) {
53
+ const names = new Set([
54
+ 'OPTLazyForEach',
55
+ 'can_preview_text',
56
+ 'halfLeading',
57
+ ]);
58
+
59
+ return (Array.isArray(items) ? items : [])
60
+ .filter(item => !names.has(item?.name))
61
+ .concat([
62
+ { name: 'OPTLazyForEach', value: 'true' },
63
+ { name: 'can_preview_text', value: 'true' },
64
+ { name: 'halfLeading', value: 'true' },
65
+ ]);
66
+ }
67
+
68
+ function isAbilityValueClaimed(plugins, field, value) {
69
+ return plugins.some(plugin => plugin.ability?.[field] === value);
70
+ }
71
+
72
+ function getSourceExtension(value) {
73
+ const extension = path.extname(value || '').toLowerCase();
74
+
75
+ if (!['.png', '.jpg', '.jpeg', '.svg', '.webp'].includes(extension)) {
76
+ throw new HarmonyPrebuildError(
77
+ 'ERR_HARMONY_CONFIG_INVALID',
78
+ `Unsupported Harmony icon format: ${extension || '(none)'}`,
79
+ { file: value, operation: 'render-icons' }
80
+ );
81
+ }
82
+
83
+ return extension;
84
+ }
85
+
86
+ function resolveInputFile(root, value) {
87
+ const file = path.resolve(root, value);
88
+
89
+ let stat;
90
+
91
+ try {
92
+ stat = fs.statSync(file);
93
+ } catch (cause) {
94
+ throw new HarmonyPrebuildError(
95
+ 'ERR_HARMONY_CONFIG_INVALID',
96
+ `Harmony input file does not exist: ${file}`,
97
+ { cause, file, operation: 'render-icons' }
98
+ );
99
+ }
100
+
101
+ if (!stat.isFile()) {
102
+ throw new HarmonyPrebuildError(
103
+ 'ERR_HARMONY_CONFIG_INVALID',
104
+ `Harmony input is not a file: ${file}`,
105
+ { file, operation: 'render-icons' }
106
+ );
107
+ }
108
+
109
+ return file;
110
+ }
111
+
112
+ function withEntryMods(config, harmony) {
113
+ config = withEntryBuildProfile(config, (mod) => {
114
+ const build = readRecord(mod.modResults.buildOption);
115
+ const native = readRecord(build.externalNativeOptions);
116
+
117
+ mod.modResults = {
118
+ ...mod.modResults,
119
+ apiType: 'stageMode',
120
+ buildOption: {
121
+ ...build,
122
+ externalNativeOptions: {
123
+ ...native,
124
+ path: './src/main/cpp/CMakeLists.txt',
125
+ abiFilters: harmony.abiFilters,
126
+ },
127
+ },
128
+ targets: upsertNamed(
129
+ upsertNamed(mod.modResults.targets, 'default', existing => ({
130
+ ...existing,
131
+ name: 'default',
132
+ runtimeOS: 'HarmonyOS',
133
+ })),
134
+ 'ohosTest',
135
+ existing => ({ ...existing, name: 'ohosTest' })
136
+ ),
137
+ };
138
+
139
+ return mod;
140
+ });
141
+
142
+ config = withEntryOhPackage(config, (mod) => {
143
+ mod.modResults = {
144
+ ...mod.modResults,
145
+ name: harmony.moduleName,
146
+ version: harmony.versionName,
147
+ description: `${harmony.label} Harmony entry module`,
148
+ license: mod.modResults.license || 'MIT',
149
+ dependencies: mod.modResults.dependencies || {},
150
+ };
151
+
152
+ return mod;
153
+ });
154
+
155
+ config = withEntryHvigor(config, async (mod) => {
156
+ const build = createHarmonyBuildDescriptor(harmony, mod._internal?.harmonySigningConfig?.name ?? null);
157
+ const relative = path.posix.relative(build.harmonyRoot, build.projectFiles.moduleHvigor);
158
+
159
+ mod.modResults = render.renderCanonical(
160
+ await readTemplateSource(relative),
161
+ build.projectFiles.moduleHvigor
162
+ );
163
+
164
+ return mod;
165
+ });
166
+
167
+ config = withModuleJson(config, (mod) => {
168
+ const home = {
169
+ entities: ['entity.system.home'],
170
+ actions: ['action.system.home'],
171
+ };
172
+ const module = removeStaleExtensionAbilities(
173
+ readRecord(mod.modResults.module),
174
+ HarmonyPaths.toPosixRelative(
175
+ mod.modRequest.projectRoot,
176
+ path.join(mod.modRequest.platformProjectRoot, HarmonyPaths.HARMONY_PATHS.moduleJson)
177
+ ),
178
+ mod._internal?.harmonyStalePluginFiles || []
179
+ );
180
+ const previous = mod._internal?.harmonyPreviousManagedIdentity;
181
+ const plugins = getHarmonyConfigPlugins(mod);
182
+
183
+ const abilities = upsertManagedNamed(
184
+ module.abilities,
185
+ harmony.abilityName,
186
+ previous?.abilityName,
187
+ 'EntryAbility',
188
+ existing => ({
189
+ ...existing,
190
+ name: harmony.abilityName,
191
+ srcEntry: './ets/entryability/EntryAbility.ets',
192
+ description: '$string:expo_harmony_ability_desc',
193
+ icon: '$media:app_icon',
194
+ label: '$string:expo_harmony_ability_label',
195
+ startWindowIcon: isAbilityValueClaimed(
196
+ plugins,
197
+ 'startWindowIcon',
198
+ existing.startWindowIcon
199
+ )
200
+ ? existing.startWindowIcon
201
+ : '$media:app_icon',
202
+ startWindowBackground: isAbilityValueClaimed(
203
+ plugins,
204
+ 'startWindowBackground',
205
+ existing.startWindowBackground
206
+ )
207
+ ? existing.startWindowBackground
208
+ : '$color:expo_harmony_start_window_background',
209
+ exported: true,
210
+ visible: true,
211
+ orientation: harmony.nativeOrientation,
212
+ skills: appendUnique([home], harmony.skills),
213
+ }),
214
+ 'abilityName'
215
+ );
216
+ const metadata = reconcileRuntimeMetadata(module.metadata);
217
+
218
+ mod.modResults = {
219
+ ...mod.modResults,
220
+ module: {
221
+ ...module,
222
+ name: harmony.moduleName,
223
+ type: 'entry',
224
+ description: '$string:expo_harmony_module_desc',
225
+ mainElement: harmony.abilityName,
226
+ deviceTypes: harmony.deviceTypes,
227
+ deliveryWithInstall: true,
228
+ installationFree: false,
229
+ pages: '$profile:main_pages',
230
+ requestPermissions: harmony.permissions,
231
+ querySchemes: harmony.querySchemes,
232
+ metadata,
233
+ abilities,
234
+ },
235
+ };
236
+
237
+ return mod;
238
+ });
239
+
240
+ config = withStrings(config, (mod) => {
241
+ mod.modResults = removeStaleResources(
242
+ mod.modResults,
243
+ 'strings',
244
+ mod._internal?.harmonyStaleConfigPlugins || []
245
+ );
246
+ mod.modResults.app ??= {};
247
+ mod.modResults.entry ??= {};
248
+
249
+ mod.modResults.app.string = setResource(
250
+ mod.modResults.app.string,
251
+ 'app_name',
252
+ harmony.label
253
+ );
254
+
255
+ let strings = mod.modResults.entry.string || [];
256
+
257
+ strings = setResource(
258
+ strings,
259
+ 'expo_harmony_ability_desc',
260
+ `${harmony.label} main ability`
261
+ );
262
+ strings = setResource(strings, 'expo_harmony_ability_label', harmony.label);
263
+ strings = setResource(
264
+ strings,
265
+ 'expo_harmony_module_desc',
266
+ `${harmony.label} entry module`
267
+ );
268
+ mod.modResults.entry.string = strings;
269
+
270
+ return mod;
271
+ });
272
+
273
+ config = withColors(config, (mod) => {
274
+ mod.modResults = removeStaleResources(
275
+ mod.modResults,
276
+ 'colors',
277
+ mod._internal?.harmonyStaleConfigPlugins || []
278
+ );
279
+ mod.modResults.entry ??= {};
280
+ mod.modResults.entryDark ??= {};
281
+
282
+ mod.modResults.entry.color = setResource(
283
+ mod.modResults.entry.color,
284
+ 'expo_harmony_start_window_background',
285
+ harmony.backgroundColor
286
+ );
287
+
288
+ return mod;
289
+ });
290
+
291
+ config = withMedia(config, (mod) => {
292
+ mod.modResults = removeStaleResources(
293
+ mod.modResults,
294
+ 'media',
295
+ mod._internal?.harmonyStaleConfigPlugins || []
296
+ );
297
+
298
+ const icon = harmony.icon
299
+ ? resolveInputFile(mod.modRequest.projectRoot, harmony.icon)
300
+ : null;
301
+ const sources = icon
302
+ ? { app: icon, entry: icon }
303
+ : {
304
+ app: resolveTemplateFile(`${HarmonyPlatformDirectory}/${HarmonyPaths.RESOURCE_PATHS.media.app}/app_icon.svg`),
305
+ entry: resolveTemplateFile(`${HarmonyPlatformDirectory}/${HarmonyPaths.RESOURCE_PATHS.media.entry}/app_icon.svg`),
306
+ };
307
+
308
+ for (const [scope, source] of Object.entries(sources)) {
309
+ mod.modResults[scope] ??= {};
310
+ replaceMediaBase(mod.modResults[scope], 'app_icon', {
311
+ name: `app_icon${getSourceExtension(source)}`,
312
+ source,
313
+ });
314
+ replaceMediaBase(mod.modResults[scope], 'app_icon_round');
315
+ }
316
+
317
+ return mod;
318
+ });
319
+
320
+ config = withProfiles(config, (mod) => {
321
+ mod.modResults = {
322
+ ...mod.modResults,
323
+ src: appendUnique(mod.modResults.src, ['pages/Index']),
324
+ };
325
+
326
+ return mod;
327
+ });
328
+
329
+ return config;
330
+ }
331
+
332
+ export { withEntryMods };
@@ -0,0 +1,85 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import {
5
+ getHarmonyConfigPlugins,
6
+ recordManagedFile,
7
+ withHarmonyDangerousMod,
8
+ } from '@expo-harmony/config-plugins';
9
+
10
+ import { createHarmonyBuildDescriptor } from '../buildDescriptor';
11
+ import { HarmonyPrebuildError } from '../errors';
12
+ import { ensureGitignoreEntryAsync } from '../generatedFiles';
13
+ import { readSigningConfigFile } from '../signing';
14
+ import {
15
+ findStaleConfigPlugins,
16
+ readPreviousCngManifestAsync,
17
+ removeStalePluginFilesAsync,
18
+ } from '../stale';
19
+
20
+ function withPreparationMod(config, harmony) {
21
+ return withHarmonyDangerousMod(config, async (mod) => {
22
+ const root = mod.modRequest.projectRoot;
23
+ const platform = mod.modRequest.platformProjectRoot;
24
+ const manifest = await readPreviousCngManifestAsync(root);
25
+ const plugins = getHarmonyConfigPlugins(mod);
26
+ const stale = findStaleConfigPlugins(manifest, plugins);
27
+
28
+ mod._internal ??= {};
29
+ mod._internal.harmonyPreviousSigningConfigName
30
+ = typeof manifest?.signingConfigName === 'string'
31
+ ? manifest.signingConfigName
32
+ : null;
33
+ mod._internal.harmonyPreviousManagedIdentity
34
+ = manifest?.managedIdentity && typeof manifest.managedIdentity === 'object'
35
+ ? manifest.managedIdentity
36
+ : null;
37
+ mod._internal.harmonyConfigPlugins = plugins;
38
+ mod._internal.harmonyStaleConfigPlugins = stale;
39
+
40
+ mod._internal.harmonyStalePluginFiles = await removeStalePluginFilesAsync(root, manifest, stale);
41
+
42
+ const packed = path.join(platform, 'gitignore');
43
+ const gitignore = path.join(platform, '.gitignore');
44
+
45
+ if (fs.existsSync(packed)) {
46
+ if (fs.existsSync(gitignore)) {
47
+ const [source, current] = await Promise.all([
48
+ fs.promises.readFile(packed),
49
+ fs.promises.readFile(gitignore),
50
+ ]);
51
+
52
+ if (!source.equals(Uint8Array.from(current))) {
53
+ throw new HarmonyPrebuildError(
54
+ 'ERR_HARMONY_CONFIG_INVALID',
55
+ 'The packed Harmony gitignore conflicts with an existing harmony/.gitignore.',
56
+ { file: gitignore, operation: 'restore-gitignore' }
57
+ );
58
+ }
59
+
60
+ await fs.promises.rm(packed);
61
+ } else {
62
+ await fs.promises.rename(packed, gitignore);
63
+ }
64
+ }
65
+
66
+ const build = createHarmonyBuildDescriptor(harmony, null);
67
+ const profile = path.posix.relative(build.harmonyRoot, build.projectFiles.projectBuildProfile);
68
+
69
+ await ensureGitignoreEntryAsync(gitignore, `/${profile}`);
70
+ recordManagedFile(mod, gitignore, 'dangerous');
71
+
72
+ if (harmony.signingConfigFile) {
73
+ const signing = await readSigningConfigFile(
74
+ root,
75
+ harmony.signingConfigFile
76
+ );
77
+
78
+ mod._internal.harmonySigningConfig = signing.config;
79
+ }
80
+
81
+ return mod;
82
+ });
83
+ }
84
+
85
+ export { withPreparationMod };
@@ -0,0 +1,258 @@
1
+ import path from 'node:path';
2
+
3
+ import {
4
+ withAppJson,
5
+ withHvigorConfig,
6
+ withNativeInputsStamp,
7
+ withProjectBuildProfile,
8
+ withReactNativeConfig,
9
+ withRootHvigor,
10
+ withRootOhPackage,
11
+ } from '@expo-harmony/config-plugins';
12
+ import { loadConfigAsync as loadReactNativeCliConfigAsync } from '@react-native-community/cli-config';
13
+
14
+ import {
15
+ createHarmonyBuildDescriptor,
16
+ harmonyModuleSourcePath,
17
+ resolveHarmonyBuildPath,
18
+ } from '../buildDescriptor';
19
+ import {
20
+ readTemplateSource,
21
+ resolvePackageVersion,
22
+ resolveRnohHvigorPlugin,
23
+ toRelativeDependency,
24
+ } from '../dependencies';
25
+ import { HarmonyPrebuildError } from '../errors';
26
+ import { readRecord, replaceManagedString, upsertManagedNamed, upsertNamed } from '../reconcile';
27
+ import * as render from '../renderers';
28
+
29
+ function hasRnohLinkCommand(config) {
30
+ const names = new Set((config?.commands || []).map(command => command?.name));
31
+ return names.has('link-harmony');
32
+ }
33
+
34
+ async function loadReactNativeConfigAsync(root, file) {
35
+ try {
36
+ return await loadReactNativeCliConfigAsync({ projectRoot: root });
37
+ } catch (cause) {
38
+ throw new HarmonyPrebuildError(
39
+ 'ERR_HARMONY_CONFIG_INVALID',
40
+ `Cannot load the existing React Native CLI config: ${file}`,
41
+ { cause, file, operation: 'react-native-config' }
42
+ );
43
+ }
44
+ }
45
+
46
+ export function withProjectMods(config, harmony) {
47
+ config = withReactNativeConfig(config, async (mod) => {
48
+ const root = mod.modRequest.projectRoot;
49
+ const request = mod.modRequest as typeof mod.modRequest & {
50
+ modFile: string;
51
+ modFileExists: boolean;
52
+ };
53
+ const file = request.modFile;
54
+
55
+ if (request.modFileExists) {
56
+ if (!hasRnohLinkCommand(await loadReactNativeConfigAsync(root, file))) {
57
+ throw new HarmonyPrebuildError(
58
+ 'ERR_HARMONY_CONFIG_INVALID',
59
+ 'The React Native CLI config must expose the RNOH link-harmony command.',
60
+ { file, operation: 'react-native-config' }
61
+ );
62
+ }
63
+
64
+ return mod;
65
+ }
66
+
67
+ mod.modResults = render.renderReactNativeConfig();
68
+
69
+ return mod;
70
+ });
71
+
72
+ config = withAppJson(config, (mod) => {
73
+ const app = mod.modResults.app && typeof mod.modResults.app === 'object'
74
+ ? mod.modResults.app
75
+ : {};
76
+
77
+ mod.modResults = {
78
+ ...mod.modResults,
79
+ app: {
80
+ ...app,
81
+ bundleName: harmony.bundleName,
82
+ icon: '$media:app_icon',
83
+ label: '$string:app_name',
84
+ vendor: harmony.vendor,
85
+ versionCode: harmony.versionCode,
86
+ versionName: harmony.versionName,
87
+ },
88
+ };
89
+
90
+ return mod;
91
+ });
92
+
93
+ config = withProjectBuildProfile(config, (mod) => {
94
+ const build = createHarmonyBuildDescriptor(
95
+ harmony,
96
+ mod._internal?.harmonySigningConfig?.name ?? null
97
+ );
98
+ const { moduleName, productName, targetName } = build.identity;
99
+
100
+ const profile = mod.modResults;
101
+ const app = readRecord(profile.app);
102
+ const signing = mod._internal?.harmonySigningConfig;
103
+ const previousSigning = mod._internal?.harmonyPreviousSigningConfigName;
104
+ const previous = mod._internal?.harmonyPreviousManagedIdentity;
105
+
106
+ const products = upsertManagedNamed(
107
+ app.products,
108
+ productName,
109
+ previous?.productName,
110
+ 'default',
111
+ (existing) => {
112
+ const product = {
113
+ ...existing,
114
+ name: productName,
115
+ compatibleSdkVersion: harmony.compatibleSdkVersionString,
116
+ targetSdkVersion: harmony.targetSdkVersionString,
117
+ runtimeOS: 'HarmonyOS',
118
+ buildOption: { ...(existing.buildOption || {}), nativeCompiler: 'BiSheng' },
119
+ ...(signing ? { signingConfig: signing.name } : {}),
120
+ };
121
+
122
+ if (!signing && product.signingConfig === previousSigning) {
123
+ delete product.signingConfig;
124
+ }
125
+
126
+ return product;
127
+ },
128
+ 'productName'
129
+ );
130
+ const modules = upsertManagedNamed(
131
+ profile.modules,
132
+ moduleName,
133
+ previous?.moduleName,
134
+ 'entry',
135
+ existing => ({
136
+ ...existing,
137
+ name: moduleName,
138
+ srcPath: harmonyModuleSourcePath(build),
139
+ targets: upsertNamed(existing.targets, targetName, target => ({
140
+ ...target,
141
+ name: targetName,
142
+ applyToProducts: replaceManagedString(
143
+ target.applyToProducts,
144
+ productName,
145
+ previous?.productName,
146
+ 'default'
147
+ ),
148
+ })),
149
+ }),
150
+ 'moduleName'
151
+ );
152
+
153
+ let configs = app.signingConfigs;
154
+
155
+ if (signing) {
156
+ configs = upsertManagedNamed(
157
+ configs,
158
+ signing.name,
159
+ previousSigning,
160
+ '',
161
+ () => signing,
162
+ 'signingConfigName'
163
+ );
164
+ } else if (previousSigning) {
165
+ configs = (Array.isArray(configs) ? configs : [])
166
+ .filter(item => item?.name !== previousSigning);
167
+ }
168
+
169
+ mod.modResults = {
170
+ ...profile,
171
+ app: {
172
+ ...app,
173
+ products,
174
+ buildModeSet: upsertNamed(
175
+ upsertNamed(app.buildModeSet, 'debug', existing => ({ ...existing, name: 'debug' })),
176
+ 'release',
177
+ existing => ({ ...existing, name: 'release' })
178
+ ),
179
+ ...(configs === undefined ? {} : { signingConfigs: configs }),
180
+ },
181
+ modules,
182
+ };
183
+
184
+ return mod;
185
+ });
186
+
187
+ config = withRootOhPackage(config, (mod) => {
188
+ const version = resolvePackageVersion(
189
+ mod.modRequest.projectRoot,
190
+ '@react-native-oh/react-native-harmony'
191
+ );
192
+ const dependencies = { ...readRecord(mod.modResults.dependencies) };
193
+ const overrides = { ...readRecord(mod.modResults.overrides) };
194
+
195
+ mod.modResults = {
196
+ ...mod.modResults,
197
+ name: harmony.bundleName,
198
+ version: harmony.versionName,
199
+ license: mod.modResults.license || 'MIT',
200
+ dependencies: {
201
+ ...dependencies,
202
+ '@rnoh/react-native-openharmony': version,
203
+ },
204
+ overrides: {
205
+ ...overrides,
206
+ '@rnoh/react-native-openharmony': version,
207
+ },
208
+ };
209
+
210
+ return mod;
211
+ });
212
+
213
+ config = withRootHvigor(config, async (mod) => {
214
+ const build = createHarmonyBuildDescriptor(
215
+ harmony,
216
+ mod._internal?.harmonySigningConfig?.name ?? null
217
+ );
218
+ const relative = path.posix.relative(build.harmonyRoot, build.projectFiles.rootHvigor);
219
+ const source = await readTemplateSource(relative);
220
+
221
+ mod.modResults = render.renderRootHvigor(source, build);
222
+
223
+ return mod;
224
+ });
225
+
226
+ config = withNativeInputsStamp(config, async (mod) => {
227
+ const build = createHarmonyBuildDescriptor(harmony, mod._internal?.harmonySigningConfig?.name ?? null);
228
+ const relative = path.posix.relative(build.harmonyRoot, build.projectFiles.nativeInputsStamp);
229
+ const source = await readTemplateSource(relative);
230
+
231
+ mod.modResults = render.renderCanonical(source, build.projectFiles.nativeInputsStamp);
232
+
233
+ return mod;
234
+ });
235
+
236
+ config = withHvigorConfig(config, (mod) => {
237
+ const root = mod.modRequest.projectRoot;
238
+ const build = createHarmonyBuildDescriptor(harmony, mod._internal?.harmonySigningConfig?.name ?? null);
239
+ const directory = path.dirname(resolveHarmonyBuildPath(root, build.projectFiles.hvigorConfig));
240
+ const plugin = toRelativeDependency(directory, resolveRnohHvigorPlugin(root));
241
+
242
+ mod.modResults = {
243
+ ...mod.modResults,
244
+ dependencies: {
245
+ ...readRecord(mod.modResults.dependencies),
246
+ '@rnoh/hvigor-plugin': plugin,
247
+ },
248
+ execution: mod.modResults.execution || {},
249
+ logging: mod.modResults.logging || {},
250
+ debugging: mod.modResults.debugging || {},
251
+ nodeOptions: mod.modResults.nodeOptions || {},
252
+ };
253
+
254
+ return mod;
255
+ });
256
+
257
+ return config;
258
+ }
@@ -0,0 +1,32 @@
1
+ import {
2
+ HarmonyPaths, withArkTSPackageProvider, withCMakeLists, withCppPackageProvider,
3
+ withEntryAbility, withIndexPage, withWorker,
4
+ } from '@expo-harmony/config-plugins';
5
+
6
+ import { readTemplateSource } from '../dependencies';
7
+ import * as render from '../renderers';
8
+
9
+ const SourceMods = [
10
+ [withEntryAbility, HarmonyPaths.HARMONY_PATHS.entryAbility, render.renderEntryAbility],
11
+ [withIndexPage, HarmonyPaths.HARMONY_PATHS.indexPage, render.renderIndexPage],
12
+ [withWorker, HarmonyPaths.HARMONY_PATHS.worker],
13
+ [withArkTSPackageProvider, HarmonyPaths.HARMONY_PATHS.arktsPackageProvider, render.renderArktsPackageProvider],
14
+ [withCppPackageProvider, HarmonyPaths.HARMONY_PATHS.cppPackageProvider, render.renderCppPackageProvider],
15
+ [withCMakeLists, HarmonyPaths.HARMONY_PATHS.cmakeLists, render.renderCmakeLists],
16
+ ] as const;
17
+
18
+ export function withSourceMods(config, harmony) {
19
+ for (const [plugin, relative, renderer] of SourceMods) {
20
+ config = plugin(config, async (mod) => {
21
+ const source = await readTemplateSource(relative);
22
+
23
+ mod.modResults = renderer
24
+ ? renderer(source, harmony)
25
+ : render.renderCanonical(source, `harmony/${relative}`);
26
+
27
+ return mod;
28
+ });
29
+ }
30
+
31
+ return config;
32
+ }