@react-native-oh/react-native-harmony 0.72.82 → 0.77.18
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/LICENSE +21 -0
- package/LICENSE-Meta +21 -0
- package/Libraries/Alert/delegates/AlertDelegate.harmony.ts +84 -0
- package/Libraries/Alert/{AlertManager.ts → delegates/AlertManager.harmony.ts} +10 -4
- package/Libraries/Animated/shouldUseTurboAnimatedModule.harmony.ts +10 -0
- package/Libraries/Components/AccessibilityInfo/delegates/AccessibilityInfoDelegate.harmony.ts +44 -0
- package/Libraries/Components/AccessibilityInfo/{NativeAccessibilityInfoHarmony.ts → delegates/NativeAccessibilityInfoHarmony.harmony.ts} +9 -2
- package/Libraries/Components/Keyboard/delegates/KeyboardAvoidingViewDelegate.harmony.ts +42 -0
- package/Libraries/Components/RefreshControl/delegates/RefreshControlDelegate.harmony.tsx +29 -0
- package/Libraries/Components/SafeAreaView/SafeAreaView.harmony.tsx +93 -31
- package/Libraries/Components/ScrollView/delegates/ScrollViewDelegate.harmony.tsx +41 -0
- package/Libraries/Components/ScrollView/delegates/ScrollViewNativeComponentDelegate.harmony.ts +89 -0
- package/Libraries/Components/ScrollView/processDecelerationRate.harmony.ts +19 -0
- package/Libraries/Components/StatusBar/delegates/NativeStatusBarManagerHarmony.harmony.ts +53 -0
- package/Libraries/Components/StatusBar/delegates/StatusBarDelegate.harmony.ts +83 -0
- package/Libraries/Components/TextInput/delegates/TextInputDelegate.harmony.tsx +98 -0
- package/Libraries/Components/TextInput/delegates/TextInputStateDelegate.harmony.tsx +20 -0
- package/Libraries/Components/Touchable/delegates/TouchableHighlightDelegate.harmony.ts +14 -0
- package/Libraries/Components/Touchable/delegates/TouchableNativeFeedbackDelegate.harmony.ts +14 -0
- package/Libraries/Components/Touchable/delegates/TouchableWithoutFeedbackDelegate.harmony.ts +14 -0
- package/Libraries/Components/delegates/ButtonDelegate.harmony.ts +41 -0
- package/Libraries/Core/setUpPlatform.harmony.js +30 -0
- package/Libraries/Image/AssetSourceResolver.harmony.ts +75 -29
- package/Libraries/Image/Image.harmony.ts +17 -0
- package/Libraries/NativeComponent/BaseViewConfig.harmony.js +12 -326
- package/Libraries/NativeComponent/delegates/ViewConfigIgnoreDelegate.harmony.ts +13 -0
- package/Libraries/ReactNative/delegates/BridgelessUIManagerDelegate.harmony.ts +14 -0
- package/Libraries/ReactNative/delegates/I18nManagerDelegate.harmony.ts +22 -0
- package/Libraries/Settings/Settings.harmony.ts +20 -0
- package/Libraries/Share/delegates/ShareDelegate.harmony.ts +42 -0
- package/Libraries/StyleSheet/NativePlatformColor.harmony.ts +15 -0
- package/Libraries/StyleSheet/PlatformColorValueTypes.harmony.ts +8 -1
- package/Libraries/Utilities/BackHandler.harmony.ts +10 -0
- package/Libraries/Utilities/NativePlatformConstantsHarmony.harmony.ts +17 -0
- package/Libraries/Utilities/Platform.harmony.ts +38 -13
- package/Libraries/Vibration/delegates/VibrationDelegate.harmony.ts +14 -0
- package/NOTICE.md +846 -0
- package/README.md +2 -2
- package/index.js +53 -63
- package/jest.config.js +0 -7
- package/metro.config.d.ts +17 -0
- package/metro.config.js +398 -115
- package/package.json +58 -37
- package/react-native.config.js +57 -9
- package/react_native_openharmony.har +0 -0
- package/tsconfig.json +10 -4
- package/types/index.harmony.d.ts +99 -0
- package/Libraries/Alert/Alert.harmony.js +0 -77
- package/Libraries/Animated/NativeAnimatedHelper.harmony.js +0 -601
- package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.harmony.js +0 -441
- package/Libraries/Components/Button/Button.harmony.js +0 -451
- package/Libraries/Components/Image/Image.flow.harmony.js +0 -53
- package/Libraries/Components/Image/Image.harmony.js +0 -317
- package/Libraries/Components/Image/NativeImageLoaderHarmony.js +0 -38
- package/Libraries/Components/Keyboard/KeyboardAvoidingView.harmony.js +0 -256
- package/Libraries/Components/RefreshControl/RefreshControl.harmony.js +0 -210
- package/Libraries/Components/ScrollView/ScrollView.harmony.js +0 -1951
- package/Libraries/Components/ScrollView/processDecelerationRate.harmony.js +0 -24
- package/Libraries/Components/StatusBar/NativeStatusBarManagerHarmony.js +0 -71
- package/Libraries/Components/StatusBar/StatusBar.harmony.js +0 -447
- package/Libraries/Components/TextInput/TextInput.harmony.js +0 -1716
- package/Libraries/Components/TextInput/TextInputState.harmony.js +0 -220
- package/Libraries/Components/Touchable/TouchableHighlight.harmony.js +0 -396
- package/Libraries/Components/Touchable/TouchableNativeFeedback.harmony.js +0 -364
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.harmony.js +0 -227
- package/Libraries/Components/View/View.harmony.js +0 -149
- package/Libraries/Core/setUpReactDevTools.harmony.js +0 -93
- package/Libraries/ReactNative/I18nManager.harmony.js +0 -78
- package/Libraries/ReactNative/UIManager.harmony.js +0 -210
- package/Libraries/Settings/Settings.harmony.js +0 -15
- package/Libraries/Share/Share.harmony.js +0 -174
- package/Libraries/StyleSheet/NativePlatformColor.ts +0 -8
- package/Libraries/Utilities/BackHandler.harmony.js +0 -109
- package/Libraries/Utilities/NativePlatformConstants.harmony.ts +0 -8
- package/Libraries/Utilities/Platform.d.ts +0 -117
- package/Libraries/Utilities/createPerformanceLogger.harmony.js +0 -328
- package/Libraries/Vibration/Vibration.harmony.js +0 -88
- package/harmony/.keep +0 -0
- package/harmony/rnoh-hvigor-plugin-0.2.0.tgz +0 -0
- package/react_native_openharmony_release.har +0 -0
- package/types/index.d.ts +0 -108
package/metro.config.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2024 Huawei Technologies Co., Ltd.
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
//@ts-check
|
|
@@ -10,7 +10,8 @@ const pathUtils = require('path');
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const colors = require('colors/safe');
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
const HARMONY_PLATFORM_NAME = 'harmony';
|
|
14
|
+
const RNOH_FALLBACK_PLATFORM_NAME = 'ios';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* @param msg {string}
|
|
@@ -21,12 +22,28 @@ function info(msg) {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
* @
|
|
25
|
+
* @type {string | null}
|
|
26
|
+
*/
|
|
27
|
+
let REQUEST_RESOLUTION_LATEST_PLATFORM = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param options {import("./metro.config").HarmonyMetroConfigOptions}
|
|
25
31
|
* @returns {import("metro-config").InputConfigT}
|
|
26
32
|
*/
|
|
27
33
|
function createHarmonyMetroConfig(options) {
|
|
28
|
-
|
|
34
|
+
/**
|
|
35
|
+
* The default value needs to be changed to @react-native-oh/react-native-harmony but this is a breaking change.
|
|
36
|
+
*/
|
|
37
|
+
const reactNativeHarmonyPackageName =
|
|
29
38
|
options?.reactNativeHarmonyPackageName ?? 'react-native-harmony';
|
|
39
|
+
const reactNativeHarmonyPattern =
|
|
40
|
+
options?.__reactNativeHarmonyPattern ??
|
|
41
|
+
pathUtils.sep +
|
|
42
|
+
reactNativeHarmonyPackageName.replace('/', pathUtils.sep) +
|
|
43
|
+
pathUtils.sep;
|
|
44
|
+
const reactNativeInteropLibraryPackagePattern =
|
|
45
|
+
options?.__reactNativeInteropLibraryPackagePattern;
|
|
46
|
+
|
|
30
47
|
return {
|
|
31
48
|
transformer: {
|
|
32
49
|
assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry',
|
|
@@ -37,45 +54,149 @@ function createHarmonyMetroConfig(options) {
|
|
|
37
54
|
},
|
|
38
55
|
}),
|
|
39
56
|
},
|
|
57
|
+
serializer: {
|
|
58
|
+
getModulesRunBeforeMainModule: () => {
|
|
59
|
+
if (REQUEST_RESOLUTION_LATEST_PLATFORM !== 'harmony') {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return [require.resolve('./Libraries/Core/InitializeCore')];
|
|
63
|
+
},
|
|
64
|
+
},
|
|
40
65
|
resolver: {
|
|
41
|
-
blockList: [/
|
|
66
|
+
blockList: [/\.cxx/],
|
|
42
67
|
resolveRequest: (ctx, moduleName, platform) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
68
|
+
REQUEST_RESOLUTION_LATEST_PLATFORM = platform;
|
|
69
|
+
const nodeModulesPaths = [
|
|
70
|
+
pathUtils.resolve('node_modules'),
|
|
71
|
+
...(ctx.nodeModulesPaths ?? []),
|
|
72
|
+
];
|
|
73
|
+
if (platform === HARMONY_PLATFORM_NAME) {
|
|
74
|
+
if (
|
|
75
|
+
moduleName === 'react-native' ||
|
|
76
|
+
moduleName.startsWith(`react-native/`)
|
|
77
|
+
) {
|
|
78
|
+
/**
|
|
79
|
+
* Importing from `react-native` when preparing offline bundle.
|
|
80
|
+
* For some reason there's a difference in behavior when a bundle is provided via Metro server and when creating an offline bundle.
|
|
81
|
+
*/
|
|
82
|
+
const newModuleName = moduleName.replace(
|
|
83
|
+
'react-native',
|
|
84
|
+
reactNativeHarmonyPackageName
|
|
49
85
|
);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Special case for a library which hijacks imports to react-native-harmony.
|
|
88
|
+
*/
|
|
89
|
+
const maybeInteropLibraryResult = resolveIfInteropLibraryRequest(
|
|
90
|
+
ctx,
|
|
91
|
+
newModuleName,
|
|
92
|
+
nodeModulesPaths,
|
|
93
|
+
reactNativeHarmonyPackageName,
|
|
94
|
+
reactNativeInteropLibraryPackagePattern
|
|
95
|
+
);
|
|
96
|
+
if (maybeInteropLibraryResult) {
|
|
97
|
+
return maybeInteropLibraryResult;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return ctx.resolveRequest(
|
|
101
|
+
ctx,
|
|
102
|
+
newModuleName,
|
|
103
|
+
HARMONY_PLATFORM_NAME
|
|
104
|
+
);
|
|
105
|
+
} catch {
|
|
106
|
+
return ctx.resolveRequest(
|
|
107
|
+
ctx,
|
|
108
|
+
newModuleName,
|
|
109
|
+
RNOH_FALLBACK_PLATFORM_NAME
|
|
110
|
+
);
|
|
111
|
+
}
|
|
56
112
|
} else if (
|
|
57
|
-
|
|
113
|
+
moduleName === reactNativeHarmonyPackageName ||
|
|
114
|
+
moduleName.startsWith(`${reactNativeHarmonyPackageName}/`)
|
|
58
115
|
) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Importing from `react-native` when bundle is provided from Metro server.
|
|
118
|
+
*
|
|
119
|
+
* `moduleName` is equal here to the value provided in
|
|
120
|
+
* react-native-harmony/react-native.config.js::config::platforms::harmony::npmPackageName
|
|
121
|
+
* when importing from `react-native`.
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Special case for a library which hijacks imports to react-native-harmony.
|
|
126
|
+
*/
|
|
127
|
+
const result = resolveIfInteropLibraryRequest(
|
|
128
|
+
ctx,
|
|
129
|
+
moduleName,
|
|
130
|
+
nodeModulesPaths,
|
|
131
|
+
reactNativeHarmonyPackageName,
|
|
132
|
+
reactNativeInteropLibraryPackagePattern
|
|
133
|
+
);
|
|
134
|
+
if (result) {
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
return ctx.resolveRequest(ctx, moduleName, HARMONY_PLATFORM_NAME);
|
|
140
|
+
} catch {
|
|
141
|
+
return ctx.resolveRequest(
|
|
142
|
+
ctx,
|
|
143
|
+
moduleName,
|
|
144
|
+
RNOH_FALLBACK_PLATFORM_NAME
|
|
66
145
|
);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
146
|
+
}
|
|
147
|
+
} else if (ctx.originModulePath.includes(reactNativeHarmonyPattern)) {
|
|
148
|
+
const rnInteropLibraryPackage =
|
|
149
|
+
getHarmonyPackageByAliasMap(nodeModulesPaths)[
|
|
150
|
+
reactNativeHarmonyPackageName
|
|
151
|
+
];
|
|
152
|
+
// Redirect internal react-native-harmony imports to the interop package
|
|
153
|
+
if (rnInteropLibraryPackage && moduleName.startsWith('.')) {
|
|
154
|
+
const rnInteropLibraryPackageName = rnInteropLibraryPackage.name;
|
|
155
|
+
const redirectInternalImports =
|
|
156
|
+
rnInteropLibraryPackage.redirectInternalImports;
|
|
157
|
+
if (redirectInternalImports) {
|
|
158
|
+
const moduleAbsPath = pathUtils.resolve(
|
|
159
|
+
pathUtils.dirname(ctx.originModulePath),
|
|
160
|
+
moduleName
|
|
72
161
|
);
|
|
73
|
-
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
// We have to replace either /react-native-harmony/ or /@react-native-oh/react-native-harmony/ with the interop package name.
|
|
165
|
+
const newModuleName = moduleAbsPath.replace(
|
|
166
|
+
reactNativeHarmonyPattern,
|
|
167
|
+
reactNativeInteropLibraryPackagePattern ??
|
|
168
|
+
getRNInteropLibraryPackagePattern(
|
|
169
|
+
rnInteropLibraryPackageName
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
return ctx.resolveRequest(
|
|
174
|
+
ctx,
|
|
175
|
+
newModuleName,
|
|
176
|
+
HARMONY_PLATFORM_NAME
|
|
177
|
+
);
|
|
178
|
+
} catch {}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Internal RN imports
|
|
182
|
+
const maybeResult = resolveRequestOnlyForHarmony(ctx, moduleName);
|
|
183
|
+
if (maybeResult) {
|
|
184
|
+
return maybeResult;
|
|
74
185
|
}
|
|
75
|
-
return ctx.resolveRequest(
|
|
76
|
-
|
|
186
|
+
return ctx.resolveRequest(
|
|
187
|
+
ctx,
|
|
188
|
+
moduleName,
|
|
189
|
+
RNOH_FALLBACK_PLATFORM_NAME
|
|
190
|
+
);
|
|
191
|
+
} else if (
|
|
192
|
+
isHarmonyPackageInternalImport(
|
|
193
|
+
nodeModulesPaths,
|
|
194
|
+
ctx.originModulePath,
|
|
195
|
+
moduleName
|
|
196
|
+
)
|
|
197
|
+
) {
|
|
77
198
|
/**
|
|
78
|
-
* Replace internal imports in `react-native-foo` with equivalent files from `react-native-harmony-foo`
|
|
199
|
+
* Replace internal imports in `react-native-foo` with equivalent files from `react-native-harmony-foo`
|
|
79
200
|
* if a package has internal import redirection enabled in its package.json configuration e.g.
|
|
80
201
|
*
|
|
81
202
|
* react-native-harmony-foo/package.json:
|
|
@@ -84,30 +205,52 @@ function createHarmonyMetroConfig(options) {
|
|
|
84
205
|
* "redirectInternalImports": true,
|
|
85
206
|
* }
|
|
86
207
|
*/
|
|
87
|
-
const alias = getPackageNameFromOriginModulePath(
|
|
208
|
+
const alias = getPackageNameFromOriginModulePath(
|
|
209
|
+
ctx.originModulePath
|
|
210
|
+
);
|
|
211
|
+
|
|
88
212
|
if (alias) {
|
|
89
|
-
const harmonyPackage =
|
|
213
|
+
const harmonyPackage =
|
|
214
|
+
getHarmonyPackageByAliasMap(nodeModulesPaths);
|
|
215
|
+
|
|
90
216
|
const harmonyPackageName = harmonyPackage[alias]?.name;
|
|
91
|
-
|
|
92
|
-
|
|
217
|
+
|
|
218
|
+
const redirectInternalImports =
|
|
219
|
+
harmonyPackage[alias]?.redirectInternalImports;
|
|
220
|
+
|
|
221
|
+
if (
|
|
222
|
+
harmonyPackageName &&
|
|
223
|
+
!isRequestFromHarmonyPackage(
|
|
224
|
+
ctx.originModulePath,
|
|
225
|
+
harmonyPackageName
|
|
226
|
+
) &&
|
|
227
|
+
redirectInternalImports
|
|
228
|
+
) {
|
|
93
229
|
const moduleAbsPath = pathUtils.resolve(
|
|
94
230
|
pathUtils.dirname(ctx.originModulePath),
|
|
95
|
-
moduleName
|
|
231
|
+
moduleName
|
|
96
232
|
);
|
|
233
|
+
|
|
97
234
|
const slashes = new RegExp('/', 'g');
|
|
98
|
-
const [_, modulePathRelativeToOriginalPackage] =
|
|
99
|
-
|
|
100
|
-
|
|
235
|
+
const [_, modulePathRelativeToOriginalPackage] =
|
|
236
|
+
moduleAbsPath.split(
|
|
237
|
+
`${pathUtils.sep}node_modules${
|
|
238
|
+
pathUtils.sep
|
|
239
|
+
}${alias.replace(slashes, pathUtils.sep)}${pathUtils.sep}`
|
|
240
|
+
);
|
|
101
241
|
const backslashes = new RegExp('\\\\', 'g');
|
|
102
|
-
const
|
|
242
|
+
const newModuleName = `${harmonyPackageName}/${modulePathRelativeToOriginalPackage.replace(
|
|
243
|
+
backslashes,
|
|
244
|
+
'/'
|
|
245
|
+
)}`;
|
|
103
246
|
try {
|
|
104
247
|
return ctx.resolveRequest(
|
|
105
248
|
ctx,
|
|
106
|
-
|
|
107
|
-
|
|
249
|
+
newModuleName,
|
|
250
|
+
HARMONY_PLATFORM_NAME
|
|
108
251
|
);
|
|
109
|
-
} catch (err) {
|
|
110
|
-
|
|
252
|
+
} catch (err) {}
|
|
253
|
+
} else {
|
|
111
254
|
}
|
|
112
255
|
}
|
|
113
256
|
} else {
|
|
@@ -119,7 +262,8 @@ function createHarmonyMetroConfig(options) {
|
|
|
119
262
|
* "alias": "react-native-foo"
|
|
120
263
|
* }
|
|
121
264
|
*/
|
|
122
|
-
const harmonyPackageByAlias =
|
|
265
|
+
const harmonyPackageByAlias =
|
|
266
|
+
getHarmonyPackageByAliasMap(nodeModulesPaths);
|
|
123
267
|
const alias = getPackageName(moduleName);
|
|
124
268
|
if (alias) {
|
|
125
269
|
const harmonyPackageName = harmonyPackageByAlias[alias]?.name;
|
|
@@ -149,6 +293,84 @@ module.exports = {
|
|
|
149
293
|
createHarmonyMetroConfig,
|
|
150
294
|
};
|
|
151
295
|
|
|
296
|
+
/**
|
|
297
|
+
* @param ctx {Parameters<NonNullable<import("metro-config").ResolverConfigT["resolveRequest"]>>[0]}
|
|
298
|
+
* @param moduleName {string}
|
|
299
|
+
* @param nodeModulesPaths {string[]}
|
|
300
|
+
* @param reactNativeHarmonyPackageName {string}
|
|
301
|
+
* @param reactNativeInteropLibraryPackagePattern {string | undefined}
|
|
302
|
+
*/
|
|
303
|
+
function resolveIfInteropLibraryRequest(
|
|
304
|
+
ctx,
|
|
305
|
+
moduleName,
|
|
306
|
+
nodeModulesPaths,
|
|
307
|
+
reactNativeHarmonyPackageName,
|
|
308
|
+
reactNativeInteropLibraryPackagePattern
|
|
309
|
+
) {
|
|
310
|
+
const rnInteropLibraryPackageName =
|
|
311
|
+
getHarmonyPackageByAliasMap(nodeModulesPaths)[reactNativeHarmonyPackageName]
|
|
312
|
+
?.name;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* We have to check if the module is not resolved from interop package
|
|
316
|
+
* to prevent an infinite resolution loop caused by a circular dependency.
|
|
317
|
+
* e.g.
|
|
318
|
+
* origin module: react-native-harmony/Libraries/Image/ImageSourceUtils.js
|
|
319
|
+
* redirected to module: react-native-harmony-61-interop/Libraries/Image/ImageSourceUtils.js
|
|
320
|
+
* and react-native-harmony-61-interop/Libraries/Image/ImageSourceUtils.js imports react-native-harmony/Libraries/Image/ImageSourceUtils.js
|
|
321
|
+
* This creates a circular dependency, causing an infinite resolution loop.
|
|
322
|
+
*/
|
|
323
|
+
if (
|
|
324
|
+
rnInteropLibraryPackageName &&
|
|
325
|
+
!ctx.originModulePath.includes(
|
|
326
|
+
reactNativeInteropLibraryPackagePattern ??
|
|
327
|
+
getRNInteropLibraryPackagePattern(rnInteropLibraryPackageName)
|
|
328
|
+
)
|
|
329
|
+
) {
|
|
330
|
+
try {
|
|
331
|
+
const newModuleName = moduleName.replace(
|
|
332
|
+
reactNativeHarmonyPackageName,
|
|
333
|
+
rnInteropLibraryPackageName
|
|
334
|
+
);
|
|
335
|
+
return ctx.resolveRequest(ctx, newModuleName, HARMONY_PLATFORM_NAME);
|
|
336
|
+
} catch {}
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Let's say we have following files:
|
|
343
|
+
* foo.js
|
|
344
|
+
* foo.harmony.tsx
|
|
345
|
+
*
|
|
346
|
+
* By default, in that situation foo.js will be resolved. This function however chooses foo.harmony.tsx.
|
|
347
|
+
* In the past, RNOH redirected imports back to the RN package, and RNOH used different extensions than original files.
|
|
348
|
+
*
|
|
349
|
+
* @param ctx {Parameters<NonNullable<import("metro-config").ResolverConfigT["resolveRequest"]>>[0]}
|
|
350
|
+
* @param moduleName {string}
|
|
351
|
+
*/
|
|
352
|
+
function resolveRequestOnlyForHarmony(ctx, moduleName) {
|
|
353
|
+
for (const sourceExt of ctx.sourceExts) {
|
|
354
|
+
const newCtx = { ...ctx };
|
|
355
|
+
newCtx.sourceExts = [sourceExt];
|
|
356
|
+
try {
|
|
357
|
+
const result = ctx.resolveRequest(
|
|
358
|
+
newCtx,
|
|
359
|
+
moduleName,
|
|
360
|
+
HARMONY_PLATFORM_NAME
|
|
361
|
+
);
|
|
362
|
+
if (result.type === 'sourceFile') {
|
|
363
|
+
const lastDotIndex = result.filePath.lastIndexOf('.');
|
|
364
|
+
const beforeLastDot = result.filePath.substring(0, lastDotIndex);
|
|
365
|
+
if (beforeLastDot.endsWith('.' + HARMONY_PLATFORM_NAME)) {
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
} catch {}
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
|
|
152
374
|
/**
|
|
153
375
|
* @param moduleName {string}
|
|
154
376
|
* @returns {string | null}
|
|
@@ -176,52 +398,53 @@ function getPackageName(moduleName) {
|
|
|
176
398
|
* @returns {string}
|
|
177
399
|
*/
|
|
178
400
|
function getPackageNameFromOriginModulePath(originModulePath) {
|
|
179
|
-
const nodeModulesPosition = originModulePath.search(
|
|
180
|
-
const pathRelativeToNodeModules =
|
|
401
|
+
const nodeModulesPosition = originModulePath.search('node_modules');
|
|
402
|
+
const pathRelativeToNodeModules =
|
|
403
|
+
originModulePath.substring(nodeModulesPosition);
|
|
181
404
|
const pathSegments = pathRelativeToNodeModules.split(pathUtils.sep);
|
|
182
405
|
const module = pathSegments[1];
|
|
183
406
|
if (module.startsWith('@')) {
|
|
184
407
|
return `${pathSegments[1]}/${pathSegments[2]}`;
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
408
|
+
} else {
|
|
187
409
|
return pathSegments[1];
|
|
188
410
|
}
|
|
189
411
|
}
|
|
190
412
|
|
|
191
413
|
/**
|
|
414
|
+
* @param nodeModulesPaths {readonly string[]}
|
|
192
415
|
* @param originModulePath {string}
|
|
193
416
|
* @param moduleName {string}
|
|
194
417
|
* @returns {boolean}
|
|
195
418
|
*/
|
|
196
|
-
function isHarmonyPackageInternalImport(
|
|
197
|
-
|
|
419
|
+
function isHarmonyPackageInternalImport(
|
|
420
|
+
nodeModulesPaths,
|
|
421
|
+
originModulePath,
|
|
422
|
+
moduleName
|
|
423
|
+
) {
|
|
424
|
+
if (moduleName.startsWith('.')) {
|
|
198
425
|
const alias = getPackageNameFromOriginModulePath(originModulePath);
|
|
199
426
|
const slashes = new RegExp('/', 'g');
|
|
200
|
-
if (
|
|
201
|
-
|
|
427
|
+
if (
|
|
428
|
+
alias &&
|
|
429
|
+
originModulePath.includes(
|
|
430
|
+
`${pathUtils.sep}node_modules${pathUtils.sep}${alias.replace(
|
|
431
|
+
slashes,
|
|
432
|
+
pathUtils.sep
|
|
433
|
+
)}${pathUtils.sep}`
|
|
434
|
+
)
|
|
435
|
+
) {
|
|
436
|
+
const harmonyPackage = getHarmonyPackageByAliasMap(nodeModulesPaths);
|
|
202
437
|
const harmonyPackageName = harmonyPackage[alias]?.name;
|
|
203
438
|
if (
|
|
204
439
|
harmonyPackageName &&
|
|
205
|
-
!isRequestFromHarmonyPackage(
|
|
206
|
-
originModulePath,
|
|
207
|
-
harmonyPackageName,
|
|
208
|
-
)
|
|
440
|
+
!isRequestFromHarmonyPackage(originModulePath, harmonyPackageName)
|
|
209
441
|
) {
|
|
210
442
|
return true;
|
|
211
443
|
}
|
|
212
444
|
}
|
|
213
445
|
}
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
446
|
|
|
217
|
-
|
|
218
|
-
* @param originModulePath {string}
|
|
219
|
-
* @returns {boolean}
|
|
220
|
-
*/
|
|
221
|
-
function isInternalReactNativeRelativeImport(originModulePath) {
|
|
222
|
-
return originModulePath.includes(
|
|
223
|
-
`${pathUtils.sep}node_modules${pathUtils.sep}react-native${pathUtils.sep}`
|
|
224
|
-
);
|
|
447
|
+
return false;
|
|
225
448
|
}
|
|
226
449
|
|
|
227
450
|
/**
|
|
@@ -232,6 +455,7 @@ function isInternalReactNativeRelativeImport(originModulePath) {
|
|
|
232
455
|
function isRequestFromHarmonyPackage(originModulePath, harmonyPackageName) {
|
|
233
456
|
const slashes = new RegExp('/', 'g');
|
|
234
457
|
const packagePath = harmonyPackageName.replace(slashes, pathUtils.sep);
|
|
458
|
+
|
|
235
459
|
return originModulePath.includes(
|
|
236
460
|
`${pathUtils.sep}node_modules${pathUtils.sep}${packagePath}${pathUtils.sep}`
|
|
237
461
|
);
|
|
@@ -243,9 +467,9 @@ function isRequestFromHarmonyPackage(originModulePath, harmonyPackageName) {
|
|
|
243
467
|
let cachedHarmonyPackageByAliasMap = undefined;
|
|
244
468
|
|
|
245
469
|
/**
|
|
246
|
-
* @param
|
|
470
|
+
* @param nodeModulesPaths {readonly string[]}
|
|
247
471
|
*/
|
|
248
|
-
function getHarmonyPackageByAliasMap(
|
|
472
|
+
function getHarmonyPackageByAliasMap(nodeModulesPaths) {
|
|
249
473
|
/**
|
|
250
474
|
* @type {Record<string, {name: string, redirectInternalImports: boolean}>}
|
|
251
475
|
*/
|
|
@@ -254,51 +478,71 @@ function getHarmonyPackageByAliasMap(projectRootPath) {
|
|
|
254
478
|
return cachedHarmonyPackageByAliasMap;
|
|
255
479
|
}
|
|
256
480
|
cachedHarmonyPackageByAliasMap = findHarmonyNodeModulePaths(
|
|
257
|
-
findHarmonyNodeModuleSearchPaths(
|
|
258
|
-
).reduce(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (harmonyNodeModulePathSegments.length > 1) {
|
|
265
|
-
const harmonyNodeModuleParentDirName =
|
|
266
|
-
harmonyNodeModulePathSegments[harmonyNodeModulePathSegments.length - 2];
|
|
267
|
-
if (harmonyNodeModuleParentDirName.startsWith('@')) {
|
|
268
|
-
harmonyNodeModuleName = `${harmonyNodeModuleParentDirName}/${harmonyNodeModuleName}`;
|
|
481
|
+
findHarmonyNodeModuleSearchPaths(nodeModulesPaths)
|
|
482
|
+
).reduce(
|
|
483
|
+
(
|
|
484
|
+
acc,
|
|
485
|
+
{
|
|
486
|
+
resolvedPath: harmonyNodeModuleResolvedPath,
|
|
487
|
+
unresolvedPath: harmonyNodeModuleUnresolvedPath,
|
|
269
488
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
489
|
+
) => {
|
|
490
|
+
// use unresolved path for monorepos to find actual package name (which can be installed under an alias)
|
|
491
|
+
const harmonyNodeModulePath = harmonyNodeModuleResolvedPath.includes(
|
|
492
|
+
'node_modules'
|
|
493
|
+
)
|
|
494
|
+
? harmonyNodeModuleResolvedPath
|
|
495
|
+
: harmonyNodeModuleUnresolvedPath;
|
|
496
|
+
|
|
497
|
+
const harmonyNodeModulePathSegments = harmonyNodeModulePath.split(
|
|
498
|
+
pathUtils.sep
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
let harmonyNodeModuleName =
|
|
502
|
+
harmonyNodeModulePathSegments[harmonyNodeModulePathSegments.length - 1];
|
|
503
|
+
if (harmonyNodeModulePathSegments.length > 1) {
|
|
504
|
+
const harmonyNodeModuleParentDirName =
|
|
505
|
+
harmonyNodeModulePathSegments[
|
|
506
|
+
harmonyNodeModulePathSegments.length - 2
|
|
507
|
+
];
|
|
508
|
+
if (harmonyNodeModuleParentDirName.startsWith('@')) {
|
|
509
|
+
harmonyNodeModuleName = `${harmonyNodeModuleParentDirName}/${harmonyNodeModuleName}`;
|
|
510
|
+
}
|
|
279
511
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
512
|
+
const packageJsonPath = `${harmonyNodeModuleResolvedPath}${pathUtils.sep}package.json`;
|
|
513
|
+
const packageJson = readHarmonyModulePackageJSON(packageJsonPath);
|
|
514
|
+
const alias = packageJson.harmony?.alias;
|
|
515
|
+
const redirectInternalImports =
|
|
516
|
+
packageJson?.harmony?.redirectInternalImports ?? false;
|
|
517
|
+
if (alias) {
|
|
518
|
+
acc[alias] = {
|
|
519
|
+
name: harmonyNodeModuleName,
|
|
520
|
+
redirectInternalImports: redirectInternalImports,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
return acc;
|
|
524
|
+
},
|
|
525
|
+
initialAcc
|
|
526
|
+
);
|
|
283
527
|
const harmonyPackagesCount = Object.keys(
|
|
284
|
-
cachedHarmonyPackageByAliasMap
|
|
528
|
+
cachedHarmonyPackageByAliasMap
|
|
285
529
|
).length;
|
|
286
530
|
if (harmonyPackagesCount > 0) {
|
|
287
531
|
const prettyHarmonyPackagesCount = colors.bold(
|
|
288
532
|
harmonyPackagesCount > 0
|
|
289
533
|
? colors.green(harmonyPackagesCount.toString())
|
|
290
|
-
: harmonyPackagesCount.toString()
|
|
534
|
+
: harmonyPackagesCount.toString()
|
|
291
535
|
);
|
|
292
536
|
info(
|
|
293
|
-
`Redirected imports to ${prettyHarmonyPackagesCount} harmony-specific third-party package(s)
|
|
537
|
+
`Redirected imports to ${prettyHarmonyPackagesCount} harmony-specific third-party package(s):`
|
|
294
538
|
);
|
|
295
539
|
if (harmonyPackagesCount > 0) {
|
|
296
540
|
Object.entries(cachedHarmonyPackageByAliasMap).forEach(
|
|
297
|
-
([original, {name: alias}]) => {
|
|
541
|
+
([original, { name: alias }]) => {
|
|
298
542
|
info(
|
|
299
|
-
`• ${colors.bold(colors.gray(original))} → ${colors.bold(alias)}
|
|
543
|
+
`• ${colors.bold(colors.gray(original))} → ${colors.bold(alias)}`
|
|
300
544
|
);
|
|
301
|
-
}
|
|
545
|
+
}
|
|
302
546
|
);
|
|
303
547
|
}
|
|
304
548
|
} else {
|
|
@@ -309,30 +553,55 @@ function getHarmonyPackageByAliasMap(projectRootPath) {
|
|
|
309
553
|
}
|
|
310
554
|
|
|
311
555
|
/**
|
|
312
|
-
* @param
|
|
556
|
+
* @param nodeModulesPaths {readonly string[]}
|
|
313
557
|
* @returns {string[]}
|
|
314
558
|
*/
|
|
315
|
-
function findHarmonyNodeModuleSearchPaths(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
559
|
+
function findHarmonyNodeModuleSearchPaths(nodeModulesPaths) {
|
|
560
|
+
/**
|
|
561
|
+
* @type string[]
|
|
562
|
+
*/
|
|
563
|
+
let searchPaths = [];
|
|
564
|
+
for (const nodeModulesPath of nodeModulesPaths) {
|
|
565
|
+
if (fs.existsSync(nodeModulesPath)) {
|
|
566
|
+
fs.readdirSync(nodeModulesPath)
|
|
567
|
+
.filter((dirName) => dirName.startsWith('@'))
|
|
568
|
+
.forEach((dirName) =>
|
|
569
|
+
searchPaths.push(`${nodeModulesPath}${pathUtils.sep}${dirName}`)
|
|
570
|
+
);
|
|
571
|
+
searchPaths.push(nodeModulesPath);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
322
574
|
return searchPaths;
|
|
323
575
|
}
|
|
324
576
|
|
|
325
577
|
/**
|
|
326
578
|
* @param searchPaths {string[]}
|
|
327
|
-
* @returns {string[]}
|
|
579
|
+
* @returns {{resolvedPath:string, unresolvedPath: string}[]}
|
|
328
580
|
*/
|
|
329
581
|
function findHarmonyNodeModulePaths(searchPaths) {
|
|
330
582
|
return searchPaths
|
|
331
583
|
.map((searchPath) => {
|
|
332
584
|
return fs
|
|
333
|
-
.readdirSync(searchPath)
|
|
334
|
-
.map((
|
|
335
|
-
|
|
585
|
+
.readdirSync(searchPath, { withFileTypes: true })
|
|
586
|
+
.map((dirent) => {
|
|
587
|
+
const direntPath =
|
|
588
|
+
(dirent.parentPath ?? dirent.path) + pathUtils.sep + dirent.name;
|
|
589
|
+
if (dirent.isSymbolicLink()) {
|
|
590
|
+
return {
|
|
591
|
+
resolvedPath: pathUtils.resolve(
|
|
592
|
+
dirent.parentPath ?? dirent.path,
|
|
593
|
+
fs.readlinkSync(direntPath)
|
|
594
|
+
),
|
|
595
|
+
unresolvedPath: pathUtils.resolve(
|
|
596
|
+
dirent.parentPath ?? dirent.path,
|
|
597
|
+
direntPath
|
|
598
|
+
),
|
|
599
|
+
};
|
|
600
|
+
} else {
|
|
601
|
+
return { resolvedPath: direntPath, unresolvedPath: direntPath };
|
|
602
|
+
}
|
|
603
|
+
})
|
|
604
|
+
.filter(({ resolvedPath }) => hasPackageJSON(resolvedPath));
|
|
336
605
|
})
|
|
337
606
|
.flat();
|
|
338
607
|
}
|
|
@@ -342,7 +611,12 @@ function findHarmonyNodeModulePaths(searchPaths) {
|
|
|
342
611
|
* @returns {boolean}
|
|
343
612
|
*/
|
|
344
613
|
function hasPackageJSON(nodeModulePath) {
|
|
345
|
-
if (!fs.
|
|
614
|
+
if (!fs.existsSync(nodeModulePath)) {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
if (!fs.lstatSync(nodeModulePath).isDirectory()) {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
346
620
|
const nodeModuleContentNames = fs.readdirSync(nodeModulePath);
|
|
347
621
|
return nodeModuleContentNames.includes('package.json');
|
|
348
622
|
}
|
|
@@ -354,3 +628,12 @@ function hasPackageJSON(nodeModulePath) {
|
|
|
354
628
|
function readHarmonyModulePackageJSON(packageJSONPath) {
|
|
355
629
|
return JSON.parse(fs.readFileSync(packageJSONPath).toString());
|
|
356
630
|
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* @param rnInteropLibraryPackageName {string}
|
|
634
|
+
* @param isInMonorepo {boolean}
|
|
635
|
+
* @returns {string} - Either package name without the scope or the full package name with platform specific separator
|
|
636
|
+
*/
|
|
637
|
+
function getRNInteropLibraryPackagePattern(rnInteropLibraryPackageName) {
|
|
638
|
+
return `${pathUtils.sep}${rnInteropLibraryPackageName.replace('/', pathUtils.sep)}${pathUtils.sep}`;
|
|
639
|
+
}
|