metro-file-map 0.84.1 → 0.84.3

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 (56) hide show
  1. package/package.json +1 -1
  2. package/src/Watcher.d.ts +74 -0
  3. package/src/Watcher.js +66 -39
  4. package/src/Watcher.js.flow +84 -51
  5. package/src/cache/DiskCacheManager.d.ts +49 -0
  6. package/src/constants.d.ts +22 -0
  7. package/src/crawlers/node/hasNativeFindSupport.d.ts +19 -0
  8. package/src/crawlers/node/index.d.ts +21 -0
  9. package/src/crawlers/node/index.js +4 -1
  10. package/src/crawlers/node/index.js.flow +8 -6
  11. package/src/crawlers/watchman/index.d.ts +23 -0
  12. package/src/crawlers/watchman/index.js.flow +2 -6
  13. package/src/flow-types.d.ts +460 -0
  14. package/src/flow-types.js.flow +89 -29
  15. package/src/index.d.ts +182 -0
  16. package/src/index.js +145 -120
  17. package/src/index.js.flow +199 -149
  18. package/src/lib/FileProcessor.d.ts +60 -0
  19. package/src/lib/FileSystemChangeAggregator.d.ts +40 -0
  20. package/src/lib/FileSystemChangeAggregator.js +89 -0
  21. package/src/lib/FileSystemChangeAggregator.js.flow +143 -0
  22. package/src/lib/RootPathUtils.d.ts +30 -0
  23. package/src/lib/TreeFS.d.ts +174 -0
  24. package/src/lib/TreeFS.js +67 -16
  25. package/src/lib/TreeFS.js.flow +89 -16
  26. package/src/lib/checkWatchmanCapabilities.d.ts +20 -0
  27. package/src/lib/normalizePathSeparatorsToPosix.d.ts +20 -0
  28. package/src/lib/normalizePathSeparatorsToSystem.d.ts +20 -0
  29. package/src/lib/rootRelativeCacheKeys.d.ts +24 -0
  30. package/src/lib/sorting.d.ts +23 -0
  31. package/src/plugins/DependencyPlugin.d.ts +52 -0
  32. package/src/plugins/DependencyPlugin.js +1 -3
  33. package/src/plugins/DependencyPlugin.js.flow +1 -16
  34. package/src/plugins/HastePlugin.d.ts +69 -0
  35. package/src/plugins/HastePlugin.js +11 -11
  36. package/src/plugins/HastePlugin.js.flow +12 -12
  37. package/src/plugins/MockPlugin.d.ts +48 -0
  38. package/src/plugins/MockPlugin.js +17 -20
  39. package/src/plugins/MockPlugin.js.flow +18 -22
  40. package/src/plugins/haste/DuplicateHasteCandidatesError.d.ts +31 -0
  41. package/src/plugins/haste/HasteConflictsError.d.ts +23 -0
  42. package/src/plugins/haste/computeConflicts.d.ts +34 -0
  43. package/src/plugins/haste/getPlatformExtension.d.ts +21 -0
  44. package/src/plugins/mocks/getMockName.d.ts +20 -0
  45. package/src/watchers/AbstractWatcher.d.ts +41 -0
  46. package/src/watchers/FallbackWatcher.d.ts +28 -0
  47. package/src/watchers/FallbackWatcher.js +19 -3
  48. package/src/watchers/FallbackWatcher.js.flow +28 -5
  49. package/src/watchers/NativeWatcher.d.ts +55 -0
  50. package/src/watchers/NativeWatcher.js +27 -5
  51. package/src/watchers/NativeWatcher.js.flow +33 -6
  52. package/src/watchers/RecrawlWarning.d.ts +32 -0
  53. package/src/watchers/WatchmanWatcher.d.ts +34 -0
  54. package/src/watchers/common.d.ts +70 -0
  55. package/src/watchers/common.js +6 -1
  56. package/src/watchers/common.js.flow +1 -0
