metro 0.84.2 → 0.84.4

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 (42) hide show
  1. package/package.json +15 -16
  2. package/src/Assets.js +20 -13
  3. package/src/Assets.js.flow +20 -13
  4. package/src/Bundler/util.js.flow +3 -3
  5. package/src/DeltaBundler/DeltaCalculator.d.ts +1 -11
  6. package/src/DeltaBundler/DeltaCalculator.js +55 -46
  7. package/src/DeltaBundler/DeltaCalculator.js.flow +72 -61
  8. package/src/DeltaBundler/getTransformCacheKey.js +3 -1
  9. package/src/DeltaBundler/getTransformCacheKey.js.flow +7 -2
  10. package/src/HmrServer.d.ts +15 -3
  11. package/src/HmrServer.js +7 -0
  12. package/src/HmrServer.js.flow +15 -5
  13. package/src/ModuleGraph/worker/collectDependencies.js +52 -0
  14. package/src/ModuleGraph/worker/collectDependencies.js.flow +67 -0
  15. package/src/Server.d.ts +4 -1
  16. package/src/Server.js +42 -5
  17. package/src/Server.js.flow +45 -5
  18. package/src/index.d.ts +22 -3
  19. package/src/index.flow.js +2 -2
  20. package/src/index.flow.js.flow +23 -4
  21. package/src/lib/JsonReporter.js.flow +2 -2
  22. package/src/lib/TerminalReporter.js +39 -41
  23. package/src/lib/TerminalReporter.js.flow +51 -32
  24. package/src/lib/getAppendScripts.js.flow +2 -2
  25. package/src/lib/logToConsole.js +8 -7
  26. package/src/lib/logToConsole.js.flow +7 -7
  27. package/src/lib/reporting.js +16 -7
  28. package/src/lib/reporting.js.flow +16 -5
  29. package/src/node-haste/DependencyGraph/ModuleResolution.d.ts +9 -22
  30. package/src/node-haste/DependencyGraph/ModuleResolution.js +4 -22
  31. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +10 -59
  32. package/src/node-haste/DependencyGraph/createFileMap.js +1 -2
  33. package/src/node-haste/DependencyGraph/createFileMap.js.flow +4 -3
  34. package/src/node-haste/DependencyGraph.d.ts +2 -5
  35. package/src/node-haste/DependencyGraph.js +22 -11
  36. package/src/node-haste/DependencyGraph.js.flow +24 -13
  37. package/src/node-haste/PackageCache.d.ts +12 -16
  38. package/src/node-haste/PackageCache.js +65 -54
  39. package/src/node-haste/PackageCache.js.flow +103 -79
  40. package/src/node-haste/Package.d.ts +0 -28
  41. package/src/node-haste/Package.js +0 -28
  42. package/src/node-haste/Package.js.flow +0 -39
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @noformat
8
8
  * @oncall react_native
9
- * @generated SignedSource<<eb945b3566e9ed370894adaada197736>>
9
+ * @generated SignedSource<<13f1483d2a732241f8d9eae463399b0e>>
10
10
  *
11
11
  * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
12
12
  * Original file: packages/metro/src/node-haste/DependencyGraph.js
@@ -20,7 +20,6 @@ import type {
20
20
  TransformResultDependency,
21
21
  } from '../DeltaBundler/types';
22
22
  import type {ResolverInputOptions} from '../shared/types';
23
- import type Package from './Package';
24
23
  import type {ConfigT} from 'metro-config';
