metro-file-map 0.73.7 → 0.74.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/src/HasteFS.js +84 -11
  3. package/src/HasteFS.js.flow +92 -9
  4. package/src/Watcher.js +1 -1
  5. package/src/Watcher.js.flow +3 -3
  6. package/src/cache/DiskCacheManager.js.flow +3 -3
  7. package/src/constants.js +1 -0
  8. package/src/constants.js.flow +1 -0
  9. package/src/crawlers/__fixtures__/directory/bar.js +11 -0
  10. package/src/crawlers/__fixtures__/directory/bar.js.flow +10 -0
  11. package/src/crawlers/__fixtures__/directory/other.file +0 -0
  12. package/src/crawlers/__fixtures__/foo.js +11 -0
  13. package/src/crawlers/__fixtures__/foo.js.flow +10 -0
  14. package/src/crawlers/__fixtures__/ignored/hidden.js +11 -0
  15. package/src/crawlers/__fixtures__/ignored/hidden.js.flow +10 -0
  16. package/src/crawlers/__fixtures__/link-to-directory/bar.js +11 -0
  17. package/src/crawlers/__fixtures__/link-to-directory/bar.js.flow +10 -0
  18. package/src/crawlers/__fixtures__/link-to-directory/other.file +0 -0
  19. package/src/crawlers/__fixtures__/link-to-foo.js +11 -0
  20. package/src/crawlers/__fixtures__/link-to-foo.js.flow +10 -0
  21. package/src/crawlers/node/hasNativeFindSupport.js +48 -0
  22. package/src/crawlers/node/hasNativeFindSupport.js.flow +41 -0
  23. package/src/crawlers/{node.js → node/index.js} +66 -95
  24. package/src/crawlers/node/index.js.flow +223 -0
  25. package/src/crawlers/watchman/index.js +35 -14
  26. package/src/crawlers/watchman/index.js.flow +38 -17
  27. package/src/crawlers/watchman/planQuery.js +15 -1
  28. package/src/crawlers/watchman/planQuery.js.flow +15 -1
  29. package/src/flow-types.js.flow +36 -15
  30. package/src/index.js +253 -218
  31. package/src/index.js.flow +220 -207
  32. package/src/lib/{deepCloneInternalData.js → deepCloneRawModuleMap.js} +6 -9
  33. package/src/lib/{deepCloneInternalData.js.flow → deepCloneRawModuleMap.js.flow} +9 -12
  34. package/src/watchers/FSEventsWatcher.js +34 -26
  35. package/src/watchers/FSEventsWatcher.js.flow +38 -33
  36. package/src/watchers/NodeWatcher.js +62 -36
  37. package/src/watchers/NodeWatcher.js.flow +63 -36
  38. package/src/watchers/common.js +2 -0
  39. package/src/watchers/common.js.flow +2 -0
  40. package/src/worker.js +48 -43
  41. package/src/worker.js.flow +57 -55
  42. package/src/crawlers/node.js.flow +0 -250
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metro-file-map",
3
- "version": "0.73.7",
3
+ "version": "0.74.1",
4
4
  "description": "[Experimental] - 🚇 File crawling, watching and mapping for Metro",
5
5
  "main": "src/index.js",
