metro-file-map 0.83.4 → 0.83.6
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 +3 -2
- package/src/Watcher.d.ts +74 -0
- package/src/Watcher.js +68 -48
- package/src/Watcher.js.flow +84 -51
- package/src/cache/DiskCacheManager.d.ts +49 -0
- package/src/cache/DiskCacheManager.js +1 -5
- package/src/constants.d.ts +22 -0
- package/src/crawlers/node/hasNativeFindSupport.d.ts +19 -0
- package/src/crawlers/node/index.d.ts +21 -0
- package/src/crawlers/node/index.js +6 -10
- package/src/crawlers/node/index.js.flow +8 -6
- package/src/crawlers/watchman/index.d.ts +23 -0
- package/src/crawlers/watchman/index.js +2 -9
- package/src/crawlers/watchman/index.js.flow +2 -6
- package/src/flow-types.d.ts +460 -0
- package/src/flow-types.js.flow +89 -29
- package/src/index.d.ts +182 -0
- package/src/index.js +148 -132
- package/src/index.js.flow +200 -155
- package/src/lib/FileProcessor.d.ts +60 -0
- package/src/lib/FileProcessor.js +1 -5
- package/src/lib/FileSystemChangeAggregator.d.ts +40 -0
- package/src/lib/FileSystemChangeAggregator.js +89 -0
- package/src/lib/FileSystemChangeAggregator.js.flow +143 -0
- package/src/lib/RootPathUtils.d.ts +30 -0
- package/src/lib/RootPathUtils.js +2 -9
- package/src/lib/TreeFS.d.ts +174 -0
- package/src/lib/TreeFS.js +68 -21
- package/src/lib/TreeFS.js.flow +89 -16
- package/src/lib/checkWatchmanCapabilities.d.ts +20 -0
- package/src/lib/normalizePathSeparatorsToPosix.d.ts +20 -0
- package/src/lib/normalizePathSeparatorsToPosix.js +1 -4
- package/src/lib/normalizePathSeparatorsToSystem.d.ts +20 -0
- package/src/lib/normalizePathSeparatorsToSystem.js +1 -4
- package/src/lib/rootRelativeCacheKeys.d.ts +24 -0
- package/src/lib/rootRelativeCacheKeys.js +1 -5
- package/src/lib/sorting.d.ts +23 -0
- package/src/plugins/DependencyPlugin.d.ts +52 -0
- package/src/plugins/DependencyPlugin.js +1 -3
- package/src/plugins/DependencyPlugin.js.flow +1 -16
- package/src/plugins/HastePlugin.d.ts +69 -0
- package/src/plugins/HastePlugin.js +12 -16
- package/src/plugins/HastePlugin.js.flow +12 -12
- package/src/plugins/MockPlugin.d.ts +48 -0
- package/src/plugins/MockPlugin.js +18 -25
- package/src/plugins/MockPlugin.js.flow +18 -22
- package/src/plugins/dependencies/dependencyExtractor.d.ts +1 -1
- package/src/plugins/haste/DuplicateHasteCandidatesError.d.ts +31 -0
- package/src/plugins/haste/DuplicateHasteCandidatesError.js +1 -5
- package/src/plugins/haste/HasteConflictsError.d.ts +23 -0
- package/src/plugins/haste/HasteConflictsError.js +1 -5
- package/src/plugins/haste/computeConflicts.d.ts +34 -0
- package/src/plugins/haste/computeConflicts.js +1 -5
- package/src/plugins/haste/getPlatformExtension.d.ts +21 -0
- package/src/plugins/mocks/getMockName.d.ts +20 -0
- package/src/plugins/mocks/getMockName.js +1 -4
- package/src/watchers/AbstractWatcher.d.ts +41 -0
- package/src/watchers/AbstractWatcher.js +2 -9
- package/src/watchers/FallbackWatcher.d.ts +28 -0
- package/src/watchers/FallbackWatcher.js +21 -12
- package/src/watchers/FallbackWatcher.js.flow +28 -5
- package/src/watchers/NativeWatcher.d.ts +55 -0
- package/src/watchers/NativeWatcher.js +28 -9
- package/src/watchers/NativeWatcher.js.flow +33 -6
- package/src/watchers/RecrawlWarning.d.ts +32 -0
- package/src/watchers/WatchmanWatcher.d.ts +34 -0
- package/src/watchers/WatchmanWatcher.js +2 -9
- package/src/watchers/common.d.ts +70 -0
- package/src/watchers/common.js +7 -6
- package/src/watchers/common.js.flow +1 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
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<<806d228988308075b7a911c3dfb513d3>>
|
|
10
|
+
*
|
|
11
|
+
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
|
|
12
|
+
* Original file: packages/metro-file-map/src/index.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 {
|
|
19
|
+
BuildParameters,
|
|
20
|
+
BuildResult,
|
|
21
|
+
CacheData,
|
|
22
|
+
CacheManagerFactory,
|
|
23
|
+
ChangeEventMetadata,
|
|
24
|
+
Console,
|
|
25
|
+
FileData,
|
|
26
|
+
FileSystem,
|
|
27
|
+
HasteMapData,
|
|
28
|
+
HasteMapItem,
|
|
29
|
+
HType,
|
|
30
|
+
InputFileMapPlugin,
|
|
31
|
+
PerfLoggerFactory,
|
|
32
|
+
} from './flow-types';
|
|
33
|
+
|
|
34
|
+
import EventEmitter from 'events';
|
|
35
|
+
|
|
36
|
+
export type {
|
|
37
|
+
BuildParameters,
|
|
38
|
+
BuildResult,
|
|
39
|
+
CacheData,
|
|
40
|
+
ChangeEventMetadata,
|
|
41
|
+
FileData,
|
|
42
|
+
FileMap,
|
|
43
|
+
FileSystem,
|
|
44
|
+
HasteMapData,
|
|
45
|
+
HasteMapItem,
|
|
46
|
+
InputFileMapPlugin,
|
|
47
|
+
};
|
|
48
|
+
export type InputOptions = Readonly<{
|
|
49
|
+
computeSha1?: null | undefined | boolean;
|
|
50
|
+
enableSymlinks?: null | undefined | boolean;
|
|
51
|
+
extensions: ReadonlyArray<string>;
|
|
52
|
+
forceNodeFilesystemAPI?: null | undefined | boolean;
|
|
53
|
+
ignorePattern?: null | undefined | RegExp;
|
|
54
|
+
plugins?: ReadonlyArray<InputFileMapPlugin>;
|
|
55
|
+
retainAllFiles: boolean;
|
|
56
|
+
rootDir: string;
|
|
57
|
+
roots: ReadonlyArray<string>;
|
|
58
|
+
cacheManagerFactory?: null | undefined | CacheManagerFactory;
|
|
59
|
+
console?: Console;
|
|
60
|
+
healthCheck: HealthCheckOptions;
|
|
61
|
+
maxFilesPerWorker?: null | undefined | number;
|
|
62
|
+
maxWorkers: number;
|
|
63
|
+
perfLoggerFactory?: null | undefined | PerfLoggerFactory;
|
|
64
|
+
resetCache?: null | undefined | boolean;
|
|
65
|
+
useWatchman?: null | undefined | boolean;
|
|
66
|
+
watch?: null | undefined | boolean;
|
|
67
|
+
watchmanDeferStates?: ReadonlyArray<string>;
|
|
68
|
+
}>;
|
|
69
|
+
type HealthCheckOptions = Readonly<{
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
interval: number;
|
|
72
|
+
timeout: number;
|
|
73
|
+
filePrefix: string;
|
|
74
|
+
}>;
|
|
75
|
+
export {DiskCacheManager} from './cache/DiskCacheManager';
|
|
76
|
+
export {default as DependencyPlugin} from './plugins/DependencyPlugin';
|
|
77
|
+
export type {DependencyPluginOptions} from './plugins/DependencyPlugin';
|
|
78
|
+
export {DuplicateHasteCandidatesError} from './plugins/haste/DuplicateHasteCandidatesError';
|
|
79
|
+
export {HasteConflictsError} from './plugins/haste/HasteConflictsError';
|
|
80
|
+
export {default as HastePlugin} from './plugins/HastePlugin';
|
|
81
|
+
export type {HasteMap} from './flow-types';
|
|
82
|
+
export type {HealthCheckResult} from './Watcher';
|
|
83
|
+
export type {
|
|
84
|
+
CacheManager,
|
|
85
|
+
CacheManagerFactory,
|
|
86
|
+
CacheManagerFactoryOptions,
|
|
87
|
+
CacheManagerWriteOptions,
|
|
88
|
+
ChangeEvent,
|
|
89
|
+
DependencyExtractor,
|
|
90
|
+
WatcherStatus,
|
|
91
|
+
} from './flow-types';
|
|
92
|
+
/**
|
|
93
|
+
* FileMap includes a JavaScript implementation of Facebook's haste module system.
|
|
94
|
+
*
|
|
95
|
+
* This implementation is inspired by https://github.com/facebook/node-haste
|
|
96
|
+
* and was built with for high-performance in large code repositories with
|
|
97
|
+
* hundreds of thousands of files. This implementation is scalable and provides
|
|
98
|
+
* predictable performance.
|
|
99
|
+
*
|
|
100
|
+
* Because the file map creation and synchronization is critical to startup
|
|
101
|
+
* performance and most tasks are blocked by I/O this class makes heavy use of
|
|
102
|
+
* synchronous operations. It uses worker processes for parallelizing file
|
|
103
|
+
* access and metadata extraction.
|
|
104
|
+
*
|
|
105
|
+
* The data structures created by `metro-file-map` can be used directly from the
|
|
106
|
+
* cache without further processing. The metadata objects in the `files` and
|
|
107
|
+
* `map` objects contain cross-references: a metadata object from one can look
|
|
108
|
+
* up the corresponding metadata object in the other map. Note that in most
|
|
109
|
+
* projects, the number of files will be greater than the number of haste
|
|
110
|
+
* modules one module can refer to many files based on platform extensions.
|
|
111
|
+
*
|
|
112
|
+
* type CacheData = {
|
|
113
|
+
* clocks: WatchmanClocks,
|
|
114
|
+
* files: {[filepath: string]: FileMetadata},
|
|
115
|
+
* map: {[id: string]: HasteMapItem},
|
|
116
|
+
* mocks: {[id: string]: string},
|
|
117
|
+
* }
|
|
118
|
+
*
|
|
119
|
+
* // Watchman clocks are used for query synchronization and file system deltas.
|
|
120
|
+
* type WatchmanClocks = {[filepath: string]: string};
|
|
121
|
+
*
|
|
122
|
+
* type FileMetadata = {
|
|
123
|
+
* id: ?string, // used to look up module metadata objects in `map`.
|
|
124
|
+
* mtime: number, // check for outdated files.
|
|
125
|
+
* size: number, // size of the file in bytes.
|
|
126
|
+
* visited: boolean, // whether the file has been parsed or not.
|
|
127
|
+
* dependencies: Array<string>, // all relative dependencies of this file.
|
|
128
|
+
* sha1: ?string, // SHA-1 of the file, if requested via options.
|
|
129
|
+
* symlink: ?(1 | 0 | string), // Truthy if symlink, string is target
|
|
130
|
+
* };
|
|
131
|
+
*
|
|
132
|
+
* // Modules can be targeted to a specific platform based on the file name.
|
|
133
|
+
* // Example: platform.ios.js and Platform.android.js will both map to the same
|
|
134
|
+
* // `Platform` module. The platform should be specified during resolution.
|
|
135
|
+
* type HasteMapItem = {[platform: string]: ModuleMetadata};
|
|
136
|
+
*
|
|
137
|
+
* //
|
|
138
|
+
* type ModuleMetadata = {
|
|
139
|
+
* path: string, // the path to look up the file object in `files`.
|
|
140
|
+
* type: string, // the module type (either `package` or `module`).
|
|
141
|
+
* };
|
|
142
|
+
*
|
|
143
|
+
* Note that the data structures described above are conceptual only. The actual
|
|
144
|
+
* implementation uses arrays and constant keys for metadata storage. Instead of
|
|
145
|
+
* `{id: 'flatMap', mtime: 3421, size: 42, visited: true, dependencies: []}` the real
|
|
146
|
+
* representation is similar to `['flatMap', 3421, 42, 1, []]` to save storage space
|
|
147
|
+
* and reduce parse and write time of a big JSON blob.
|
|
148
|
+
*
|
|
149
|
+
* The FileMap is created as follows:
|
|
150
|
+
* 1. read data from the cache or create an empty structure.
|
|
151
|
+
*
|
|
152
|
+
* 2. crawl the file system.
|
|
153
|
+
* * empty cache: crawl the entire file system.
|
|
154
|
+
* * cache available:
|
|
155
|
+
* * if watchman is available: get file system delta changes.
|
|
156
|
+
* * if watchman is unavailable: crawl the entire file system.
|
|
157
|
+
* * build metadata objects for every file. This builds the `files` part of
|
|
158
|
+
* the `FileMap`.
|
|
159
|
+
*
|
|
160
|
+
* 3. visit and extract metadata from changed files, including sha1,
|
|
161
|
+
* depedendencies, and any plugins.
|
|
162
|
+
* * this is done in parallel over worker processes to improve performance.
|
|
163
|
+
* * the worst case is to visit all files.
|
|
164
|
+
* * the best case is no file system access and retrieving all data from
|
|
165
|
+
* the cache.
|
|
166
|
+
* * the average case is a small number of changed files.
|
|
167
|
+
*
|
|
168
|
+
* 4. serialize the new `FileMap` in a cache file.
|
|
169
|
+
*
|
|
170
|
+
*/
|
|
171
|
+
declare class FileMap extends EventEmitter {
|
|
172
|
+
static create(options: InputOptions): FileMap;
|
|
173
|
+
constructor(options: InputOptions);
|
|
174
|
+
build(): Promise<BuildResult>;
|
|
175
|
+
/**
|
|
176
|
+
* 1. read data from the cache or create an empty structure.
|
|
177
|
+
*/
|
|
178
|
+
read(): Promise<null | undefined | CacheData>;
|
|
179
|
+
end(): Promise<void>;
|
|
180
|
+
static H: HType;
|
|
181
|
+
}
|
|
182
|
+
export default FileMap;
|
package/src/index.js
CHANGED
|
@@ -40,6 +40,7 @@ var _checkWatchmanCapabilities = _interopRequireDefault(
|
|
|
40
40
|
require("./lib/checkWatchmanCapabilities"),
|
|
41
41
|
);
|
|
42
42
|
var _FileProcessor = require("./lib/FileProcessor");
|
|
43
|
+
var _FileSystemChangeAggregator = require("./lib/FileSystemChangeAggregator");
|
|
43
44
|
var _normalizePathSeparatorsToPosix = _interopRequireDefault(
|
|
44
45
|
require("./lib/normalizePathSeparatorsToPosix"),
|
|
45
46
|
);
|
|
@@ -52,7 +53,6 @@ var _Watcher = require("./Watcher");
|
|
|
52
53
|
var _events = _interopRequireDefault(require("events"));
|
|
53
54
|
var _fs = require("fs");
|
|
54
55
|
var _invariant = _interopRequireDefault(require("invariant"));
|
|
55
|
-
var _nullthrows = _interopRequireDefault(require("nullthrows"));
|
|
56
56
|
var path = _interopRequireWildcard(require("path"));
|
|
57
57
|
var _perf_hooks = require("perf_hooks");
|
|
58
58
|
var _DependencyPlugin = _interopRequireDefault(
|
|
@@ -69,10 +69,7 @@ function _interopRequireWildcard(e, t) {
|
|
|
69
69
|
if (!t && e && e.__esModule) return e;
|
|
70
70
|
var o,
|
|
71
71
|
i,
|
|
72
|
-
f = {
|
|
73
|
-
__proto__: null,
|
|
74
|
-
default: e,
|
|
75
|
-
};
|
|
72
|
+
f = { __proto__: null, default: e };
|
|
76
73
|
if (null === e || ("object" != typeof e && "function" != typeof e))
|
|
77
74
|
return f;
|
|
78
75
|
if ((o = t ? n : r)) {
|
|
@@ -92,11 +89,7 @@ function _interopRequireWildcard(e, t) {
|
|
|
92
89
|
})(e, t);
|
|
93
90
|
}
|
|
94
91
|
function _interopRequireDefault(e) {
|
|
95
|
-
return e && e.__esModule
|
|
96
|
-
? e
|
|
97
|
-
: {
|
|
98
|
-
default: e,
|
|
99
|
-
};
|
|
92
|
+
return e && e.__esModule ? e : { default: e };
|
|
100
93
|
}
|
|
101
94
|
const debug = require("debug")("Metro:FileMap");
|
|
102
95
|
const CACHE_BREAKER = "11";
|
|
@@ -277,7 +270,7 @@ class FileMap extends _events.default {
|
|
|
277
270
|
};
|
|
278
271
|
},
|
|
279
272
|
fileIterator: (opts) =>
|
|
280
|
-
|
|
273
|
+
mapIterable(
|
|
281
274
|
fileSystem.metadataIterator(opts),
|
|
282
275
|
({ baseName, canonicalPath, metadata }) => ({
|
|
283
276
|
baseName,
|
|
@@ -291,21 +284,21 @@ class FileMap extends _events.default {
|
|
|
291
284
|
),
|
|
292
285
|
),
|
|
293
286
|
]);
|
|
294
|
-
await this.#applyFileDelta(
|
|
287
|
+
const actualChanges = await this.#applyFileDelta(
|
|
288
|
+
fileSystem,
|
|
289
|
+
plugins,
|
|
290
|
+
fileDelta,
|
|
291
|
+
);
|
|
292
|
+
const changeSize = actualChanges.getSize();
|
|
295
293
|
plugins.forEach(({ plugin }) => plugin.assertValid());
|
|
296
294
|
const watchmanClocks = new Map(fileDelta.clocks ?? []);
|
|
297
295
|
await this.#takeSnapshotAndPersist(
|
|
298
296
|
fileSystem,
|
|
299
297
|
watchmanClocks,
|
|
300
298
|
plugins,
|
|
301
|
-
|
|
302
|
-
fileDelta.removedFiles,
|
|
303
|
-
);
|
|
304
|
-
debug(
|
|
305
|
-
"Finished mapping files (%d changes, %d removed).",
|
|
306
|
-
fileDelta.changedFiles.size,
|
|
307
|
-
fileDelta.removedFiles.size,
|
|
299
|
+
changeSize > 0,
|
|
308
300
|
);
|
|
301
|
+
debug("Finished mapping files (%d changes).", changeSize);
|
|
309
302
|
await this.#watch(fileSystem, watchmanClocks, plugins);
|
|
310
303
|
return {
|
|
311
304
|
fileSystem,
|
|
@@ -375,10 +368,9 @@ class FileMap extends _events.default {
|
|
|
375
368
|
});
|
|
376
369
|
const watcher = this.#watcher;
|
|
377
370
|
watcher.on("status", (status) => this.emit("status", status));
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
});
|
|
371
|
+
const result = await watcher.crawl();
|
|
372
|
+
this.#startupPerfLogger?.point("buildFileDelta_end");
|
|
373
|
+
return result;
|
|
382
374
|
}
|
|
383
375
|
#maybeReadLink(normalPath, fileMetadata) {
|
|
384
376
|
if (fileMetadata[_constants.default.SYMLINK] === 1) {
|
|
@@ -395,14 +387,11 @@ class FileMap extends _events.default {
|
|
|
395
387
|
this.#startupPerfLogger?.point("applyFileDelta_start");
|
|
396
388
|
const { changedFiles, removedFiles } = delta;
|
|
397
389
|
this.#startupPerfLogger?.point("applyFileDelta_preprocess_start");
|
|
398
|
-
const missingFiles = new Set();
|
|
399
390
|
this.#startupPerfLogger?.point("applyFileDelta_remove_start");
|
|
400
|
-
const
|
|
391
|
+
const changeAggregator =
|
|
392
|
+
new _FileSystemChangeAggregator.FileSystemChangeAggregator();
|
|
401
393
|
for (const relativeFilePath of removedFiles) {
|
|
402
|
-
|
|
403
|
-
if (metadata) {
|
|
404
|
-
removed.push([relativeFilePath, metadata]);
|
|
405
|
-
}
|
|
394
|
+
fileSystem.remove(relativeFilePath, changeAggregator);
|
|
406
395
|
}
|
|
407
396
|
this.#startupPerfLogger?.point("applyFileDelta_remove_end");
|
|
408
397
|
const readLinkPromises = [];
|
|
@@ -418,12 +407,12 @@ class FileMap extends _events.default {
|
|
|
418
407
|
const maybeReadLink = this.#maybeReadLink(normalFilePath, fileData);
|
|
419
408
|
if (maybeReadLink) {
|
|
420
409
|
readLinkPromises.push(
|
|
421
|
-
maybeReadLink.catch((error) =>
|
|
410
|
+
maybeReadLink.catch((error) => {
|
|
422
411
|
readLinkErrors.push({
|
|
423
412
|
normalFilePath,
|
|
424
413
|
error,
|
|
425
|
-
})
|
|
426
|
-
),
|
|
414
|
+
});
|
|
415
|
+
}),
|
|
427
416
|
);
|
|
428
417
|
}
|
|
429
418
|
}
|
|
@@ -448,39 +437,34 @@ class FileMap extends _events.default {
|
|
|
448
437
|
readLinkErrors,
|
|
449
438
|
)) {
|
|
450
439
|
if (["ENOENT", "EACCESS"].includes(error.code)) {
|
|
451
|
-
|
|
440
|
+
delta.changedFiles.delete(normalFilePath);
|
|
441
|
+
fileSystem.remove(normalFilePath, changeAggregator);
|
|
452
442
|
} else {
|
|
453
443
|
throw error;
|
|
454
444
|
}
|
|
455
445
|
}
|
|
456
|
-
for (const relativeFilePath of missingFiles) {
|
|
457
|
-
changedFiles.delete(relativeFilePath);
|
|
458
|
-
const metadata = fileSystem.remove(relativeFilePath);
|
|
459
|
-
if (metadata) {
|
|
460
|
-
removed.push([relativeFilePath, metadata]);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
446
|
this.#startupPerfLogger?.point("applyFileDelta_missing_end");
|
|
464
447
|
this.#startupPerfLogger?.point("applyFileDelta_add_start");
|
|
465
|
-
fileSystem.bulkAddOrModify(changedFiles);
|
|
448
|
+
fileSystem.bulkAddOrModify(changedFiles, changeAggregator);
|
|
466
449
|
this.#startupPerfLogger?.point("applyFileDelta_add_end");
|
|
467
450
|
this.#startupPerfLogger?.point("applyFileDelta_updatePlugins_start");
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
dataIdx != null
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
addedOrModified: mapIterator(changedFiles.entries(), mapFn),
|
|
476
|
-
removed: mapIterator(removed.values(), mapFn),
|
|
477
|
-
});
|
|
478
|
-
}),
|
|
479
|
-
]);
|
|
451
|
+
this.#plugins.forEach(({ plugin, dataIdx }) => {
|
|
452
|
+
plugin.onChanged(
|
|
453
|
+
changeAggregator.getMappedView(
|
|
454
|
+
dataIdx != null ? (metadata) => metadata[dataIdx] : () => null,
|
|
455
|
+
),
|
|
456
|
+
);
|
|
457
|
+
});
|
|
480
458
|
this.#startupPerfLogger?.point("applyFileDelta_updatePlugins_end");
|
|
481
459
|
this.#startupPerfLogger?.point("applyFileDelta_end");
|
|
460
|
+
return changeAggregator;
|
|
482
461
|
}
|
|
483
|
-
async #takeSnapshotAndPersist(
|
|
462
|
+
async #takeSnapshotAndPersist(
|
|
463
|
+
fileSystem,
|
|
464
|
+
clocks,
|
|
465
|
+
plugins,
|
|
466
|
+
changedSinceCacheRead,
|
|
467
|
+
) {
|
|
484
468
|
this.#startupPerfLogger?.point("persist_start");
|
|
485
469
|
await this.#cacheManager.write(
|
|
486
470
|
() => ({
|
|
@@ -494,7 +478,7 @@ class FileMap extends _events.default {
|
|
|
494
478
|
),
|
|
495
479
|
}),
|
|
496
480
|
{
|
|
497
|
-
changedSinceCacheRead
|
|
481
|
+
changedSinceCacheRead,
|
|
498
482
|
eventSource: {
|
|
499
483
|
onChange: (cb) => {
|
|
500
484
|
this.on("change", cb);
|
|
@@ -520,14 +504,46 @@ class FileMap extends _events.default {
|
|
|
520
504
|
}
|
|
521
505
|
const hasWatchedExtension = (filePath) =>
|
|
522
506
|
this.#options.extensions.some((ext) => filePath.endsWith(ext));
|
|
523
|
-
let changeQueue = Promise.resolve();
|
|
524
507
|
let nextEmit = null;
|
|
525
508
|
const emitChange = () => {
|
|
526
|
-
if (nextEmit == null
|
|
509
|
+
if (nextEmit == null) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
const { events, firstEventTimestamp, firstEnqueuedTimestamp } = nextEmit;
|
|
513
|
+
const changeAggregator =
|
|
514
|
+
new _FileSystemChangeAggregator.FileSystemChangeAggregator();
|
|
515
|
+
for (const event of events) {
|
|
516
|
+
const { relativeFilePath, clock } = event;
|
|
517
|
+
if (event.type === "delete") {
|
|
518
|
+
fileSystem.remove(relativeFilePath, changeAggregator);
|
|
519
|
+
} else {
|
|
520
|
+
fileSystem.addOrModify(
|
|
521
|
+
relativeFilePath,
|
|
522
|
+
event.metadata,
|
|
523
|
+
changeAggregator,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
this.#updateClock(clocks, clock);
|
|
527
|
+
}
|
|
528
|
+
const changeSize = changeAggregator.getSize();
|
|
529
|
+
if (changeSize === 0) {
|
|
530
|
+
nextEmit = null;
|
|
527
531
|
return;
|
|
528
532
|
}
|
|
529
|
-
const
|
|
530
|
-
|
|
533
|
+
const _netChange = changeAggregator.getView();
|
|
534
|
+
this.#plugins.forEach(({ plugin, dataIdx }) => {
|
|
535
|
+
plugin.onChanged(
|
|
536
|
+
changeAggregator.getMappedView(
|
|
537
|
+
dataIdx != null ? (metadata) => metadata[dataIdx] : () => null,
|
|
538
|
+
),
|
|
539
|
+
);
|
|
540
|
+
});
|
|
541
|
+
const toPublicMetadata = (metadata) => ({
|
|
542
|
+
isSymlink: metadata[_constants.default.SYMLINK] !== 0,
|
|
543
|
+
modifiedTime: metadata[_constants.default.MTIME] ?? null,
|
|
544
|
+
});
|
|
545
|
+
const changesWithMetadata =
|
|
546
|
+
changeAggregator.getMappedView(toPublicMetadata);
|
|
531
547
|
const hmrPerfLogger = this.#options.perfLoggerFactory?.("HMR", {
|
|
532
548
|
key: this.#getNextChangeID(),
|
|
533
549
|
});
|
|
@@ -541,20 +557,23 @@ class FileMap extends _events.default {
|
|
|
541
557
|
hmrPerfLogger.point("waitingForChangeInterval_end");
|
|
542
558
|
hmrPerfLogger.annotate({
|
|
543
559
|
int: {
|
|
544
|
-
|
|
560
|
+
changeSize,
|
|
545
561
|
},
|
|
546
562
|
});
|
|
547
563
|
hmrPerfLogger.point("fileChange_start");
|
|
548
564
|
}
|
|
549
565
|
const changeEvent = {
|
|
550
|
-
|
|
566
|
+
changes: changesWithMetadata,
|
|
551
567
|
logger: hmrPerfLogger,
|
|
568
|
+
rootDir: this.#options.rootDir,
|
|
552
569
|
};
|
|
553
570
|
this.emit("change", changeEvent);
|
|
554
571
|
nextEmit = null;
|
|
555
572
|
};
|
|
573
|
+
let changeQueue = Promise.resolve();
|
|
556
574
|
const onChange = (change) => {
|
|
557
575
|
if (
|
|
576
|
+
change.event !== "recrawl" &&
|
|
558
577
|
change.metadata &&
|
|
559
578
|
(change.metadata.type === "d" ||
|
|
560
579
|
(change.metadata.type === "f" &&
|
|
@@ -572,62 +591,36 @@ class FileMap extends _events.default {
|
|
|
572
591
|
}
|
|
573
592
|
const relativeFilePath =
|
|
574
593
|
this.#pathUtils.absoluteToNormal(absoluteFilePath);
|
|
575
|
-
const linkStats = fileSystem.linkStats(relativeFilePath);
|
|
576
|
-
if (
|
|
577
|
-
change.event === "touch" &&
|
|
578
|
-
linkStats != null &&
|
|
579
|
-
change.metadata.modifiedTime != null &&
|
|
580
|
-
linkStats.modifiedTime === change.metadata.modifiedTime
|
|
581
|
-
) {
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
const eventTypeToEmit =
|
|
585
|
-
change.event === "touch"
|
|
586
|
-
? linkStats == null
|
|
587
|
-
? "add"
|
|
588
|
-
: "change"
|
|
589
|
-
: "delete";
|
|
590
594
|
const onChangeStartTime =
|
|
591
595
|
_perf_hooks.performance.timeOrigin + _perf_hooks.performance.now();
|
|
596
|
+
const enqueueEvent = (event) => {
|
|
597
|
+
nextEmit ??= {
|
|
598
|
+
events: [],
|
|
599
|
+
firstEnqueuedTimestamp:
|
|
600
|
+
_perf_hooks.performance.timeOrigin + _perf_hooks.performance.now(),
|
|
601
|
+
firstEventTimestamp: onChangeStartTime,
|
|
602
|
+
};
|
|
603
|
+
nextEmit.events.push(event);
|
|
604
|
+
};
|
|
592
605
|
changeQueue = changeQueue
|
|
593
606
|
.then(async () => {
|
|
594
607
|
if (
|
|
595
608
|
nextEmit != null &&
|
|
596
|
-
nextEmit.
|
|
609
|
+
nextEmit.events.find(
|
|
597
610
|
(event) =>
|
|
598
|
-
event.type ===
|
|
599
|
-
event.
|
|
611
|
+
event.type === change.event &&
|
|
612
|
+
event.relativeFilePath === relativeFilePath &&
|
|
600
613
|
((!event.metadata && !change.metadata) ||
|
|
601
614
|
(event.metadata &&
|
|
602
615
|
change.metadata &&
|
|
603
|
-
event.metadata.
|
|
616
|
+
event.metadata[_constants.default.MTIME] != null &&
|
|
604
617
|
change.metadata.modifiedTime != null &&
|
|
605
|
-
event.metadata.
|
|
618
|
+
event.metadata[_constants.default.MTIME] ===
|
|
606
619
|
change.metadata.modifiedTime)),
|
|
607
620
|
)
|
|
608
621
|
) {
|
|
609
622
|
return null;
|
|
610
623
|
}
|
|
611
|
-
const linkStats = fileSystem.linkStats(relativeFilePath);
|
|
612
|
-
const enqueueEvent = (metadata) => {
|
|
613
|
-
const event = {
|
|
614
|
-
filePath: absoluteFilePath,
|
|
615
|
-
metadata,
|
|
616
|
-
type: eventTypeToEmit,
|
|
617
|
-
};
|
|
618
|
-
if (nextEmit == null) {
|
|
619
|
-
nextEmit = {
|
|
620
|
-
eventsQueue: [event],
|
|
621
|
-
firstEnqueuedTimestamp:
|
|
622
|
-
_perf_hooks.performance.timeOrigin +
|
|
623
|
-
_perf_hooks.performance.now(),
|
|
624
|
-
firstEventTimestamp: onChangeStartTime,
|
|
625
|
-
};
|
|
626
|
-
} else {
|
|
627
|
-
nextEmit.eventsQueue.push(event);
|
|
628
|
-
}
|
|
629
|
-
return null;
|
|
630
|
-
};
|
|
631
624
|
if (change.event === "touch") {
|
|
632
625
|
(0, _invariant.default)(
|
|
633
626
|
change.metadata.size != null,
|
|
@@ -654,40 +647,65 @@ class FileMap extends _events.default {
|
|
|
654
647
|
},
|
|
655
648
|
);
|
|
656
649
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
fileMetadata[dataIdx],
|
|
664
|
-
)
|
|
665
|
-
: plugin.onNewOrModifiedFile(relativeFilePath),
|
|
666
|
-
);
|
|
667
|
-
enqueueEvent(change.metadata);
|
|
650
|
+
enqueueEvent({
|
|
651
|
+
clock: change.clock,
|
|
652
|
+
relativeFilePath,
|
|
653
|
+
metadata: fileMetadata,
|
|
654
|
+
type: change.event,
|
|
655
|
+
});
|
|
668
656
|
} catch (e) {
|
|
669
657
|
if (!["ENOENT", "EACCESS"].includes(e.code)) {
|
|
670
658
|
throw e;
|
|
671
659
|
}
|
|
672
660
|
}
|
|
673
661
|
} else if (change.event === "delete") {
|
|
674
|
-
|
|
662
|
+
enqueueEvent({
|
|
663
|
+
clock: change.clock,
|
|
664
|
+
relativeFilePath,
|
|
665
|
+
type: "delete",
|
|
666
|
+
});
|
|
667
|
+
} else if (change.event === "recrawl") {
|
|
668
|
+
emitChange();
|
|
669
|
+
const absoluteDirPath = path.join(
|
|
670
|
+
change.root,
|
|
671
|
+
(0, _normalizePathSeparatorsToSystem.default)(
|
|
672
|
+
change.relativePath,
|
|
673
|
+
),
|
|
674
|
+
);
|
|
675
|
+
const subpath = this.#pathUtils.absoluteToNormal(absoluteDirPath);
|
|
676
|
+
const watcher = this.#watcher;
|
|
677
|
+
(0, _invariant.default)(
|
|
678
|
+
watcher != null,
|
|
679
|
+
"Watcher must be initialized",
|
|
680
|
+
);
|
|
681
|
+
const crawlResult = await watcher.recrawl(subpath, fileSystem);
|
|
682
|
+
if (
|
|
683
|
+
crawlResult.changedFiles.size === 0 &&
|
|
684
|
+
crawlResult.removedFiles.size === 0
|
|
685
|
+
) {
|
|
675
686
|
return null;
|
|
676
687
|
}
|
|
677
|
-
const
|
|
678
|
-
fileSystem
|
|
688
|
+
const recrawlChangeAggregator = await this.#applyFileDelta(
|
|
689
|
+
fileSystem,
|
|
690
|
+
this.#plugins,
|
|
691
|
+
crawlResult,
|
|
679
692
|
);
|
|
680
693
|
this.#updateClock(clocks, change.clock);
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
modifiedTime: null,
|
|
688
|
-
size: null,
|
|
689
|
-
type: linkStats.fileType,
|
|
694
|
+
if (recrawlChangeAggregator.getSize() === 0) {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
const toPublicMetadata = (metadata) => ({
|
|
698
|
+
isSymlink: metadata[_constants.default.SYMLINK] !== 0,
|
|
699
|
+
modifiedTime: metadata[_constants.default.MTIME] ?? null,
|
|
690
700
|
});
|
|
701
|
+
const changesWithMetadata =
|
|
702
|
+
recrawlChangeAggregator.getMappedView(toPublicMetadata);
|
|
703
|
+
const changeEvent = {
|
|
704
|
+
changes: changesWithMetadata,
|
|
705
|
+
logger: null,
|
|
706
|
+
rootDir: this.#options.rootDir,
|
|
707
|
+
};
|
|
708
|
+
this.emit("change", changeEvent);
|
|
691
709
|
} else {
|
|
692
710
|
throw new Error(
|
|
693
711
|
`metro-file-map: Unrecognized event type from watcher: ${change.event}`,
|
|
@@ -787,11 +805,9 @@ class FileMap extends _events.default {
|
|
|
787
805
|
static H = _constants.default;
|
|
788
806
|
}
|
|
789
807
|
exports.default = FileMap;
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
})();
|
|
808
|
+
const mapIterable = (it, fn) =>
|
|
809
|
+
(function* mapped() {
|
|
810
|
+
for (const item of it) {
|
|
811
|
+
yield fn(item);
|
|
812
|
+
}
|
|
813
|
+
})();
|