25
24
  import type {
26
25
  ChangeEvent,
@@ -32,7 +31,6 @@ import type {
32
31
  } from 'metro-file-map';
33
32
 
34
33
  import {ModuleResolver} from './DependencyGraph/ModuleResolution';
35
- import {PackageCache} from './PackageCache';
36
34
  import EventEmitter from 'events';
37
35
 
38
36
  declare class DependencyGraph extends EventEmitter {
@@ -40,7 +38,7 @@ declare class DependencyGraph extends EventEmitter {
40
38
  _haste: MetroFileMap;
41
39
  _fileSystem: FileSystem;
42
40
  _hasteMap: HasteMap;
43
- _moduleResolver: ModuleResolver<Package>;
41
+ _moduleResolver: ModuleResolver;
44
42
  _resolutionCache: Map<
45
43
  string | symbol,
46
44
  Map<
@@ -64,7 +62,6 @@ declare class DependencyGraph extends EventEmitter {
64
62
  _getClosestPackage(
65
63
  absoluteModulePath: string,
66
64
  ): null | undefined | {packageJsonPath: string; packageRelativePath: string};
67
- _createPackageCache(): PackageCache;
68
65
  getAllFiles(): Array<string>;
69
66
  /**
70
67
  * Used when watcher.unstable_lazySha1 is true
@@ -71,7 +71,10 @@ class DependencyGraph extends _events.default {
71
71
  this._onWatcherHealthCheck(result),
72
72
  );
73
73
  this._resolutionCache = new Map();
74
- this.#packageCache = this._createPackageCache();
74
+ this.#packageCache = new _PackageCache.PackageCache({
75
+ getClosestPackage: (absoluteModulePath) =>
76
+ this._getClosestPackage(absoluteModulePath),
77
+ });
75
78
  this._createModuleResolver();
76
79
  });
77
80
  }
@@ -90,10 +93,14 @@ class DependencyGraph extends _events.default {
90
93
  async ready() {
91
94
  await this._initializedPromise;
92
95
  }
93
- _onHasteChange({ eventsQueue }) {
96
+ _onHasteChange({ changes, rootDir }) {
94
97
  this._resolutionCache = new Map();
95
- eventsQueue.forEach(({ filePath }) =>
96
- this.#packageCache.invalidate(filePath),
98
+ [
99
+ ...changes.addedFiles,
100
+ ...changes.modifiedFiles,
101
+ ...changes.removedFiles,
102
+ ].forEach(([canonicalPath]) =>
103
+ this.#packageCache.invalidate(_path.default.join(rootDir, canonicalPath)),
97
104
  );
98
105
  this._createModuleResolver();
99
106
  this.emit("change");
@@ -130,9 +137,19 @@ class DependencyGraph extends _events.default {
130
137
  this._hasteMap.getModule(name, platform, true),
131
138
  getHastePackagePath: (name, platform) =>
132
139
  this._hasteMap.getPackage(name, platform, true),
140
+ getPackage: (packageJsonPath) => {
141
+ try {
142
+ return (
143
+ this.#packageCache.getPackage(packageJsonPath).packageJson ?? null
144
+ );
145
+ } catch {
146
+ return null;
147
+ }
148
+ },
149
+ getPackageForModule: (absolutePath) =>
150
+ this.#packageCache.getPackageForModule(absolutePath),
133
151
  mainFields: this._config.resolver.resolverMainFields,
134
152
  nodeModulesPaths: this._config.resolver.nodeModulesPaths,
135
- packageCache: this.#packageCache,
136
153
  preferNativePlatform: true,
137
154
  projectRoot: this._config.projectRoot,
138
155
  reporter: this._config.reporter,
@@ -176,12 +193,6 @@ class DependencyGraph extends _events.default {
176
193
  }
177
194
  : null;
178
195
  }
179
- _createPackageCache() {
180
- return new _PackageCache.PackageCache({
181
- getClosestPackage: (absolutePath) =>
182
- this._getClosestPackage(absolutePath),
183
- });
184
- }
185
196
  getAllFiles() {
186
197
  return (0, _nullthrows.default)(this._fileSystem).getAllFiles();
187
198
  }
@@ -14,7 +14,6 @@ import type {
14
14
  TransformResultDependency,
15
15
  } from '../DeltaBundler/types';
16
16
  import type {ResolverInputOptions} from '../shared/types';
17
- import type Package from './Package';
18
17
  import type {ConfigT} from 'metro-config';
19
18
  import type {
20
19
  ChangeEvent,
@@ -66,7 +65,7 @@ export default class DependencyGraph extends EventEmitter {
66
65
  #packageCache: PackageCache;
67
66
  _hasteMap: HasteMap;
68
67
  #dependencyPlugin: ?DependencyPlugin;
69
- _moduleResolver: ModuleResolver<Package>;
68
+ _moduleResolver: ModuleResolver;
70
69
  _resolutionCache: Map<
71
70
  // Custom resolver options
72
71
  string | symbol,
@@ -131,7 +130,10 @@ export default class DependencyGraph extends EventEmitter {
131
130
  this._onWatcherHealthCheck(result),
132
131
  );
133
132
  this._resolutionCache = new Map();
134
- this.#packageCache = this._createPackageCache();
133
+ this.#packageCache = new PackageCache({
134
+ getClosestPackage: absoluteModulePath =>
135
+ this._getClosestPackage(absoluteModulePath),
136
+ });
135
137
  this._createModuleResolver();
136
138
  });
137
139
  }
@@ -150,10 +152,14 @@ export default class DependencyGraph extends EventEmitter {
150
152
  await this._initializedPromise;
151
153
  }
152
154
 
153
- _onHasteChange({eventsQueue}: ChangeEvent) {
155
+ _onHasteChange({changes, rootDir}: ChangeEvent) {
154
156
  this._resolutionCache = new Map();
155
- eventsQueue.forEach(({filePath}) =>
156
- this.#packageCache.invalidate(filePath),
157
+ [
158
+ ...changes.addedFiles,
159
+ ...changes.modifiedFiles,
160
+ ...changes.removedFiles,
161
+ ].forEach(([canonicalPath]) =>
162
+ this.#packageCache.invalidate(path.join(rootDir, canonicalPath)),
157
163
  );
158
164
  this._createModuleResolver();
159
165
  this.emit('change');
@@ -190,9 +196,20 @@ export default class DependencyGraph extends EventEmitter {
190
196
  this._hasteMap.getModule(name, platform, true),
191
197
  getHastePackagePath: (name, platform) =>
192
198
  this._hasteMap.getPackage(name, platform, true),
199
+ getPackage: (packageJsonPath: string) => {
200
+ try {
201
+ return (
202
+ this.#packageCache.getPackage(packageJsonPath).packageJson ?? null
203
+ );
204
+ } catch {
205
+ // Non-existence or malformed JSON, we treat both as non-existent
206
+ return null;
207
+ }
208
+ },
209
+ getPackageForModule: (absolutePath: string) =>
210
+ this.#packageCache.getPackageForModule(absolutePath),
193
211
  mainFields: this._config.resolver.resolverMainFields,
194
212
  nodeModulesPaths: this._config.resolver.nodeModulesPaths,
195
- packageCache: this.#packageCache,
196
213
  preferNativePlatform: true,
197
214
  projectRoot: this._config.projectRoot,
198
215
  reporter: this._config.reporter,
@@ -241,12 +258,6 @@ export default class DependencyGraph extends EventEmitter {
241
258
  : null;
242
259
  }
243
260
 
244
- _createPackageCache(): PackageCache {
245
- return new PackageCache({
246
- getClosestPackage: absolutePath => this._getClosestPackage(absolutePath),
247
- });
248
- }
249
-
250
261
  getAllFiles(): Array<string> {
251
262
  return nullthrows(this._fileSystem).getAllFiles();
252
263
  }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @noformat
8
8
  * @oncall react_native
9
- * @generated SignedSource<<eaea6d7e01d54353f700cdadd60c4bf2>>
9
+ * @generated SignedSource<<768dba0958b531c8edd43c2df24e25f6>>
10
10
  *
11
11
  * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
12
12
  * Original file: packages/metro/src/node-haste/PackageCache.js
@@ -15,27 +15,23 @@
15
15
  * yarn run build-ts-defs (OSS)
16
16
  */
17
17
 
18
- import Package from './Package';
18
+ import type {PackageJson} from 'metro-resolver/private/types';
19
19
 
20
20
  type GetClosestPackageFn = (
21
21
  absoluteFilePath: string,
22
22
  ) => null | undefined | {packageJsonPath: string; packageRelativePath: string};
23
+ type PackageForModule = Readonly<{
24
+ packageJson: PackageJson;
25
+ rootPath: string;
26
+ packageRelativePath: string;
27
+ }>;
23
28
  export declare class PackageCache {
24
- _getClosestPackage: GetClosestPackageFn;
25
- _packageCache: {[filePath: string]: Package};
26
- _packagePathAndSubpathByModulePath: {
27
- [filePath: string]:
28
- | null
29
- | undefined
30
- | {packageJsonPath: string; packageRelativePath: string};
31
- };
32
- _modulePathsByPackagePath: {
33
- [filePath: string]: Set<string>;
34
- };
35
29
  constructor(options: {getClosestPackage: GetClosestPackageFn});
36
- getPackage(filePath: string): Package;
37
- getPackageOf(
30
+ getPackage(
31
+ filePath: string,
32
+ ): Readonly<{rootPath: string; packageJson: PackageJson}>;
33
+ getPackageForModule(
38
34
  absoluteModulePath: string,
39
- ): null | undefined | {pkg: Package; packageRelativePath: string};
35
+ ): null | undefined | PackageForModule;
40
36
  invalidate(filePath: string): void;
41
37
  }
@@ -4,78 +4,89 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true,
5
5
  });
6
6
  exports.PackageCache = void 0;
7
- var _Package = _interopRequireDefault(require("./Package"));
8
- function _interopRequireDefault(e) {
9
- return e && e.__esModule ? e : { default: e };
10
- }
7
+ var _fs = require("fs");
8
+ var _path = require("path");
11
9
  class PackageCache {
10
+ #getClosestPackage;
11
+ #packageCache;
12
+ #resultByModulePath;
13
+ #modulePathsByPackagePath;
14
+ #modulePathsWithNoPackage;
12
15
  constructor(options) {
13
- this._getClosestPackage = options.getClosestPackage;
14
- this._packageCache = Object.create(null);
15
- this._packagePathAndSubpathByModulePath = Object.create(null);
16
- this._modulePathsByPackagePath = Object.create(null);
16
+ this.#getClosestPackage = options.getClosestPackage;
17
+ this.#packageCache = new Map();
18
+ this.#resultByModulePath = new Map();
19
+ this.#modulePathsByPackagePath = new Map();
20
+ this.#modulePathsWithNoPackage = new Set();
17
21
  }
18
22
  getPackage(filePath) {
19
- if (!this._packageCache[filePath]) {
20
- this._packageCache[filePath] = new _Package.default({
21
- file: filePath,
22
- });
23
+ let cached = this.#packageCache.get(filePath);
24
+ if (cached == null) {
25
+ cached = {
26
+ rootPath: (0, _path.dirname)(filePath),
27
+ packageJson: JSON.parse((0, _fs.readFileSync)(filePath, "utf8")),
28
+ };
29
+ this.#packageCache.set(filePath, cached);
23
30
  }
24
- return this._packageCache[filePath];
31
+ return cached;
25
32
  }
26
- getPackageOf(absoluteModulePath) {
27
- let packagePathAndSubpath =
28
- this._packagePathAndSubpathByModulePath[absoluteModulePath];
29
- if (
30
- packagePathAndSubpath &&
31
- this._packageCache[packagePathAndSubpath.packageJsonPath]
32
- ) {
33
- return {
34
- pkg: this._packageCache[packagePathAndSubpath.packageJsonPath],
35
- packageRelativePath: packagePathAndSubpath.packageRelativePath,
36
- };
33
+ getPackageForModule(absoluteModulePath) {
34
+ const cached = this.#resultByModulePath.get(absoluteModulePath);
35
+ if (cached !== undefined) {
36
+ return cached;
37
37
  }
38
- packagePathAndSubpath = this._getClosestPackage(absoluteModulePath);
39
- if (!packagePathAndSubpath) {
38
+ const closest = this.#getClosestPackage(absoluteModulePath);
39
+ if (closest == null) {
40
+ this.#resultByModulePath.set(absoluteModulePath, null);
41
+ this.#modulePathsWithNoPackage.add(absoluteModulePath);
40
42
  return null;
41
43
  }
42
- const packagePath = packagePathAndSubpath.packageJsonPath;
43
- this._packagePathAndSubpathByModulePath[absoluteModulePath] =
44
- packagePathAndSubpath;
45
- const modulePaths =
46
- this._modulePathsByPackagePath[packagePath] ?? new Set();
44
+ const packagePath = closest.packageJsonPath;
45
+ let modulePaths = this.#modulePathsByPackagePath.get(packagePath);
46
+ if (modulePaths == null) {
47
+ modulePaths = new Set();
48
+ this.#modulePathsByPackagePath.set(packagePath, modulePaths);
49
+ }
47
50
  modulePaths.add(absoluteModulePath);
48
- this._modulePathsByPackagePath[packagePath] = modulePaths;
49
- return {
50
- pkg: this.getPackage(packagePath),
51
- packageRelativePath: packagePathAndSubpath.packageRelativePath,
51
+ const pkg = this.getPackage(packagePath);
52
+ if (pkg == null) {
53
+ return null;
54
+ }
55
+ const result = {
56
+ packageJson: pkg.packageJson,
57
+ packageRelativePath: closest.packageRelativePath,
58
+ rootPath: pkg.rootPath,
52
59
  };
60
+ this.#resultByModulePath.set(absoluteModulePath, result);
61
+ return result;
53
62
  }
54
63
  invalidate(filePath) {
55
- if (this._packageCache[filePath]) {
56
- this._packageCache[filePath].invalidate();
57
- delete this._packageCache[filePath];
58
- }
59
- const packagePathAndSubpath =
60
- this._packagePathAndSubpathByModulePath[filePath];
61
- if (packagePathAndSubpath) {
62
- const packagePath = packagePathAndSubpath.packageJsonPath;
63
- delete this._packagePathAndSubpathByModulePath[filePath];
64
- const modulePaths = this._modulePathsByPackagePath[packagePath];
65
- if (modulePaths) {
66
- modulePaths.delete(filePath);
67
- if (modulePaths.size === 0) {
68
- delete this._modulePathsByPackagePath[packagePath];
64
+ this.#packageCache.delete(filePath);
65
+ const cachedResult = this.#resultByModulePath.get(filePath);
66
+ this.#resultByModulePath.delete(filePath);
67
+ this.#modulePathsWithNoPackage.delete(filePath);
68
+ if (cachedResult != null) {
69
+ const packagePath = cachedResult.rootPath + _path.sep + "package.json";
70
+ const modules = this.#modulePathsByPackagePath.get(packagePath);
71
+ if (modules != null) {
72
+ modules.delete(filePath);
73
+ if (modules.size === 0) {
74
+ this.#modulePathsByPackagePath.delete(packagePath);
69
75
  }
70
76
  }
71
77
  }
72
- if (this._modulePathsByPackagePath[filePath]) {
73
- const modulePaths = this._modulePathsByPackagePath[filePath];
78
+ const modulePaths = this.#modulePathsByPackagePath.get(filePath);
79
+ if (modulePaths != null) {
74
80
  for (const modulePath of modulePaths) {
75
- delete this._packagePathAndSubpathByModulePath[modulePath];
81
+ this.#resultByModulePath.delete(modulePath);
82
+ }
83
+ this.#modulePathsByPackagePath.delete(filePath);
84
+ }
85
+ if (filePath.endsWith(_path.sep + "package.json")) {
86
+ for (const modulePath of this.#modulePathsWithNoPackage) {
87
+ this.#resultByModulePath.delete(modulePath);
76
88
  }
77
- modulePaths.clear();
78
- delete this._modulePathsByPackagePath[filePath];
89
+ this.#modulePathsWithNoPackage.clear();
79
90
  }
80
91
  }
81
92
  }
@@ -9,117 +9,141 @@
9
9
  * @oncall react_native
10
10
  */
11
11
 
12
- import Package from './Package';
12
+ import type {PackageJson} from 'metro-resolver/private/types';
13
+
14
+ import {readFileSync} from 'fs';
15
+ import {dirname, sep} from 'path';
13
16
 
14
17
  type GetClosestPackageFn = (absoluteFilePath: string) => ?{
15
18
  packageJsonPath: string,
16
19
  packageRelativePath: string,
17
20
  };
18
21
 
22
+ type PackageForModule = Readonly<{
23
+ packageJson: PackageJson,
24
+ rootPath: string,
25
+ packageRelativePath: string,
26
+ }>;
27
+
19
28
  export class PackageCache {
20
- _getClosestPackage: GetClosestPackageFn;
21
- _packageCache: {
22
- [filePath: string]: Package,
23
- __proto__: null,
24
- ...
25
- };
26
- // Cache for "closest package.json" queries by module path.
27
- _packagePathAndSubpathByModulePath: {
28
- [filePath: string]: ?{
29
- packageJsonPath: string,
30
- packageRelativePath: string,
29
+ #getClosestPackage: GetClosestPackageFn;
30
+ #packageCache: Map<
31
+ string,
32
+ {
33
+ rootPath: string,
34
+ packageJson: PackageJson,
31
35
  },
32
- __proto__: null,
33
- ...
34
- };
35
- // The inverse of _packagePathByModulePath.
36
- _modulePathsByPackagePath: {
37
- [filePath: string]: Set<string>,
38
- __proto__: null,
39
- ...
40
- };
36
+ >;
37
+ // Single cache: module path → pre-built result object, or null (no allocation on hit)
38
+ #resultByModulePath: Map<string, PackageForModule | null>;
39
+ // Reverse index for invalidation: package.json path → set of module paths
40
+ #modulePathsByPackagePath: Map<string, Set<string>>;
41
+ // Module paths that resolved to no package.json (null), for invalidation
42
+ #modulePathsWithNoPackage: Set<string>;
41
43
 
42
44
  constructor(options: {getClosestPackage: GetClosestPackageFn, ...}) {
43
- this._getClosestPackage = options.getClosestPackage;
44
- this._packageCache = Object.create(null);
45
- this._packagePathAndSubpathByModulePath = Object.create(null);
46
- this._modulePathsByPackagePath = Object.create(null);
45
+ this.#getClosestPackage = options.getClosestPackage;
46
+ this.#packageCache = new Map();
47
+ this.#resultByModulePath = new Map();
48
+ this.#modulePathsByPackagePath = new Map();
49
+ this.#modulePathsWithNoPackage = new Set();
47
50
  }
48
51
 
49
- getPackage(filePath: string): Package {
50
- if (!this._packageCache[filePath]) {
51
- this._packageCache[filePath] = new Package({
52
- file: filePath,
53
- });
52
+ getPackage(filePath: string): Readonly<{
53
+ rootPath: string,
54
+ packageJson: PackageJson,
55
+ }> {
56
+ let cached = this.#packageCache.get(filePath);
57
+ if (cached == null) {
58
+ cached = {
59
+ rootPath: dirname(filePath),
60
+ packageJson: JSON.parse(readFileSync(filePath, 'utf8')),
61
+ };
62
+ this.#packageCache.set(filePath, cached);
54
63
  }
55
- return this._packageCache[filePath];
64
+ return cached;
56
65
  }
57
66
 
58
- getPackageOf(
59
- absoluteModulePath: string,
60
- ): ?{pkg: Package, packageRelativePath: string} {
61
- let packagePathAndSubpath =
62
- this._packagePathAndSubpathByModulePath[absoluteModulePath];
63
- if (
64
- packagePathAndSubpath &&
65
- this._packageCache[packagePathAndSubpath.packageJsonPath]
66
- ) {
67
- return {
68
- pkg: this._packageCache[packagePathAndSubpath.packageJsonPath],
69
- packageRelativePath: packagePathAndSubpath.packageRelativePath,
70
- };
67
+ getPackageForModule(absoluteModulePath: string): ?PackageForModule {
68
+ const cached = this.#resultByModulePath.get(absoluteModulePath);
69
+
70
+ // Distinguish between `null` (positively no closest package) and
71
+ // `undefined` (no cached result yet)
72
+ // eslint-disable-next-line lint/strictly-null
73
+ if (cached !== undefined) {
74
+ return cached;
71
75
  }
72
76
 
73
- packagePathAndSubpath = this._getClosestPackage(absoluteModulePath);
74
- if (!packagePathAndSubpath) {
77
+ const closest = this.#getClosestPackage(absoluteModulePath);
78
+ if (closest == null) {
79
+ this.#resultByModulePath.set(absoluteModulePath, null);
80
+ this.#modulePathsWithNoPackage.add(absoluteModulePath);
75
81
  return null;
76
82
  }
77
83
 
78
- const packagePath = packagePathAndSubpath.packageJsonPath;
84
+ const packagePath = closest.packageJsonPath;
79
85
 
80
- this._packagePathAndSubpathByModulePath[absoluteModulePath] =
81
- packagePathAndSubpath;
82
- const modulePaths =
83
- this._modulePathsByPackagePath[packagePath] ?? new Set();
86
+ // Track module→package for invalidation
87
+ let modulePaths = this.#modulePathsByPackagePath.get(packagePath);
88
+ if (modulePaths == null) {
89
+ modulePaths = new Set();
90
+ this.#modulePathsByPackagePath.set(packagePath, modulePaths);
91
+ }
84
92
  modulePaths.add(absoluteModulePath);
85
- this._modulePathsByPackagePath[packagePath] = modulePaths;
86
93
 
87
- return {
88
- pkg: this.getPackage(packagePath),
89
- packageRelativePath: packagePathAndSubpath.packageRelativePath,
94
+ const pkg = this.getPackage(packagePath);
95
+ if (pkg == null) {
96
+ return null;
97
+ }
98
+
99
+ // Cache the pre-built result object — no allocation on future hits
100
+ const result: PackageForModule = {
101
+ packageJson: pkg.packageJson,
102
+ packageRelativePath: closest.packageRelativePath,
103
+ rootPath: pkg.rootPath,
90
104
  };
105
+ this.#resultByModulePath.set(absoluteModulePath, result);
106
+ return result;
91
107
  }
92
108
 
93
109
  invalidate(filePath: string) {
94
- if (this._packageCache[filePath]) {
95
- this._packageCache[filePath].invalidate();
96
- delete this._packageCache[filePath];
97
- }
98
- const packagePathAndSubpath =
99
- this._packagePathAndSubpathByModulePath[filePath];
100
- if (packagePathAndSubpath) {
101
- // filePath is a module inside a package.
102
- const packagePath = packagePathAndSubpath.packageJsonPath;
103
- delete this._packagePathAndSubpathByModulePath[filePath];
104
- // This change doesn't invalidate any cached "closest package.json"
105
- // queries for the package's other modules. Clean up only this module.
106
- const modulePaths = this._modulePathsByPackagePath[packagePath];
107
- if (modulePaths) {
108
- modulePaths.delete(filePath);
109
- if (modulePaths.size === 0) {
110
- delete this._modulePathsByPackagePath[packagePath];
110
+ this.#packageCache.delete(filePath);
111
+
112
+ // Clean up any cached result for this module path (including null).
113
+ // Derive the package.json path from the cached result to clean up the
114
+ // reverse index.
115
+ const cachedResult = this.#resultByModulePath.get(filePath);
116
+ this.#resultByModulePath.delete(filePath);
117
+ this.#modulePathsWithNoPackage.delete(filePath);
118
+
119
+ if (cachedResult != null) {
120
+ const packagePath = cachedResult.rootPath + sep + 'package.json';
121
+ const modules = this.#modulePathsByPackagePath.get(packagePath);
122
+ if (modules != null) {
123
+ modules.delete(filePath);
124
+ if (modules.size === 0) {
125
+ this.#modulePathsByPackagePath.delete(packagePath);
111
126
  }
112
127
  }
113
128
  }
114
- if (this._modulePathsByPackagePath[filePath]) {
115
- // filePath is a package. This change invalidates all cached "closest
116
- // package.json" queries for modules inside this package.
117
- const modulePaths = this._modulePathsByPackagePath[filePath];
129
+
130
+ // If filePath is a package.json, invalidate all module lookups pointing to it
131
+ const modulePaths = this.#modulePathsByPackagePath.get(filePath);
132
+ if (modulePaths != null) {
118
133
  for (const modulePath of modulePaths) {
119
- delete this._packagePathAndSubpathByModulePath[modulePath];
134
+ this.#resultByModulePath.delete(modulePath);
135
+ }
136
+ this.#modulePathsByPackagePath.delete(filePath);
137
+ }
138
+
139
+ // If a package.json was created, modified, or deleted, invalidate all
140
+ // null-cached module results, since modules that previously had no
141
+ // enclosing package.json may now resolve to this one.
142
+ if (filePath.endsWith(sep + 'package.json')) {
143
+ for (const modulePath of this.#modulePathsWithNoPackage) {
144
+ this.#resultByModulePath.delete(modulePath);
120
145
  }
121
- modulePaths.clear();
122
- delete this._modulePathsByPackagePath[filePath];
146
+ this.#modulePathsWithNoPackage.clear();
123
147
  }
124
148
  }
125
149
  }
@@ -1,28 +0,0 @@
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
- * @noformat
8
- * @oncall react_native
9
- * @generated SignedSource<<17776d35467f02c7e07dcde4be309545>>
10
- *
11
- * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
12
- * Original file: packages/metro/src/node-haste/Package.js
13
- * To regenerate, run:
14
- * js1 build metro-ts-defs (internal) OR
15
- * yarn run build-ts-defs (OSS)
16
- */
17
-
18
- import type {PackageJson} from 'metro-resolver/private/types';
19
-
20
- declare class Package {
21
- path: string;
22
- _root: string;
23
- _content: null | undefined | PackageJson;
24
- constructor($$PARAM_0$$: {file: string});
25
- invalidate(): void;
26
- read(): PackageJson;
27
- }
28
- export default Package;
@@ -1,28 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true,
5
- });
6
- exports.default = void 0;
7
- var _fs = _interopRequireDefault(require("fs"));
8
- var _path = _interopRequireDefault(require("path"));
9
- function _interopRequireDefault(e) {
10
- return e && e.__esModule ? e : { default: e };
11
- }
12
- class Package {
13
- constructor({ file }) {
14
- this.path = _path.default.resolve(file);
15
- this._root = _path.default.dirname(this.path);
16
- this._content = null;
17
- }
18
- invalidate() {
19
- this._content = null;
20
- }
21
- read() {
22
- if (this._content == null) {
23
- this._content = JSON.parse(_fs.default.readFileSync(this.path, "utf8"));
24
- }
25
- return this._content;
26
- }
27
- }
28
- exports.default = Package;