@expo-harmony/config-plugins 55.0.10-harmony.2 → 55.0.10-harmony.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -11
- package/build/compiler.d.ts +7 -0
- package/build/compiler.js +12 -0
- package/build/composition.d.ts +24 -0
- package/build/composition.js +11 -0
- package/build/config.d.ts +2 -15
- package/build/customFiles.d.ts +15 -0
- package/build/customFiles.js +108 -0
- package/build/files.d.ts +1 -1
- package/build/files.js +2 -2
- package/build/generatedFiles.d.ts +15 -0
- package/build/generatedFiles.js +70 -0
- package/build/index.d.ts +20 -5
- package/build/index.js +52 -6
- package/build/internal.d.ts +3 -0
- package/build/internal.js +13 -0
- package/build/manifest.d.ts +38 -0
- package/build/manifest.js +71 -0
- package/build/mods.d.ts +36 -31
- package/build/mods.js +114 -86
- package/build/normalizeConfig.d.ts +10 -3
- package/build/normalizeConfig.js +41 -47
- package/build/ownership.d.ts +4 -3
- package/build/ownership.js +17 -0
- package/build/paths.d.ts +12 -10
- package/build/paths.js +31 -31
- package/build/permissions.d.ts +12 -0
- package/build/permissions.js +60 -0
- package/build/pluginTypes.d.ts +15 -0
- package/build/pluginTypes.js +2 -0
- package/build/resources.d.ts +13 -0
- package/build/resources.js +55 -0
- package/package.json +9 -9
- package/src/compiler.ts +21 -0
- package/src/composition.ts +45 -0
- package/src/config.ts +3 -19
- package/src/customFiles.ts +142 -0
- package/src/files.ts +3 -4
- package/src/generatedFiles.ts +85 -0
- package/src/index.ts +19 -11
- package/src/internal.ts +3 -0
- package/src/manifest.ts +151 -0
- package/src/mods.ts +170 -129
- package/src/nativeInputs.ts +0 -1
- package/src/normalizeConfig.ts +51 -59
- package/src/ownership.ts +25 -5
- package/src/paths.ts +38 -46
- package/src/permissions.ts +68 -0
- package/src/pluginTypes.ts +24 -0
- package/src/resources.ts +65 -0
package/src/mods.ts
CHANGED
|
@@ -3,11 +3,15 @@ import path from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
withBaseMod, withMod,
|
|
6
|
-
type
|
|
6
|
+
type ExportedConfig, type ModPlatform,
|
|
7
7
|
} from '@expo/config-plugins';
|
|
8
8
|
import type { ExpoConfig } from '@expo/config-types';
|
|
9
9
|
|
|
10
10
|
import { HarmonyConfigPluginError } from './errors';
|
|
11
|
+
import type { ExpoConfigWithHarmony } from './config';
|
|
12
|
+
import type { HarmonyModuleJson } from './manifest';
|
|
13
|
+
import type { HarmonyConfigPlugin, HarmonyModAction, HarmonyModConfig } from './pluginTypes';
|
|
14
|
+
import type { HarmonyResourceFile } from './resources';
|
|
11
15
|
import { atomicWrite, readJson5, readText, writeJson5 } from './files';
|
|
12
16
|
import {
|
|
13
17
|
ManagedPaths, ProjectPaths, ResourcePaths,
|
|
@@ -21,7 +25,6 @@ export type HarmonyModName
|
|
|
21
25
|
| 'projectBuildProfile'
|
|
22
26
|
| 'rootOhPackage'
|
|
23
27
|
| 'rootHvigor'
|
|
24
|
-
| 'nativeInputsStamp'
|
|
25
28
|
| 'hvigorConfig'
|
|
26
29
|
| 'entryBuildProfile'
|
|
27
30
|
| 'entryOhPackage'
|
|
@@ -37,15 +40,13 @@ export type HarmonyModName
|
|
|
37
40
|
| 'arktsPackageProvider'
|
|
38
41
|
| 'cppPackageProvider'
|
|
39
42
|
| 'cmakeLists'
|
|
40
|
-
| 'autolinking'
|
|
41
|
-
| 'manifest';
|
|
43
|
+
| 'autolinking';
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
) => ExportedConfigWithProps<T> | Promise<ExportedConfigWithProps<T>>;
|
|
45
|
+
type InternalModName = 'nativeInputsStamp' | 'manifest' | 'prepare' | 'patch';
|
|
46
|
+
type AnyModName = HarmonyModName | InternalModName;
|
|
46
47
|
|
|
47
48
|
export type HarmonyJson = Record<string, unknown>;
|
|
48
|
-
export type HarmonyResourceMap = Record<string,
|
|
49
|
+
export type HarmonyResourceMap = Record<string, HarmonyResourceFile>;
|
|
49
50
|
export type HarmonyMediaDescriptor
|
|
50
51
|
= | {
|
|
51
52
|
source: string;
|
|
@@ -104,11 +105,12 @@ const TextMods = new Set<FileModName>([
|
|
|
104
105
|
'cmakeLists',
|
|
105
106
|
]);
|
|
106
107
|
const ResourceMods = new Set<HarmonyModName>(['strings', 'colors', 'media']);
|
|
107
|
-
const VirtualMods = new Set<
|
|
108
|
+
const VirtualMods = new Set<AnyModName>(['dangerous', 'autolinking', 'manifest', 'prepare', 'patch']);
|
|
108
109
|
const ResourceModNames: readonly ResourceModName[] = ['strings', 'colors', 'media'];
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
const AllModNames: readonly AnyModName[] = Object.freeze([
|
|
111
112
|
'dangerous',
|
|
113
|
+
'prepare',
|
|
112
114
|
'reactNativeConfig',
|
|
113
115
|
'appJson',
|
|
114
116
|
'projectBuildProfile',
|
|
@@ -131,9 +133,14 @@ export const HarmonyModNames: readonly HarmonyModName[] = Object.freeze([
|
|
|
131
133
|
'cppPackageProvider',
|
|
132
134
|
'cmakeLists',
|
|
133
135
|
'autolinking',
|
|
136
|
+
'patch',
|
|
134
137
|
'manifest',
|
|
135
138
|
]);
|
|
136
139
|
|
|
140
|
+
export const HarmonyModNames: readonly HarmonyModName[] = Object.freeze(
|
|
141
|
+
AllModNames.filter((name): name is HarmonyModName => name !== 'manifest' && name !== 'nativeInputsStamp' && name !== 'prepare' && name !== 'patch')
|
|
142
|
+
);
|
|
143
|
+
|
|
137
144
|
export function recordManagedFile(config: ManagedConfig, file: string, owner: string): void {
|
|
138
145
|
config._internal ??= {};
|
|
139
146
|
config._internal.harmonyManagedFiles ??= [];
|
|
@@ -146,7 +153,7 @@ export function recordManagedFile(config: ManagedConfig, file: string, owner: st
|
|
|
146
153
|
config._internal.harmonyManagedFiles = files;
|
|
147
154
|
}
|
|
148
155
|
|
|
149
|
-
function assertModResults(
|
|
156
|
+
function assertModResults(name: AnyModName, value: unknown, kind: 'json' | 'resource' | 'text'): void {
|
|
150
157
|
const valid = kind === 'text'
|
|
151
158
|
? typeof value === 'string'
|
|
152
159
|
: value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -154,35 +161,41 @@ function assertModResults(modName: HarmonyModName, value: unknown, kind: 'json'
|
|
|
154
161
|
if (!valid) {
|
|
155
162
|
throw new HarmonyConfigPluginError(
|
|
156
163
|
'ERR_HARMONY_MOD_RESULTS_INVALID',
|
|
157
|
-
`harmony.${
|
|
158
|
-
{ operation: `harmony.${
|
|
164
|
+
`harmony.${name} must return ${kind === 'text' ? 'a string' : 'an object'} modResults.`,
|
|
165
|
+
{ operation: `harmony.${name}.write` }
|
|
159
166
|
);
|
|
160
167
|
}
|
|
161
168
|
}
|
|
162
169
|
|
|
163
|
-
function withFileProvider(config: ExpoConfig,
|
|
170
|
+
function withFileProvider(config: ExpoConfig, name: FileModName): ExpoConfig {
|
|
164
171
|
return withBaseMod<FileResult>(config, {
|
|
165
172
|
platform: 'harmony' as ModPlatform,
|
|
166
|
-
mod:
|
|
173
|
+
mod: name,
|
|
167
174
|
isProvider: true,
|
|
168
|
-
isIntrospective: JsonMods.has(
|
|
169
|
-
saveToInternal: JsonMods.has(
|
|
175
|
+
isIntrospective: JsonMods.has(name),
|
|
176
|
+
saveToInternal: JsonMods.has(name),
|
|
170
177
|
async action(value) {
|
|
171
|
-
const { nextMod, ...
|
|
172
|
-
const
|
|
173
|
-
const root =
|
|
174
|
-
const file =
|
|
175
|
-
? await resolveProjectPath(root,
|
|
176
|
-
: await resolveHarmonyPath(root, ManagedPaths[
|
|
177
|
-
const exists = fs.existsSync(file);
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
const { nextMod: next, ...request } = value.modRequest;
|
|
179
|
+
const project = name in ProjectPaths;
|
|
180
|
+
const root = project ? request.projectRoot : request.platformProjectRoot;
|
|
181
|
+
const file = project
|
|
182
|
+
? await resolveProjectPath(root, name as keyof typeof ProjectPaths)
|
|
183
|
+
: await resolveHarmonyPath(root, ManagedPaths[name as keyof typeof ManagedPaths]);
|
|
184
|
+
const exists = !request.ignoreExistingNativeFiles && fs.existsSync(file);
|
|
185
|
+
const template = value._internal?.harmonyTemplateDirectory;
|
|
186
|
+
const input = !exists && !project && typeof template === 'string'
|
|
187
|
+
? await resolveHarmonyPath(template, ManagedPaths[name as keyof typeof ManagedPaths])
|
|
188
|
+
: file;
|
|
189
|
+
|
|
190
|
+
const data = request.ignoreExistingNativeFiles && input === file
|
|
191
|
+
? (JsonMods.has(name) ? {} : '')
|
|
192
|
+
: JsonMods.has(name)
|
|
193
|
+
? await readJson5<HarmonyJson>(input, {}, name)
|
|
194
|
+
: await readText(file);
|
|
195
|
+
|
|
196
|
+
const context = { ...request, modFile: file, modFileExists: exists } as typeof value.modRequest;
|
|
197
|
+
const result = await next!({ ...value, modRequest: context, modResults: data });
|
|
198
|
+
assertModResults(name, result.modResults, JsonMods.has(name) ? 'json' : 'text');
|
|
186
199
|
|
|
187
200
|
if (!result.modRequest.introspect) {
|
|
188
201
|
if (typeof result.modResults === 'string') {
|
|
@@ -191,7 +204,7 @@ function withFileProvider(config: ExpoConfig, modName: FileModName): ExpoConfig
|
|
|
191
204
|
await writeJson5(file, result.modResults);
|
|
192
205
|
}
|
|
193
206
|
|
|
194
|
-
recordManagedFile(result, file,
|
|
207
|
+
recordManagedFile(result, file, name);
|
|
195
208
|
}
|
|
196
209
|
|
|
197
210
|
return result;
|
|
@@ -202,13 +215,18 @@ function withFileProvider(config: ExpoConfig, modName: FileModName): ExpoConfig
|
|
|
202
215
|
async function readResourceMap(
|
|
203
216
|
root: string,
|
|
204
217
|
entries: Readonly<Record<string, string>>,
|
|
205
|
-
|
|
218
|
+
name: ResourceModName,
|
|
219
|
+
template?: string,
|
|
220
|
+
ignore = false
|
|
206
221
|
): Promise<HarmonyResourceMap> {
|
|
207
222
|
const resources: HarmonyResourceMap = {};
|
|
208
223
|
|
|
209
224
|
for (const [scope, relative] of Object.entries(entries)) {
|
|
210
225
|
const file = await resolveHarmonyPath(root, relative);
|
|
211
|
-
|
|
226
|
+
const fallback = ignore || !fs.existsSync(file);
|
|
227
|
+
const input = fallback && template ? await resolveHarmonyPath(template, relative) : file;
|
|
228
|
+
|
|
229
|
+
resources[scope] = ignore && input === file ? {} : await readJson5<HarmonyJson>(input, {}, name);
|
|
212
230
|
}
|
|
213
231
|
|
|
214
232
|
return resources;
|
|
@@ -283,10 +301,7 @@ async function writeMediaMap(
|
|
|
283
301
|
}
|
|
284
302
|
|
|
285
303
|
const item = descriptor as Partial<HarmonyMediaDescriptor>;
|
|
286
|
-
|
|
287
|
-
const hasContent = Object.hasOwn(item, 'content');
|
|
288
|
-
|
|
289
|
-
if (hasSource === hasContent) {
|
|
304
|
+
if (Object.hasOwn(item, 'source') === Object.hasOwn(item, 'content')) {
|
|
290
305
|
throw new HarmonyConfigPluginError(
|
|
291
306
|
'ERR_HARMONY_CONFIG_INVALID',
|
|
292
307
|
`Harmony media ${scope}/${name} must define exactly one of source or content.`,
|
|
@@ -303,7 +318,7 @@ async function writeMediaMap(
|
|
|
303
318
|
|
|
304
319
|
let content: string | Uint8Array;
|
|
305
320
|
|
|
306
|
-
if (
|
|
321
|
+
if (Object.hasOwn(item, 'source')) {
|
|
307
322
|
if (typeof item.source !== 'string' || item.source.length === 0) {
|
|
308
323
|
throw new HarmonyConfigPluginError(
|
|
309
324
|
'ERR_HARMONY_CONFIG_INVALID',
|
|
@@ -334,11 +349,9 @@ async function writeMediaMap(
|
|
|
334
349
|
}
|
|
335
350
|
}
|
|
336
351
|
|
|
337
|
-
// Resolve and read every desired input before removing stale resources. A
|
|
338
|
-
// malformed descriptor or missing source therefore cannot partially mutate
|
|
339
|
-
// an otherwise valid generated project.
|
|
340
352
|
for (const [scope, names] of Object.entries(previous)) {
|
|
341
353
|
if (!(scope in ResourcePaths.media)) continue;
|
|
354
|
+
|
|
342
355
|
const directory = await resolveHarmonyPath(
|
|
343
356
|
root,
|
|
344
357
|
ResourcePaths.media[scope as keyof typeof ResourcePaths.media]
|
|
@@ -360,9 +373,9 @@ async function writeMediaMap(
|
|
|
360
373
|
if (replaceBase) {
|
|
361
374
|
const base = path.parse(name).name;
|
|
362
375
|
|
|
363
|
-
for (const
|
|
364
|
-
if (path.parse(
|
|
365
|
-
await fs.promises.rm(path.join(directory,
|
|
376
|
+
for (const entry of await fs.promises.readdir(directory)) {
|
|
377
|
+
if (path.parse(entry).name === base && entry !== name) {
|
|
378
|
+
await fs.promises.rm(path.join(directory, entry), { force: true });
|
|
366
379
|
}
|
|
367
380
|
}
|
|
368
381
|
}
|
|
@@ -374,53 +387,55 @@ async function writeMediaMap(
|
|
|
374
387
|
}
|
|
375
388
|
}
|
|
376
389
|
|
|
377
|
-
function withResourceProvider(config: ExpoConfig,
|
|
378
|
-
const
|
|
390
|
+
function withResourceProvider(config: ExpoConfig, name: ResourceModName): ExpoConfig {
|
|
391
|
+
const introspective = name !== 'media';
|
|
379
392
|
|
|
380
393
|
return withBaseMod<ResourceResult>(config, {
|
|
381
394
|
platform: 'harmony' as ModPlatform,
|
|
382
|
-
mod:
|
|
395
|
+
mod: name,
|
|
383
396
|
isProvider: true,
|
|
384
|
-
isIntrospective,
|
|
385
|
-
saveToInternal:
|
|
397
|
+
isIntrospective: introspective,
|
|
398
|
+
saveToInternal: introspective,
|
|
386
399
|
async action(value) {
|
|
387
|
-
const { nextMod, ...
|
|
388
|
-
const root =
|
|
389
|
-
const data =
|
|
390
|
-
?
|
|
391
|
-
|
|
392
|
-
|
|
400
|
+
const { nextMod: next, ...request } = value.modRequest;
|
|
401
|
+
const root = request.platformProjectRoot;
|
|
402
|
+
const data = name === 'media'
|
|
403
|
+
? (request.ignoreExistingNativeFiles
|
|
404
|
+
? Object.fromEntries(Object.keys(ResourcePaths.media).map(scope => [scope, {}]))
|
|
405
|
+
: await readMediaMap(root))
|
|
406
|
+
: await readResourceMap(
|
|
407
|
+
root, ResourcePaths[name], name,
|
|
408
|
+
value._internal?.harmonyTemplateDirectory, request.ignoreExistingNativeFiles
|
|
409
|
+
);
|
|
410
|
+
const previous = name === 'media'
|
|
393
411
|
? Object.fromEntries(
|
|
394
412
|
Object.entries(data).map(([scope, files]) => [scope, Object.keys(files)])
|
|
395
413
|
)
|
|
396
414
|
: {};
|
|
397
415
|
|
|
398
|
-
const result = await
|
|
399
|
-
|
|
400
|
-
assertModResults(modName, result.modResults, 'resource');
|
|
416
|
+
const result = await next!({ ...value, modRequest: request, modResults: data });
|
|
417
|
+
assertModResults(name, result.modResults, 'resource');
|
|
401
418
|
|
|
402
419
|
if (!result.modRequest.introspect) {
|
|
403
|
-
if (
|
|
420
|
+
if (name === 'media') {
|
|
404
421
|
await writeMediaMap(root, result.modResults as HarmonyMediaMap, result, previous);
|
|
405
422
|
} else {
|
|
406
|
-
const paths = ResourcePaths[
|
|
423
|
+
const paths = ResourcePaths[name];
|
|
407
424
|
|
|
408
425
|
for (const [scope, resource] of Object.entries(result.modResults)) {
|
|
409
426
|
if (!(scope in paths)) continue;
|
|
410
427
|
|
|
411
|
-
// Harmony's resource compiler requires the JSON root to contain
|
|
412
|
-
// exactly one resource-kind member. An empty scope serialized as
|
|
413
|
-
// `{}` is invalid, so omit it until a plugin contributes content.
|
|
414
428
|
if (!resource || typeof resource !== 'object' || Array.isArray(resource)) {
|
|
415
429
|
throw new HarmonyConfigPluginError(
|
|
416
430
|
'ERR_HARMONY_CONFIG_INVALID',
|
|
417
|
-
`Harmony ${
|
|
418
|
-
{ operation: `harmony.${
|
|
431
|
+
`Harmony ${name} scope ${scope} must be an object.`,
|
|
432
|
+
{ operation: `harmony.${name}.write` }
|
|
419
433
|
);
|
|
420
434
|
}
|
|
421
435
|
|
|
422
436
|
const file = await resolveHarmonyPath(root, paths[scope as keyof typeof paths]);
|
|
423
437
|
|
|
438
|
+
// Harmony's resource compiler rejects an empty JSON root.
|
|
424
439
|
if (Object.keys(resource).length === 0) {
|
|
425
440
|
await fs.promises.rm(file, { force: true });
|
|
426
441
|
|
|
@@ -428,7 +443,7 @@ function withResourceProvider(config: ExpoConfig, modName: ResourceModName): Exp
|
|
|
428
443
|
}
|
|
429
444
|
|
|
430
445
|
await writeJson5(file, resource);
|
|
431
|
-
recordManagedFile(result, file,
|
|
446
|
+
recordManagedFile(result, file, name);
|
|
432
447
|
}
|
|
433
448
|
}
|
|
434
449
|
}
|
|
@@ -438,158 +453,184 @@ function withResourceProvider(config: ExpoConfig, modName: ResourceModName): Exp
|
|
|
438
453
|
});
|
|
439
454
|
}
|
|
440
455
|
|
|
441
|
-
function withVirtualProvider(config: ExpoConfig,
|
|
456
|
+
function withVirtualProvider(config: ExpoConfig, name: AnyModName): ExpoConfig {
|
|
442
457
|
return withBaseMod<null>(config, {
|
|
443
458
|
platform: 'harmony' as ModPlatform,
|
|
444
|
-
mod:
|
|
459
|
+
mod: name,
|
|
445
460
|
isProvider: true,
|
|
461
|
+
isIntrospective: name === 'prepare',
|
|
446
462
|
async action(value) {
|
|
447
|
-
const { nextMod, ...
|
|
448
|
-
|
|
449
|
-
return nextMod!({ ...value, modRequest, modResults: null });
|
|
463
|
+
const { nextMod: next, ...request } = value.modRequest;
|
|
464
|
+
return next!({ ...value, modRequest: request, modResults: null });
|
|
450
465
|
},
|
|
451
466
|
});
|
|
452
467
|
}
|
|
453
468
|
|
|
454
|
-
function withProvider(config: ExpoConfig,
|
|
469
|
+
function withProvider(config: ExpoConfig, name: AnyModName): ExpoConfig {
|
|
455
470
|
const actions: HarmonyModAction[] = [];
|
|
456
471
|
|
|
457
472
|
config = withMod(config, {
|
|
458
473
|
platform: 'harmony' as ModPlatform,
|
|
459
|
-
mod:
|
|
474
|
+
mod: name,
|
|
460
475
|
async action(value) {
|
|
461
476
|
let result = value;
|
|
462
477
|
|
|
463
|
-
//
|
|
464
|
-
// that ordering for Harmony plugins registered after the provider.
|
|
478
|
+
// Late mods must follow Expo's last-registered-first order.
|
|
465
479
|
for (let index = actions.length - 1; index >= 0; index -= 1) {
|
|
466
|
-
result = await actions[index](result);
|
|
480
|
+
result = await actions[index](result as unknown as HarmonyModConfig<unknown>) as unknown as typeof result;
|
|
467
481
|
}
|
|
468
482
|
|
|
469
483
|
return result;
|
|
470
484
|
},
|
|
471
485
|
});
|
|
472
486
|
|
|
473
|
-
if (JsonMods.has(
|
|
474
|
-
config = withFileProvider(config,
|
|
475
|
-
} else if (ResourceMods.has(
|
|
476
|
-
config = withResourceProvider(config,
|
|
477
|
-
} else if (VirtualMods.has(
|
|
478
|
-
config = withVirtualProvider(config,
|
|
487
|
+
if (JsonMods.has(name as FileModName) || TextMods.has(name as FileModName)) {
|
|
488
|
+
config = withFileProvider(config, name as FileModName);
|
|
489
|
+
} else if (ResourceMods.has(name as HarmonyModName)) {
|
|
490
|
+
config = withResourceProvider(config, name as ResourceModName);
|
|
491
|
+
} else if (VirtualMods.has(name)) {
|
|
492
|
+
config = withVirtualProvider(config, name);
|
|
479
493
|
} else {
|
|
480
494
|
throw new HarmonyConfigPluginError(
|
|
481
495
|
'ERR_HARMONY_MOD_NOT_REGISTERED',
|
|
482
|
-
`Unknown Harmony mod: ${
|
|
496
|
+
`Unknown Harmony mod: ${name}`,
|
|
483
497
|
{ operation: 'register-base-mods' }
|
|
484
498
|
);
|
|
485
499
|
}
|
|
486
500
|
|
|
487
501
|
const mods = (config as ExportedConfig).mods as unknown as ModTable | undefined;
|
|
488
|
-
const provider = mods?.harmony?.[
|
|
502
|
+
const provider = mods?.harmony?.[name];
|
|
489
503
|
|
|
490
504
|
if (provider?.isProvider) provider.expoHarmonyLateActions = actions;
|
|
491
505
|
|
|
492
506
|
return config;
|
|
493
507
|
}
|
|
494
508
|
|
|
495
|
-
export function withHarmonyBaseMods(config:
|
|
496
|
-
for (const
|
|
509
|
+
export function withHarmonyBaseMods<Config extends ExpoConfigWithHarmony>(config: Config): Config {
|
|
510
|
+
for (const name of AllModNames) {
|
|
497
511
|
const mods = (config as ExportedConfig).mods as unknown as ModTable;
|
|
498
512
|
|
|
499
|
-
if (!mods?.harmony?.[
|
|
513
|
+
if (!mods?.harmony?.[name]?.isProvider) config = withProvider(config as ExpoConfig, name) as Config;
|
|
500
514
|
}
|
|
501
515
|
|
|
502
516
|
const mods = (config as ExportedConfig).mods as unknown as ModTable;
|
|
503
517
|
const table = mods.harmony!;
|
|
504
518
|
|
|
505
519
|
mods.harmony = Object.fromEntries([
|
|
506
|
-
...
|
|
507
|
-
...Object.entries(table).filter(([name]) => !
|
|
520
|
+
...AllModNames.filter(name => table[name] && name !== 'manifest' && name !== 'patch').map(name => [name, table[name]]),
|
|
521
|
+
...Object.entries(table).filter(([name]) => !AllModNames.includes(name as AnyModName)),
|
|
522
|
+
['patch', table.patch],
|
|
523
|
+
['manifest', table.manifest],
|
|
508
524
|
]);
|
|
509
525
|
|
|
510
526
|
return config;
|
|
511
527
|
}
|
|
512
528
|
|
|
513
|
-
export function withHarmonyMod<T = unknown>(
|
|
514
|
-
config:
|
|
529
|
+
export function withHarmonyMod<T = unknown, Config extends ExpoConfigWithHarmony = ExpoConfigWithHarmony>(
|
|
530
|
+
config: Config,
|
|
515
531
|
tuple: [HarmonyModName, HarmonyModAction<T>]
|
|
516
|
-
):
|
|
532
|
+
): Config {
|
|
517
533
|
if (!Array.isArray(tuple) || tuple.length !== 2) {
|
|
518
534
|
throw new TypeError('withHarmonyMod expects [modName, action].');
|
|
519
535
|
}
|
|
520
536
|
|
|
521
|
-
const [
|
|
522
|
-
if (!HarmonyModNames.includes(
|
|
537
|
+
const [name, action] = tuple;
|
|
538
|
+
if (!HarmonyModNames.includes(name) || typeof action !== 'function') {
|
|
523
539
|
throw new HarmonyConfigPluginError(
|
|
524
540
|
'ERR_HARMONY_MOD_NOT_REGISTERED',
|
|
525
|
-
`Cannot register Harmony mod: ${
|
|
541
|
+
`Cannot register Harmony mod: ${name}`,
|
|
526
542
|
{ operation: 'register-mod' }
|
|
527
543
|
);
|
|
528
544
|
}
|
|
529
545
|
|
|
546
|
+
return registerMod(config, name, action);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
export function registerMod<T, Config extends ExpoConfigWithHarmony>(
|
|
550
|
+
config: Config,
|
|
551
|
+
name: string,
|
|
552
|
+
action: HarmonyModAction<T>
|
|
553
|
+
): Config {
|
|
530
554
|
const mods = (config as ExportedConfig).mods as unknown as ModTable | undefined;
|
|
531
|
-
const provider = mods?.harmony?.[
|
|
555
|
+
const provider = mods?.harmony?.[name];
|
|
532
556
|
|
|
533
557
|
if (provider?.isProvider && provider.expoHarmonyLateActions) {
|
|
534
|
-
|
|
558
|
+
// Build an ordinary Expo interceptor on an isolated mod table, preserving
|
|
559
|
+
// its registration stack, error behavior and execution trace for late mods.
|
|
560
|
+
const carrier = withMod<T>({ ...config, mods: {} } as ExpoConfig, {
|
|
561
|
+
platform: 'harmony' as ModPlatform,
|
|
562
|
+
mod: name,
|
|
563
|
+
action: action as unknown as Parameters<typeof withMod<T>>[1]['action'],
|
|
564
|
+
});
|
|
565
|
+
const interceptor = (carrier.mods as unknown as Record<string, Record<string, HarmonyModAction>>).harmony[name];
|
|
566
|
+
provider.expoHarmonyLateActions.push(interceptor);
|
|
567
|
+
|
|
535
568
|
return config;
|
|
536
569
|
}
|
|
537
570
|
|
|
538
|
-
return withMod<T>(config
|
|
571
|
+
return withMod<T>(config as ExpoConfig, {
|
|
572
|
+
platform: 'harmony' as ModPlatform,
|
|
573
|
+
mod: name,
|
|
574
|
+
action: action as unknown as Parameters<typeof withMod<T>>[1]['action'],
|
|
575
|
+
}) as Config;
|
|
539
576
|
}
|
|
540
577
|
|
|
541
|
-
export const withReactNativeConfig:
|
|
578
|
+
export const withReactNativeConfig: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
542
579
|
= (config, action) => withHarmonyMod(config, ['reactNativeConfig', action]);
|
|
543
|
-
export const withAppJson:
|
|
580
|
+
export const withAppJson: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
544
581
|
= (config, action) => withHarmonyMod(config, ['appJson', action]);
|
|
545
|
-
export const withProjectBuildProfile:
|
|
582
|
+
export const withProjectBuildProfile: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
546
583
|
= (config, action) => withHarmonyMod(config, ['projectBuildProfile', action]);
|
|
547
|
-
export const withRootOhPackage:
|
|
584
|
+
export const withRootOhPackage: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
548
585
|
= (config, action) => withHarmonyMod(config, ['rootOhPackage', action]);
|
|
549
|
-
export const withRootHvigor:
|
|
586
|
+
export const withRootHvigor: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
550
587
|
= (config, action) => withHarmonyMod(config, ['rootHvigor', action]);
|
|
551
|
-
export const withNativeInputsStamp:
|
|
552
|
-
= (config, action) =>
|
|
553
|
-
export const withHvigorConfig:
|
|
588
|
+
export const withNativeInputsStamp: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
589
|
+
= (config, action) => registerMod(config, 'nativeInputsStamp', action);
|
|
590
|
+
export const withHvigorConfig: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
554
591
|
= (config, action) => withHarmonyMod(config, ['hvigorConfig', action]);
|
|
555
|
-
export const withEntryBuildProfile:
|
|
592
|
+
export const withEntryBuildProfile: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
556
593
|
= (config, action) => withHarmonyMod(config, ['entryBuildProfile', action]);
|
|
557
|
-
export const withEntryOhPackage:
|
|
594
|
+
export const withEntryOhPackage: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
558
595
|
= (config, action) => withHarmonyMod(config, ['entryOhPackage', action]);
|
|
559
|
-
export const withEntryHvigor:
|
|
596
|
+
export const withEntryHvigor: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
560
597
|
= (config, action) => withHarmonyMod(config, ['entryHvigor', action]);
|
|
561
|
-
export const withModuleJson:
|
|
598
|
+
export const withModuleJson: HarmonyConfigPlugin<HarmonyModAction<HarmonyModuleJson>>
|
|
562
599
|
= (config, action) => withHarmonyMod(config, ['moduleJson', action]);
|
|
563
|
-
export const withStrings:
|
|
600
|
+
export const withStrings: HarmonyConfigPlugin<HarmonyModAction<HarmonyResourceMap>>
|
|
564
601
|
= (config, action) => withHarmonyMod(config, ['strings', action]);
|
|
565
|
-
export const withColors:
|
|
602
|
+
export const withColors: HarmonyConfigPlugin<HarmonyModAction<HarmonyResourceMap>>
|
|
566
603
|
= (config, action) => withHarmonyMod(config, ['colors', action]);
|
|
567
|
-
export const withMedia:
|
|
604
|
+
export const withMedia: HarmonyConfigPlugin<HarmonyModAction<HarmonyMediaMap>>
|
|
568
605
|
= (config, action) => withHarmonyMod(config, ['media', action]);
|
|
569
|
-
export const withProfiles:
|
|
606
|
+
export const withProfiles: HarmonyConfigPlugin<HarmonyModAction<HarmonyJson>>
|
|
570
607
|
= (config, action) => withHarmonyMod(config, ['profiles', action]);
|
|
571
|
-
export const withEntryAbility:
|
|
608
|
+
export const withEntryAbility: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
572
609
|
= (config, action) => withHarmonyMod(config, ['entryAbility', action]);
|
|
573
|
-
export const withIndexPage:
|
|
610
|
+
export const withIndexPage: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
574
611
|
= (config, action) => withHarmonyMod(config, ['indexPage', action]);
|
|
575
|
-
export const withWorker:
|
|
612
|
+
export const withWorker: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
576
613
|
= (config, action) => withHarmonyMod(config, ['worker', action]);
|
|
577
|
-
export const withArkTSPackageProvider:
|
|
614
|
+
export const withArkTSPackageProvider: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
578
615
|
= (config, action) => withHarmonyMod(config, ['arktsPackageProvider', action]);
|
|
579
|
-
export const withCppPackageProvider:
|
|
616
|
+
export const withCppPackageProvider: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
580
617
|
= (config, action) => withHarmonyMod(config, ['cppPackageProvider', action]);
|
|
581
|
-
export const withCMakeLists:
|
|
618
|
+
export const withCMakeLists: HarmonyConfigPlugin<HarmonyModAction<string>>
|
|
582
619
|
= (config, action) => withHarmonyMod(config, ['cmakeLists', action]);
|
|
583
|
-
export const withHarmonyAutolinking:
|
|
620
|
+
export const withHarmonyAutolinking: HarmonyConfigPlugin<HarmonyModAction<null>>
|
|
584
621
|
= (config, action) => withHarmonyMod(config, ['autolinking', action]);
|
|
585
|
-
export const withCngManifest:
|
|
586
|
-
= (config, action) =>
|
|
587
|
-
export const
|
|
622
|
+
export const withCngManifest: HarmonyConfigPlugin<HarmonyModAction<null>>
|
|
623
|
+
= (config, action) => registerMod(config, 'manifest', action);
|
|
624
|
+
export const withPreparation: HarmonyConfigPlugin<HarmonyModAction<null>>
|
|
625
|
+
= (config, action) => registerMod(config, 'prepare', action);
|
|
626
|
+
export const withProjectPatch: HarmonyConfigPlugin<HarmonyModAction<null>>
|
|
627
|
+
= (config, action) => registerMod(config, 'patch', action);
|
|
628
|
+
export const withHarmonyDangerousMod: HarmonyConfigPlugin<HarmonyModAction<null>>
|
|
588
629
|
= (config, action) => withHarmonyMod(config, ['dangerous', action]);
|
|
589
630
|
|
|
590
|
-
export const withHarmonyResources:
|
|
591
|
-
for (const
|
|
592
|
-
withHarmonyMod(config, [
|
|
631
|
+
export const withHarmonyResources: HarmonyConfigPlugin<HarmonyModAction<unknown>> = (config, action) => {
|
|
632
|
+
for (const name of ResourceModNames) {
|
|
633
|
+
withHarmonyMod(config, [name, action]);
|
|
593
634
|
}
|
|
594
635
|
|
|
595
636
|
return config;
|
package/src/nativeInputs.ts
CHANGED
|
@@ -78,7 +78,6 @@ function fingerprintHarmonyNativeInputsSync(
|
|
|
78
78
|
const files = findLocalHars(root, manifest);
|
|
79
79
|
|
|
80
80
|
const hash = crypto.createHash('sha256');
|
|
81
|
-
|
|
82
81
|
hash.update(`expo-harmony-native-dependencies-v${HarmonyNativeInputsFingerprintVersion}\0`);
|
|
83
82
|
hash.update(Uint8Array.from(data));
|
|
84
83
|
if (lock) hash.update(lock);
|