@@ -0,0 +1,460 @@
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<<b3646c81d37188726a1fc27777dcbede>>
10
+ *
11
+ * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
12
+ * Original file: packages/metro-file-map/src/flow-types.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 {PerfLogger, PerfLoggerFactory, RootPerfLogger} from 'metro-config';
19
+
20
+ export type {PerfLoggerFactory, PerfLogger};
21
+ export type BuildParameters = Readonly<{
22
+ computeSha1: boolean;
23
+ enableSymlinks: boolean;
24
+ extensions: ReadonlyArray<string>;
25
+ forceNodeFilesystemAPI: boolean;
26
+ ignorePattern: RegExp;
27
+ plugins: ReadonlyArray<InputFileMapPlugin>;
28
+ retainAllFiles: boolean;
29
+ rootDir: string;
30
+ roots: ReadonlyArray<string>;
31
+ cacheBreaker: string;
32
+ }>;
33
+ export type BuildResult = {fileSystem: FileSystem};
34
+ export type CacheData = Readonly<{
35
+ clocks: WatchmanClocks;
36
+ fileSystemData: unknown;
37
+ plugins: ReadonlyMap<string, void | V8Serializable>;
38
+ }>;
39
+ export interface CacheManager {
40
+ /**
41
+ * Called during startup to load initial state, if available. Provided to
42
+ * a crawler, which will return the delta between the initial state and the
43
+ * current file system state.
44
+ */
45
+ read(): Promise<null | undefined | CacheData>;
46
+ /**
47
+ * Called when metro-file-map `build()` has applied changes returned by the
48
+ * crawler - i.e. internal state reflects the current file system state.
49
+ *
50
+ * getSnapshot may be retained and called at any time before end(), such as
51
+ * in response to eventSource 'change' events.
52
+ */
53
+ write(
54
+ getSnapshot: () => CacheData,
55
+ opts: CacheManagerWriteOptions,
56
+ ): Promise<void>;
57
+ /**
58
+ * The last call that will be made to this CacheManager. Any handles should
59
+ * be closed by the time this settles.
60
+ */
61
+ end(): Promise<void>;
62
+ }
63
+ export interface CacheManagerEventSource {
64
+ onChange(listener: () => void): () => void;
65
+ }
66
+ export type CacheManagerFactory = (
67
+ options: CacheManagerFactoryOptions,
68
+ ) => CacheManager;
69
+ export type CacheManagerFactoryOptions = Readonly<{
70
+ buildParameters: BuildParameters;
71
+ }>;
72
+ export type CacheManagerWriteOptions = Readonly<{
73
+ changedSinceCacheRead: boolean;
74
+ eventSource: CacheManagerEventSource;
75
+ onWriteError: (error: Error) => void;
76
+ }>;
77
+ export type CanonicalPath = string;
78
+ export type ChangedFileMetadata = Readonly<{
79
+ isSymlink: boolean;
80
+ modifiedTime?: null | undefined | number;
81
+ }>;
82
+ export type ChangeEvent = Readonly<{
83
+ logger: null | undefined | RootPerfLogger;
84
+ changes: ReadonlyFileSystemChanges<Readonly<ChangedFileMetadata>>;
85
+ rootDir: string;
86
+ }>;
87
+ export type ChangeEventMetadata = {
88
+ modifiedTime: null | undefined | number;
89
+ size: null | undefined | number;
90
+ type: 'f' | 'd' | 'l';
91
+ };
92
+ export type Console = typeof global.console;
93
+ export type CrawlerOptions = {
94
+ abortSignal: null | undefined | AbortSignal;
95
+ computeSha1: boolean;
96
+ console: Console;
97
+ extensions: ReadonlyArray<string>;
98
+ forceNodeFilesystemAPI: boolean;
99
+ ignore: IgnoreMatcher;
100
+ includeSymlinks: boolean;
101
+ perfLogger?: null | undefined | PerfLogger;
102
+ previousState: Readonly<{
103
+ clocks: ReadonlyMap<CanonicalPath, WatchmanClockSpec>;
104
+ fileSystem: FileSystem;
105
+ }>;
106
+ rootDir: string;
107
+ roots: ReadonlyArray<string>;
108
+ onStatus: (status: WatcherStatus) => void;
109
+ subpath?: string;
110
+ };
111
+ export type CrawlResult =
112
+ | {changedFiles: FileData; removedFiles: Set<Path>; clocks: WatchmanClocks}
113
+ | {changedFiles: FileData; removedFiles: Set<Path>};
114
+ export type DependencyExtractor = {
115
+ extract: (
116
+ content: string,
117
+ absoluteFilePath: string,
118
+ defaultExtractor?: DependencyExtractor['extract'],
119
+ ) => Set<string>;
120
+ getCacheKey: () => string;
121
+ };
122
+ export type WatcherStatus =
123
+ | {
124
+ type: 'watchman_slow_command';
125
+ timeElapsed: number;
126
+ command: 'watch-project' | 'query';
127
+ }
128
+ | {
129
+ type: 'watchman_slow_command_complete';
130
+ timeElapsed: number;
131
+ command: 'watch-project' | 'query';
132
+ }
133
+ | {
134
+ type: 'watchman_warning';
135
+ warning: unknown;
136
+ command: 'watch-project' | 'query';
137
+ };
138
+ export type DuplicatesSet = Map<string, number>;
139
+ export type DuplicatesIndex = Map<string, Map<string, DuplicatesSet>>;
140
+ export type FileMapPluginInitOptions<
141
+ SerializableState,
142
+ PerFileData = void,
143
+ > = Readonly<{
144
+ files: Readonly<{
145
+ fileIterator(
146
+ opts: Readonly<{includeNodeModules: boolean; includeSymlinks: boolean}>,
147
+ ): Iterable<{
148
+ baseName: string;
149
+ canonicalPath: string;
150
+ readonly pluginData: null | undefined | PerFileData;
151
+ }>;
152
+ lookup(
153
+ mixedPath: string,
154
+ ):
155
+ | {exists: false}
156
+ | {exists: true; type: 'f'; readonly pluginData: PerFileData}
157
+ | {exists: true; type: 'd'};
158
+ }>;
159
+ pluginState: null | undefined | SerializableState;
160
+ }>;
161
+ export type FileMapPluginWorker = Readonly<{
162
+ worker: Readonly<{modulePath: string; setupArgs: JsonData}>;
163
+ filter: ($$PARAM_0$$: {
164
+ normalPath: string;
165
+ isNodeModules: boolean;
166
+ }) => boolean;
167
+ }>;
168
+ export type V8Serializable =
169
+ | string
170
+ | number
171
+ | boolean
172
+ | null
173
+ | ReadonlyArray<V8Serializable>
174
+ | ReadonlySet<V8Serializable>
175
+ | ReadonlyMap<string, V8Serializable>
176
+ | Readonly<{[key: string]: V8Serializable}>;
177
+ export interface FileMapPlugin<
178
+ SerializableState extends void | V8Serializable = void | V8Serializable,
179
+ PerFileData extends void | V8Serializable = void | V8Serializable,
180
+ > {
181
+ readonly name: string;
182
+ initialize(
183
+ initOptions: FileMapPluginInitOptions<SerializableState, PerFileData>,
184
+ ): Promise<void>;
185
+ assertValid(): void;
186
+ onChanged(
187
+ changes: ReadonlyFileSystemChanges<null | undefined | PerFileData>,
188
+ ): void;
189
+ getSerializableSnapshot(): void | V8Serializable;
190
+ getCacheKey(): string;
191
+ getWorker(): null | undefined | FileMapPluginWorker;
192
+ }
193
+ export type InputFileMapPlugin = FileMapPlugin<
194
+ /**
195
+ * > 235 | export type InputFileMapPlugin = FileMapPlugin<empty, empty>;
196
+ * | ^^^^^ Unsupported feature: Translating "empty type" is currently not supported.
197
+ **/
198
+ any,
199
+ /**
200
+ * > 235 | export type InputFileMapPlugin = FileMapPlugin<empty, empty>;
201
+ * | ^^^^^ Unsupported feature: Translating "empty type" is currently not supported.
202
+ **/
203
+ any
204
+ >;
205
+ export interface MetadataWorker {
206
+ processFile(
207
+ $$PARAM_0$$: WorkerMessage,
208
+ $$PARAM_1$$: Readonly<{getContent: () => Buffer}>,
209
+ ): V8Serializable;
210
+ }
211
+ export type HType = {
212
+ MTIME: 0;
213
+ SIZE: 1;
214
+ VISITED: 2;
215
+ SHA1: 3;
216
+ SYMLINK: 4;
217
+ PLUGINDATA: number;
218
+ PATH: 0;
219
+ TYPE: 1;
220
+ MODULE: 0;
221
+ PACKAGE: 1;
222
+ GENERIC_PLATFORM: 'g';
223
+ NATIVE_PLATFORM: 'native';
224
+ };
225
+ export type HTypeValue = HType[keyof HType];
226
+ export type IgnoreMatcher = (item: string) => boolean;
227
+ export type FileData = Map<CanonicalPath, FileMetadata>;
228
+ export type FileMetadata = [
229
+ null | undefined | number,
230
+ number,
231
+ 0 | 1,
232
+ null | undefined | string,
233
+ 0 | 1 | string,
234
+ ...unknown[],
235
+ ];
236
+ export type FileStats = Readonly<{
237
+ fileType: 'f' | 'l';
238
+ modifiedTime: null | undefined | number;
239
+ size: null | undefined | number;
240
+ }>;
241
+ export interface FileSystem {
242
+ exists(file: Path): boolean;
243
+ getAllFiles(): Array<Path>;
244
+ /**
245
+ * Given a map of files, determine which of them are new or modified
246
+ * (changedFiles), and which of them are missing from the input
247
+ * (removedFiles), vs the current state of this instance of FileSystem.
248
+ */
249
+ getDifference(
250
+ files: FileData,
251
+ options?: Readonly<{
252
+ /**
253
+ * Only consider files under this subpath (which should be a directory)
254
+ * when computing removedFiles. If not provided, all files in the file
255
+ * system are considered.
256
+ */
257
+ subpath?: string;
258
+ }>,
259
+ ): {changedFiles: FileData; removedFiles: Set<string>};
260
+ getSerializableSnapshot(): CacheData['fileSystemData'];
261
+ getSha1(file: Path): null | undefined | string;
262
+ getOrComputeSha1(
263
+ file: Path,
264
+ ): Promise<null | undefined | {sha1: string; content?: Buffer}>;
265
+ /**
266
+ * Given a start path (which need not exist), a subpath and type, and
267
+ * optionally a 'breakOnSegment', performs the following:
268
+ *
269
+ * X = mixedStartPath
270
+ * do
271
+ * if basename(X) === opts.breakOnSegment
272
+ * return null
273
+ * if X + subpath exists and has type opts.subpathType
274
+ * return {
275
+ * absolutePath: realpath(X + subpath)
276
+ * containerRelativePath: relative(mixedStartPath, X)
277
+ * }
278
+ * X = dirname(X)
279
+ * while X !== dirname(X)
280
+ *
281
+ * If opts.invalidatedBy is given, collects all absolute, real paths that if
282
+ * added or removed may invalidate this result.
283
+ *
284
+ * Useful for finding the closest package scope (subpath: package.json,
285
+ * type f, breakOnSegment: node_modules) or closest potential package root
286
+ * (subpath: node_modules/pkg, type: d) in Node.js resolution.
287
+ */
288
+ hierarchicalLookup(
289
+ mixedStartPath: string,
290
+ subpath: string,
291
+ opts: {
292
+ breakOnSegment: null | undefined | string;
293
+ invalidatedBy: null | undefined | Set<string>;
294
+ subpathType: 'f' | 'd';
295
+ },
296
+ ): null | undefined | {absolutePath: string; containerRelativePath: string};
297
+ /**
298
+ * Analogous to posix lstat. If the file at `file` is a symlink, return
299
+ * information about the symlink without following it.
300
+ */
301
+ linkStats(file: Path): null | undefined | FileStats;
302
+ /**
303
+ * Return information about the given path, whether a directory or file.
304
+ * Always follow symlinks, and return a real path if it exists.
305
+ */
306
+ lookup(mixedPath: Path): LookupResult;
307
+ matchFiles(opts: {
308
+ filter?: RegExp | null;
309
+ filterCompareAbsolute?: boolean;
310
+ filterComparePosix?: boolean;
311
+ follow?: boolean;
312
+ recursive?: boolean;
313
+ rootDir?: Path | null;
314
+ }): Iterable<Path>;
315
+ }
316
+ export type Glob = string;
317
+ export type JsonData =
318
+ | string
319
+ | number
320
+ | boolean
321
+ | null
322
+ | Array<JsonData>
323
+ | {[key: string]: JsonData};
324
+ export type LookupResult =
325
+ | {exists: false; links: ReadonlySet<string>; missing: string}
326
+ | {exists: true; links: ReadonlySet<string>; realPath: string; type: 'd'}
327
+ | {
328
+ exists: true;
329
+ links: ReadonlySet<string>;
330
+ realPath: string;
331
+ type: 'f';
332
+ metadata: FileMetadata;
333
+ };
334
+ export interface MockMap {
335
+ getMockModule(name: string): null | undefined | Path;
336
+ }
337
+ export type HasteConflict = {
338
+ id: string;
339
+ platform: string | null;
340
+ absolutePaths: Array<string>;
341
+ type: 'duplicate' | 'shadowing';
342
+ };
343
+ export interface HasteMap {
344
+ getModule(
345
+ name: string,
346
+ platform?: null | undefined | string,
347
+ supportsNativePlatform?: null | undefined | boolean,
348
+ type?: null | undefined | HTypeValue,
349
+ ): null | undefined | Path;
350
+ getModuleNameByPath(file: Path): null | undefined | string;
351
+ getPackage(
352
+ name: string,
353
+ platform: null | undefined | string,
354
+ _supportsNativePlatform: null | undefined | boolean,
355
+ ): null | undefined | Path;
356
+ computeConflicts(): Array<HasteConflict>;
357
+ }
358
+ export type HasteMapData = Map<string, HasteMapItem>;
359
+ export type HasteMapItem = {
360
+ [platform: string]: HasteMapItemMetadata;
361
+ };
362
+ export type HasteMapItemMetadata = [string, number];
363
+ export interface FileSystemListener {
364
+ directoryAdded(canonicalPath: CanonicalPath): void;
365
+ directoryRemoved(canonicalPath: CanonicalPath): void;
366
+ fileAdded(canonicalPath: CanonicalPath, data: FileMetadata): void;
367
+ fileModified(
368
+ canonicalPath: CanonicalPath,
369
+ oldData: FileMetadata,
370
+ newData: FileMetadata,
371
+ ): void;
372
+ fileRemoved(canonicalPath: CanonicalPath, data: FileMetadata): void;
373
+ }
374
+ export interface ReadonlyFileSystemChanges<T = FileMetadata> {
375
+ readonly addedDirectories: Iterable<CanonicalPath>;
376
+ readonly removedDirectories: Iterable<CanonicalPath>;
377
+ readonly addedFiles: Iterable<Readonly<[CanonicalPath, T]>>;
378
+ readonly modifiedFiles: Iterable<Readonly<[CanonicalPath, T]>>;
379
+ readonly removedFiles: Iterable<Readonly<[CanonicalPath, T]>>;
380
+ }
381
+ export interface MutableFileSystem extends FileSystem {
382
+ remove(filePath: Path, listener?: FileSystemListener): void;
383
+ addOrModify(
384
+ filePath: Path,
385
+ fileMetadata: FileMetadata,
386
+ listener?: FileSystemListener,
387
+ ): void;
388
+ bulkAddOrModify(
389
+ addedOrModifiedFiles: FileData,
390
+ listener?: FileSystemListener,
391
+ ): void;
392
+ }
393
+ export type Path = string;
394
+ export type ProcessFileFunction = (
395
+ normalPath: string,
396
+ metadata: FileMetadata,
397
+ request: Readonly<{computeSha1: boolean}>,
398
+ ) => null | undefined | Buffer;
399
+ export type RawMockMap = Readonly<{
400
+ duplicates: Map<string, Set<string>>;
401
+ mocks: Map<string, Path>;
402
+ version: number;
403
+ }>;
404
+ export type ReadOnlyRawMockMap = Readonly<{
405
+ duplicates: ReadonlyMap<string, ReadonlySet<string>>;
406
+ mocks: ReadonlyMap<string, Path>;
407
+ version: number;
408
+ }>;
409
+ export interface WatcherBackend {
410
+ getPauseReason(): null | undefined | string;
411
+ onError(listener: (error: Error) => void): () => void;
412
+ onFileEvent(listener: (event: WatcherBackendChangeEvent) => void): () => void;
413
+ startWatching(): Promise<void>;
414
+ stopWatching(): Promise<void>;
415
+ }
416
+ export type ChangeEventClock = [string, string];
417
+ export type WatcherBackendChangeEvent =
418
+ | Readonly<{
419
+ event: 'touch';
420
+ clock?: ChangeEventClock;
421
+ relativePath: string;
422
+ root: string;
423
+ metadata: ChangeEventMetadata;
424
+ }>
425
+ | Readonly<{
426
+ event: 'delete';
427
+ clock?: ChangeEventClock;
428
+ relativePath: string;
429
+ root: string;
430
+ metadata?: void;
431
+ }>
432
+ | Readonly<{
433
+ event: 'recrawl';
434
+ clock?: ChangeEventClock;
435
+ relativePath: string;
436
+ root: string;
437
+ }>;
438
+ export type WatcherBackendOptions = Readonly<{
439
+ ignored: null | undefined | RegExp;
440
+ globs: ReadonlyArray<string>;
441
+ dot: boolean;
442
+ }>;
443
+ export type WatchmanClockSpec =
444
+ | string
445
+ | Readonly<{scm: Readonly<{'mergebase-with': string}>}>;
446
+ export type WatchmanClocks = Map<Path, WatchmanClockSpec>;
447
+ export type WorkerMessage = Readonly<{
448
+ computeSha1: boolean;
449
+ filePath: string;
450
+ maybeReturnContent: boolean;
451
+ pluginsToRun: ReadonlyArray<number>;
452
+ }>;
453
+ export type WorkerMetadata = Readonly<{
454
+ sha1?: null | undefined | string;
455
+ content?: null | undefined | Buffer;
456
+ pluginData?: ReadonlyArray<V8Serializable>;
457
+ }>;
458
+ export type WorkerSetupArgs = Readonly<{
459
+ plugins?: ReadonlyArray<FileMapPluginWorker['worker']>;
460
+ }>;
@@ -21,7 +21,7 @@ export type BuildParameters = Readonly<{
21
21
  extensions: ReadonlyArray<string>,
22
22
  forceNodeFilesystemAPI: boolean,
23
23
  ignorePattern: RegExp,
24
- plugins: ReadonlyArray<FileMapPlugin<>>,
24
+ plugins: ReadonlyArray<InputFileMapPlugin>,
25
25
  retainAllFiles: boolean,
26
26
  rootDir: string,
27
27
  roots: ReadonlyArray<string>,
@@ -90,10 +90,16 @@ export type CacheManagerWriteOptions = Readonly<{
90
90
  // - Real (no symlinks in path, though the path itself may be a symlink)
91
91
  export type CanonicalPath = string;
92
92
 
93
- export type ChangeEvent = {
93
+ export type ChangedFileMetadata = Readonly<{
94
+ isSymlink: boolean,
95
+ modifiedTime?: ?number,
96
+ }>;
97
+
98
+ export type ChangeEvent = Readonly<{
94
99
  logger: ?RootPerfLogger,
95
- eventsQueue: EventsQueue,
96
- };
100
+ changes: ReadonlyFileSystemChanges<Readonly<ChangedFileMetadata>>,
101
+ rootDir: string,
102
+ }>;
97
103
 
98
104
  export type ChangeEventMetadata = {
99
105
  modifiedTime: ?number, // Epoch ms
@@ -119,8 +125,22 @@ export type CrawlerOptions = {
119
125
  rootDir: string,
120
126
  roots: ReadonlyArray<string>,
121
127
  onStatus: (status: WatcherStatus) => void,
128
+ // Only consider files under this normalized subdirectory when computing
129
+ // removedFiles. If not provided, all files in the file system are considered.
130
+ subpath?: string,
122
131
  };
123
132
 
133
+ export type CrawlResult =
134
+ | {
135
+ changedFiles: FileData,
136
+ removedFiles: Set<Path>,
137
+ clocks: WatchmanClocks,
138
+ }
139
+ | {
140
+ changedFiles: FileData,
141
+ removedFiles: Set<Path>,
142
+ };
143
+
124
144
  export type DependencyExtractor = {
125
145
  extract: (
126
146
  content: string,
@@ -150,20 +170,9 @@ export type WatcherStatus =
150
170
  export type DuplicatesSet = Map<string, /* type */ number>;
151
171
  export type DuplicatesIndex = Map<string, Map<string, DuplicatesSet>>;
152
172
 
153
- export type EventsQueue = Array<{
154
- filePath: Path,
155
- metadata: ChangeEventMetadata,
156
- type: string,
157
- }>;
158
-
159
- export type FileMapDelta<T = null | void> = Readonly<{
160
- removed: Iterable<[CanonicalPath, T]>,
161
- addedOrModified: Iterable<[CanonicalPath, T]>,
162
- }>;
163
-
164
173
  export type FileMapPluginInitOptions<
165
- SerializableState,
166
- PerFileData = void,
174
+ +SerializableState,
175
+ +PerFileData = void,
167
176
  > = Readonly<{
168
177
  files: Readonly<{
169
178
  fileIterator(
@@ -174,13 +183,13 @@ export type FileMapPluginInitOptions<
174
183
  ): Iterable<{
175
184
  baseName: string,
176
185
  canonicalPath: string,
177
- pluginData: ?PerFileData,
186
+ +pluginData: ?PerFileData,
178
187
  }>,
179
188
  lookup(
180
189
  mixedPath: string,
181
190
  ):
182
191
  | {exists: false}
183
- | {exists: true, type: 'f', pluginData: PerFileData}
192
+ | {exists: true, type: 'f', +pluginData: PerFileData}
184
193
  | {exists: true, type: 'd'},
185
194
  }>,
186
195
  pluginState: ?SerializableState,
@@ -205,22 +214,22 @@ export type V8Serializable =
205
214
  | Readonly<{[key: string]: V8Serializable}>;
206
215
 
207
216
  export interface FileMapPlugin<
208
- SerializableState: void | V8Serializable = void | V8Serializable,
209
- PerFileData: void | V8Serializable = void | V8Serializable,
217
+ -SerializableState extends void | V8Serializable = void | V8Serializable,
218
+ -PerFileData extends void | V8Serializable = void | V8Serializable,
210
219
  > {
211
220
  +name: string;
212
221
  initialize(
213
222
  initOptions: FileMapPluginInitOptions<SerializableState, PerFileData>,
214
223
  ): Promise<void>;
215
224
  assertValid(): void;
216
- bulkUpdate(delta: FileMapDelta<?PerFileData>): void;
217
- getSerializableSnapshot(): SerializableState;
218
- onRemovedFile(relativeFilePath: string, pluginData: ?PerFileData): void;
219
- onNewOrModifiedFile(relativeFilePath: string, pluginData: ?PerFileData): void;
225
+ onChanged(changes: ReadonlyFileSystemChanges<?PerFileData>): void;
226
+ getSerializableSnapshot(): void | V8Serializable;
220
227
  getCacheKey(): string;
221
228
  getWorker(): ?FileMapPluginWorker;
222
229
  }
223
230
 
231
+ export type InputFileMapPlugin = FileMapPlugin<empty, empty>;
232
+
224
233
  export interface MetadataWorker {
225
234
  processFile(
226
235
  WorkerMessage,
@@ -268,7 +277,23 @@ export type FileStats = Readonly<{
268
277
  export interface FileSystem {
269
278
  exists(file: Path): boolean;
270
279
  getAllFiles(): Array<Path>;
271
- getDifference(files: FileData): {
280
+
281
+ /**
282
+ * Given a map of files, determine which of them are new or modified
283
+ * (changedFiles), and which of them are missing from the input
284
+ * (removedFiles), vs the current state of this instance of FileSystem.
285
+ */
286
+ getDifference(
287
+ files: FileData,
288
+ options?: Readonly<{
289
+ /**
290
+ * Only consider files under this subpath (which should be a directory)
291
+ * when computing removedFiles. If not provided, all files in the file
292
+ * system are considered.
293
+ */
294
+ subpath?: string,
295
+ }>,
296
+ ): {
272
297
  changedFiles: FileData,
273
298
  removedFiles: Set<string>,
274
299
  };
@@ -423,10 +448,39 @@ export type HasteMapItem = {
423
448
  };
424
449
  export type HasteMapItemMetadata = [/* path */ string, /* type */ number];
425
450
 
451
+ export interface FileSystemListener {
452
+ directoryAdded(canonicalPath: CanonicalPath): void;
453
+ directoryRemoved(canonicalPath: CanonicalPath): void;
454
+
455
+ fileAdded(canonicalPath: CanonicalPath, data: FileMetadata): void;
456
+ fileModified(
457
+ canonicalPath: CanonicalPath,
458
+ oldData: FileMetadata,
459
+ newData: FileMetadata,
460
+ ): void;
461
+ fileRemoved(canonicalPath: CanonicalPath, data: FileMetadata): void;
462
+ }
463
+
464
+ export interface ReadonlyFileSystemChanges<+T = FileMetadata> {
465
+ +addedDirectories: Iterable<CanonicalPath>;
466
+ +removedDirectories: Iterable<CanonicalPath>;
467
+
468
+ +addedFiles: Iterable<Readonly<[CanonicalPath, T]>>;
469
+ +modifiedFiles: Iterable<Readonly<[CanonicalPath, T]>>;
470
+ +removedFiles: Iterable<Readonly<[CanonicalPath, T]>>;
471
+ }
472
+
426
473
  export interface MutableFileSystem extends FileSystem {
427
- remove(filePath: Path): ?FileMetadata;
428
- addOrModify(filePath: Path, fileMetadata: FileMetadata): void;
429
- bulkAddOrModify(addedOrModifiedFiles: FileData): void;
474
+ remove(filePath: Path, listener?: FileSystemListener): void;
475
+ addOrModify(
476
+ filePath: Path,
477
+ fileMetadata: FileMetadata,
478
+ listener?: FileSystemListener,
479
+ ): void;
480
+ bulkAddOrModify(
481
+ addedOrModifiedFiles: FileData,
482
+ listener?: FileSystemListener,
483
+ ): void;
430
484
  }
431
485
 
432
486
  export type Path = string;
@@ -482,6 +536,12 @@ export type WatcherBackendChangeEvent =
482
536
  relativePath: string,
483
537
  root: string,
484
538
  metadata?: void,
539
+ }>
540
+ | Readonly<{
541
+ event: 'recrawl',
542
+ clock?: ChangeEventClock,
543
+ relativePath: string,
544
+ root: string,
485
545
  }>;
486
546
 
487
547
  export type WatcherBackendOptions = Readonly<{