@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.
Files changed (103) hide show
  1. package/README.md +12 -0
  2. package/bin/expo-harmony-autolinking.ts +14 -0
  3. package/build/bin/expo-harmony-autolinking.d.ts +2 -0
  4. package/build/bin/expo-harmony-autolinking.js +11 -0
  5. package/build/index.d.ts +8 -0
  6. package/build/index.js +15 -0
  7. package/build/src/autolinking/link.d.ts +3 -0
  8. package/build/src/autolinking/link.js +150 -0
  9. package/build/src/autolinking/resolve.d.ts +4 -0
  10. package/build/src/autolinking/resolve.js +25 -0
  11. package/build/src/autolinking/search.d.ts +3 -0
  12. package/build/src/autolinking/search.js +357 -0
  13. package/build/src/autolinking/verify.d.ts +4 -0
  14. package/build/src/autolinking/verify.js +366 -0
  15. package/build/src/commands/autolinkingOptions.d.ts +12 -0
  16. package/build/src/commands/autolinkingOptions.js +35 -0
  17. package/build/src/commands/cli.d.ts +2 -0
  18. package/build/src/commands/cli.js +50 -0
  19. package/build/src/commands/link.d.ts +2 -0
  20. package/build/src/commands/link.js +27 -0
  21. package/build/src/commands/output.d.ts +3 -0
  22. package/build/src/commands/output.js +33 -0
  23. package/build/src/commands/resolve.d.ts +2 -0
  24. package/build/src/commands/resolve.js +13 -0
  25. package/build/src/commands/search.d.ts +2 -0
  26. package/build/src/commands/search.js +13 -0
  27. package/build/src/commands/verify.d.ts +2 -0
  28. package/build/src/commands/verify.js +17 -0
  29. package/build/src/config/constants.d.ts +17 -0
  30. package/build/src/config/constants.js +40 -0
  31. package/build/src/config/options.d.ts +13 -0
  32. package/build/src/config/options.js +202 -0
  33. package/build/src/errors.d.ts +18 -0
  34. package/build/src/errors.js +35 -0
  35. package/build/src/harmony/manifest/generate.d.ts +4 -0
  36. package/build/src/harmony/manifest/generate.js +55 -0
  37. package/build/src/harmony/manifest/index.d.ts +7 -0
  38. package/build/src/harmony/manifest/index.js +64 -0
  39. package/build/src/harmony/materialize.d.ts +12 -0
  40. package/build/src/harmony/materialize.js +278 -0
  41. package/build/src/harmony/ohpm/dependencies.d.ts +7 -0
  42. package/build/src/harmony/ohpm/dependencies.js +52 -0
  43. package/build/src/harmony/persistence/canonicalize.d.ts +15 -0
  44. package/build/src/harmony/persistence/canonicalize.js +108 -0
  45. package/build/src/harmony/providers/host.d.ts +3 -0
  46. package/build/src/harmony/providers/host.js +88 -0
  47. package/build/src/harmony/rnoh/cli.d.ts +2 -0
  48. package/build/src/harmony/rnoh/cli.js +55 -0
  49. package/build/src/harmony/rnoh/link.d.ts +2 -0
  50. package/build/src/harmony/rnoh/link.js +419 -0
  51. package/build/src/harmony/rnoh/packageMetadata.d.ts +12 -0
  52. package/build/src/harmony/rnoh/packageMetadata.js +125 -0
  53. package/build/src/harmony/transaction/previousState.d.ts +15 -0
  54. package/build/src/harmony/transaction/previousState.js +96 -0
  55. package/build/src/harmony/transaction/publish.d.ts +6 -0
  56. package/build/src/harmony/transaction/publish.js +272 -0
  57. package/build/src/harmony/transaction/stageProject.d.ts +18 -0
  58. package/build/src/harmony/transaction/stageProject.js +313 -0
  59. package/build/src/metadata/descriptor.d.ts +19 -0
  60. package/build/src/metadata/descriptor.js +306 -0
  61. package/build/src/metadata/host.d.ts +5 -0
  62. package/build/src/metadata/host.js +37 -0
  63. package/build/src/metadata/schema.d.ts +10 -0
  64. package/build/src/metadata/schema.js +171 -0
  65. package/build/src/types.d.ts +194 -0
  66. package/build/src/types.js +2 -0
  67. package/build/src/utilities/values.d.ts +17 -0
  68. package/build/src/utilities/values.js +205 -0
  69. package/harmony-module.schema.json +28 -0
  70. package/index.ts +41 -0
  71. package/package.json +66 -0
  72. package/src/autolinking/link.ts +170 -0
  73. package/src/autolinking/resolve.ts +33 -0
  74. package/src/autolinking/search.ts +369 -0
  75. package/src/autolinking/verify.ts +415 -0
  76. package/src/commands/autolinkingOptions.ts +38 -0
  77. package/src/commands/cli.ts +56 -0
  78. package/src/commands/link.ts +28 -0
  79. package/src/commands/output.ts +36 -0
  80. package/src/commands/resolve.ts +14 -0
  81. package/src/commands/search.ts +14 -0
  82. package/src/commands/verify.ts +17 -0
  83. package/src/config/constants.ts +45 -0
  84. package/src/config/options.ts +195 -0
  85. package/src/errors.ts +48 -0
  86. package/src/harmony/manifest/generate.ts +65 -0
  87. package/src/harmony/manifest/index.ts +81 -0
  88. package/src/harmony/materialize.ts +382 -0
  89. package/src/harmony/ohpm/dependencies.ts +59 -0
  90. package/src/harmony/persistence/canonicalize.ts +156 -0
  91. package/src/harmony/providers/host.ts +147 -0
  92. package/src/harmony/rnoh/cli.ts +59 -0
  93. package/src/harmony/rnoh/link.ts +481 -0
  94. package/src/harmony/rnoh/packageMetadata.ts +105 -0
  95. package/src/harmony/transaction/previousState.ts +71 -0
  96. package/src/harmony/transaction/publish.ts +287 -0
  97. package/src/harmony/transaction/stageProject.ts +345 -0
  98. package/src/metadata/descriptor.ts +324 -0
  99. package/src/metadata/host.ts +41 -0
  100. package/src/metadata/schema.ts +184 -0
  101. package/src/types.ts +220 -0
  102. package/src/utilities/values.ts +190 -0
  103. 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
+ };