@expo-harmony/expo-modules-autolinking 55.0.25-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.
- package/README.md +12 -0
- package/bin/expo-harmony-autolinking.ts +14 -0
- package/build/bin/expo-harmony-autolinking.d.ts +2 -0
- package/build/bin/expo-harmony-autolinking.js +11 -0
- package/build/index.d.ts +8 -0
- package/build/index.js +15 -0
- package/build/src/autolinking/link.d.ts +3 -0
- package/build/src/autolinking/link.js +150 -0
- package/build/src/autolinking/resolve.d.ts +4 -0
- package/build/src/autolinking/resolve.js +25 -0
- package/build/src/autolinking/search.d.ts +3 -0
- package/build/src/autolinking/search.js +357 -0
- package/build/src/autolinking/verify.d.ts +4 -0
- package/build/src/autolinking/verify.js +366 -0
- package/build/src/commands/autolinkingOptions.d.ts +12 -0
- package/build/src/commands/autolinkingOptions.js +35 -0
- package/build/src/commands/cli.d.ts +2 -0
- package/build/src/commands/cli.js +50 -0
- package/build/src/commands/link.d.ts +2 -0
- package/build/src/commands/link.js +27 -0
- package/build/src/commands/output.d.ts +3 -0
- package/build/src/commands/output.js +33 -0
- package/build/src/commands/resolve.d.ts +2 -0
- package/build/src/commands/resolve.js +13 -0
- package/build/src/commands/search.d.ts +2 -0
- package/build/src/commands/search.js +13 -0
- package/build/src/commands/verify.d.ts +2 -0
- package/build/src/commands/verify.js +17 -0
- package/build/src/config/constants.d.ts +17 -0
- package/build/src/config/constants.js +40 -0
- package/build/src/config/options.d.ts +13 -0
- package/build/src/config/options.js +202 -0
- package/build/src/errors.d.ts +18 -0
- package/build/src/errors.js +35 -0
- package/build/src/harmony/manifest/generate.d.ts +4 -0
- package/build/src/harmony/manifest/generate.js +55 -0
- package/build/src/harmony/manifest/index.d.ts +7 -0
- package/build/src/harmony/manifest/index.js +64 -0
- package/build/src/harmony/materialize.d.ts +12 -0
- package/build/src/harmony/materialize.js +278 -0
- package/build/src/harmony/ohpm/dependencies.d.ts +7 -0
- package/build/src/harmony/ohpm/dependencies.js +52 -0
- package/build/src/harmony/persistence/canonicalize.d.ts +15 -0
- package/build/src/harmony/persistence/canonicalize.js +108 -0
- package/build/src/harmony/providers/host.d.ts +3 -0
- package/build/src/harmony/providers/host.js +88 -0
- package/build/src/harmony/rnoh/cli.d.ts +2 -0
- package/build/src/harmony/rnoh/cli.js +55 -0
- package/build/src/harmony/rnoh/link.d.ts +2 -0
- package/build/src/harmony/rnoh/link.js +419 -0
- package/build/src/harmony/rnoh/packageMetadata.d.ts +12 -0
- package/build/src/harmony/rnoh/packageMetadata.js +125 -0
- package/build/src/harmony/transaction/previousState.d.ts +15 -0
- package/build/src/harmony/transaction/previousState.js +96 -0
- package/build/src/harmony/transaction/publish.d.ts +6 -0
- package/build/src/harmony/transaction/publish.js +272 -0
- package/build/src/harmony/transaction/stageProject.d.ts +18 -0
- package/build/src/harmony/transaction/stageProject.js +313 -0
- package/build/src/metadata/descriptor.d.ts +19 -0
- package/build/src/metadata/descriptor.js +306 -0
- package/build/src/metadata/host.d.ts +5 -0
- package/build/src/metadata/host.js +37 -0
- package/build/src/metadata/schema.d.ts +10 -0
- package/build/src/metadata/schema.js +171 -0
- package/build/src/types.d.ts +194 -0
- package/build/src/types.js +2 -0
- package/build/src/utilities/values.d.ts +17 -0
- package/build/src/utilities/values.js +205 -0
- package/harmony-module.schema.json +28 -0
- package/index.ts +41 -0
- package/package.json +66 -0
- package/src/autolinking/link.ts +170 -0
- package/src/autolinking/resolve.ts +33 -0
- package/src/autolinking/search.ts +369 -0
- package/src/autolinking/verify.ts +415 -0
- package/src/commands/autolinkingOptions.ts +38 -0
- package/src/commands/cli.ts +56 -0
- package/src/commands/link.ts +28 -0
- package/src/commands/output.ts +36 -0
- package/src/commands/resolve.ts +14 -0
- package/src/commands/search.ts +14 -0
- package/src/commands/verify.ts +17 -0
- package/src/config/constants.ts +45 -0
- package/src/config/options.ts +195 -0
- package/src/errors.ts +48 -0
- package/src/harmony/manifest/generate.ts +65 -0
- package/src/harmony/manifest/index.ts +81 -0
- package/src/harmony/materialize.ts +382 -0
- package/src/harmony/ohpm/dependencies.ts +59 -0
- package/src/harmony/persistence/canonicalize.ts +156 -0
- package/src/harmony/providers/host.ts +147 -0
- package/src/harmony/rnoh/cli.ts +59 -0
- package/src/harmony/rnoh/link.ts +481 -0
- package/src/harmony/rnoh/packageMetadata.ts +105 -0
- package/src/harmony/transaction/previousState.ts +71 -0
- package/src/harmony/transaction/publish.ts +287 -0
- package/src/harmony/transaction/stageProject.ts +345 -0
- package/src/metadata/descriptor.ts +324 -0
- package/src/metadata/host.ts +41 -0
- package/src/metadata/schema.ts +184 -0
- package/src/types.ts +220 -0
- package/src/utilities/values.ts +190 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { Platform } from './constants';
|
|
5
|
+
import { HarmonyAutolinkingError } from '../errors';
|
|
6
|
+
import { isObject, readJsonAsync, realpathExistingAsync, normalizeStringArray, uniqueStrings } from '../utilities/values';
|
|
7
|
+
|
|
8
|
+
const ListFields = ['searchPaths', 'exclude', 'include'];
|
|
9
|
+
const NpmPackageNamePattern = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
|
|
10
|
+
const RnohPackageListDelimiterPattern = /[;\0\r\n]/;
|
|
11
|
+
|
|
12
|
+
function selectConfiguredValue(rawOptions, platform, sharedConfig, field, fallback) {
|
|
13
|
+
if (rawOptions[field] !== undefined) return rawOptions[field];
|
|
14
|
+
if (platform[field] !== undefined) return platform[field];
|
|
15
|
+
if (sharedConfig[field] !== undefined) return sharedConfig[field];
|
|
16
|
+
return fallback;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function configuredList(platform, sharedConfig, field) {
|
|
20
|
+
const normalize = (value) => {
|
|
21
|
+
if (value === undefined) return [];
|
|
22
|
+
const values = field === 'searchPaths' && typeof value === 'string'
|
|
23
|
+
? [value]
|
|
24
|
+
: Array.isArray(value) ? value : [];
|
|
25
|
+
return values.filter(item => typeof item === 'string' && item.trim());
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
if (field === 'include') {
|
|
29
|
+
return [
|
|
30
|
+
...normalize(sharedConfig.include),
|
|
31
|
+
...normalize(platform.include),
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return normalize(platform[field] !== undefined ? platform[field] : sharedConfig[field]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function validateConfigObject(value, field) {
|
|
39
|
+
if (value === undefined) return {};
|
|
40
|
+
|
|
41
|
+
if (!isObject(value)) {
|
|
42
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', `${field} must be an object.`, { stage: 'options' });
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function normalizeBuildType(value) {
|
|
48
|
+
const buildType = value === undefined ? 'debug' : value;
|
|
49
|
+
|
|
50
|
+
if (buildType !== 'debug' && buildType !== 'release') {
|
|
51
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', 'buildType must be either "debug" or "release".', { stage: 'options' });
|
|
52
|
+
}
|
|
53
|
+
return buildType;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function assertSafeRnohPackageList(values, field, stage = 'options') {
|
|
57
|
+
if (!Array.isArray(values)
|
|
58
|
+
|| values.some(value => typeof value !== 'string'
|
|
59
|
+
|| !value.trim()
|
|
60
|
+
|| RnohPackageListDelimiterPattern.test(value))) {
|
|
61
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', `${field} entries must not contain semicolons or NUL/CR/LF control characters.`, { stage });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function normalizeNativeModulesDirectory(value, projectRoot) {
|
|
66
|
+
if (value === null) return null;
|
|
67
|
+
|
|
68
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
69
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', 'nativeModulesDir must be a non-empty string or null.', { stage: 'options' });
|
|
70
|
+
}
|
|
71
|
+
return path.resolve(projectRoot, value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
function normalizeModuleOverrides(value, options: Record<string, any> = {}) {
|
|
76
|
+
const code = options.code || 'INVALID_OPTIONS';
|
|
77
|
+
const field = options.field || 'package.json#expo.autolinking.harmony.modules';
|
|
78
|
+
const stage = options.stage || 'options';
|
|
79
|
+
|
|
80
|
+
if (value === undefined) return Object.freeze({});
|
|
81
|
+
if (!isObject(value)) {
|
|
82
|
+
throw new HarmonyAutolinkingError(code, `${field} must be an object.`, { stage });
|
|
83
|
+
}
|
|
84
|
+
const overrides = {};
|
|
85
|
+
|
|
86
|
+
for (const packageName of Object.keys(value).sort()) {
|
|
87
|
+
const metadata = value[packageName];
|
|
88
|
+
if (!NpmPackageNamePattern.test(packageName) || !isObject(metadata)) {
|
|
89
|
+
throw new HarmonyAutolinkingError(code, `Invalid Harmony sidecar module registration for ${packageName} in ${field}.`, { stage });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (metadata.version !== undefined
|
|
93
|
+
&& (typeof metadata.version !== 'string'
|
|
94
|
+
|| !metadata.version
|
|
95
|
+
|| /^[*~^]|^(?:file|link|workspace):/u.test(metadata.version))) {
|
|
96
|
+
throw new HarmonyAutolinkingError(code, `Harmony sidecar module ${packageName} in ${field} must use an exact version.`, { stage });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
overrides[packageName] = Object.freeze({ ...metadata });
|
|
100
|
+
}
|
|
101
|
+
return Object.freeze(overrides);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
+
async function normalizeOptionsAsync(rawOptions: Record<string, any> = {}) {
|
|
106
|
+
if (!isObject(rawOptions)) {
|
|
107
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', 'Options must be an object.', { stage: 'options' });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (rawOptions.logger !== undefined) {
|
|
111
|
+
if (!isObject(rawOptions.logger)
|
|
112
|
+
|| ['debug', 'info', 'warn', 'error'].some((level) => {
|
|
113
|
+
return rawOptions.logger[level] !== undefined && typeof rawOptions.logger[level] !== 'function';
|
|
114
|
+
})) {
|
|
115
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', 'logger must expose only callable debug/info/warn/error methods.', { stage: 'options' });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (rawOptions.platform != null && rawOptions.platform !== Platform) {
|
|
120
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', 'Only platform "harmony" is supported.', { stage: 'options' });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const rawRoot = rawOptions.projectRoot === undefined ? process.cwd() : rawOptions.projectRoot;
|
|
124
|
+
if (typeof rawRoot !== 'string' || !rawRoot) {
|
|
125
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', 'projectRoot must be a non-empty string.', { stage: 'options' });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let projectRoot = await realpathExistingAsync(rawRoot, {
|
|
129
|
+
type: 'directory',
|
|
130
|
+
field: 'projectRoot',
|
|
131
|
+
stage: 'options',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
let pkgPath = path.join(projectRoot, 'package.json');
|
|
135
|
+
while (!fs.existsSync(pkgPath) && path.dirname(projectRoot) !== projectRoot) {
|
|
136
|
+
projectRoot = path.dirname(projectRoot);
|
|
137
|
+
pkgPath = path.join(projectRoot, 'package.json');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!fs.existsSync(pkgPath)) {
|
|
141
|
+
throw new HarmonyAutolinkingError('INVALID_OPTIONS', `No package.json exists at projectRoot: ${projectRoot}`, { stage: 'options' });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const packageJson = await readJsonAsync(pkgPath, 'INVALID_OPTIONS', 'options');
|
|
145
|
+
const expo = packageJson.expo === undefined ? {} : validateConfigObject(packageJson.expo, 'package.json#expo');
|
|
146
|
+
const shared = expo.autolinking === undefined ? {} : validateConfigObject(expo.autolinking, 'package.json#expo.autolinking');
|
|
147
|
+
const platform = shared.harmony === undefined ? {} : validateConfigObject(shared.harmony, 'package.json#expo.autolinking.harmony');
|
|
148
|
+
|
|
149
|
+
const configured = Object.fromEntries(ListFields.map(field => [field, configuredList(platform, shared, field)]));
|
|
150
|
+
|
|
151
|
+
const lists = {
|
|
152
|
+
searchPaths: rawOptions.searchPaths === undefined
|
|
153
|
+
? configured.searchPaths
|
|
154
|
+
: [...normalizeStringArray(rawOptions.searchPaths, 'searchPaths'), ...configured.searchPaths],
|
|
155
|
+
exclude: rawOptions.exclude === undefined
|
|
156
|
+
? configured.exclude
|
|
157
|
+
: [...configured.exclude, ...normalizeStringArray(rawOptions.exclude, 'exclude')],
|
|
158
|
+
include: rawOptions.include === undefined
|
|
159
|
+
? configured.include
|
|
160
|
+
: [...configured.include, ...normalizeStringArray(rawOptions.include, 'include')],
|
|
161
|
+
};
|
|
162
|
+
assertSafeRnohPackageList(lists.include, 'include');
|
|
163
|
+
assertSafeRnohPackageList(lists.exclude, 'exclude');
|
|
164
|
+
|
|
165
|
+
const paths = [];
|
|
166
|
+
for (const value of lists.searchPaths) {
|
|
167
|
+
const target = path.resolve(projectRoot, value);
|
|
168
|
+
paths.push(fs.existsSync(target) ? await fs.promises.realpath(target) : target);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const searchPaths = uniqueStrings(paths);
|
|
172
|
+
const rawDir = selectConfiguredValue(rawOptions, platform, shared, 'nativeModulesDir', './modules');
|
|
173
|
+
let nativeDir = normalizeNativeModulesDirectory(rawDir, projectRoot);
|
|
174
|
+
|
|
175
|
+
if (nativeDir && fs.existsSync(nativeDir)) {
|
|
176
|
+
nativeDir = await fs.promises.realpath(nativeDir);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
projectRoot,
|
|
181
|
+
platform: Platform,
|
|
182
|
+
searchPaths,
|
|
183
|
+
nativeModulesDir: nativeDir,
|
|
184
|
+
exclude: uniqueStrings(lists.exclude),
|
|
185
|
+
include: uniqueStrings(lists.include),
|
|
186
|
+
moduleOverrides: normalizeModuleOverrides(platform.modules),
|
|
187
|
+
buildType: normalizeBuildType(selectConfiguredValue(rawOptions, platform, shared, 'buildType', 'debug')),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export {
|
|
192
|
+
assertSafeRnohPackageList,
|
|
193
|
+
normalizeOptionsAsync,
|
|
194
|
+
normalizeModuleOverrides,
|
|
195
|
+
};
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AutolinkingErrorJson, Diagnostic } from './types';
|
|
2
|
+
|
|
3
|
+
const ErrorPrefix = 'ERR_EXPO_HARMONY_';
|
|
4
|
+
|
|
5
|
+
interface HarmonyAutolinkingErrorDetails {
|
|
6
|
+
cause?: unknown;
|
|
7
|
+
stage?: string;
|
|
8
|
+
packageName?: string;
|
|
9
|
+
diagnostics?: ReadonlyArray<Diagnostic>;
|
|
10
|
+
details?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class HarmonyAutolinkingError extends Error {
|
|
14
|
+
readonly code: string;
|
|
15
|
+
readonly stage: string;
|
|
16
|
+
readonly packageName?: string;
|
|
17
|
+
readonly diagnostics?: ReadonlyArray<Diagnostic>;
|
|
18
|
+
readonly details?: unknown;
|
|
19
|
+
|
|
20
|
+
constructor(code: string, message: string, details: HarmonyAutolinkingErrorDetails = {}) {
|
|
21
|
+
const value = code.startsWith(ErrorPrefix) ? code : `${ErrorPrefix}${code}`;
|
|
22
|
+
|
|
23
|
+
super(message, details.cause ? { cause: details.cause } : undefined);
|
|
24
|
+
this.name = 'HarmonyAutolinkingError';
|
|
25
|
+
this.code = value;
|
|
26
|
+
this.stage = details.stage || 'unknown';
|
|
27
|
+
this.packageName = details.packageName;
|
|
28
|
+
this.diagnostics = details.diagnostics;
|
|
29
|
+
this.details = details.details;
|
|
30
|
+
Error.captureStackTrace?.(this, HarmonyAutolinkingError);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toJSON(): AutolinkingErrorJson {
|
|
34
|
+
const value: AutolinkingErrorJson = {
|
|
35
|
+
name: 'HarmonyAutolinkingError' as const,
|
|
36
|
+
code: this.code,
|
|
37
|
+
message: this.message,
|
|
38
|
+
stage: this.stage,
|
|
39
|
+
...(this.packageName ? { packageName: this.packageName } : {}),
|
|
40
|
+
...(this.diagnostics ? { diagnostics: this.diagnostics } : {}),
|
|
41
|
+
...(this.details ? { details: this.details } : {}),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { HarmonyAutolinkingError };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ManagedArtifacts,
|
|
3
|
+
ManifestSchemaVersion,
|
|
4
|
+
Platform,
|
|
5
|
+
} from '../../config/constants';
|
|
6
|
+
import type { BuildType, Manifest } from '../../types';
|
|
7
|
+
import { stringifyJson } from '../../utilities/values';
|
|
8
|
+
|
|
9
|
+
function cloneOhPackageName(value) {
|
|
10
|
+
if (Array.isArray(value)) return value.map(mapping => ({ ...mapping }));
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function createManifestEntry(descriptor) {
|
|
15
|
+
return {
|
|
16
|
+
packageName: descriptor.packageName,
|
|
17
|
+
packageVersion: descriptor.packageVersion,
|
|
18
|
+
packageRoot: descriptor.packageRoot,
|
|
19
|
+
packageLinkPath: descriptor.packageLinkPath,
|
|
20
|
+
source: descriptor.source,
|
|
21
|
+
harmony: {
|
|
22
|
+
modules: [...descriptor.harmony.modules],
|
|
23
|
+
},
|
|
24
|
+
...(descriptor.arkTs ? { arkTs: { ...descriptor.arkTs } } : {}),
|
|
25
|
+
expo: {
|
|
26
|
+
rootViewComponents: [...descriptor.expo.rootViewComponents],
|
|
27
|
+
},
|
|
28
|
+
rnoh: {
|
|
29
|
+
...(descriptor.rnoh.ohPackageName !== undefined
|
|
30
|
+
? { ohPackageName: cloneOhPackageName(descriptor.rnoh.ohPackageName) }
|
|
31
|
+
: {}),
|
|
32
|
+
...(descriptor.rnoh.mainHarPath ? { mainHarPath: descriptor.rnoh.mainHarPath } : {}),
|
|
33
|
+
harPaths: [...descriptor.rnoh.harPaths],
|
|
34
|
+
...(descriptor.rnoh.etsPackageClassName ? { etsPackageClassName: descriptor.rnoh.etsPackageClassName } : {}),
|
|
35
|
+
...(descriptor.rnoh.etsPackageImport ? { etsPackageImport: descriptor.rnoh.etsPackageImport } : {}),
|
|
36
|
+
...(descriptor.rnoh.cppPackageClassName ? { cppPackageClassName: descriptor.rnoh.cppPackageClassName } : {}),
|
|
37
|
+
...(descriptor.rnoh.cmakeLibraryTargetName
|
|
38
|
+
? { cmakeLibraryTargetName: descriptor.rnoh.cmakeLibraryTargetName }
|
|
39
|
+
: {}),
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
function createManifest(modules, options: Record<string, any> = {}): Manifest {
|
|
46
|
+
const buildType: BuildType = options.buildType || 'debug';
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
schemaVersion: ManifestSchemaVersion,
|
|
50
|
+
platform: Platform,
|
|
51
|
+
buildType,
|
|
52
|
+
modules: modules.map(descriptor => createManifestEntry(descriptor)),
|
|
53
|
+
managedArtifacts: [...(options.managedArtifacts || ManagedArtifacts)],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
58
|
+
function serializeManifest(modules, options: Record<string, any> = {}) {
|
|
59
|
+
return stringifyJson(createManifest(modules, options));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
createManifest,
|
|
64
|
+
serializeManifest,
|
|
65
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import type { Manifest } from '../../types';
|
|
4
|
+
import { ManifestSchemaVersion, Platform } from '../../config/constants';
|
|
5
|
+
import { HarmonyAutolinkingError } from '../../errors';
|
|
6
|
+
import { collectOhpmDeps, resolveOhpmSpecifier } from '../ohpm/dependencies';
|
|
7
|
+
import { isValidOhpmPackageName } from '../../metadata/schema';
|
|
8
|
+
import { isObject } from '../../utilities/values';
|
|
9
|
+
|
|
10
|
+
const ModuleSources = new Set(['dependency', 'searchPath', 'nativeModulesDir', 'reactNativeProjectConfig']);
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
function validateManifest(manifest: unknown, options: Record<string, any> = {}): Manifest {
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
const candidate = isObject(manifest) ? manifest as Record<string, any> : null;
|
|
16
|
+
|
|
17
|
+
if (!candidate
|
|
18
|
+
|| candidate.schemaVersion !== ManifestSchemaVersion
|
|
19
|
+
|| candidate.platform !== Platform
|
|
20
|
+
|| !['debug', 'release'].includes(candidate.buildType)
|
|
21
|
+
|| !Array.isArray(candidate.modules)
|
|
22
|
+
|| !Array.isArray(candidate.managedArtifacts)) {
|
|
23
|
+
throw new HarmonyAutolinkingError('INVALID_MANIFEST', `Harmony autolinking manifest must use schema ${ManifestSchemaVersion}.`, {
|
|
24
|
+
details: options.file ? { file: options.file } : undefined,
|
|
25
|
+
stage: 'manifest',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
for (const [index, entry] of candidate.modules.entries()) {
|
|
29
|
+
if (!isObject(entry)
|
|
30
|
+
|| typeof entry.packageName !== 'string'
|
|
31
|
+
|| !entry.packageName
|
|
32
|
+
|| typeof entry.packageVersion !== 'string'
|
|
33
|
+
|| !entry.packageVersion
|
|
34
|
+
|| typeof entry.packageRoot !== 'string'
|
|
35
|
+
|| !path.isAbsolute(entry.packageRoot)
|
|
36
|
+
|| typeof entry.packageLinkPath !== 'string'
|
|
37
|
+
|| !path.isAbsolute(entry.packageLinkPath)
|
|
38
|
+
|| !ModuleSources.has(entry.source)
|
|
39
|
+
|| (entry.harmony !== undefined && (
|
|
40
|
+
!isObject(entry.harmony)
|
|
41
|
+
|| !Array.isArray(entry.harmony.modules)
|
|
42
|
+
|| entry.harmony.modules.some(moduleClass => typeof moduleClass !== 'string' || !moduleClass)
|
|
43
|
+
))
|
|
44
|
+
|| (entry.arkTs !== undefined && (
|
|
45
|
+
!isObject(entry.arkTs)
|
|
46
|
+
|| entry.arkTs.harPath !== 'harmony/library.har'
|
|
47
|
+
|| !isValidOhpmPackageName(entry.arkTs.ohPackageName)
|
|
48
|
+
))
|
|
49
|
+
|| (entry.harmony?.modules.length > 0 && !isObject(entry.arkTs))
|
|
50
|
+
|| !isObject(entry.expo)
|
|
51
|
+
|| !Array.isArray(entry.expo.rootViewComponents)
|
|
52
|
+
|| !isObject(entry.rnoh)
|
|
53
|
+
|| !Array.isArray(entry.rnoh.harPaths)) {
|
|
54
|
+
throw new HarmonyAutolinkingError(
|
|
55
|
+
'INVALID_MANIFEST',
|
|
56
|
+
`Harmony autolinking manifest module ${index} is invalid.`,
|
|
57
|
+
{ details: options.file ? { file: options.file } : undefined, stage: 'manifest' }
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return structuredClone(candidate) as Manifest;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ohpmDependenciesFromManifest(
|
|
66
|
+
manifest: Manifest,
|
|
67
|
+
options: { harmonyProjectPath?: string; nodeModulesPath?: string } = {}
|
|
68
|
+
): Readonly<Record<string, string>> {
|
|
69
|
+
const validated = validateManifest(manifest);
|
|
70
|
+
|
|
71
|
+
return Object.fromEntries(collectOhpmDeps(validated.modules)
|
|
72
|
+
.map(({ descriptor, mapping }) => [
|
|
73
|
+
mapping.ohPackageName,
|
|
74
|
+
resolveOhpmSpecifier(descriptor, mapping, options),
|
|
75
|
+
]));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
ohpmDependenciesFromManifest,
|
|
80
|
+
validateManifest,
|
|
81
|
+
};
|