@react-native-oh/react-native-harmony 0.72.13-lazy-2 → 0.72.17

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.
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ * @format
9
+ */
10
+
11
+ // RNOH patch: imports
12
+ import type {RootTag} from 'react-native/Libraries/Types/RootTagTypes';
13
+ import type {Spec} from 'react-native/Libraries/ReactNative/NativeUIManager';
14
+
15
+ import {getFabricUIManager} from 'react-native/Libraries/ReactNative/FabricUIManager';
16
+ import nullthrows from 'nullthrows';
17
+
18
+ export interface UIManagerJSInterface extends Spec {
19
+ +getViewManagerConfig: (viewManagerName: string) => Object;
20
+ +hasViewManagerConfig: (viewManagerName: string) => boolean;
21
+ +createView: (
22
+ reactTag: ?number,
23
+ viewName: string,
24
+ rootTag: RootTag,
25
+ props: Object,
26
+ ) => void;
27
+ +updateView: (reactTag: number, viewName: string, props: Object) => void;
28
+ +manageChildren: (
29
+ containerTag: ?number,
30
+ moveFromIndices: Array<number>,
31
+ moveToIndices: Array<number>,
32
+ addChildReactTags: Array<number>,
33
+ addAtIndices: Array<number>,
34
+ removeAtIndices: Array<number>,
35
+ ) => void;
36
+ }
37
+
38
+ function isFabricReactTag(reactTag: number): boolean {
39
+ // React reserves even numbers for Fabric.
40
+ return reactTag % 2 === 0;
41
+ }
42
+
43
+ // RNOH patch: always export BridgelessUIManager properties
44
+ const BridgelessUIManager: UIManagerJSInterface = require('react-native/Libraries/ReactNative/BridgelessUIManager')
45
+ const PaperUIManager: UIManagerJSInterface =
46
+ global.RN$Bridgeless === true
47
+ ? {}
48
+ : require('react-native/Libraries/ReactNative/PaperUIManager');
49
+
50
+ // $FlowFixMe[cannot-spread-interface]
51
+ const UIManager = {
52
+ ...BridgelessUIManager,
53
+ ...PaperUIManager,
54
+ measure(
55
+ reactTag: number,
56
+ callback: (
57
+ left: number,
58
+ top: number,
59
+ width: number,
60
+ height: number,
61
+ pageX: number,
62
+ pageY: number,
63
+ ) => void,
64
+ ): void {
65
+ if (isFabricReactTag(reactTag)) {
66
+ const FabricUIManager = nullthrows(getFabricUIManager());
67
+ const shadowNode =
68
+ FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
69
+ if (shadowNode) {
70
+ FabricUIManager.measure(shadowNode, callback);
71
+ } else {
72
+ console.warn(`measure cannot find view with tag #${reactTag}`);
73
+ // $FlowFixMe[incompatible-call]
74
+ callback();
75
+ }
76
+ } else {
77
+ // Paper
78
+ UIManagerImpl.measure(reactTag, callback);
79
+ }
80
+ },
81
+
82
+ measureInWindow(
83
+ reactTag: number,
84
+ callback: (
85
+ left: number,
86
+ top: number,
87
+ width: number,
88
+ height: number,
89
+ ) => void,
90
+ ): void {
91
+ if (isFabricReactTag(reactTag)) {
92
+ const FabricUIManager = nullthrows(getFabricUIManager());
93
+ const shadowNode =
94
+ FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
95
+ if (shadowNode) {
96
+ FabricUIManager.measureInWindow(shadowNode, callback);
97
+ } else {
98
+ console.warn(`measure cannot find view with tag #${reactTag}`);
99
+ // $FlowFixMe[incompatible-call]
100
+ callback();
101
+ }
102
+ } else {
103
+ // Paper
104
+ UIManagerImpl.measureInWindow(reactTag, callback);
105
+ }
106
+ },
107
+
108
+ measureLayout(
109
+ reactTag: number,
110
+ ancestorReactTag: number,
111
+ errorCallback: (error: Object) => void,
112
+ callback: (
113
+ left: number,
114
+ top: number,
115
+ width: number,
116
+ height: number,
117
+ ) => void,
118
+ ): void {
119
+ if (isFabricReactTag(reactTag)) {
120
+ const FabricUIManager = nullthrows(getFabricUIManager());
121
+ const shadowNode =
122
+ FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
123
+ const ancestorShadowNode =
124
+ FabricUIManager.findShadowNodeByTag_DEPRECATED(ancestorReactTag);
125
+
126
+ if (!shadowNode || !ancestorShadowNode) {
127
+ return;
128
+ }
129
+
130
+ FabricUIManager.measureLayout(
131
+ shadowNode,
132
+ ancestorShadowNode,
133
+ errorCallback,
134
+ callback,
135
+ );
136
+ } else {
137
+ // Paper
138
+ UIManagerImpl.measureLayout(
139
+ reactTag,
140
+ ancestorReactTag,
141
+ errorCallback,
142
+ callback,
143
+ );
144
+ }
145
+ },
146
+
147
+ measureLayoutRelativeToParent(
148
+ reactTag: number,
149
+ errorCallback: (error: Object) => void,
150
+ callback: (
151
+ left: number,
152
+ top: number,
153
+ width: number,
154
+ height: number,
155
+ ) => void,
156
+ ): void {
157
+ if (isFabricReactTag(reactTag)) {
158
+ console.warn(
159
+ 'RCTUIManager.measureLayoutRelativeToParent method is deprecated and it will not be implemented in newer versions of RN (Fabric) - T47686450',
160
+ );
161
+ const FabricUIManager = nullthrows(getFabricUIManager());
162
+ const shadowNode =
163
+ FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
164
+ if (shadowNode) {
165
+ FabricUIManager.measure(
166
+ shadowNode,
167
+ (left, top, width, height, pageX, pageY) => {
168
+ callback(left, top, width, height);
169
+ },
170
+ );
171
+ }
172
+ } else {
173
+ // Paper
174
+ UIManagerImpl.measureLayoutRelativeToParent(
175
+ reactTag,
176
+ errorCallback,
177
+ callback,
178
+ );
179
+ }
180
+ },
181
+
182
+ dispatchViewManagerCommand(
183
+ reactTag: number,
184
+ commandName: number | string,
185
+ commandArgs: any[],
186
+ ) {
187
+ if (isFabricReactTag(reactTag)) {
188
+ const FabricUIManager = nullthrows(getFabricUIManager());
189
+ const shadowNode =
190
+ FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
191
+ if (shadowNode) {
192
+ // Transform the accidental CommandID into a CommandName which is the stringified number.
193
+ // The interop layer knows how to convert this number into the right method name.
194
+ // Stringify a string is a no-op, so it's safe.
195
+ commandName = `${commandName}`;
196
+ FabricUIManager.dispatchCommand(shadowNode, commandName, commandArgs);
197
+ }
198
+ } else {
199
+ UIManagerImpl.dispatchViewManagerCommand(
200
+ reactTag,
201
+ // We have some legacy components that are actually already using strings. ¯\_(ツ)_/¯
202
+ // $FlowFixMe[incompatible-call]
203
+ commandName,
204
+ commandArgs,
205
+ );
206
+ }
207
+ },
208
+ };
209
+
210
+ module.exports = UIManager;
@@ -0,0 +1,8 @@
1
+ import { TurboModule, TurboModuleRegistry } from "react-native";
2
+
3
+ interface Spec extends TurboModule {
4
+ getSystemColor: () => string | null;
5
+ }
6
+
7
+ export const NativePlatformColor =
8
+ TurboModuleRegistry.getEnforcing<Spec>("PlatformColor");
@@ -0,0 +1,14 @@
1
+ import { NativePlatformColor } from "./NativePlatformColor";
2
+
3
+ export const PlatformColor = (...colors: string[]) => {
4
+ const color = NativePlatformColor.getSystemColor(colors);
5
+ return color;
6
+ };
7
+
8
+ export const normalizeColorObject = (color: string) => {
9
+ return color;
10
+ };
11
+
12
+ export const processColorObject = (color: string) => {
13
+ return color;
14
+ };
@@ -0,0 +1,88 @@
1
+ // This implementation is based on iOS logic from file - react-native/Libraries/Vibration/Vibration.js
2
+ import NativeVibration from 'react-native/Libraries/Vibration/NativeVibration'; // RNOH: patch
3
+
4
+ /**
5
+ * Vibration API
6
+ *
7
+ * See https://reactnative.dev/docs/vibration
8
+ */
9
+
10
+ let _vibrating: boolean = false;
11
+ let _id: number = 0; // _id is necessary to prevent race condition.
12
+ const _default_vibration_length = 400;
13
+
14
+
15
+ function vibrateByPattern(pattern: Array<number>, repeat: boolean = false) {
16
+ if (_vibrating) {
17
+ return;
18
+ }
19
+ _vibrating = true;
20
+ if (pattern.length === 0) {
21
+ _vibrating = false;
22
+ return;
23
+ }
24
+ vibrateScheduler(++_id, pattern, repeat, 0);
25
+ }
26
+
27
+ function vibrateScheduler(
28
+ id: number,
29
+ pattern: Array<number>,
30
+ repeat: boolean,
31
+ nextIndex: number,
32
+ shouldVibrate: boolean = false, // first value in pattern is delay
33
+ ) {
34
+ if (!_vibrating || id !== _id) {
35
+ return;
36
+ }
37
+ if (shouldVibrate && nextIndex < pattern.length) {
38
+ NativeVibration.vibrate(pattern[nextIndex]);
39
+ }
40
+ if (nextIndex >= pattern.length) {
41
+ if (repeat) {
42
+ // $FlowFixMe[reassign-const]
43
+ nextIndex = 0;
44
+ shouldVibrate = true;
45
+ } else {
46
+ _vibrating = false;
47
+ return;
48
+ }
49
+ }
50
+ setTimeout(
51
+ () => vibrateScheduler(id, pattern, repeat, nextIndex + 1, !shouldVibrate),
52
+ pattern[nextIndex],
53
+ );
54
+ }
55
+
56
+ const Vibration = {
57
+ /**
58
+ * Trigger a vibration with specified `pattern`.
59
+ *
60
+ * See https://reactnative.dev/docs/vibration#vibrate
61
+ */
62
+ vibrate: function (
63
+ pattern: number | Array<number> = _default_vibration_length,
64
+ repeat: boolean = false,
65
+ ) {
66
+ if (_vibrating) {
67
+ return;
68
+ }
69
+ if (typeof pattern === 'number') {
70
+ NativeVibration.vibrate(pattern);
71
+ } else if (Array.isArray(pattern)) {
72
+ vibrateByPattern(pattern, repeat);
73
+ } else {
74
+ throw new Error('Vibration pattern should be a number or array');
75
+ }
76
+ },
77
+ /**
78
+ * Stop vibration
79
+ *
80
+ * See https://reactnative.dev/docs/vibration#cancel
81
+ */
82
+ cancel: function () {
83
+ _vibrating = false;
84
+ NativeVibration.cancel();
85
+ },
86
+ };
87
+
88
+ module.exports = Vibration;
package/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  module.exports = {
2
+ get AccessibilityInfo() {
3
+ return require('./Libraries/Components/AccessibilityInfo/AccessibilityInfo')
4
+ .default;
5
+ },
2
6
  get ActivityIndicator() {
3
7
  return require('react-native/Libraries/Components/ActivityIndicator/ActivityIndicator')
4
8
  .default;
@@ -24,6 +28,9 @@ module.exports = {
24
28
  get Button() {
25
29
  return require('./Libraries/Components/Button/Button');
26
30
  },
31
+ get DevSettings() {
32
+ return require('react-native/Libraries/Utilities/DevSettings');
33
+ },
27
34
  get Dimensions() {
28
35
  return require('react-native/Libraries/Utilities/Dimensions').default;
29
36
  },
@@ -82,6 +89,10 @@ module.exports = {
82
89
  get Platform() {
83
90
  return require('./Libraries/Utilities/Platform');
84
91
  },
92
+ get PlatformColor() {
93
+ return require('./Libraries/StyleSheet/PlatformColorValueTypes')
94
+ .PlatformColor;
95
+ },
85
96
  get Pressable() {
86
97
  return require('react-native/Libraries/Components/Pressable/Pressable')
87
98
  .default;
@@ -99,6 +110,9 @@ module.exports = {
99
110
  get SafeAreaView() {
100
111
  return require('./Libraries/Components/SafeAreaView/SafeAreaView').default;
101
112
  },
113
+ get Share() {
114
+ return require('react-native/Libraries/Share/Share');
115
+ },
102
116
  get ScrollView() {
103
117
  return require('./Libraries/Components/ScrollView/ScrollView');
104
118
  },
@@ -117,6 +131,9 @@ module.exports = {
117
131
  get TextInput() {
118
132
  return require('./Libraries/Components/TextInput/TextInput.harmony');
119
133
  },
134
+ get ToastAndroid() {
135
+ return require('react-native/Libraries/Components/ToastAndroid/ToastAndroid.android');
136
+ },
120
137
  get Touchable() {
121
138
  return require('react-native/Libraries/Components/Touchable/Touchable');
122
139
  },
@@ -136,7 +153,7 @@ module.exports = {
136
153
  return require('react-native/Libraries/TurboModule/TurboModuleRegistry');
137
154
  },
138
155
  get UIManager() {
139
- return require('react-native/Libraries/ReactNative/UIManager');
156
+ return require('./Libraries/ReactNative/UIManager');
140
157
  },
141
158
  get useAnimatedValue() {
142
159
  return require('react-native/Libraries/Animated/useAnimatedValue').default;
@@ -164,7 +181,7 @@ module.exports = {
164
181
  return require('react-native/Libraries/Lists/SectionList').default;
165
182
  },
166
183
  get Vibration() {
167
- return require('react-native/Libraries/Vibration/Vibration');
184
+ return require('./Libraries/Vibration/Vibration');
168
185
  },
169
186
  get VirtualizedList() {
170
187
  return require('react-native/Libraries/Lists/VirtualizedList');
package/jest.config.js ADDED
@@ -0,0 +1,6 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ rootDir: "./tests/"
6
+ };
package/metro.config.js CHANGED
@@ -38,8 +38,8 @@ function createHarmonyMetroConfig(options) {
38
38
  if (shouldPrintInfoAboutRNRedirection) {
39
39
  info(
40
40
  `Redirected imports from ${colors.bold(
41
- colors.gray('react-native'),
42
- )} to ${colors.bold(reactNativeHarmonyName)}`,
41
+ colors.gray('react-native')
42
+ )} to ${colors.bold(reactNativeHarmonyName)}`
43
43
  );
44
44
  shouldPrintInfoAboutRNRedirection = false;
45
45
  }
@@ -53,20 +53,56 @@ function createHarmonyMetroConfig(options) {
53
53
  if (moduleName.startsWith('.')) {
54
54
  const moduleAbsPath = pathUtils.resolve(
55
55
  pathUtils.dirname(ctx.originModulePath),
56
- moduleName,
56
+ moduleName
57
57
  );
58
58
  const [_, modulePathRelativeToReactNative] = moduleAbsPath.split(
59
- `${pathUtils.sep}node_modules${pathUtils.sep}react-native${pathUtils.sep}`,
59
+ `${pathUtils.sep}node_modules${pathUtils.sep}react-native${pathUtils.sep}`
60
60
  );
61
61
  try {
62
62
  return ctx.resolveRequest(
63
63
  ctx,
64
64
  `${reactNativeHarmonyName}${pathUtils.sep}${modulePathRelativeToReactNative}`,
65
- 'harmony',
65
+ 'harmony'
66
66
  );
67
67
  } catch (err) {}
68
68
  }
69
69
  return ctx.resolveRequest(ctx, moduleName, 'ios');
70
+ } else if(isHarmonyPackageInternalImport(ctx.originModulePath, moduleName)) {
71
+ /**
72
+ * Replace internal imports in `react-native-foo` with equivalent files from `react-native-harmony-foo`
73
+ * if a package has internal import redirection enabled in its package.json configuration e.g.
74
+ *
75
+ * react-native-harmony-foo/package.json:
76
+ * "harmony": {
77
+ * "alias": "react-native-foo"
78
+ * "redirectInternalImports": true,
79
+ * }
80
+ */
81
+ const alias = getPackageNameFromOriginModulePath(ctx.originModulePath);
82
+ if (alias) {
83
+ const harmonyPackage = getHarmonyPackageByAliasMap(".");
84
+ const harmonyPackageName = harmonyPackage[alias]?.name;
85
+ const redirectInternalImports = harmonyPackage[alias]?.redirectInternalImports;
86
+ if (harmonyPackageName && !isRequestFromHarmonyPackage(ctx.originModulePath, harmonyPackageName) && redirectInternalImports) {
87
+ const moduleAbsPath = pathUtils.resolve(
88
+ pathUtils.dirname(ctx.originModulePath),
89
+ moduleName,
90
+ );
91
+ const [_, modulePathRelativeToOriginalPackage] = moduleAbsPath.split(
92
+ `${pathUtils.sep}node_modules${pathUtils.sep}${alias}${pathUtils.sep}`,
93
+ );
94
+ const backslashes = new RegExp('\\\\', 'g');
95
+ const pathToHarmonyModule = `${harmonyPackageName}/${modulePathRelativeToOriginalPackage.replace(backslashes, "/")}`;
96
+ try {
97
+ return ctx.resolveRequest(
98
+ ctx,
99
+ pathToHarmonyModule,
100
+ 'harmony',
101
+ );
102
+ } catch (err) {
103
+ }
104
+ }
105
+ }
70
106
  } else {
71
107
  /**
72
108
  * Replace `react-native-foo` with `react-native-harmony-foo` if a package has harmony directory and proper package.json configuration e.g.
@@ -76,21 +112,21 @@ function createHarmonyMetroConfig(options) {
76
112
  * "alias": "react-native-foo"
77
113
  * }
78
114
  */
79
- const harmonyPackageNameByAlias = getHarmonyPackageNameByAlias('.');
115
+ const harmonyPackageByAlias = getHarmonyPackageByAliasMap(".");
80
116
  const alias = getPackageName(moduleName);
81
117
  if (alias) {
82
- const harmonyPackageName = harmonyPackageNameByAlias[alias];
118
+ const harmonyPackageName = harmonyPackageByAlias[alias]?.name;
83
119
  if (
84
120
  harmonyPackageName &&
85
121
  !isRequestFromHarmonyPackage(
86
122
  ctx.originModulePath,
87
- harmonyPackageName,
123
+ harmonyPackageName
88
124
  )
89
125
  ) {
90
126
  return ctx.resolveRequest(
91
127
  ctx,
92
128
  moduleName.replace(alias, harmonyPackageName),
93
- platform,
129
+ platform
94
130
  );
95
131
  }
96
132
  }
@@ -128,13 +164,56 @@ function getPackageName(moduleName) {
128
164
  }
129
165
  }
130
166
 
167
+ /**
168
+ * @param originModulePath {string}
169
+ * @returns {string}
170
+ */
171
+ function getPackageNameFromOriginModulePath(originModulePath) {
172
+ const nodeModulesPosition = originModulePath.search("node_modules");
173
+ const pathRelativeToNodeModules = originModulePath.substring(nodeModulesPosition);
174
+ const pathSegments = pathRelativeToNodeModules.split(pathUtils.sep);
175
+ const module = pathSegments[1];
176
+ if (module.startsWith('@')) {
177
+ return `${pathSegments[1]}/${pathSegments[2]}`;
178
+ }
179
+ else {
180
+ return pathSegments[1];
181
+ }
182
+ }
183
+
184
+ /**
185
+ * @param originModulePath {string}
186
+ * @param moduleName {string}
187
+ * @returns {boolean}
188
+ */
189
+ function isHarmonyPackageInternalImport(originModulePath, moduleName) {
190
+ if (moduleName.startsWith(".")) {
191
+ const alias = getPackageNameFromOriginModulePath(originModulePath);
192
+ const slashes = new RegExp('/', 'g');
193
+ if (alias && originModulePath.includes(`${pathUtils.sep}node_modules${pathUtils.sep}${alias.replace(slashes, pathUtils.sep)}${pathUtils.sep}`)) {
194
+ const harmonyPackage = getHarmonyPackageByAliasMap(".");
195
+ const harmonyPackageName = harmonyPackage[alias]?.name;
196
+ if (
197
+ harmonyPackageName &&
198
+ !isRequestFromHarmonyPackage(
199
+ originModulePath,
200
+ harmonyPackageName,
201
+ )
202
+ ) {
203
+ return true;
204
+ }
205
+ }
206
+ }
207
+ return false;
208
+ }
209
+
131
210
  /**
132
211
  * @param originModulePath {string}
133
212
  * @returns {boolean}
134
213
  */
135
214
  function isInternalReactNativeRelativeImport(originModulePath) {
136
215
  return originModulePath.includes(
137
- `${pathUtils.sep}node_modules${pathUtils.sep}react-native${pathUtils.sep}`,
216
+ `${pathUtils.sep}node_modules${pathUtils.sep}react-native${pathUtils.sep}`
138
217
  );
139
218
  }
140
219
 
@@ -147,27 +226,27 @@ function isRequestFromHarmonyPackage(originModulePath, harmonyPackageName) {
147
226
  const slashes = new RegExp('/', 'g');
148
227
  const packagePath = harmonyPackageName.replace(slashes, pathUtils.sep);
149
228
  return originModulePath.includes(
150
- `${pathUtils.sep}node_modules${pathUtils.sep}${packagePath}${pathUtils.sep}`,
229
+ `${pathUtils.sep}node_modules${pathUtils.sep}${packagePath}${pathUtils.sep}`
151
230
  );
152
231
  }
153
232
 
154
233
  /**
155
- * @type {Record<string, string> | undefined}
234
+ * @type {Record<string, {name: string, redirectInternalImports: boolean}> | undefined}
156
235
  */
157
- let cachedHarmonyPackageAliasByName = undefined;
236
+ let cachedHarmonyPackageByAliasMap = undefined;
158
237
 
159
238
  /**
160
239
  * @param projectRootPath {string}
161
240
  */
162
- function getHarmonyPackageNameByAlias(projectRootPath) {
241
+ function getHarmonyPackageByAliasMap(projectRootPath) {
163
242
  /**
164
- * @type {Record<string, string>}
243
+ * @type {Record<string, {name: string, redirectInternalImports: boolean}>}
165
244
  */
166
245
  const initialAcc = {};
167
- if (cachedHarmonyPackageAliasByName) {
168
- return cachedHarmonyPackageAliasByName;
246
+ if (cachedHarmonyPackageByAliasMap) {
247
+ return cachedHarmonyPackageByAliasMap;
169
248
  }
170
- cachedHarmonyPackageAliasByName = findHarmonyNodeModulePaths(
249
+ cachedHarmonyPackageByAliasMap = findHarmonyNodeModulePaths(
171
250
  findHarmonyNodeModuleSearchPaths(projectRootPath),
172
251
  ).reduce((acc, harmonyNodeModulePath) => {
173
252
  const harmonyNodeModulePathSegments = harmonyNodeModulePath.split(
@@ -185,13 +264,17 @@ function getHarmonyPackageNameByAlias(projectRootPath) {
185
264
  const packageJSONPath = `${harmonyNodeModulePath}${pathUtils.sep}package.json`;
186
265
  const packageJSON = readHarmonyModulePackageJSON(packageJSONPath);
187
266
  const alias = packageJSON.harmony?.alias;
267
+ const redirectInternalImports = packageJSON?.harmony?.redirectInternalImports ?? false;
188
268
  if (alias) {
189
- acc[alias] = harmonyNodeModuleName;
269
+ acc[alias] ={
270
+ name: harmonyNodeModuleName,
271
+ redirectInternalImports: redirectInternalImports
272
+ }
190
273
  }
191
274
  return acc;
192
275
  }, initialAcc);
193
276
  const harmonyPackagesCount = Object.keys(
194
- cachedHarmonyPackageAliasByName,
277
+ cachedHarmonyPackageByAliasMap,
195
278
  ).length;
196
279
  if (harmonyPackagesCount > 0) {
197
280
  const prettyHarmonyPackagesCount = colors.bold(
@@ -203,8 +286,8 @@ function getHarmonyPackageNameByAlias(projectRootPath) {
203
286
  `Redirected imports to ${prettyHarmonyPackagesCount} harmony-specific third-party package(s):`,
204
287
  );
205
288
  if (harmonyPackagesCount > 0) {
206
- Object.entries(cachedHarmonyPackageAliasByName).forEach(
207
- ([original, alias]) => {
289
+ Object.entries(cachedHarmonyPackageByAliasMap).forEach(
290
+ ([original, {name: alias}]) => {
208
291
  info(
209
292
  `• ${colors.bold(colors.gray(original))} → ${colors.bold(alias)}`,
210
293
  );
@@ -215,8 +298,7 @@ function getHarmonyPackageNameByAlias(projectRootPath) {
215
298
  info('No harmony-specific third-party packages have been detected');
216
299
  }
217
300
  console.log('');
218
-
219
- return cachedHarmonyPackageAliasByName;
301
+ return cachedHarmonyPackageByAliasMap;
220
302
  }
221
303
 
222
304
  /**
@@ -227,8 +309,8 @@ function findHarmonyNodeModuleSearchPaths(projectRootPath) {
227
309
  const nodeModulesPath = `${projectRootPath}${pathUtils.sep}node_modules`;
228
310
  const searchPaths = fs
229
311
  .readdirSync(nodeModulesPath)
230
- .filter(dirName => dirName.startsWith('@'))
231
- .map(dirName => `${nodeModulesPath}${pathUtils.sep}${dirName}`);
312
+ .filter((dirName) => dirName.startsWith('@'))
313
+ .map((dirName) => `${nodeModulesPath}${pathUtils.sep}${dirName}`);
232
314
  searchPaths.push(nodeModulesPath);
233
315
  return searchPaths;
234
316
  }
@@ -239,11 +321,11 @@ function findHarmonyNodeModuleSearchPaths(projectRootPath) {
239
321
  */
240
322
  function findHarmonyNodeModulePaths(searchPaths) {
241
323
  return searchPaths
242
- .map(searchPath => {
324
+ .map((searchPath) => {
243
325
  return fs
244
326
  .readdirSync(searchPath)
245
- .map(dirName => `${searchPath}${pathUtils.sep}${dirName}`)
246
- .filter(hasNodeModulePathHarmonyCode);
327
+ .map((dirName) => `${searchPath}${pathUtils.sep}${dirName}`)
328
+ .filter(hasPackageJSON);
247
329
  })
248
330
  .flat();
249
331
  }
@@ -252,18 +334,15 @@ function findHarmonyNodeModulePaths(searchPaths) {
252
334
  * @param nodeModulePath {string}
253
335
  * @returns {boolean}
254
336
  */
255
- function hasNodeModulePathHarmonyCode(nodeModulePath) {
337
+ function hasPackageJSON(nodeModulePath) {
256
338
  if (!fs.lstatSync(nodeModulePath).isDirectory()) return false;
257
339
  const nodeModuleContentNames = fs.readdirSync(nodeModulePath);
258
- return (
259
- nodeModuleContentNames.includes('harmony') ||
260
- nodeModuleContentNames.includes('harmony.tar.gz')
261
- );
340
+ return nodeModuleContentNames.includes('package.json');
262
341
  }
263
342
 
264
343
  /**
265
344
  * @param packageJSONPath {string}
266
- * @returns {{name: string, harmony?: {alias?: string}}}
345
+ * @returns {{name: string, harmony?: {alias?: string, redirectInternalImports?: boolean}}}
267
346
  */
268
347
  function readHarmonyModulePackageJSON(packageJSONPath) {
269
348
  return JSON.parse(fs.readFileSync(packageJSONPath).toString());