metro 0.74.1 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metro",
3
- "version": "0.74.1",
3
+ "version": "0.75.0",
4
4
  "description": "🚇 The JavaScript bundler for React Native.",
5
5
  "main": "src/index.js",
6
6
  "bin": "src/cli.js",
@@ -35,23 +35,23 @@
35
35
  "invariant": "^2.2.4",
36
36
  "jest-worker": "^27.2.0",
37
37
  "lodash.throttle": "^4.1.1",
38
- "metro-babel-transformer": "0.74.1",
39
- "metro-cache": "0.74.1",
40
- "metro-cache-key": "0.74.1",
41
- "metro-config": "0.74.1",
42
- "metro-core": "0.74.1",
43
- "metro-file-map": "0.74.1",
44
- "metro-hermes-compiler": "0.74.1",
45
- "metro-inspector-proxy": "0.74.1",
46
- "metro-minify-terser": "0.74.1",
47
- "metro-minify-uglify": "0.74.1",
48
- "metro-react-native-babel-preset": "0.74.1",
49
- "metro-resolver": "0.74.1",
50
- "metro-runtime": "0.74.1",
51
- "metro-source-map": "0.74.1",
52
- "metro-symbolicate": "0.74.1",
53
- "metro-transform-plugins": "0.74.1",
54
- "metro-transform-worker": "0.74.1",
38
+ "metro-babel-transformer": "0.75.0",
39
+ "metro-cache": "0.75.0",
40
+ "metro-cache-key": "0.75.0",
41
+ "metro-config": "0.75.0",
42
+ "metro-core": "0.75.0",
43
+ "metro-file-map": "0.75.0",
44
+ "metro-hermes-compiler": "0.75.0",
45
+ "metro-inspector-proxy": "0.75.0",
46
+ "metro-minify-terser": "0.75.0",
47
+ "metro-minify-uglify": "0.75.0",
48
+ "metro-react-native-babel-preset": "0.75.0",
49
+ "metro-resolver": "0.75.0",
50
+ "metro-runtime": "0.75.0",
51
+ "metro-source-map": "0.75.0",
52
+ "metro-symbolicate": "0.75.0",
53
+ "metro-transform-plugins": "0.75.0",
54
+ "metro-transform-worker": "0.75.0",
55
55
  "mime-types": "^2.1.27",
56
56
  "node-fetch": "^2.2.0",
57
57
  "nullthrows": "^1.1.1",
@@ -70,13 +70,16 @@
70
70
  "dedent": "^0.7.0",
71
71
  "jest-snapshot": "^26.5.2",
72
72
  "jest-snapshot-serializer-raw": "^1.2.0",
73
- "metro-babel-register": "0.74.1",
74
- "metro-memory-fs": "0.74.1",
75
- "metro-react-native-babel-preset": "0.74.1",
76
- "metro-react-native-babel-transformer": "0.74.1",
73
+ "metro-babel-register": "0.75.0",
74
+ "metro-memory-fs": "0.75.0",
75
+ "metro-react-native-babel-preset": "0.75.0",
76
+ "metro-react-native-babel-transformer": "0.75.0",
77
77
  "mock-req": "^0.2.0",
78
78
  "mock-res": "^0.6.0",
79
79
  "stack-trace": "^0.0.10"
80
80
  },
81
- "license": "MIT"
81
+ "license": "MIT",
82
+ "engines": {
83
+ "node": ">=14.17.0"
84
+ }
82
85
  }
