expo-harmony-toolkit 1.7.2 → 1.8.0
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.en.md +25 -11
- package/README.md +27 -13
- package/build/core/autolinking.d.ts +10 -0
- package/build/core/autolinking.js +421 -0
- package/build/core/build/commands.d.ts +19 -0
- package/build/core/build/commands.js +61 -0
- package/build/core/build/compatibilityShims.d.ts +1 -0
- package/build/core/build/compatibilityShims.js +272 -0
- package/build/core/build/localHar.d.ts +13 -0
- package/build/core/build/localHar.js +337 -0
- package/build/core/build/reporting.d.ts +19 -0
- package/build/core/build/reporting.js +67 -0
- package/build/core/build/rnohCompatibility.d.ts +1 -0
- package/build/core/build/rnohCompatibility.js +38 -0
- package/build/core/build.d.ts +4 -12
- package/build/core/build.js +70 -762
- package/build/core/constants.d.ts +2 -1
- package/build/core/constants.js +3 -2
- package/build/core/dependencyInspection.d.ts +2 -0
- package/build/core/dependencyInspection.js +130 -0
- package/build/core/env.js +1 -1
- package/build/core/report.js +162 -10
- package/build/core/signing.d.ts +2 -0
- package/build/core/signing.js +30 -0
- package/build/core/template/capabilityRegistry.d.ts +9 -0
- package/build/core/template/capabilityRegistry.js +84 -0
- package/build/core/template/expoModulesCoreShim.d.ts +2 -0
- package/build/core/template/expoModulesCoreShim.js +279 -0
- package/build/core/template/metro.d.ts +2 -0
- package/build/core/template/metro.js +213 -0
- package/build/core/template/nativeFiles.d.ts +8 -0
- package/build/core/template/nativeFiles.js +333 -0
- package/build/core/template/renderers/camera.d.ts +4 -0
- package/build/core/template/renderers/camera.js +612 -0
- package/build/core/template/renderers/fileSystem.d.ts +4 -0
- package/build/core/template/renderers/fileSystem.js +814 -0
- package/build/core/template/renderers/imagePicker.d.ts +4 -0
- package/build/core/template/renderers/imagePicker.js +753 -0
- package/build/core/template/renderers/location.d.ts +4 -0
- package/build/core/template/renderers/location.js +836 -0
- package/build/core/template/runtimeShims.d.ts +2 -0
- package/build/core/template/runtimeShims.js +192 -0
- package/build/core/template/support.d.ts +11 -0
- package/build/core/template/support.js +108 -0
- package/build/core/template.d.ts +3 -6
- package/build/core/template.js +49 -4457
- package/build/data/capabilities.js +21 -4
- package/build/data/dependencyCatalog.js +10 -0
- package/build/data/publicDocs.d.ts +11 -0
- package/build/data/publicDocs.js +28 -0
- package/build/data/validatedMatrices.js +9 -1
- package/build/docs/render.d.ts +9 -0
- package/build/docs/render.js +250 -0
- package/build/types.d.ts +19 -0
- package/docs/cli-build.md +1 -1
- package/docs/npm-release.md +1 -0
- package/docs/official-app-shell-sample.md +2 -1
- package/docs/official-minimal-sample.md +2 -1
- package/docs/official-native-capabilities-sample.md +12 -2
- package/docs/official-ui-stack-sample.md +2 -1
- package/docs/roadmap.md +146 -51
- package/docs/signing-and-release.md +3 -0
- package/docs/support-matrix.md +59 -13
- package/package.json +13 -5
- package/docs/v1.5.1-acceptance.md +0 -385
- package/docs/v1.6.0-acceptance.md +0 -193
- package/docs/v1.7.0-acceptance.md +0 -111
- package/docs/v1.7.1-acceptance.md +0 -111
- package/docs/v1.7.2-acceptance.md +0 -37
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AutolinkingFailureError = exports.AUTOLINKED_FILE_PATHS = void 0;
|
|
7
|
+
exports.buildAutolinkedManagedFiles = buildAutolinkedManagedFiles;
|
|
8
|
+
exports.normalizeKnownHarmonyPackageJsons = normalizeKnownHarmonyPackageJsons;
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const json5_1 = __importDefault(require("json5"));
|
|
11
|
+
const os_1 = __importDefault(require("os"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const uiStack_1 = require("../data/uiStack");
|
|
14
|
+
exports.AUTOLINKED_FILE_PATHS = [
|
|
15
|
+
path_1.default.join('harmony', 'oh-package.json5'),
|
|
16
|
+
path_1.default.join('harmony', 'entry', 'src', 'main', 'ets', 'RNOHPackagesFactory.ets'),
|
|
17
|
+
path_1.default.join('harmony', 'entry', 'src', 'main', 'cpp', 'RNOHPackagesFactory.h'),
|
|
18
|
+
path_1.default.join('harmony', 'entry', 'src', 'main', 'cpp', 'autolinking.cmake'),
|
|
19
|
+
];
|
|
20
|
+
const HARMONY_PACKAGE_JSON_NORMALIZERS = {
|
|
21
|
+
'@react-native-oh-tpl/react-native-gesture-handler': (packageJson) => {
|
|
22
|
+
const harmony = packageJson.harmony && typeof packageJson.harmony === 'object' && !Array.isArray(packageJson.harmony)
|
|
23
|
+
? { ...packageJson.harmony }
|
|
24
|
+
: null;
|
|
25
|
+
if (!harmony || !('codegenConfig' in harmony)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
delete harmony.codegenConfig;
|
|
29
|
+
return {
|
|
30
|
+
...packageJson,
|
|
31
|
+
harmony,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
class AutolinkingFailureError extends Error {
|
|
36
|
+
constructor(stage, command, options = {}) {
|
|
37
|
+
const details = [
|
|
38
|
+
`Harmony autolinking failed during ${stage}.`,
|
|
39
|
+
`Command: ${command}`,
|
|
40
|
+
];
|
|
41
|
+
if (options.missingFiles && options.missingFiles.length > 0) {
|
|
42
|
+
details.push(`Missing files: ${options.missingFiles.join(', ')}`);
|
|
43
|
+
}
|
|
44
|
+
if (options.cause) {
|
|
45
|
+
details.push(`Cause: ${options.cause}`);
|
|
46
|
+
}
|
|
47
|
+
super(details.join(' '));
|
|
48
|
+
this.name = 'AutolinkingFailureError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.AutolinkingFailureError = AutolinkingFailureError;
|
|
52
|
+
async function buildAutolinkedManagedFiles(projectRoot, harmonyRootPackageContents) {
|
|
53
|
+
const generated = await generateAutolinkingArtifacts(projectRoot, harmonyRootPackageContents);
|
|
54
|
+
return [
|
|
55
|
+
{
|
|
56
|
+
relativePath: exports.AUTOLINKED_FILE_PATHS[0],
|
|
57
|
+
contents: generated.ohPackageContents,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
relativePath: exports.AUTOLINKED_FILE_PATHS[1],
|
|
61
|
+
contents: generated.etsFactoryContents,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
relativePath: exports.AUTOLINKED_FILE_PATHS[2],
|
|
65
|
+
contents: generated.cppFactoryContents,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
relativePath: exports.AUTOLINKED_FILE_PATHS[3],
|
|
69
|
+
contents: generated.cmakeContents,
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
async function normalizeKnownHarmonyPackageJsons(projectRoot) {
|
|
74
|
+
const originalContentsByPath = new Map();
|
|
75
|
+
for (const [packageName, normalizePackageJson] of Object.entries(HARMONY_PACKAGE_JSON_NORMALIZERS)) {
|
|
76
|
+
const packageJsonPath = resolveProjectPackageJson(projectRoot, packageName);
|
|
77
|
+
if (!packageJsonPath || originalContentsByPath.has(packageJsonPath)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const currentContents = await fs_extra_1.default.readFile(packageJsonPath, 'utf8');
|
|
82
|
+
const packageJson = JSON.parse(currentContents);
|
|
83
|
+
const normalizedPackageJson = normalizePackageJson(packageJson);
|
|
84
|
+
if (!normalizedPackageJson) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
originalContentsByPath.set(packageJsonPath, currentContents);
|
|
88
|
+
await fs_extra_1.default.writeFile(packageJsonPath, JSON.stringify(normalizedPackageJson, null, 2) + '\n');
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Ignore malformed adapter package metadata and let downstream tooling surface the failure.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return async () => {
|
|
95
|
+
for (const [packageJsonPath, originalContents] of originalContentsByPath) {
|
|
96
|
+
await fs_extra_1.default.writeFile(packageJsonPath, originalContents);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function generateAutolinkingArtifacts(projectRoot, harmonyRootPackageContents) {
|
|
101
|
+
const rnohCliPackageJsonPath = resolveProjectPackageJson(projectRoot, '@react-native-oh/react-native-harmony-cli');
|
|
102
|
+
const managedOhPackageContents = await buildManagedHarmonyRootPackageContents(projectRoot, harmonyRootPackageContents);
|
|
103
|
+
const managedAutolinkingEntries = await resolveManagedAutolinkingEntries(projectRoot);
|
|
104
|
+
if (!rnohCliPackageJsonPath) {
|
|
105
|
+
return createEmptyAutolinkingArtifacts(managedOhPackageContents, managedAutolinkingEntries);
|
|
106
|
+
}
|
|
107
|
+
const restoreNormalizedHarmonyPackageJsons = await normalizeKnownHarmonyPackageJsons(projectRoot);
|
|
108
|
+
try {
|
|
109
|
+
const temporaryRoot = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'expo-harmony-autolinking-'));
|
|
110
|
+
try {
|
|
111
|
+
const temporaryHarmonyRoot = path_1.default.join(temporaryRoot, 'harmony');
|
|
112
|
+
const commandDescription = buildRnohLinkHarmonyCommand(projectRoot, temporaryHarmonyRoot);
|
|
113
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(temporaryHarmonyRoot, 'entry', 'src', 'main', 'ets'));
|
|
114
|
+
await fs_extra_1.default.ensureDir(path_1.default.join(temporaryHarmonyRoot, 'entry', 'src', 'main', 'cpp'));
|
|
115
|
+
await fs_extra_1.default.writeFile(path_1.default.join(temporaryHarmonyRoot, 'oh-package.json5'), harmonyRootPackageContents);
|
|
116
|
+
await runRnohLinkHarmonyCommand(projectRoot, rnohCliPackageJsonPath, temporaryHarmonyRoot, commandDescription);
|
|
117
|
+
await assertGeneratedAutolinkingFilesExist(temporaryHarmonyRoot, commandDescription);
|
|
118
|
+
let normalizedEtsFactoryContents;
|
|
119
|
+
let normalizedCppFactoryContents;
|
|
120
|
+
let normalizedCmakeContents;
|
|
121
|
+
try {
|
|
122
|
+
normalizedEtsFactoryContents = await normalizeAutolinkingEtsFactoryContents(projectRoot, await fs_extra_1.default.readFile(path_1.default.join(temporaryHarmonyRoot, 'entry', 'src', 'main', 'ets', 'RNOHPackagesFactory.ets'), 'utf8'));
|
|
123
|
+
normalizedCppFactoryContents = await normalizeAutolinkingCppFactoryContents(projectRoot, await fs_extra_1.default.readFile(path_1.default.join(temporaryHarmonyRoot, 'entry', 'src', 'main', 'cpp', 'RNOHPackagesFactory.h'), 'utf8'));
|
|
124
|
+
normalizedCmakeContents = await fs_extra_1.default.readFile(path_1.default.join(temporaryHarmonyRoot, 'entry', 'src', 'main', 'cpp', 'autolinking.cmake'), 'utf8');
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
throw new AutolinkingFailureError('normalize-generated-files', commandDescription, {
|
|
128
|
+
cause: getErrorMessage(error),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
ohPackageContents: managedOhPackageContents,
|
|
133
|
+
etsFactoryContents: injectManagedAutolinkingIntoEtsFactory(normalizedEtsFactoryContents, managedAutolinkingEntries),
|
|
134
|
+
cppFactoryContents: injectManagedAutolinkingIntoCppFactory(normalizedCppFactoryContents, managedAutolinkingEntries),
|
|
135
|
+
cmakeContents: injectManagedAutolinkingIntoCmake(normalizedCmakeContents, managedAutolinkingEntries),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
await fs_extra_1.default.remove(temporaryRoot);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
await restoreNormalizedHarmonyPackageJsons();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function resolveManagedAutolinkingEntries(projectRoot) {
|
|
147
|
+
const entries = await Promise.all(uiStack_1.UI_STACK_VALIDATED_ADAPTERS.map(async (adapter) => {
|
|
148
|
+
if (adapter.supportsAutolinking || !adapter.managedAutolinking) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const dependencySpecifier = await resolveHarmonyAdapterHarDependency(projectRoot, adapter.adapterPackageName);
|
|
152
|
+
if (!dependencySpecifier) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
adapterPackageName: adapter.adapterPackageName,
|
|
157
|
+
...adapter.managedAutolinking,
|
|
158
|
+
};
|
|
159
|
+
}));
|
|
160
|
+
return entries.filter((entry) => entry !== null);
|
|
161
|
+
}
|
|
162
|
+
async function normalizeAutolinkingEtsFactoryContents(projectRoot, contents) {
|
|
163
|
+
let normalizedContents = contents
|
|
164
|
+
.replace(/import type \{\s*RNPackageContext\s*,\s*RNOHPackage\s*\} from '@rnoh\/react-native-openharmony';/, "import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony';")
|
|
165
|
+
.replace(/export function createRNOHPackages\(([^)]*)\):\s*RNOHPackage\[\]/, 'export function createRNOHPackages($1): RNPackage[]');
|
|
166
|
+
const gestureHandlerPackageJsonPath = resolveProjectPackageJson(projectRoot, '@react-native-oh-tpl/react-native-gesture-handler');
|
|
167
|
+
if (!gestureHandlerPackageJsonPath) {
|
|
168
|
+
return normalizedContents;
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const gestureHandlerPackageJson = (await fs_extra_1.default.readJson(gestureHandlerPackageJsonPath));
|
|
172
|
+
if (gestureHandlerPackageJson.harmony?.codegenConfig) {
|
|
173
|
+
return normalizedContents;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return normalizedContents;
|
|
178
|
+
}
|
|
179
|
+
let gestureHandlerPackageImportName = null;
|
|
180
|
+
normalizedContents = normalizedContents.replace(/import\s+([A-Za-z_$][\w$]*)\s+from ['"]@react-native-oh-tpl\/react-native-gesture-handler['"];?/, (_match, importName) => {
|
|
181
|
+
gestureHandlerPackageImportName = importName;
|
|
182
|
+
return "import { GestureHandlerPackage } from '@react-native-oh-tpl/react-native-gesture-handler/ts';";
|
|
183
|
+
});
|
|
184
|
+
if (!gestureHandlerPackageImportName) {
|
|
185
|
+
return normalizedContents;
|
|
186
|
+
}
|
|
187
|
+
return normalizedContents.replace(new RegExp(`new\\s+${escapeRegExp(gestureHandlerPackageImportName)}\\(ctx\\)`, 'g'), 'new GestureHandlerPackage(ctx)');
|
|
188
|
+
}
|
|
189
|
+
function injectManagedAutolinkingIntoEtsFactory(contents, entries) {
|
|
190
|
+
if (entries.length === 0) {
|
|
191
|
+
return contents;
|
|
192
|
+
}
|
|
193
|
+
const missingImports = entries
|
|
194
|
+
.filter((entry) => !contents.includes(`from '${entry.etsImportPath}'`))
|
|
195
|
+
.map((entry) => `import { ${entry.etsPackageName} } from '${entry.etsImportPath}';`);
|
|
196
|
+
if (missingImports.length > 0) {
|
|
197
|
+
contents = contents.replace("import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony';", `import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony';\n${missingImports.join('\n')}`);
|
|
198
|
+
}
|
|
199
|
+
const missingFactoryEntries = entries
|
|
200
|
+
.filter((entry) => !contents.includes(`new ${entry.etsPackageName}(ctx)`))
|
|
201
|
+
.map((entry) => ` new ${entry.etsPackageName}(ctx),`);
|
|
202
|
+
if (missingFactoryEntries.length > 0) {
|
|
203
|
+
contents = contents.replace(/return \[\n/, `return [\n${missingFactoryEntries.join('\n')}\n`);
|
|
204
|
+
}
|
|
205
|
+
return contents;
|
|
206
|
+
}
|
|
207
|
+
async function normalizeAutolinkingCppFactoryContents(projectRoot, contents) {
|
|
208
|
+
const gestureHandlerPackageJsonPath = resolveProjectPackageJson(projectRoot, '@react-native-oh-tpl/react-native-gesture-handler');
|
|
209
|
+
if (!gestureHandlerPackageJsonPath) {
|
|
210
|
+
return contents;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const gestureHandlerPackageJson = (await fs_extra_1.default.readJson(gestureHandlerPackageJsonPath));
|
|
214
|
+
if (gestureHandlerPackageJson.harmony?.codegenConfig) {
|
|
215
|
+
return contents;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return contents;
|
|
220
|
+
}
|
|
221
|
+
return contents
|
|
222
|
+
.replace(/#include "ReactNativeOhTplReactNativeGestureHandlerPackage\.h"/, '#include "RnohReactNativeHarmonyGestureHandlerPackage.h"')
|
|
223
|
+
.replace(/\brnoh::ReactNativeOhTplReactNativeGestureHandlerPackage\b/g, 'rnoh::RnohReactNativeHarmonyGestureHandlerPackage');
|
|
224
|
+
}
|
|
225
|
+
function injectManagedAutolinkingIntoCppFactory(contents, entries) {
|
|
226
|
+
if (entries.length === 0) {
|
|
227
|
+
return contents;
|
|
228
|
+
}
|
|
229
|
+
const missingIncludes = entries
|
|
230
|
+
.filter((entry) => !contents.includes(`#include "${entry.cppHeaderName}"`))
|
|
231
|
+
.map((entry) => `#include "${entry.cppHeaderName}"`);
|
|
232
|
+
if (missingIncludes.length > 0) {
|
|
233
|
+
contents = contents.replace('#include "RNOH/Package.h"', `#include "RNOH/Package.h"\n${missingIncludes.join('\n')}`);
|
|
234
|
+
}
|
|
235
|
+
const missingFactoryEntries = entries
|
|
236
|
+
.filter((entry) => !contents.includes(`std::make_shared<rnoh::${entry.cppPackageName}>(ctx)`))
|
|
237
|
+
.map((entry) => ` std::make_shared<rnoh::${entry.cppPackageName}>(ctx),`);
|
|
238
|
+
if (missingFactoryEntries.length > 0) {
|
|
239
|
+
contents = contents.replace(/return \{\n/, `return {\n${missingFactoryEntries.join('\n')}\n`);
|
|
240
|
+
}
|
|
241
|
+
return contents;
|
|
242
|
+
}
|
|
243
|
+
function injectManagedAutolinkingIntoCmake(contents, entries) {
|
|
244
|
+
if (entries.length === 0) {
|
|
245
|
+
return contents;
|
|
246
|
+
}
|
|
247
|
+
const missingSubdirectories = entries
|
|
248
|
+
.filter((entry) => !contents.includes(`./${entry.cmakeTargetName}`))
|
|
249
|
+
.map((entry) => ` add_subdirectory("\${OH_MODULES_DIR}/${entry.adapterPackageName}/src/main/cpp" ./${entry.cmakeTargetName})`);
|
|
250
|
+
if (missingSubdirectories.length > 0) {
|
|
251
|
+
contents = contents.replace(/function\(autolink_libraries target\)\n/, `function(autolink_libraries target)\n${missingSubdirectories.join('\n')}\n`);
|
|
252
|
+
}
|
|
253
|
+
const missingLibraryTargets = entries
|
|
254
|
+
.filter((entry) => !contents.includes(` ${entry.cmakeTargetName}`))
|
|
255
|
+
.map((entry) => ` ${entry.cmakeTargetName}`);
|
|
256
|
+
if (missingLibraryTargets.length > 0) {
|
|
257
|
+
contents = contents.replace(/set\(AUTOLINKED_LIBRARIES\n/, `set(AUTOLINKED_LIBRARIES\n${missingLibraryTargets.join('\n')}\n`);
|
|
258
|
+
}
|
|
259
|
+
return contents;
|
|
260
|
+
}
|
|
261
|
+
async function runRnohLinkHarmonyCommand(projectRoot, rnohCliPackageJsonPath, harmonyProjectPath, commandDescription) {
|
|
262
|
+
const rnohCliRoot = path_1.default.dirname(rnohCliPackageJsonPath);
|
|
263
|
+
let commandLinkHarmony;
|
|
264
|
+
try {
|
|
265
|
+
({ commandLinkHarmony } = require(path_1.default.join(rnohCliRoot, 'dist', 'commands', 'link-harmony.js')));
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
throw new AutolinkingFailureError('load-link-harmony', commandDescription, {
|
|
269
|
+
cause: getErrorMessage(error),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
await commandLinkHarmony.func([], {}, {
|
|
274
|
+
harmonyProjectPath,
|
|
275
|
+
nodeModulesPath: path_1.default.join(projectRoot, 'node_modules'),
|
|
276
|
+
cmakeAutolinkPathRelativeToHarmony: './entry/src/main/cpp/autolinking.cmake',
|
|
277
|
+
cppRnohPackagesFactoryPathRelativeToHarmony: './entry/src/main/cpp/RNOHPackagesFactory.h',
|
|
278
|
+
etsRnohPackagesFactoryPathRelativeToHarmony: './entry/src/main/ets/RNOHPackagesFactory.ets',
|
|
279
|
+
ohPackagePathRelativeToHarmony: './oh-package.json5',
|
|
280
|
+
includeNpmPackages: uiStack_1.UI_STACK_ADAPTER_PACKAGE_NAMES,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
throw new AutolinkingFailureError('link-harmony', commandDescription, {
|
|
285
|
+
cause: getErrorMessage(error),
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function buildRnohLinkHarmonyCommand(projectRoot, harmonyProjectPath) {
|
|
290
|
+
return [
|
|
291
|
+
'link-harmony',
|
|
292
|
+
`--harmonyProjectPath ${harmonyProjectPath}`,
|
|
293
|
+
`--nodeModulesPath ${path_1.default.join(projectRoot, 'node_modules')}`,
|
|
294
|
+
'--cmakeAutolinkPathRelativeToHarmony ./entry/src/main/cpp/autolinking.cmake',
|
|
295
|
+
'--cppRnohPackagesFactoryPathRelativeToHarmony ./entry/src/main/cpp/RNOHPackagesFactory.h',
|
|
296
|
+
'--etsRnohPackagesFactoryPathRelativeToHarmony ./entry/src/main/ets/RNOHPackagesFactory.ets',
|
|
297
|
+
'--ohPackagePathRelativeToHarmony ./oh-package.json5',
|
|
298
|
+
].join(' ');
|
|
299
|
+
}
|
|
300
|
+
async function assertGeneratedAutolinkingFilesExist(harmonyProjectPath, commandDescription) {
|
|
301
|
+
const requiredFiles = [
|
|
302
|
+
path_1.default.join(harmonyProjectPath, 'entry', 'src', 'main', 'ets', 'RNOHPackagesFactory.ets'),
|
|
303
|
+
path_1.default.join(harmonyProjectPath, 'entry', 'src', 'main', 'cpp', 'RNOHPackagesFactory.h'),
|
|
304
|
+
path_1.default.join(harmonyProjectPath, 'entry', 'src', 'main', 'cpp', 'autolinking.cmake'),
|
|
305
|
+
];
|
|
306
|
+
const missingFiles = requiredFiles.filter((filePath) => !fs_extra_1.default.existsSync(filePath));
|
|
307
|
+
if (missingFiles.length > 0) {
|
|
308
|
+
throw new AutolinkingFailureError('validate-generated-files', commandDescription, {
|
|
309
|
+
missingFiles: missingFiles.map((filePath) => path_1.default.relative(harmonyProjectPath, filePath)),
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
async function buildManagedHarmonyRootPackageContents(projectRoot, harmonyRootPackageContents) {
|
|
314
|
+
const parsedPackageJson = json5_1.default.parse(harmonyRootPackageContents);
|
|
315
|
+
const dependencies = {
|
|
316
|
+
...(parsedPackageJson.dependencies ?? {}),
|
|
317
|
+
...(await readPreservedHarmonyRootDependencies(projectRoot)),
|
|
318
|
+
};
|
|
319
|
+
for (const adapter of uiStack_1.UI_STACK_VALIDATED_ADAPTERS) {
|
|
320
|
+
const dependencySpecifier = await resolveHarmonyAdapterHarDependency(projectRoot, adapter.adapterPackageName);
|
|
321
|
+
if (dependencySpecifier) {
|
|
322
|
+
dependencies[adapter.adapterPackageName] = dependencySpecifier;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
parsedPackageJson.dependencies = sortRecordByKey(dependencies);
|
|
326
|
+
return json5_1.default.stringify(parsedPackageJson, null, 2) + '\n';
|
|
327
|
+
}
|
|
328
|
+
async function readPreservedHarmonyRootDependencies(projectRoot) {
|
|
329
|
+
const harmonyRootPackagePath = path_1.default.join(projectRoot, 'harmony', 'oh-package.json5');
|
|
330
|
+
if (!(await fs_extra_1.default.pathExists(harmonyRootPackagePath))) {
|
|
331
|
+
return {};
|
|
332
|
+
}
|
|
333
|
+
const currentHarmonyRootPackage = json5_1.default.parse(await fs_extra_1.default.readFile(harmonyRootPackagePath, 'utf8'));
|
|
334
|
+
const preservedDependencies = {};
|
|
335
|
+
const validatedAdapterPackageNames = new Set(uiStack_1.UI_STACK_ADAPTER_PACKAGE_NAMES);
|
|
336
|
+
for (const [packageName, specifier] of Object.entries(currentHarmonyRootPackage.dependencies ?? {})) {
|
|
337
|
+
if (typeof specifier !== 'string') {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (validatedAdapterPackageNames.has(packageName)) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
preservedDependencies[packageName] = specifier;
|
|
344
|
+
}
|
|
345
|
+
return preservedDependencies;
|
|
346
|
+
}
|
|
347
|
+
async function resolveHarmonyAdapterHarDependency(projectRoot, adapterPackageName) {
|
|
348
|
+
const adapterEntry = uiStack_1.UI_STACK_VALIDATED_ADAPTERS.find((candidate) => candidate.adapterPackageName === adapterPackageName);
|
|
349
|
+
if (!adapterEntry) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
const adapterRoot = path_1.default.join(projectRoot, 'node_modules', ...adapterPackageName.split('/'));
|
|
353
|
+
const harPath = path_1.default.join(adapterRoot, 'harmony', adapterEntry.harmonyHarFileName);
|
|
354
|
+
if (!(await fs_extra_1.default.pathExists(harPath))) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
const relativeHarPath = path_1.default.relative(path_1.default.join(projectRoot, 'harmony'), harPath).replace(/\\/g, '/');
|
|
358
|
+
return `file:${relativeHarPath}`;
|
|
359
|
+
}
|
|
360
|
+
function createEmptyAutolinkingArtifacts(harmonyRootPackageContents, managedAutolinkingEntries) {
|
|
361
|
+
return {
|
|
362
|
+
ohPackageContents: harmonyRootPackageContents,
|
|
363
|
+
etsFactoryContents: injectManagedAutolinkingIntoEtsFactory(`/*
|
|
364
|
+
* This file was generated by Expo Harmony Toolkit autolinking.
|
|
365
|
+
* DO NOT modify it manually, your changes WILL be overwritten.
|
|
366
|
+
*/
|
|
367
|
+
import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony';
|
|
368
|
+
|
|
369
|
+
export function createRNOHPackages(_ctx: RNPackageContext): RNPackage[] {
|
|
370
|
+
return [];
|
|
371
|
+
}
|
|
372
|
+
`, managedAutolinkingEntries),
|
|
373
|
+
cppFactoryContents: injectManagedAutolinkingIntoCppFactory(`/*
|
|
374
|
+
* This file was generated by Expo Harmony Toolkit autolinking.
|
|
375
|
+
* DO NOT modify it manually, your changes WILL be overwritten.
|
|
376
|
+
*/
|
|
377
|
+
#pragma once
|
|
378
|
+
#include "RNOH/Package.h"
|
|
379
|
+
|
|
380
|
+
std::vector<rnoh::Package::Shared> createRNOHPackages(const rnoh::Package::Context &_ctx) {
|
|
381
|
+
return {};
|
|
382
|
+
}
|
|
383
|
+
`, managedAutolinkingEntries),
|
|
384
|
+
cmakeContents: injectManagedAutolinkingIntoCmake(`# This file was generated by Expo Harmony Toolkit autolinking.
|
|
385
|
+
# DO NOT modify it manually, your changes WILL be overwritten.
|
|
386
|
+
cmake_minimum_required(VERSION 3.5)
|
|
387
|
+
|
|
388
|
+
function(autolink_libraries target)
|
|
389
|
+
set(AUTOLINKED_LIBRARIES
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
foreach(lib \${AUTOLINKED_LIBRARIES})
|
|
393
|
+
target_link_libraries(\${target} PUBLIC \${lib})
|
|
394
|
+
endforeach()
|
|
395
|
+
endfunction()
|
|
396
|
+
`, managedAutolinkingEntries),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function resolveProjectPackageJson(projectRoot, request) {
|
|
400
|
+
const directPackageJsonPath = path_1.default.join(projectRoot, 'node_modules', ...request.split('/'), 'package.json');
|
|
401
|
+
if (fs_extra_1.default.existsSync(directPackageJsonPath)) {
|
|
402
|
+
return directPackageJsonPath;
|
|
403
|
+
}
|
|
404
|
+
try {
|
|
405
|
+
return require.resolve(path_1.default.join(request, 'package.json'), {
|
|
406
|
+
paths: [projectRoot],
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function sortRecordByKey(record) {
|
|
414
|
+
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
415
|
+
}
|
|
416
|
+
function escapeRegExp(value) {
|
|
417
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
418
|
+
}
|
|
419
|
+
function getErrorMessage(error) {
|
|
420
|
+
return error instanceof Error ? error.message : String(error);
|
|
421
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { buildEnvReport } from '../env';
|
|
2
|
+
export interface CommandRunnerResult {
|
|
3
|
+
exitCode: number;
|
|
4
|
+
stdout: string;
|
|
5
|
+
stderr: string;
|
|
6
|
+
}
|
|
7
|
+
export type CommandRunner = (file: string, args: string[], options: {
|
|
8
|
+
cwd: string;
|
|
9
|
+
env: NodeJS.ProcessEnv;
|
|
10
|
+
}) => Promise<CommandRunnerResult>;
|
|
11
|
+
export declare function buildInvocation(file: string, args: string[]): {
|
|
12
|
+
file: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
};
|
|
15
|
+
export declare function createHarmonyBuildEnvironment(runtimeEnv: NodeJS.ProcessEnv, envReport: Awaited<ReturnType<typeof buildEnvReport>>): NodeJS.ProcessEnv;
|
|
16
|
+
export declare function defaultCommandRunner(file: string, args: string[], options: {
|
|
17
|
+
cwd: string;
|
|
18
|
+
env: NodeJS.ProcessEnv;
|
|
19
|
+
}): Promise<CommandRunnerResult>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildInvocation = buildInvocation;
|
|
7
|
+
exports.createHarmonyBuildEnvironment = createHarmonyBuildEnvironment;
|
|
8
|
+
exports.defaultCommandRunner = defaultCommandRunner;
|
|
9
|
+
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const node_util_1 = require("node:util");
|
|
12
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
13
|
+
function buildInvocation(file, args) {
|
|
14
|
+
if (file.endsWith('.js')) {
|
|
15
|
+
return {
|
|
16
|
+
file: process.execPath,
|
|
17
|
+
args: [file, ...args],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
file,
|
|
22
|
+
args,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function createHarmonyBuildEnvironment(runtimeEnv, envReport) {
|
|
26
|
+
const buildEnvironment = {
|
|
27
|
+
...runtimeEnv,
|
|
28
|
+
};
|
|
29
|
+
if (envReport.sdkRoot) {
|
|
30
|
+
buildEnvironment.DEVECO_SDK_HOME = envReport.sdkRoot;
|
|
31
|
+
buildEnvironment.OHOS_BASE_SDK_HOME = envReport.sdkRoot;
|
|
32
|
+
}
|
|
33
|
+
if (envReport.devecoStudioPath) {
|
|
34
|
+
buildEnvironment.NODE_HOME =
|
|
35
|
+
buildEnvironment.NODE_HOME ??
|
|
36
|
+
path_1.default.join(envReport.devecoStudioPath, 'Contents', 'tools', 'node');
|
|
37
|
+
}
|
|
38
|
+
return buildEnvironment;
|
|
39
|
+
}
|
|
40
|
+
async function defaultCommandRunner(file, args, options) {
|
|
41
|
+
try {
|
|
42
|
+
const result = await execFileAsync(file, args, {
|
|
43
|
+
cwd: options.cwd,
|
|
44
|
+
env: options.env,
|
|
45
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
exitCode: 0,
|
|
49
|
+
stdout: result.stdout,
|
|
50
|
+
stderr: result.stderr,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
const failed = error;
|
|
55
|
+
return {
|
|
56
|
+
exitCode: typeof failed.code === 'number' ? failed.code : 1,
|
|
57
|
+
stdout: failed.stdout ?? '',
|
|
58
|
+
stderr: failed.stderr ?? failed.message ?? '',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ensureNormalizedLocalHarCompatibilityShims(directoryPath: string, packageName: string): Promise<void>;
|