@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,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.materializeLocalSourcesAsync = materializeLocalSourcesAsync;
|
|
37
|
+
exports.materializeModuleArtifactAsync = materializeModuleArtifactAsync;
|
|
38
|
+
const fs = __importStar(require("node:fs"));
|
|
39
|
+
const path = __importStar(require("node:path"));
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const errors_1 = require("../errors");
|
|
42
|
+
const values_1 = require("../utilities/values");
|
|
43
|
+
const publish_1 = require("./transaction/publish");
|
|
44
|
+
const DefaultBuildTimeoutMs = 10 * 60_000;
|
|
45
|
+
const DefaultOutputLimit = 64 * 1024;
|
|
46
|
+
const HarmonyProjectPath = 'harmony';
|
|
47
|
+
const HarmonyBuildOutputPath = 'library/build/default/outputs/default/library.har';
|
|
48
|
+
function materializationError(code, message, options, details) {
|
|
49
|
+
throw new errors_1.HarmonyAutolinkingError(code, message, {
|
|
50
|
+
packageName: options.packageName,
|
|
51
|
+
stage: 'artifact-materialize',
|
|
52
|
+
details,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function createFixedHvigorBuildDescriptor(projectPath, buildType) {
|
|
56
|
+
return {
|
|
57
|
+
executable: 'hvigorw',
|
|
58
|
+
cwd: projectPath,
|
|
59
|
+
args: [
|
|
60
|
+
'--mode', 'module',
|
|
61
|
+
'-p', 'module=library@default',
|
|
62
|
+
'-p', 'product=default',
|
|
63
|
+
'-p', `buildMode=${buildType}`,
|
|
64
|
+
'--no-daemon',
|
|
65
|
+
'assembleHar',
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function isNonEmptyRegularHarAsync(harPath, allowedRoot, packageName) {
|
|
70
|
+
const root = path.resolve(allowedRoot);
|
|
71
|
+
const target = path.resolve(harPath);
|
|
72
|
+
if (!(0, values_1.isPathInside)(root, target)) {
|
|
73
|
+
throw new errors_1.HarmonyAutolinkingError('UNSAFE_SOURCE_ARTIFACT', 'Harmony HAR path must stay inside its expected package or project root.', { packageName, stage: 'artifact-materialize' });
|
|
74
|
+
}
|
|
75
|
+
let stat;
|
|
76
|
+
try {
|
|
77
|
+
stat = await fs.promises.lstat(target);
|
|
78
|
+
}
|
|
79
|
+
catch (cause) {
|
|
80
|
+
if (cause.code === 'ENOENT')
|
|
81
|
+
return false;
|
|
82
|
+
throw new errors_1.HarmonyAutolinkingError('UNSAFE_SOURCE_ARTIFACT', 'Harmony HAR could not be checked safely.', { cause, packageName, stage: 'artifact-materialize' });
|
|
83
|
+
}
|
|
84
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
85
|
+
throw new errors_1.HarmonyAutolinkingError('UNSAFE_SOURCE_ARTIFACT', 'Harmony HAR must be a regular non-symlink file.', { packageName, stage: 'artifact-materialize' });
|
|
86
|
+
}
|
|
87
|
+
const [realRoot, realTarget] = await Promise.all([
|
|
88
|
+
fs.promises.realpath(root),
|
|
89
|
+
fs.promises.realpath(target),
|
|
90
|
+
]);
|
|
91
|
+
if (!(0, values_1.isPathInside)(realRoot, realTarget)) {
|
|
92
|
+
throw new errors_1.HarmonyAutolinkingError('UNSAFE_SOURCE_ARTIFACT', 'Harmony HAR resolves outside its expected package or project root.', { packageName, stage: 'artifact-materialize' });
|
|
93
|
+
}
|
|
94
|
+
return stat.size > 0;
|
|
95
|
+
}
|
|
96
|
+
async function validateBundledArtifactsAsync(options) {
|
|
97
|
+
const harPaths = [...new Set([
|
|
98
|
+
...options.rnoh.harPaths,
|
|
99
|
+
...(options.arkTs ? [options.arkTs.harPath] : []),
|
|
100
|
+
])].sort(values_1.compareText);
|
|
101
|
+
for (const relative of harPaths) {
|
|
102
|
+
const harPath = path.resolve(options.packageRoot, relative);
|
|
103
|
+
if (!await isNonEmptyRegularHarAsync(harPath, options.packageRoot, options.packageName)) {
|
|
104
|
+
materializationError('SOURCE_ARTIFACT_NOT_PUBLISHED', `${options.packageName} has a missing or empty Harmony HAR.`, options, { harPath: relative });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { kind: 'bundled', harPaths };
|
|
108
|
+
}
|
|
109
|
+
async function materializeModuleArtifactAsync(options) {
|
|
110
|
+
const localArkTs = options.source === 'nativeModulesDir' && options.arkTs;
|
|
111
|
+
if (!localArkTs && (options.rnoh.harPaths.length > 0
|
|
112
|
+
|| options.arkTs)) {
|
|
113
|
+
return validateBundledArtifactsAsync(options);
|
|
114
|
+
}
|
|
115
|
+
if (!localArkTs) {
|
|
116
|
+
return { kind: 'bundled', harPaths: [] };
|
|
117
|
+
}
|
|
118
|
+
const packageRoot = await fs.promises.realpath(options.packageRoot);
|
|
119
|
+
const sourceRoot = await (0, values_1.resolveInsideAsync)(packageRoot, HarmonyProjectPath, 'Harmony source project', {
|
|
120
|
+
packageName: options.packageName,
|
|
121
|
+
type: 'directory',
|
|
122
|
+
});
|
|
123
|
+
const outputPath = await (0, values_1.resolveInsideAsync)(sourceRoot, HarmonyBuildOutputPath, 'Harmony build output', {
|
|
124
|
+
packageName: options.packageName,
|
|
125
|
+
mustExist: false,
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
kind: 'local-source',
|
|
129
|
+
outputPath,
|
|
130
|
+
materialized: false,
|
|
131
|
+
build: createFixedHvigorBuildDescriptor(sourceRoot, options.buildType),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function appendBounded(current, chunk, limit) {
|
|
135
|
+
if (current.length >= limit)
|
|
136
|
+
return current;
|
|
137
|
+
return current + chunk.toString('utf8').slice(0, limit - current.length);
|
|
138
|
+
}
|
|
139
|
+
function fixedLocalSourceBuildSteps(build) {
|
|
140
|
+
return [
|
|
141
|
+
{
|
|
142
|
+
id: 'ohpm-install',
|
|
143
|
+
label: 'OHPM dependency install',
|
|
144
|
+
executable: 'ohpm',
|
|
145
|
+
cwd: build.cwd,
|
|
146
|
+
args: ['install', '--all'],
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 'hvigor-build',
|
|
150
|
+
label: 'Hvigor build',
|
|
151
|
+
...build,
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
function resolveFixedBuildStep(step, env) {
|
|
156
|
+
if (step.id === 'ohpm-install') {
|
|
157
|
+
return env.HARMONY_OHPM ? { ...step, executable: env.HARMONY_OHPM } : step;
|
|
158
|
+
}
|
|
159
|
+
const configured = env.HARMONY_HVIGORW;
|
|
160
|
+
if (configured) {
|
|
161
|
+
return /\.(?:c|m)?js$/iu.test(configured)
|
|
162
|
+
? { ...step, executable: env.HARMONY_NODE || process.execPath, args: [configured, ...step.args] }
|
|
163
|
+
: { ...step, executable: configured };
|
|
164
|
+
}
|
|
165
|
+
return step;
|
|
166
|
+
}
|
|
167
|
+
async function runFixedBuildStepAsync(step, packageName, options) {
|
|
168
|
+
const timeoutMs = options.timeoutMs ?? DefaultBuildTimeoutMs;
|
|
169
|
+
const outputLimit = options.outputLimit ?? DefaultOutputLimit;
|
|
170
|
+
const stage = `artifact-materialize:${step.id}`;
|
|
171
|
+
const env = { ...process.env, ...options.env };
|
|
172
|
+
const resolvedStep = resolveFixedBuildStep(step, env);
|
|
173
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0
|
|
174
|
+
|| !Number.isInteger(outputLimit) || outputLimit <= 0) {
|
|
175
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_OPTIONS', 'timeoutMs and outputLimit must be positive integers.', { packageName, stage });
|
|
176
|
+
}
|
|
177
|
+
const result = await new Promise((resolve, reject) => {
|
|
178
|
+
let output = '';
|
|
179
|
+
let timedOut = false;
|
|
180
|
+
let settled = false;
|
|
181
|
+
let killTimer;
|
|
182
|
+
let child;
|
|
183
|
+
try {
|
|
184
|
+
child = (0, node_child_process_1.spawn)(resolvedStep.executable, [...resolvedStep.args], {
|
|
185
|
+
cwd: step.cwd,
|
|
186
|
+
env,
|
|
187
|
+
shell: false,
|
|
188
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (cause) {
|
|
192
|
+
reject(cause);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
child.stdout.on('data', (chunk) => {
|
|
196
|
+
output = appendBounded(output, chunk, outputLimit);
|
|
197
|
+
});
|
|
198
|
+
child.stderr.on('data', (chunk) => {
|
|
199
|
+
output = appendBounded(output, chunk, outputLimit);
|
|
200
|
+
});
|
|
201
|
+
const timeout = setTimeout(() => {
|
|
202
|
+
timedOut = true;
|
|
203
|
+
child.kill('SIGTERM');
|
|
204
|
+
killTimer = setTimeout(() => child.kill('SIGKILL'), 1_000);
|
|
205
|
+
killTimer.unref?.();
|
|
206
|
+
}, timeoutMs);
|
|
207
|
+
timeout.unref?.();
|
|
208
|
+
child.on('error', (cause) => {
|
|
209
|
+
if (settled)
|
|
210
|
+
return;
|
|
211
|
+
settled = true;
|
|
212
|
+
clearTimeout(timeout);
|
|
213
|
+
if (killTimer)
|
|
214
|
+
clearTimeout(killTimer);
|
|
215
|
+
reject(cause);
|
|
216
|
+
});
|
|
217
|
+
child.on('close', (code, signal) => {
|
|
218
|
+
if (settled)
|
|
219
|
+
return;
|
|
220
|
+
settled = true;
|
|
221
|
+
clearTimeout(timeout);
|
|
222
|
+
if (killTimer)
|
|
223
|
+
clearTimeout(killTimer);
|
|
224
|
+
resolve({ code, signal, output, timedOut });
|
|
225
|
+
});
|
|
226
|
+
}).catch((cause) => {
|
|
227
|
+
throw new errors_1.HarmonyAutolinkingError('SOURCE_BUILD_FAILED', `Unable to execute the fixed ${step.label} for local Harmony source at ${step.cwd}.`, { cause, packageName, stage });
|
|
228
|
+
});
|
|
229
|
+
if (result.code !== 0 || result.signal || result.timedOut) {
|
|
230
|
+
const reason = result.timedOut
|
|
231
|
+
? 'timed out'
|
|
232
|
+
: result.signal ? `was terminated by ${result.signal}` : `exited with code ${result.code}`;
|
|
233
|
+
const output = (0, values_1.sanitizeOutput)(result.output, [step.cwd], outputLimit);
|
|
234
|
+
throw new errors_1.HarmonyAutolinkingError('SOURCE_BUILD_FAILED', `Fixed ${step.label} ${reason}${output ? `: ${output}` : '.'}`, { packageName, stage });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async function materializeLocalSourceAsync(options) {
|
|
238
|
+
const module = options.module;
|
|
239
|
+
if (module.source !== 'nativeModulesDir' || module.artifact.kind !== 'local-source') {
|
|
240
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_OPTIONS', `${module.packageName} is not a nativeModulesDir local-source module.`, { packageName: module.packageName, stage: 'artifact-materialize' });
|
|
241
|
+
}
|
|
242
|
+
const artifact = module.artifact;
|
|
243
|
+
const projectRoot = await fs.promises.realpath(options.projectRoot);
|
|
244
|
+
const packageRoot = await fs.promises.realpath(module.packageRoot);
|
|
245
|
+
if (!(0, values_1.isPathInside)(projectRoot, packageRoot)) {
|
|
246
|
+
throw new errors_1.HarmonyAutolinkingError('UNSAFE_SOURCE_ARTIFACT', 'Harmony local modules must live inside the application project root.', { packageName: module.packageName, stage: 'artifact-materialize' });
|
|
247
|
+
}
|
|
248
|
+
if (!module.arkTs) {
|
|
249
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_METADATA', `${module.packageName} local-source descriptor has no derived ArkTS package.`, { packageName: module.packageName, stage: 'artifact-materialize' });
|
|
250
|
+
}
|
|
251
|
+
const harPath = await (0, values_1.resolveInsideAsync)(packageRoot, module.arkTs.harPath, 'Harmony materialized HAR path', { packageName: module.packageName, mustExist: false });
|
|
252
|
+
for (const step of fixedLocalSourceBuildSteps(artifact.build)) {
|
|
253
|
+
await runFixedBuildStepAsync(step, module.packageName, options);
|
|
254
|
+
}
|
|
255
|
+
const outputReady = await isNonEmptyRegularHarAsync(artifact.outputPath, artifact.build.cwd, module.packageName);
|
|
256
|
+
if (!outputReady) {
|
|
257
|
+
throw new errors_1.HarmonyAutolinkingError('SOURCE_BUILD_FAILED', `Hvigor did not produce a non-empty HAR at ${(0, values_1.normalizeSlashes)(path.relative(packageRoot, artifact.outputPath))}.`, { packageName: module.packageName, stage: 'artifact-materialize' });
|
|
258
|
+
}
|
|
259
|
+
await (0, publish_1.publishArtifactsAsync)({
|
|
260
|
+
allowedRoot: projectRoot,
|
|
261
|
+
lockPath: path.join(projectRoot, '.expo/harmony/module-materialize.lock'),
|
|
262
|
+
files: [{ source: artifact.outputPath, target: harPath }],
|
|
263
|
+
});
|
|
264
|
+
if (!await isNonEmptyRegularHarAsync(harPath, packageRoot, module.packageName)) {
|
|
265
|
+
throw new errors_1.HarmonyAutolinkingError('SOURCE_BUILD_FAILED', 'Harmony HAR materialization produced a missing or empty file.', { packageName: module.packageName, stage: 'artifact-materialize' });
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
packageName: module.packageName,
|
|
269
|
+
harPath,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
async function materializeLocalSourcesAsync(modules, options) {
|
|
273
|
+
const results = [];
|
|
274
|
+
for (const module of [...modules].sort((left, right) => (0, values_1.compareText)(left.packageName, right.packageName))) {
|
|
275
|
+
results.push(await materializeLocalSourceAsync({ ...options, module }));
|
|
276
|
+
}
|
|
277
|
+
return results;
|
|
278
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
declare function collectOhpmDeps(descriptors: any): any[];
|
|
2
|
+
declare function resolveOhpmSpecifier(descriptor: any, mapping: any, options?: {
|
|
3
|
+
harmonyProjectPath?: string;
|
|
4
|
+
nodeModulesPath?: string;
|
|
5
|
+
}): any;
|
|
6
|
+
declare function normalizeLocalOhpmSpecifier(specifier: any): any;
|
|
7
|
+
export { collectOhpmDeps, resolveOhpmSpecifier, normalizeLocalOhpmSpecifier, };
|
|
@@ -0,0 +1,52 @@
|
|
|
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.collectOhpmDeps = collectOhpmDeps;
|
|
7
|
+
exports.resolveOhpmSpecifier = resolveOhpmSpecifier;
|
|
8
|
+
exports.normalizeLocalOhpmSpecifier = normalizeLocalOhpmSpecifier;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const packageMetadata_1 = require("../rnoh/packageMetadata");
|
|
11
|
+
const values_1 = require("../../utilities/values");
|
|
12
|
+
function collectOhpmDeps(descriptors) {
|
|
13
|
+
const dependencies = new Map();
|
|
14
|
+
for (const descriptor of descriptors) {
|
|
15
|
+
if (!descriptor.arkTs)
|
|
16
|
+
continue;
|
|
17
|
+
dependencies.set(descriptor.arkTs.ohPackageName, {
|
|
18
|
+
descriptor,
|
|
19
|
+
mapping: {
|
|
20
|
+
harPath: descriptor.arkTs.harPath,
|
|
21
|
+
ohPackageName: descriptor.arkTs.ohPackageName,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
for (const descriptor of descriptors.filter(item => item.rnoh.harPaths.length > 0)) {
|
|
26
|
+
for (const mapping of (0, packageMetadata_1.resolveRnohMetadata)(descriptor).harMappings) {
|
|
27
|
+
dependencies.set(mapping.ohPackageName, { descriptor, mapping });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return [...dependencies.values()].sort((left, right) => {
|
|
31
|
+
return left.mapping.ohPackageName.localeCompare(right.mapping.ohPackageName, 'en');
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function resolveOhpmSpecifier(descriptor, mapping, options = {}) {
|
|
35
|
+
if (options.harmonyProjectPath) {
|
|
36
|
+
const packageRoot = options.nodeModulesPath
|
|
37
|
+
? node_path_1.default.join(options.nodeModulesPath, ...descriptor.packageName.split('/'))
|
|
38
|
+
: descriptor.packageLinkPath;
|
|
39
|
+
const target = node_path_1.default.join(packageRoot, ...mapping.harPath.split('/'));
|
|
40
|
+
const relative = (0, values_1.normalizeSlashes)(node_path_1.default.relative(options.harmonyProjectPath, target));
|
|
41
|
+
return relative.startsWith('.') ? relative : `./${relative}`;
|
|
42
|
+
}
|
|
43
|
+
return mapping.version || descriptor.packageVersion;
|
|
44
|
+
}
|
|
45
|
+
function normalizeLocalOhpmSpecifier(specifier) {
|
|
46
|
+
if (typeof specifier !== 'string' || !specifier)
|
|
47
|
+
return null;
|
|
48
|
+
if (node_path_1.default.isAbsolute(specifier) || node_path_1.default.win32.isAbsolute(specifier) || !/^\.\.?[\\/]/u.test(specifier)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return (0, values_1.normalizeSlashes)(specifier);
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CanonicalizeAutolinkingArtifactsOptions, CanonicalizedAutolinkingArtifacts, Manifest } from '../../types';
|
|
2
|
+
interface CanonicalizeOhpmManifestOptions {
|
|
3
|
+
previousManagedOhpmPackageNames?: ReadonlyArray<string>;
|
|
4
|
+
requireManagedEntries?: boolean;
|
|
5
|
+
harmonyProjectPath?: string;
|
|
6
|
+
nodeModulesPath?: string;
|
|
7
|
+
errorCode?: string;
|
|
8
|
+
stage?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function canonicalizeOhpmManifest(source: string, manifest: Manifest, options?: CanonicalizeOhpmManifestOptions): {
|
|
11
|
+
manifest: Readonly<Record<string, unknown>>;
|
|
12
|
+
source: string;
|
|
13
|
+
};
|
|
14
|
+
declare function canonicalizeAutolinkingArtifacts(options: CanonicalizeAutolinkingArtifactsOptions): CanonicalizedAutolinkingArtifacts;
|
|
15
|
+
export { canonicalizeAutolinkingArtifacts, canonicalizeOhpmManifest, };
|
|
@@ -0,0 +1,108 @@
|
|
|
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.canonicalizeAutolinkingArtifacts = canonicalizeAutolinkingArtifacts;
|
|
7
|
+
exports.canonicalizeOhpmManifest = canonicalizeOhpmManifest;
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const json5_1 = __importDefault(require("json5"));
|
|
10
|
+
const errors_1 = require("../../errors");
|
|
11
|
+
const manifest_1 = require("../manifest");
|
|
12
|
+
const values_1 = require("../../utilities/values");
|
|
13
|
+
function requireProjectRoot(value, field) {
|
|
14
|
+
if (typeof value !== 'string' || !node_path_1.default.isAbsolute(value)) {
|
|
15
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_OPTIONS', `${field} must be an absolute path.`, { stage: 'canonicalization' });
|
|
16
|
+
}
|
|
17
|
+
return node_path_1.default.resolve(value);
|
|
18
|
+
}
|
|
19
|
+
function rebaseProjectPath(value, fromRoot, toRoot) {
|
|
20
|
+
if (!node_path_1.default.isAbsolute(value) || !(0, values_1.isPathInside)(fromRoot, value))
|
|
21
|
+
return value;
|
|
22
|
+
return node_path_1.default.join(toRoot, node_path_1.default.relative(fromRoot, value));
|
|
23
|
+
}
|
|
24
|
+
function canonicalizeAutolinkingManifest(manifest, options) {
|
|
25
|
+
const generatedProjectRoot = requireProjectRoot(options.generatedProjectRoot, 'generatedProjectRoot');
|
|
26
|
+
const canonicalProjectRoot = requireProjectRoot(options.canonicalProjectRoot, 'canonicalProjectRoot');
|
|
27
|
+
const validated = (0, manifest_1.validateManifest)(manifest);
|
|
28
|
+
const canonical = {
|
|
29
|
+
...validated,
|
|
30
|
+
modules: validated.modules.map(module => ({
|
|
31
|
+
...module,
|
|
32
|
+
packageRoot: rebaseProjectPath(module.packageRoot, generatedProjectRoot, canonicalProjectRoot),
|
|
33
|
+
packageLinkPath: rebaseProjectPath(module.packageLinkPath, generatedProjectRoot, canonicalProjectRoot),
|
|
34
|
+
})),
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
manifest: canonical,
|
|
38
|
+
source: (0, values_1.stringifyJson)(canonical),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function canonicalizeOhpmManifest(source, manifest, options = {}) {
|
|
42
|
+
const errorCode = options.errorCode || 'INVALID_OPTIONS';
|
|
43
|
+
const stage = options.stage || 'canonicalization';
|
|
44
|
+
let candidate;
|
|
45
|
+
try {
|
|
46
|
+
candidate = json5_1.default.parse(source);
|
|
47
|
+
}
|
|
48
|
+
catch (cause) {
|
|
49
|
+
throw new errors_1.HarmonyAutolinkingError(errorCode, 'harmony/oh-package.json5 must contain a JSON5 object.', { cause, stage });
|
|
50
|
+
}
|
|
51
|
+
if (!(0, values_1.isObject)(candidate)) {
|
|
52
|
+
throw new errors_1.HarmonyAutolinkingError(errorCode, 'harmony/oh-package.json5 must contain a JSON5 object.', { stage });
|
|
53
|
+
}
|
|
54
|
+
for (const field of ['dependencies', 'overrides']) {
|
|
55
|
+
if (candidate[field] !== undefined && !(0, values_1.isObject)(candidate[field])) {
|
|
56
|
+
throw new errors_1.HarmonyAutolinkingError(errorCode, `harmony/oh-package.json5 ${field} must be an object.`, { stage });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const specifiers = (0, manifest_1.ohpmDependenciesFromManifest)(manifest, {
|
|
60
|
+
harmonyProjectPath: options.harmonyProjectPath,
|
|
61
|
+
nodeModulesPath: options.nodeModulesPath,
|
|
62
|
+
});
|
|
63
|
+
const currentNames = Object.keys(specifiers).sort((left, right) => left.localeCompare(right, 'en'));
|
|
64
|
+
const managedNames = new Set([
|
|
65
|
+
...(options.previousManagedOhpmPackageNames || []),
|
|
66
|
+
...currentNames,
|
|
67
|
+
]);
|
|
68
|
+
if (options.requireManagedEntries) {
|
|
69
|
+
for (const field of ['dependencies', 'overrides']) {
|
|
70
|
+
if (!(0, values_1.isObject)(candidate[field])) {
|
|
71
|
+
throw new errors_1.HarmonyAutolinkingError(errorCode, `harmony/oh-package.json5 ${field} must be an object.`, { stage });
|
|
72
|
+
}
|
|
73
|
+
for (const packageName of currentNames) {
|
|
74
|
+
if (!Object.hasOwn(candidate[field], packageName)) {
|
|
75
|
+
throw new errors_1.HarmonyAutolinkingError(errorCode, `RNOH omitted the managed ${field} entry for ${packageName}.`, { stage, details: { packageName, field } });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const field of ['dependencies', 'overrides']) {
|
|
81
|
+
const values = { ...(candidate[field] || {}) };
|
|
82
|
+
for (const packageName of managedNames)
|
|
83
|
+
delete values[packageName];
|
|
84
|
+
for (const packageName of currentNames)
|
|
85
|
+
values[packageName] = specifiers[packageName];
|
|
86
|
+
candidate[field] = values;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
manifest: candidate,
|
|
90
|
+
source: `${json5_1.default.stringify(candidate, null, 2)}\n`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function canonicalizeAutolinkingArtifacts(options) {
|
|
94
|
+
let parsedManifest;
|
|
95
|
+
try {
|
|
96
|
+
parsedManifest = JSON.parse(options.manifestSource);
|
|
97
|
+
}
|
|
98
|
+
catch (cause) {
|
|
99
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_MANIFEST', 'Harmony autolinking manifest must contain valid JSON.', { cause, stage: 'canonicalization' });
|
|
100
|
+
}
|
|
101
|
+
const canonicalManifest = canonicalizeAutolinkingManifest(parsedManifest, options);
|
|
102
|
+
const canonicalOhpm = canonicalizeOhpmManifest(options.ohPackageSource, canonicalManifest.manifest, { requireManagedEntries: true, harmonyProjectPath: options.harmonyProjectPath });
|
|
103
|
+
return {
|
|
104
|
+
manifest: canonicalManifest.manifest,
|
|
105
|
+
manifestSource: canonicalManifest.source,
|
|
106
|
+
ohPackageSource: canonicalOhpm.source,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.moduleRegistrationId = moduleRegistrationId;
|
|
4
|
+
exports.renderArkTsHostProviderSource = renderArkTsHostProviderSource;
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
const host_1 = require("../../metadata/host");
|
|
7
|
+
function collectHostExtensions(descriptors) {
|
|
8
|
+
const collected = Object.fromEntries(host_1.HostMetadataFields.map(field => [field, []]));
|
|
9
|
+
for (const descriptor of [...descriptors].sort((left, right) => (left.packageName.localeCompare(right.packageName, 'en')))) {
|
|
10
|
+
const declarations = host_1.HostMetadataFields.flatMap(field => descriptor.expo[field] || []);
|
|
11
|
+
if (declarations.length === 0)
|
|
12
|
+
continue;
|
|
13
|
+
const name = descriptor.arkTs?.ohPackageName;
|
|
14
|
+
if (!name) {
|
|
15
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_METADATA', 'Harmony host extension classes must be exported by the module primary HAR.', { packageName: descriptor.packageName, stage: 'generate-host-provider' });
|
|
16
|
+
}
|
|
17
|
+
for (const field of host_1.HostMetadataFields) {
|
|
18
|
+
for (const className of descriptor.expo[field] || []) {
|
|
19
|
+
collected[field].push({ className, ohPackageName: name, packageName: descriptor.packageName });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return collected;
|
|
24
|
+
}
|
|
25
|
+
function moduleRegistrationId(ohPackageName, moduleClass) {
|
|
26
|
+
return `${ohPackageName}:${moduleClass}`;
|
|
27
|
+
}
|
|
28
|
+
function collectArkTsModuleRegistrations(descriptors) {
|
|
29
|
+
const registrations = [];
|
|
30
|
+
for (const descriptor of [...descriptors].sort((left, right) => (left.packageName.localeCompare(right.packageName, 'en')))) {
|
|
31
|
+
if (descriptor.harmony.modules.length === 0)
|
|
32
|
+
continue;
|
|
33
|
+
const arkTs = descriptor.arkTs;
|
|
34
|
+
if (!arkTs) {
|
|
35
|
+
throw new errors_1.HarmonyAutolinkingError('INVALID_METADATA', 'Harmony ArkTS modules require the conventional Harmony library package.', { packageName: descriptor.packageName, stage: 'generate-host-provider' });
|
|
36
|
+
}
|
|
37
|
+
for (const moduleClass of descriptor.harmony.modules) {
|
|
38
|
+
registrations.push({
|
|
39
|
+
moduleClass,
|
|
40
|
+
ohPackageName: arkTs.ohPackageName,
|
|
41
|
+
packageName: descriptor.packageName,
|
|
42
|
+
registrationId: moduleRegistrationId(arkTs.ohPackageName, moduleClass),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return registrations;
|
|
47
|
+
}
|
|
48
|
+
function renderArkTsHostProviderSource(descriptors) {
|
|
49
|
+
const extensions = collectHostExtensions(descriptors);
|
|
50
|
+
const registrations = collectArkTsModuleRegistrations(descriptors);
|
|
51
|
+
const imports = new Map();
|
|
52
|
+
for (const field of host_1.HostMetadataFields) {
|
|
53
|
+
for (const extension of extensions[field]) {
|
|
54
|
+
const key = `${extension.ohPackageName}\0${extension.className}`;
|
|
55
|
+
if (!imports.has(key)) {
|
|
56
|
+
imports.set(key, {
|
|
57
|
+
...extension,
|
|
58
|
+
alias: `ExpoHarmonyHostExtension${imports.size}`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
extension.alias = imports.get(key).alias;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const lines = [
|
|
65
|
+
'/**',
|
|
66
|
+
' * Automatically generated by @expo-harmony/expo-modules-autolinking.',
|
|
67
|
+
' */',
|
|
68
|
+
'',
|
|
69
|
+
];
|
|
70
|
+
lines.push(`import { ExpoHarmonyHostState } from '@expo-harmony/expo-modules-core/Autolinking';`, 'import type {', ' ExpoHarmonyHostProvider,', ...(registrations.length > 0 ? [' ExpoModuleContext,'] : []), ' ExpoModuleRegistration,', `} from '@expo-harmony/expo-modules-core/Autolinking';`);
|
|
71
|
+
registrations.forEach((registration, index) => {
|
|
72
|
+
registration.alias = `ExpoHarmonyModule${index}`;
|
|
73
|
+
lines.push(`import { ${registration.moduleClass} as ${registration.alias} } from '${registration.ohPackageName}';`);
|
|
74
|
+
});
|
|
75
|
+
for (const extension of imports.values()) {
|
|
76
|
+
lines.push(`import { ${extension.className} as ${extension.alias} } from '${extension.ohPackageName}';`);
|
|
77
|
+
}
|
|
78
|
+
lines.push('', 'class GeneratedExpoHarmonyHostProvider implements ExpoHarmonyHostProvider {', ' readonly hostState: ExpoHarmonyHostState = new ExpoHarmonyHostState();', '', ' readonly expoModules: ExpoModuleRegistration[] = [');
|
|
79
|
+
for (const registration of registrations) {
|
|
80
|
+
lines.push(' {', ` registrationId: ${JSON.stringify(registration.registrationId)},`, ` moduleClassName: ${JSON.stringify(registration.moduleClass)},`, ` factory: (context: ExpoModuleContext) => new ${registration.alias}(context),`, ' },');
|
|
81
|
+
}
|
|
82
|
+
lines.push(' ];', '}', '', 'export const expoHarmonyHostProvider: ExpoHarmonyHostProvider =', ' new GeneratedExpoHarmonyHostProvider();', '', '@Builder', 'export function ExpoHarmonyRootView(): void {');
|
|
83
|
+
for (const extension of extensions.rootViewComponents) {
|
|
84
|
+
lines.push(` ${extension.alias}()`);
|
|
85
|
+
}
|
|
86
|
+
lines.push('}', '');
|
|
87
|
+
return lines.join('\n');
|
|
88
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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.resolveCliAsync = resolveCliAsync;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const constants_1 = require("../../config/constants");
|
|
10
|
+
const errors_1 = require("../../errors");
|
|
11
|
+
const values_1 = require("../../utilities/values");
|
|
12
|
+
function findPackageJson(projectRoot, packageName) {
|
|
13
|
+
try {
|
|
14
|
+
return (0, values_1.resolvePackageFromProject)(projectRoot, `${packageName}/package.json`);
|
|
15
|
+
}
|
|
16
|
+
catch (cause) {
|
|
17
|
+
throw new errors_1.HarmonyAutolinkingError('RNOH_CLI_NOT_FOUND', `${constants_1.RnohCliPackage} is not installed.`, {
|
|
18
|
+
cause,
|
|
19
|
+
stage: 'rnoh-preflight',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function resolveCliAsync(cliOptions) {
|
|
24
|
+
const projectRoot = await (0, values_1.realpathExistingAsync)(cliOptions.projectRoot, {
|
|
25
|
+
type: 'directory',
|
|
26
|
+
field: 'projectRoot',
|
|
27
|
+
stage: 'rnoh-preflight',
|
|
28
|
+
});
|
|
29
|
+
const raw = cliOptions.rnohCliPackageJsonPath
|
|
30
|
+
|| findPackageJson(projectRoot, constants_1.RnohCliPackage);
|
|
31
|
+
const pkg = await (0, values_1.realpathExistingAsync)(raw, {
|
|
32
|
+
type: 'file',
|
|
33
|
+
code: 'RNOH_CLI_NOT_FOUND',
|
|
34
|
+
field: 'RNOH CLI package.json',
|
|
35
|
+
stage: 'rnoh-preflight',
|
|
36
|
+
});
|
|
37
|
+
const packageJson = await (0, values_1.readJsonAsync)(pkg, 'RNOH_CLI_NOT_FOUND', 'rnoh-preflight');
|
|
38
|
+
if (packageJson.name !== constants_1.RnohCliPackage) {
|
|
39
|
+
throw new errors_1.HarmonyAutolinkingError('RNOH_CLI_NOT_FOUND', `Expected ${constants_1.RnohCliPackage}, found ${String(packageJson.name)}.`, { stage: 'rnoh-preflight' });
|
|
40
|
+
}
|
|
41
|
+
const pluginRoot = node_path_1.default.dirname(pkg);
|
|
42
|
+
const pluginConfig = node_path_1.default.join(pluginRoot, 'react-native.config.js');
|
|
43
|
+
if (!node_fs_1.default.existsSync(pluginConfig)) {
|
|
44
|
+
throw new errors_1.HarmonyAutolinkingError('RNOH_CLI_NOT_FOUND', `${constants_1.RnohCliPackage} does not expose its public React Native CLI plugin config.`, { stage: 'rnoh-preflight' });
|
|
45
|
+
}
|
|
46
|
+
const exec = cliOptions.reactNativeExecutable
|
|
47
|
+
|| node_path_1.default.join(cliOptions.nodeModulesPath || node_path_1.default.join(projectRoot, 'node_modules'), '.bin', 'react-native');
|
|
48
|
+
const executable = await (0, values_1.realpathExistingAsync)(exec, {
|
|
49
|
+
type: 'file',
|
|
50
|
+
code: 'RNOH_CLI_NOT_FOUND',
|
|
51
|
+
field: 'project-local react-native executable',
|
|
52
|
+
stage: 'rnoh-preflight',
|
|
53
|
+
});
|
|
54
|
+
return executable;
|
|
55
|
+
}
|