@@ -25,6 +25,7 @@ class DeltaCalculator extends EventEmitter {
25
25
  _deletedFiles = new Set();
26
26
  _modifiedFiles = new Set();
27
27
  _addedFiles = new Set();
28
+ _hasSymlinkChanges = false;
28
29
  constructor(entryPoints, changeEventSource, options) {
29
30
  super();
30
31
  this._options = options;
@@ -61,6 +62,7 @@ class DeltaCalculator extends EventEmitter {
61
62
  * which contain the modified/added modules and the removed modules.
62
63
  */
63
64
  async getDelta({ reset, shallow }) {
65
+ debug("Calculating delta (reset: %s, shallow: %s)", reset, shallow);
64
66
  // If there is already a build in progress, wait until it finish to start
65
67
  // processing a new one (delta server doesn't support concurrent builds).
66
68
  if (this._currentBuildPromise) {
@@ -76,6 +78,21 @@ class DeltaCalculator extends EventEmitter {
76
78
  this._deletedFiles = new Set();
77
79
  const addedFiles = this._addedFiles;
78
80
  this._addedFiles = new Set();
81
+ const hasSymlinkChanges = this._hasSymlinkChanges;
82
+ this._hasSymlinkChanges = false;
83
+
84
+ // Revisit all files if changes include symlinks - resolutions may be
85
+ // invalidated but we don't yet know which. This should be optimized in the
86
+ // future.
87
+ if (hasSymlinkChanges) {
88
+ const markModified = (file) => {
89
+ if (!addedFiles.has(file) && !deletedFiles.has(file)) {
90
+ modifiedFiles.add(file);
91
+ }
92
+ };
93
+ this._graph.dependencies.forEach((_, key) => markModified(key));
94
+ this._graph.entryPoints.forEach(markModified);
95
+ }
79
96
 
80
97
  // Concurrent requests should reuse the same bundling process. To do so,
81
98
  // this method stores the promise as an instance variable, and then it's
@@ -148,6 +165,13 @@ class DeltaCalculator extends EventEmitter {
148
165
  */
149
166
  _handleFileChange = ({ type, filePath, metadata }, logger) => {
150
167
  debug("Handling %s: %s (type: %s)", type, filePath, metadata.type);
168
+ if (metadata.type === "l") {
169
+ this._hasSymlinkChanges = true;
170
+ this.emit("change", {
171
+ logger,
172
+ });
173
+ return;
174
+ }
151
175
  let state;
152
176
  if (this._deletedFiles.has(filePath)) {
153
177
  state = "deleted";
@@ -33,6 +33,7 @@ class DeltaCalculator<T> extends EventEmitter {
33
33
  _deletedFiles: Set<string> = new Set();
34
34
  _modifiedFiles: Set<string> = new Set();
35
35
  _addedFiles: Set<string> = new Set();
36
+ _hasSymlinkChanges = false;
36
37
 
37
38
  _graph: Graph<T>;
38
39
 
@@ -87,6 +88,7 @@ class DeltaCalculator<T> extends EventEmitter {
87
88
  shallow: boolean,
88
89
  ...
89
90
  }): Promise<DeltaResult<T>> {
91
+ debug('Calculating delta (reset: %s, shallow: %s)', reset, shallow);
90
92
  // If there is already a build in progress, wait until it finish to start
91
93
  // processing a new one (delta server doesn't support concurrent builds).
92
94
  if (this._currentBuildPromise) {
@@ -102,6 +104,21 @@ class DeltaCalculator<T> extends EventEmitter {
102
104
  this._deletedFiles = new Set();
103
105
  const addedFiles = this._addedFiles;
104
106
  this._addedFiles = new Set();
107
+ const hasSymlinkChanges = this._hasSymlinkChanges;
108
+ this._hasSymlinkChanges = false;
109
+
110
+ // Revisit all files if changes include symlinks - resolutions may be
111
+ // invalidated but we don't yet know which. This should be optimized in the
112
+ // future.
113
+ if (hasSymlinkChanges) {
114
+ const markModified = (file: string) => {
115
+ if (!addedFiles.has(file) && !deletedFiles.has(file)) {
116
+ modifiedFiles.add(file);
117
+ }
118
+ };
119
+ this._graph.dependencies.forEach((_, key) => markModified(key));
120
+ this._graph.entryPoints.forEach(markModified);
121
+ }
105
122
 
106
123
  // Concurrent requests should reuse the same bundling process. To do so,
107
124
  // this method stores the promise as an instance variable, and then it's
@@ -190,6 +207,11 @@ class DeltaCalculator<T> extends EventEmitter {
190
207
  logger: ?RootPerfLogger,
191
208
  ): mixed => {
192
209
  debug('Handling %s: %s (type: %s)', type, filePath, metadata.type);
210
+ if (metadata.type === 'l') {
211
+ this._hasSymlinkChanges = true;
212
+ this.emit('change', {logger});
213
+ return;
214
+ }
193
215
  let state: void | 'deleted' | 'modified' | 'added';
194
216
  if (this._deletedFiles.has(filePath)) {
195
217
  state = 'deleted';
@@ -78,6 +78,7 @@ class WorkerFarm {
78
78
  return new JestWorker(workerPath, {
79
79
  computeWorkerKey: this._config.stickyWorkers
80
80
  ? // $FlowFixMe[method-unbinding] added when improving typing for this parameters
81
+ // $FlowFixMe[incompatible-call]
81
82
  this._computeWorkerKey
82
83
  : undefined,
83
84
  exposedMethods,
@@ -120,6 +120,7 @@ class WorkerFarm {
120
120
  return new JestWorker(workerPath, {
121
121
  computeWorkerKey: this._config.stickyWorkers
122
122
  ? // $FlowFixMe[method-unbinding] added when improving typing for this parameters
123
+ // $FlowFixMe[incompatible-call]
123
124
  this._computeWorkerKey
124
125
  : undefined,
125
126
  exposedMethods,
package/src/Server.js CHANGED
@@ -392,7 +392,7 @@ class Server {
392
392
  bundlePerfLogger:
393
393
  (_this$_config$unstabl =
394
394
  (_this$_config$unstabl2 = (_this$_config = this._config)
395
- .unstable_perfLogger) === null ||
395
+ .unstable_perfLoggerFactory) === null ||
396
396
  _this$_config$unstabl2 === void 0
397
397
  ? void 0
398
398
  : _this$_config$unstabl2.call(
@@ -519,7 +519,7 @@ class Server {
519
519
  await this._processBundleRequest(req, res, options, {
520
520
  buildNumber,
521
521
  bundlePerfLogger:
522
- this._config.unstable_perfLogger?.('BUNDLING_REQUEST', {
522
+ this._config.unstable_perfLoggerFactory?.('BUNDLING_REQUEST', {
523
523
  key: buildNumber,
524
524
  }) ?? noopLogger,
525
525
  });
@@ -60,6 +60,7 @@ function formatBundlingError(error) {
60
60
  return {
61
61
  type: "ResourceNotFoundError",
62
62
  // $FlowFixMe[missing-empty-array-annot]
63
+ // $FlowFixMe[incompatible-return]
63
64
  errors: [],
64
65
  message: error.message,
65
66
  };
@@ -67,6 +68,7 @@ function formatBundlingError(error) {
67
68
  return {
68
69
  type: "GraphNotFoundError",
69
70
  // $FlowFixMe[missing-empty-array-annot]
71
+ // $FlowFixMe[incompatible-return]
70
72
  errors: [],
71
73
  message: error.message,
72
74
  };
@@ -74,6 +76,7 @@ function formatBundlingError(error) {
74
76
  return {
75
77
  type: "RevisionNotFoundError",
76
78
  // $FlowFixMe[missing-empty-array-annot]
79
+ // $FlowFixMe[incompatible-return]
77
80
  errors: [],
78
81
  message: error.message,
79
82
  };
@@ -75,6 +75,7 @@ function formatBundlingError(error: CustomError): FormattedError {
75
75
  return {
76
76
  type: 'ResourceNotFoundError',
77
77
  // $FlowFixMe[missing-empty-array-annot]
78
+ // $FlowFixMe[incompatible-return]
78
79
  errors: [],
79
80
  message: error.message,
80
81
  };
@@ -82,6 +83,7 @@ function formatBundlingError(error: CustomError): FormattedError {
82
83
  return {
83
84
  type: 'GraphNotFoundError',
84
85
  // $FlowFixMe[missing-empty-array-annot]
86
+ // $FlowFixMe[incompatible-return]
85
87
  errors: [],
86
88
  message: error.message,
87
89
  };
@@ -89,6 +91,7 @@ function formatBundlingError(error: CustomError): FormattedError {
89
91
  return {
90
92
  type: 'RevisionNotFoundError',
91
93
  // $FlowFixMe[missing-empty-array-annot]
94
+ // $FlowFixMe[incompatible-return]
92
95
  errors: [],
93
96
  message: error.message,
94
97
  };
@@ -15,6 +15,7 @@ const { codeFrameColumns } = require("@babel/code-frame");
15
15
  const fs = require("fs");
16
16
  const invariant = require("invariant");
17
17
  const Resolver = require("metro-resolver");
18
+ const createDefaultContext = require("metro-resolver/src/createDefaultContext");
18
19
  const path = require("path");
19
20
  const util = require("util");
20
21
  class ModuleResolver {
@@ -52,53 +53,6 @@ class ModuleResolver {
52
53
  }
53
54
  return emptyModule;
54
55
  }
55
- _redirectRequire(fromModule, modulePath) {
56
- const moduleCache = this._options.moduleCache;
57
- try {
58
- if (modulePath.startsWith(".")) {
59
- const fromPackage = fromModule.getPackage();
60
- if (fromPackage) {
61
- // We need to convert the module path from module-relative to
62
- // package-relative, so that we can easily match it against the
63
- // "browser" map (where all paths are relative to the package root)
64
- const fromPackagePath =
65
- "./" +
66
- path.relative(
67
- path.dirname(fromPackage.path),
68
- path.resolve(path.dirname(fromModule.path), modulePath)
69
- );
70
- let redirectedPath = fromPackage.redirectRequire(
71
- fromPackagePath,
72
- this._options.mainFields
73
- );
74
-
75
- // Since the redirected path is still relative to the package root,
76
- // we have to transform it back to be module-relative (as it
77
- // originally was)
78
- if (redirectedPath !== false) {
79
- redirectedPath =
80
- "./" +
81
- path.relative(
82
- path.dirname(fromModule.path),
83
- path.resolve(path.dirname(fromPackage.path), redirectedPath)
84
- );
85
- }
86
- return redirectedPath;
87
- }
88
- } else {
89
- const pck = path.isAbsolute(modulePath)
90
- ? moduleCache.getPackageOf(modulePath)
91
- : fromModule.getPackage();
92
- if (pck) {
93
- return pck.redirectRequire(modulePath, this._options.mainFields);
94
- }
95
- }
96
- } catch (err) {
97
- // Do nothing. The standard module cache does not trigger any error, but
98
- // the ModuleGraph one does, if the module does not exist.
99
- }
100
- return modulePath;
101
- }
102
56
  resolveDependency(
103
57
  fromModule,
104
58
  moduleName,
@@ -106,29 +60,53 @@ class ModuleResolver {
106
60
  platform,
107
61
  resolverOptions
108
62
  ) {
63
+ const {
64
+ disableHierarchicalLookup,
65
+ doesFileExist,
66
+ extraNodeModules,
67
+ isAssetFile,
68
+ mainFields,
69
+ nodeModulesPaths,
70
+ preferNativePlatform,
71
+ resolveAsset,
72
+ resolveRequest,
73
+ sourceExts,
74
+ unstable_conditionNames,
75
+ unstable_conditionsByPlatform,
76
+ unstable_enablePackageExports,
77
+ } = this._options;
109
78
  try {
110
79
  var _resolverOptions$cust;
111
80
  const result = Resolver.resolve(
112
- {
113
- ...this._options,
81
+ createDefaultContext({
82
+ allowHaste,
83
+ disableHierarchicalLookup,
84
+ doesFileExist,
85
+ extraNodeModules,
86
+ isAssetFile,
87
+ mainFields,
88
+ nodeModulesPaths,
89
+ preferNativePlatform,
90
+ resolveAsset,
91
+ resolveRequest,
92
+ sourceExts,
93
+ unstable_conditionNames,
94
+ unstable_conditionsByPlatform,
95
+ unstable_enablePackageExports,
114
96
  customResolverOptions:
115
97
  (_resolverOptions$cust = resolverOptions.customResolverOptions) !==
116
98
  null && _resolverOptions$cust !== void 0
117
99
  ? _resolverOptions$cust
118
100
  : {},
119
101
  originModulePath: fromModule.path,
120
- redirectModulePath: (modulePath) =>
121
- this._redirectRequire(fromModule, modulePath),
122
- allowHaste,
123
- platform,
124
102
  resolveHasteModule: (name) =>
125
103
  this._options.getHasteModulePath(name, platform),
126
104
  resolveHastePackage: (name) =>
127
105
  this._options.getHastePackagePath(name, platform),
128
- getPackageMainPath: this._getPackageMainPath,
129
- unstable_enablePackageExports:
130
- this._options.unstable_enablePackageExports,
131
- },
106
+ getPackage: this._getPackage,
107
+ getPackageForModule: (modulePath) =>
108
+ this._getPackageForModule(fromModule, modulePath),
109
+ }),
132
110
  moduleName,
133
111
  platform
134
112
  );
@@ -176,9 +154,29 @@ class ModuleResolver {
176
154
  throw error;
177
155
  }
178
156
  }
179
- _getPackageMainPath = (packageJsonPath) => {
180
- const package_ = this._options.moduleCache.getPackage(packageJsonPath);
181
- return package_.getMain(this._options.mainFields);
157
+ _getPackage = (packageJsonPath) => {
158
+ try {
159
+ return this._options.moduleCache.getPackage(packageJsonPath).read();
160
+ } catch (e) {
161
+ // Do nothing. The standard module cache does not trigger any error, but
162
+ // the ModuleGraph one does, if the module does not exist.
163
+ }
164
+ return null;
165
+ };
166
+ _getPackageForModule = (fromModule, modulePath) => {
167
+ let pkg;
168
+ try {
169
+ pkg = this._options.moduleCache.getPackageOf(modulePath);
170
+ } catch (e) {
171
+ // Do nothing. The standard module cache does not trigger any error, but
172
+ // the ModuleGraph one does, if the module does not exist.
173
+ }
174
+ return pkg != null
175
+ ? {
176
+ rootPath: path.dirname(pkg.path),
177
+ packageJson: pkg.read(),
178
+ }
179
+ : null;
182
180
  };
183
181
 
184
182
  /**
@@ -19,25 +19,23 @@ import type {
19
19
  Resolution,
20
20
  ResolveAsset,
21
21
  } from 'metro-resolver';
22
+ import type {ResolverInputOptions} from '../../shared/types.flow';
23
+ import type {PackageInfo, PackageJson} from 'metro-resolver/src/types';
22
24
 
23
25
  const {codeFrameColumns} = require('@babel/code-frame');
24
26
  const fs = require('fs');
25
27
  const invariant = require('invariant');
26
28
  const Resolver = require('metro-resolver');
29
+ const createDefaultContext = require('metro-resolver/src/createDefaultContext');
27
30
  const path = require('path');
28
31
  const util = require('util');
29
- import type {ResolverInputOptions} from '../../shared/types.flow';
30
32
  import type {BundlerResolution} from '../../DeltaBundler/types.flow';
31
33
 
32
34
  export type DirExistsFn = (filePath: string) => boolean;
33
35
 
34
36
  export type Packageish = interface {
35
37
  path: string,
36
- redirectRequire(
37
- toModuleName: string,
38
- mainFields: $ReadOnlyArray<string>,
39
- ): string | false,
40
- getMain(mainFields: $ReadOnlyArray<string>): string,
38
+ read(): PackageJson,
41
39
  };
42
40
 
43
41
  export type Moduleish = interface {
@@ -117,59 +115,6 @@ class ModuleResolver<TPackage: Packageish> {
117
115
  return emptyModule;
118
116
  }
119
117
 
120
- _redirectRequire(fromModule: Moduleish, modulePath: string): string | false {
121
- const moduleCache = this._options.moduleCache;
122
- try {
123
- if (modulePath.startsWith('.')) {
124
- const fromPackage = fromModule.getPackage();
125
-
126
- if (fromPackage) {
127
- // We need to convert the module path from module-relative to
128
- // package-relative, so that we can easily match it against the
129
- // "browser" map (where all paths are relative to the package root)
130
- const fromPackagePath =
131
- './' +
132
- path.relative(
133
- path.dirname(fromPackage.path),
134
- path.resolve(path.dirname(fromModule.path), modulePath),
135
- );
136
-
137
- let redirectedPath = fromPackage.redirectRequire(
138
- fromPackagePath,
139
- this._options.mainFields,
140
- );
141
-
142
- // Since the redirected path is still relative to the package root,
143
- // we have to transform it back to be module-relative (as it
144
- // originally was)
145
- if (redirectedPath !== false) {
146
- redirectedPath =
147
- './' +
148
- path.relative(
149
- path.dirname(fromModule.path),
150
- path.resolve(path.dirname(fromPackage.path), redirectedPath),
151
- );
152
- }
153
-
154
- return redirectedPath;
155
- }
156
- } else {
157
- const pck = path.isAbsolute(modulePath)
158
- ? moduleCache.getPackageOf(modulePath)
159
- : fromModule.getPackage();
160
-
161
- if (pck) {
162
- return pck.redirectRequire(modulePath, this._options.mainFields);
163
- }
164
- }
165
- } catch (err) {
166
- // Do nothing. The standard module cache does not trigger any error, but
167
- // the ModuleGraph one does, if the module does not exist.
168
- }
169
-
170
- return modulePath;
171
- }
172
-
173
118
  resolveDependency(
174
119
  fromModule: Moduleish,
175
120
  moduleName: string,
@@ -177,24 +122,49 @@ class ModuleResolver<TPackage: Packageish> {
177
122
  platform: string | null,
178
123
  resolverOptions: ResolverInputOptions,
179
124
  ): BundlerResolution {
125
+ const {
126
+ disableHierarchicalLookup,
127
+ doesFileExist,
128
+ extraNodeModules,
129
+ isAssetFile,
130
+ mainFields,
131
+ nodeModulesPaths,
132
+ preferNativePlatform,
133
+ resolveAsset,
134
+ resolveRequest,
135
+ sourceExts,
136
+ unstable_conditionNames,
137
+ unstable_conditionsByPlatform,
138
+ unstable_enablePackageExports,
139
+ } = this._options;
140
+
180
141
  try {
181
142
  const result = Resolver.resolve(
182
- {
183
- ...this._options,
143
+ createDefaultContext({
144
+ allowHaste,
145
+ disableHierarchicalLookup,
146
+ doesFileExist,
147
+ extraNodeModules,
148
+ isAssetFile,
149
+ mainFields,
150
+ nodeModulesPaths,
151
+ preferNativePlatform,
152
+ resolveAsset,
153
+ resolveRequest,
154
+ sourceExts,
155
+ unstable_conditionNames,
156
+ unstable_conditionsByPlatform,
157
+ unstable_enablePackageExports,
184
158
  customResolverOptions: resolverOptions.customResolverOptions ?? {},
185
159
  originModulePath: fromModule.path,
186
- redirectModulePath: (modulePath: string) =>
187
- this._redirectRequire(fromModule, modulePath),
188
- allowHaste,
189
- platform,
190
160
  resolveHasteModule: (name: string) =>
191
161
  this._options.getHasteModulePath(name, platform),
192
162
  resolveHastePackage: (name: string) =>
193
163
  this._options.getHastePackagePath(name, platform),
194
- getPackageMainPath: this._getPackageMainPath,
195
- unstable_enablePackageExports:
196
- this._options.unstable_enablePackageExports,
197
- },
164
+ getPackage: this._getPackage,
165
+ getPackageForModule: (modulePath: string) =>
166
+ this._getPackageForModule(fromModule, modulePath),
167
+ }),
198
168
  moduleName,
199
169
  platform,
200
170
  );
@@ -245,9 +215,36 @@ class ModuleResolver<TPackage: Packageish> {
245
215
  }
246
216
  }
247
217
 
248
- _getPackageMainPath = (packageJsonPath: string): string => {
249
- const package_ = this._options.moduleCache.getPackage(packageJsonPath);
250
- return package_.getMain(this._options.mainFields);
218
+ _getPackage = (packageJsonPath: string): ?PackageJson => {
219
+ try {
220
+ return this._options.moduleCache.getPackage(packageJsonPath).read();
221
+ } catch (e) {
222
+ // Do nothing. The standard module cache does not trigger any error, but
223
+ // the ModuleGraph one does, if the module does not exist.
224
+ }
225
+
226
+ return null;
227
+ };
228
+
229
+ _getPackageForModule = (
230
+ fromModule: Moduleish,
231
+ modulePath: string,
232
+ ): ?PackageInfo => {
233
+ let pkg;
234
+
235
+ try {
236
+ pkg = this._options.moduleCache.getPackageOf(modulePath);
237
+ } catch (e) {
238
+ // Do nothing. The standard module cache does not trigger any error, but
239
+ // the ModuleGraph one does, if the module does not exist.
240
+ }
241
+
242
+ return pkg != null
243
+ ? {
244
+ rootPath: path.dirname(pkg.path),
245
+ packageJson: pkg.read(),
246
+ }
247
+ : null;
251
248
  };
252
249
 
253
250
  /**
@@ -108,7 +108,7 @@ function createHasteMap(config, options) {
108
108
  : options.cacheFilePrefix,
109
109
  });
110
110
  },
111
- perfLoggerFactory: config.unstable_perfLogger,
111
+ perfLoggerFactory: config.unstable_perfLoggerFactory,
112
112
  computeDependencies,
113
113
  computeSha1: true,
114
114
  dependencyExtractor: config.resolver.dependencyExtractor,
@@ -66,7 +66,7 @@ function createHasteMap(
66
66
  config.fileMapCacheDirectory ?? config.hasteMapCacheDirectory,
67
67
  cacheFilePrefix: options?.cacheFilePrefix,
68
68
  })),
69
- perfLoggerFactory: config.unstable_perfLogger,
69
+ perfLoggerFactory: config.unstable_perfLoggerFactory,
70
70
  computeDependencies,
71
71
  computeSha1: true,
72
72
  dependencyExtractor: config.resolver.dependencyExtractor,
@@ -19,85 +19,9 @@ class Package {
19
19
  this._root = path.dirname(this.path);
20
20
  this._content = null;
21
21
  }
22
-
23
- /**
24
- * The `browser` field and replacement behavior is specified in
25
- * https://github.com/defunctzombie/package-browser-field-spec.
26
- */
27
- getMain(mainFields) {
28
- const json = this.read();
29
- let main;
30
- for (const name of mainFields) {
31
- if (typeof json[name] === "string") {
32
- main = json[name];
33
- break;
34
- }
35
- }
36
-
37
- // flowlint-next-line sketchy-null-string:off
38
- if (!main) {
39
- main = "index";
40
- }
41
- const replacements = getReplacements(json, mainFields);
42
- if (replacements) {
43
- const variants = [main];
44
- if (main.slice(0, 2) === "./") {
45
- variants.push(main.slice(2));
46
- } else {
47
- variants.push("./" + main);
48
- }
49
- for (const variant of variants) {
50
- const winner =
51
- replacements[variant] ||
52
- replacements[variant + ".js"] ||
53
- replacements[variant + ".json"] ||
54
- replacements[variant.replace(/(\.js|\.json)$/, "")];
55
- if (winner) {
56
- main = winner;
57
- break;
58
- }
59
- }
60
- }
61
- return path.join(this._root, main);
62
- }
63
22
  invalidate() {
64
23
  this._content = null;
65
24
  }
66
- redirectRequire(name, mainFields) {
67
- const json = this.read();
68
- const replacements = getReplacements(json, mainFields);
69
- if (!replacements) {
70
- return name;
71
- }
72
- if (!name.startsWith(".") && !path.isAbsolute(name)) {
73
- const replacement = replacements[name];
74
- // support exclude with "someDependency": false
75
- return replacement === false ? false : replacement || name;
76
- }
77
- let relPath =
78
- "./" + path.relative(this._root, path.resolve(this._root, name));
79
- if (path.sep !== "/") {
80
- relPath = relPath.replace(new RegExp("\\" + path.sep, "g"), "/");
81
- }
82
- let redirect = replacements[relPath];
83
-
84
- // false is a valid value
85
- if (redirect == null) {
86
- redirect = replacements[relPath + ".js"];
87
- if (redirect == null) {
88
- redirect = replacements[relPath + ".json"];
89
- }
90
- }
91
-
92
- // support exclude with "./someFile": false
93
- if (redirect === false) {
94
- return false;
95
- }
96
- if (redirect) {
97
- return path.join(this._root, redirect);
98
- }
99
- return name;
100
- }
101
25
  read() {
102
26
  if (this._content == null) {
103
27
  this._content = JSON.parse(fs.readFileSync(this.path, "utf8"));
@@ -105,20 +29,4 @@ class Package {
105
29
  return this._content;
106
30
  }
107
31
  }
108
- function getReplacements(pkg, mainFields) {
109
- const replacements = mainFields
110
- .map((name) => {
111
- // If the field is a string, that doesn't mean we want to redirect the
112
- // `main` file itself to anything else. See the spec.
113
- if (!pkg[name] || typeof pkg[name] === "string") {
114
- return null;
115
- }
116
- return pkg[name];
117
- })
118
- .filter(Boolean);
119
- if (!replacements.length) {
120
- return null;
121
- }
122
- return Object.assign({}, ...replacements.reverse());
123
- }
124
32
  module.exports = Package;
@@ -11,22 +11,16 @@
11
11
 
12
12
  'use strict';
13
13
 
14
+ import type {PackageJson} from 'metro-resolver/src/types';
15
+
14
16
  const fs = require('fs');
15
17
  const path = require('path');
16
18
 
17
- type PackageContent = {
18
- name: string,
19
- 'react-native': mixed,
20
- browser: mixed,
21
- main: ?string,
22
- ...
23
- };
24
-
25
19
  class Package {
26
20
  path: string;
27
21
 
28
22
  _root: string;
29
- _content: ?PackageContent;
23
+ _content: ?PackageJson;
30
24
 
31
25
  constructor({file}: {file: string, ...}) {
32
26
  this.path = path.resolve(file);
@@ -34,104 +28,11 @@ class Package {
34
28
  this._content = null;
35
29
  }
36
30
 
37
- /**
38
- * The `browser` field and replacement behavior is specified in
39
- * https://github.com/defunctzombie/package-browser-field-spec.
40
- */
41
- getMain(mainFields: $ReadOnlyArray<string>): string {
42
- const json = this.read();
43
-
44
- let main;
45
-
46
- for (const name of mainFields) {
47
- if (typeof json[name] === 'string') {
48
- main = json[name];
49
- break;
50
- }
51
- }
52
-
53
- // flowlint-next-line sketchy-null-string:off
54
- if (!main) {
55
- main = 'index';
56
- }
57
-
58
- const replacements = getReplacements(json, mainFields);
59
- if (replacements) {
60
- const variants = [main];
61
- if (main.slice(0, 2) === './') {
62
- variants.push(main.slice(2));
63
- } else {
64
- variants.push('./' + main);
65
- }
66
-
67
- for (const variant of variants) {
68
- const winner =
69
- replacements[variant] ||
70
- replacements[variant + '.js'] ||
71
- replacements[variant + '.json'] ||
72
- replacements[variant.replace(/(\.js|\.json)$/, '')];
73
-
74
- if (winner) {
75
- main = winner;
76
- break;
77
- }
78
- }
79
- }
80
-
81
- return path.join(this._root, main);
82
- }
83
-
84
31
  invalidate() {
85
32
  this._content = null;
86
33
  }
87
34
 
88
- redirectRequire(
89
- name: string,
90
- mainFields: $ReadOnlyArray<string>,
91
- ): string | false {
92
- const json = this.read();
93
- const replacements = getReplacements(json, mainFields);
94
-
95
- if (!replacements) {
96
- return name;
97
- }
98
-
99
- if (!name.startsWith('.') && !path.isAbsolute(name)) {
100
- const replacement = replacements[name];
101
- // support exclude with "someDependency": false
102
- return replacement === false ? false : replacement || name;
103
- }
104
-
105
- let relPath =
106
- './' + path.relative(this._root, path.resolve(this._root, name));
107
-
108
- if (path.sep !== '/') {
109
- relPath = relPath.replace(new RegExp('\\' + path.sep, 'g'), '/');
110
- }
111
-
112
- let redirect = replacements[relPath];
113
-
114
- // false is a valid value
115
- if (redirect == null) {
116
- redirect = replacements[relPath + '.js'];
117
- if (redirect == null) {
118
- redirect = replacements[relPath + '.json'];
119
- }
120
- }
121
-
122
- // support exclude with "./someFile": false
123
- if (redirect === false) {
124
- return false;
125
- }
126
-
127
- if (redirect) {
128
- return path.join(this._root, redirect);
129
- }
130
-
131
- return name;
132
- }
133
-
134
- read(): PackageContent {
35
+ read(): PackageJson {
135
36
  if (this._content == null) {
136
37
  this._content = JSON.parse(fs.readFileSync(this.path, 'utf8'));
137
38
  }
@@ -139,27 +40,4 @@ class Package {
139
40
  }
140
41
  }
141
42
 
142
- function getReplacements(
143
- pkg: PackageContent,
144
- mainFields: $ReadOnlyArray<string>,
145
- ): ?{[string]: string | false, ...} {
146
- const replacements = mainFields
147
- .map((name: string) => {
148
- // If the field is a string, that doesn't mean we want to redirect the
149
- // `main` file itself to anything else. See the spec.
150
- if (!pkg[name] || typeof pkg[name] === 'string') {
151
- return null;
152
- }
153
-
154
- return pkg[name];
155
- })
156
- .filter(Boolean);
157
-
158
- if (!replacements.length) {
159
- return null;
160
- }
161
-
162
- return Object.assign({}, ...replacements.reverse());
163
- }
164
-
165
43
  module.exports = Package;