6
6
  "repository": {
package/src/HasteFS.js CHANGED
@@ -65,18 +65,78 @@ class HasteFS {
65
65
  #rootDir;
66
66
  #files;
67
67
  constructor({ rootDir, files }) {
68
- // $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
69
68
  this.#rootDir = rootDir;
70
- // $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
71
69
  this.#files = files;
72
70
  }
71
+ _normalizePath(relativeOrAbsolutePath) {
72
+ return path.isAbsolute(relativeOrAbsolutePath)
73
+ ? fastPath.relative(this.#rootDir, relativeOrAbsolutePath)
74
+ : path.normalize(relativeOrAbsolutePath);
75
+ }
76
+ remove(filePath) {
77
+ this.#files.delete(this._normalizePath(filePath));
78
+ }
79
+ bulkAddOrModify(changedFiles) {
80
+ for (const [relativePath, metadata] of changedFiles) {
81
+ this.#files.set(relativePath, metadata);
82
+ }
83
+ }
84
+ addOrModify(filePath, metadata) {
85
+ this.#files.set(this._normalizePath(filePath), metadata);
86
+ }
87
+ setVisitMetadata(filePath, visitResult) {
88
+ const metadata = this._getFileData(filePath);
89
+ if (!metadata) {
90
+ throw new Error("Visited file not found in file map: " + filePath);
91
+ }
92
+ metadata[_constants.default.VISITED] = 1;
93
+ if (visitResult.hasteId != null) {
94
+ metadata[_constants.default.ID] = visitResult.hasteId;
95
+ }
96
+ if ("sha1" in visitResult) {
97
+ metadata[_constants.default.SHA1] = visitResult.sha1;
98
+ }
99
+ if (visitResult.dependencies != null) {
100
+ metadata[_constants.default.DEPENDENCIES] = visitResult.dependencies;
101
+ }
102
+ if (visitResult.symlinkTarget != null) {
103
+ metadata[_constants.default.SYMLINK] = visitResult.symlinkTarget;
104
+ }
105
+ }
106
+ getSerializableSnapshot() {
107
+ return new Map(Array.from(this.#files.entries(), ([k, v]) => [k, [...v]]));
108
+ }
73
109
  getModuleName(file) {
110
+ var _ref;
74
111
  const fileMetadata = this._getFileData(file);
75
- return (fileMetadata && fileMetadata[_constants.default.ID]) || null;
112
+ return (_ref = fileMetadata && fileMetadata[_constants.default.ID]) !==
113
+ null && _ref !== void 0
114
+ ? _ref
115
+ : null;
76
116
  }
77
117
  getSize(file) {
118
+ var _ref2;
78
119
  const fileMetadata = this._getFileData(file);
79
- return (fileMetadata && fileMetadata[_constants.default.SIZE]) || null;
120
+ return (_ref2 = fileMetadata && fileMetadata[_constants.default.SIZE]) !==
121
+ null && _ref2 !== void 0
122
+ ? _ref2
123
+ : null;
124
+ }
125
+ getSymlinkTarget(file) {
126
+ const fileMetadata = this._getFileData(file);
127
+ if (fileMetadata == null) {
128
+ return null;
129
+ }
130
+ return typeof fileMetadata[_constants.default.SYMLINK] === "string"
131
+ ? fileMetadata[_constants.default.SYMLINK]
132
+ : null;
133
+ }
134
+ getType(file) {
135
+ const fileMetadata = this._getFileData(file);
136
+ if (fileMetadata == null) {
137
+ return null;
138
+ }
139
+ return fileMetadata[_constants.default.SYMLINK] === 0 ? "f" : "l";
80
140
  }
81
141
  getDependencies(file) {
82
142
  const fileMetadata = this._getFileData(file);
@@ -91,11 +151,19 @@ class HasteFS {
91
151
  }
92
152
  }
93
153
  getSha1(file) {
94
- var _ref;
154
+ var _ref3;
95
155
  const fileMetadata = this._getFileData(file);
96
- return (_ref = fileMetadata && fileMetadata[_constants.default.SHA1]) !==
97
- null && _ref !== void 0
98
- ? _ref
156
+ return (_ref3 = fileMetadata && fileMetadata[_constants.default.SHA1]) !==
157
+ null && _ref3 !== void 0
158
+ ? _ref3
159
+ : null;
160
+ }
161
+ getModifiedTime(file) {
162
+ var _ref4;
163
+ const fileMetadata = this._getFileData(file);
164
+ return (_ref4 = fileMetadata && fileMetadata[_constants.default.MTIME]) !==
165
+ null && _ref4 !== void 0
166
+ ? _ref4
99
167
  : null;
100
168
  }
101
169
  exists(file) {
@@ -168,9 +236,14 @@ class HasteFS {
168
236
  }
169
237
  return files;
170
238
  }
171
- _getFileData(file) {
172
- const relativePath = fastPath.relative(this.#rootDir, file);
173
- return this.#files.get(relativePath);
239
+ _getFileData(filePath) {
240
+ // Shortcut to avoid any file path parsing if the given path is already
241
+ // normalised.
242
+ const optimisticMetadata = this.#files.get(filePath);
243
+ if (optimisticMetadata) {
244
+ return optimisticMetadata;
245
+ }
246
+ return this.#files.get(this._normalizePath(filePath));
174
247
  }
175
248
  }
176
249
  exports.default = HasteFS;
@@ -11,9 +11,10 @@
11
11
  import type {
12
12
  FileData,
13
13
  FileMetaData,
14
- FileSystem,
15
14
  Glob,
15
+ MutableFileSystem,
16
16
  Path,
17
+ VisitMetadata,
17
18
  } from './flow-types';
18
19
 
19
20
  import H from './constants';
@@ -21,25 +22,97 @@ import * as fastPath from './lib/fast_path';
21
22
  import * as path from 'path';
22
23
  import {globsToMatcher, replacePathSepForGlob} from 'jest-util';
23
24
 
24
- export default class HasteFS implements FileSystem {
25
+ export default class HasteFS implements MutableFileSystem {
25
26
  +#rootDir: Path;
26
27
  +#files: FileData;
27
28
 
28
29
  constructor({rootDir, files}: {rootDir: Path, files: FileData}) {
29
- // $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
30
30
  this.#rootDir = rootDir;
31
- // $FlowIssue[cannot-write] - should be fixed in Flow 0.193 (D41130671)
32
31
  this.#files = files;
33
32
  }
34
33
 
34
+ _normalizePath(relativeOrAbsolutePath: Path): string {
35
+ return path.isAbsolute(relativeOrAbsolutePath)
36
+ ? fastPath.relative(this.#rootDir, relativeOrAbsolutePath)
37
+ : path.normalize(relativeOrAbsolutePath);
38
+ }
39
+
40
+ remove(filePath: Path) {
41
+ this.#files.delete(this._normalizePath(filePath));
42
+ }
43
+
44
+ bulkAddOrModify(changedFiles: FileData) {
45
+ for (const [relativePath, metadata] of changedFiles) {
46
+ this.#files.set(relativePath, metadata);
47
+ }
48
+ }
49
+
50
+ addOrModify(filePath: Path, metadata: FileMetaData) {
51
+ this.#files.set(this._normalizePath(filePath), metadata);
52
+ }
53
+
54
+ setVisitMetadata(
55
+ filePath: Path,
56
+ visitResult: $ReadOnly<VisitMetadata>,
57
+ ): void {
58
+ const metadata = this._getFileData(filePath);
59
+ if (!metadata) {
60
+ throw new Error('Visited file not found in file map: ' + filePath);
61
+ }
62
+ metadata[H.VISITED] = 1;
63
+
64
+ if (visitResult.hasteId != null) {
65
+ metadata[H.ID] = visitResult.hasteId;
66
+ }
67
+
68
+ if ('sha1' in visitResult) {
69
+ metadata[H.SHA1] = visitResult.sha1;
70
+ }
71
+
72
+ if (visitResult.dependencies != null) {
73
+ metadata[H.DEPENDENCIES] = visitResult.dependencies;
74
+ }
75
+
76
+ if (visitResult.symlinkTarget != null) {
77
+ metadata[H.SYMLINK] = visitResult.symlinkTarget;
78
+ }
79
+ }
80
+
81
+ getSerializableSnapshot(): FileData {
82
+ return new Map(
83
+ Array.from(this.#files.entries(), ([k, v]: [Path, FileMetaData]) => [
84
+ k,
85
+ [...v],
86
+ ]),
87
+ );
88
+ }
89
+
35
90
  getModuleName(file: Path): ?string {
36
91
  const fileMetadata = this._getFileData(file);
37
- return (fileMetadata && fileMetadata[H.ID]) || null;
92
+ return (fileMetadata && fileMetadata[H.ID]) ?? null;
38
93
  }
39
94
 
40
95
  getSize(file: Path): ?number {
41
96
  const fileMetadata = this._getFileData(file);
42
- return (fileMetadata && fileMetadata[H.SIZE]) || null;
97
+ return (fileMetadata && fileMetadata[H.SIZE]) ?? null;
98
+ }
99
+
100
+ getSymlinkTarget(file: Path): ?string {
101
+ const fileMetadata = this._getFileData(file);
102
+ if (fileMetadata == null) {
103
+ return null;
104
+ }
105
+ return typeof fileMetadata[H.SYMLINK] === 'string'
106
+ ? fileMetadata[H.SYMLINK]
107
+ : null;
108
+ }
109
+
110
+ getType(file: Path): ?('f' | 'l') {
111
+ const fileMetadata = this._getFileData(file);
112
+ if (fileMetadata == null) {
113
+ return null;
114
+ }
115
+ return fileMetadata[H.SYMLINK] === 0 ? 'f' : 'l';
43
116
  }
44
117
 
45
118
  getDependencies(file: Path): ?Array<string> {
@@ -59,6 +132,11 @@ export default class HasteFS implements FileSystem {
59
132
  return (fileMetadata && fileMetadata[H.SHA1]) ?? null;
60
133
  }
61
134
 
135
+ getModifiedTime(file: Path): ?number {
136
+ const fileMetadata = this._getFileData(file);
137
+ return (fileMetadata && fileMetadata[H.MTIME]) ?? null;
138
+ }
139
+
62
140
  exists(file: Path): boolean {
63
141
  return this._getFileData(file) != null;
64
142
  }
@@ -148,8 +226,13 @@ export default class HasteFS implements FileSystem {
148
226
  return files;
149
227
  }
150
228
 
151
- _getFileData(file: Path): void | FileMetaData {
152
- const relativePath = fastPath.relative(this.#rootDir, file);
153
- return this.#files.get(relativePath);
229
+ _getFileData(filePath: Path): void | FileMetaData {
230
+ // Shortcut to avoid any file path parsing if the given path is already
231
+ // normalised.
232
+ const optimisticMetadata = this.#files.get(filePath);
233
+ if (optimisticMetadata) {
234
+ return optimisticMetadata;
235
+ }
236
+ return this.#files.get(this._normalizePath(filePath));
154
237
  }
155
238
  }
package/src/Watcher.js CHANGED
@@ -101,7 +101,7 @@ class Watcher extends _events.default {
101
101
  const crawlerOptions = {
102
102
  abortSignal: options.abortSignal,
103
103
  computeSha1: options.computeSha1,
104
- enableSymlinks: options.enableSymlinks,
104
+ includeSymlinks: options.enableSymlinks,
105
105
  extensions: options.extensions,
106
106
  forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
107
107
  ignore,
@@ -100,7 +100,7 @@ export class Watcher extends EventEmitter {
100
100
  const crawlerOptions: CrawlerOptions = {
101
101
  abortSignal: options.abortSignal,
102
102
  computeSha1: options.computeSha1,
103
- enableSymlinks: options.enableSymlinks,
103
+ includeSymlinks: options.enableSymlinks,
104
104
  extensions: options.extensions,
105
105
  forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
106
106
  ignore,
@@ -162,7 +162,7 @@ export class Watcher extends EventEmitter {
162
162
  type: string,
163
163
  filePath: string,
164
164
  root: string,
165
- metadata: ?ChangeEventMetadata,
165
+ metadata: ChangeEventMetadata,
166
166
  ) => void,
167
167
  ) {
168
168
  const {extensions, ignorePattern, useWatchman} = this._options;
@@ -214,7 +214,7 @@ export class Watcher extends EventEmitter {
214
214
  type: string,
215
215
  filePath: string,
216
216
  root: string,
217
- metadata: ?ChangeEventMetadata,
217
+ metadata: ChangeEventMetadata,
218
218
  ) => {
219
219
  const basename = path.basename(filePath);
220
220
  if (basename.startsWith(this._options.healthCheckFilePrefix)) {
@@ -11,9 +11,9 @@
11
11
 
12
12
  import type {
13
13
  BuildParameters,
14
+ CacheData,
14
15
  CacheManager,
15
16
  FileData,
16
- InternalData,
17
17
  } from '../flow-types';
18
18
 
19
19
  import rootRelativeCacheKeys from '../lib/rootRelativeCacheKeys';
@@ -66,7 +66,7 @@ export class DiskCacheManager implements CacheManager {
66
66
  return this._cachePath;
67
67
  }
68
68
 
69
- async read(): Promise<?InternalData> {
69
+ async read(): Promise<?CacheData> {
70
70
  try {
71
71
  return deserialize(readFileSync(this._cachePath));
72
72
  } catch (e) {
@@ -80,7 +80,7 @@ export class DiskCacheManager implements CacheManager {
80
80
  }
81
81
 
82
82
  async write(
83
- dataSnapshot: InternalData,
83
+ dataSnapshot: CacheData,
84
84
  {changed, removed}: $ReadOnly<{changed: FileData, removed: FileData}>,
85
85
  ): Promise<void> {
86
86
  if (changed.size > 0 || removed.size > 0) {
package/src/constants.js CHANGED
@@ -33,6 +33,7 @@ const constants /*: HType */ = {
33
33
  VISITED: 3,
34
34
  DEPENDENCIES: 4,
35
35
  SHA1: 5,
36
+ SYMLINK: 6,
36
37
  /* module map attributes */
37
38
  PATH: 0,
38
39
  TYPE: 1,
@@ -34,6 +34,7 @@ const constants/*: HType */ = {
34
34
  VISITED: 3,
35
35
  DEPENDENCIES: 4,
36
36
  SHA1: 5,
37
+ SYMLINK: 6,
37
38
 
38
39
  /* module map attributes */
39
40
  PATH: 0,
@@ -0,0 +1,11 @@
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
+ *
8
+ * @format
9
+ * @oncall react_native
10
+ */
11
+ "use strict";
@@ -0,0 +1,10 @@
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 strict
8
+ * @format
9
+ * @oncall react_native
10
+ */
File without changes
@@ -0,0 +1,11 @@
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
+ *
8
+ * @format
9
+ * @oncall react_native
10
+ */
11
+ "use strict";
@@ -0,0 +1,10 @@
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 strict
8
+ * @format
9
+ * @oncall react_native
10
+ */
@@ -0,0 +1,11 @@
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
+ *
8
+ * @format
9
+ * @oncall react_native
10
+ */
11
+ "use strict";
@@ -0,0 +1,10 @@
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 strict
8
+ * @format
9
+ * @oncall react_native
10
+ */
@@ -0,0 +1,11 @@
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
+ *
8
+ * @format
9
+ * @oncall react_native
10
+ */
11
+ "use strict";
@@ -0,0 +1,10 @@
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 strict
8
+ * @format
9
+ * @oncall react_native
10
+ */
@@ -0,0 +1,11 @@
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
+ *
8
+ * @format
9
+ * @oncall react_native
10
+ */
11
+ "use strict";
@@ -0,0 +1,10 @@
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 strict
8
+ * @format
9
+ * @oncall react_native
10
+ */
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true,
5
+ });
6
+ exports.default = hasNativeFindSupport;
7
+ var _child_process = require("child_process");
8
+ /**
9
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
10
+ *
11
+ * This source code is licensed under the MIT license found in the
12
+ * LICENSE file in the root directory of this source tree.
13
+ *
14
+ *
15
+ * @format
16
+ * @oncall react_native
17
+ */
18
+
19
+ async function hasNativeFindSupport() {
20
+ try {
21
+ return await new Promise((resolve) => {
22
+ // Check the find binary supports the non-POSIX -iname parameter wrapped in parens.
23
+ const args = [
24
+ ".",
25
+ "-type",
26
+ "f",
27
+ "(",
28
+ "-iname",
29
+ "*.ts",
30
+ "-o",
31
+ "-iname",
32
+ "*.js",
33
+ ")",
34
+ ];
35
+ const child = (0, _child_process.spawn)("find", args, {
36
+ cwd: __dirname,
37
+ });
38
+ child.on("error", () => {
39
+ resolve(false);
40
+ });
41
+ child.on("exit", (code) => {
42
+ resolve(code === 0);
43
+ });
44
+ });
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
@@ -0,0 +1,41 @@
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 strict-local
8
+ * @format
9
+ * @oncall react_native
10
+ */
11
+
12
+ import {spawn} from 'child_process';
13
+
14
+ export default async function hasNativeFindSupport(): Promise<boolean> {
15
+ try {
16
+ return await new Promise(resolve => {
17
+ // Check the find binary supports the non-POSIX -iname parameter wrapped in parens.
18
+ const args = [
19
+ '.',
20
+ '-type',
21
+ 'f',
22
+ '(',
23
+ '-iname',
24
+ '*.ts',
25
+ '-o',
26
+ '-iname',
27
+ '*.js',
28
+ ')',
29
+ ];
30
+ const child = spawn('find', args, {cwd: __dirname});
31
+ child.on('error', () => {
32
+ resolve(false);
33
+ });
34
+ child.on('exit', code => {
35
+ resolve(code === 0);
36
+ });
37
+ });
38
+ } catch {
39
+ return false;
40
+ }
41
+ }