@expo/metro-file-map 55.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +1 -0
  2. package/build/Watcher.d.ts +53 -0
  3. package/build/Watcher.js +249 -0
  4. package/build/cache/DiskCacheManager.d.ts +25 -0
  5. package/build/cache/DiskCacheManager.js +110 -0
  6. package/build/constants.d.ts +23 -0
  7. package/build/constants.js +27 -0
  8. package/build/crawlers/node/fallback.d.ts +20 -0
  9. package/build/crawlers/node/fallback.js +148 -0
  10. package/build/crawlers/node/index.d.ts +10 -0
  11. package/build/crawlers/node/index.js +152 -0
  12. package/build/crawlers/watchman/index.d.ts +8 -0
  13. package/build/crawlers/watchman/index.js +288 -0
  14. package/build/crawlers/watchman/planQuery.d.ts +31 -0
  15. package/build/crawlers/watchman/planQuery.js +99 -0
  16. package/build/index.d.ts +140 -0
  17. package/build/index.js +836 -0
  18. package/build/lib/FileProcessor.d.ts +42 -0
  19. package/build/lib/FileProcessor.js +180 -0
  20. package/build/lib/FileSystemChangeAggregator.d.ts +18 -0
  21. package/build/lib/FileSystemChangeAggregator.js +114 -0
  22. package/build/lib/RootPathUtils.d.ts +24 -0
  23. package/build/lib/RootPathUtils.js +311 -0
  24. package/build/lib/TreeFS.d.ts +161 -0
  25. package/build/lib/TreeFS.js +1006 -0
  26. package/build/lib/checkWatchmanCapabilities.d.ts +9 -0
  27. package/build/lib/checkWatchmanCapabilities.js +50 -0
  28. package/build/lib/normalizePathSeparatorsToPosix.d.ts +8 -0
  29. package/build/lib/normalizePathSeparatorsToPosix.js +20 -0
  30. package/build/lib/normalizePathSeparatorsToSystem.d.ts +8 -0
  31. package/build/lib/normalizePathSeparatorsToSystem.js +20 -0
  32. package/build/lib/removeOverlappingRoots.d.ts +10 -0
  33. package/build/lib/removeOverlappingRoots.js +37 -0
  34. package/build/lib/rootRelativeCacheKeys.d.ts +11 -0
  35. package/build/lib/rootRelativeCacheKeys.js +56 -0
  36. package/build/lib/sorting.d.ts +8 -0
  37. package/build/lib/sorting.js +31 -0
  38. package/build/plugins/DependencyPlugin.d.ts +23 -0
  39. package/build/plugins/DependencyPlugin.js +61 -0
  40. package/build/plugins/FileDataPlugin.d.ts +28 -0
  41. package/build/plugins/FileDataPlugin.js +46 -0
  42. package/build/plugins/HastePlugin.d.ts +32 -0
  43. package/build/plugins/HastePlugin.js +358 -0
  44. package/build/plugins/MockPlugin.d.ts +27 -0
  45. package/build/plugins/MockPlugin.js +157 -0
  46. package/build/plugins/dependencies/dependencyExtractor.d.ts +7 -0
  47. package/build/plugins/dependencies/dependencyExtractor.js +66 -0
  48. package/build/plugins/dependencies/worker.d.ts +18 -0
  49. package/build/plugins/dependencies/worker.js +30 -0
  50. package/build/plugins/haste/DuplicateHasteCandidatesError.d.ts +14 -0
  51. package/build/plugins/haste/DuplicateHasteCandidatesError.js +51 -0
  52. package/build/plugins/haste/HasteConflictsError.d.ts +12 -0
  53. package/build/plugins/haste/HasteConflictsError.js +49 -0
  54. package/build/plugins/haste/computeConflicts.d.ts +19 -0
  55. package/build/plugins/haste/computeConflicts.js +74 -0
  56. package/build/plugins/haste/getPlatformExtension.d.ts +7 -0
  57. package/build/plugins/haste/getPlatformExtension.js +19 -0
  58. package/build/plugins/haste/worker.d.ts +16 -0
  59. package/build/plugins/haste/worker.js +48 -0
  60. package/build/plugins/mocks/getMockName.d.ts +8 -0
  61. package/build/plugins/mocks/getMockName.js +17 -0
  62. package/build/ts-declarations/fb-watchman.d.ts +20 -0
  63. package/build/ts-declarations/fb-watchman.js +2 -0
  64. package/build/types.d.ts +404 -0
  65. package/build/types.js +8 -0
  66. package/build/watchers/AbstractWatcher.d.ts +30 -0
  67. package/build/watchers/AbstractWatcher.js +97 -0
  68. package/build/watchers/FallbackWatcher.d.ts +18 -0
  69. package/build/watchers/FallbackWatcher.js +411 -0
  70. package/build/watchers/NativeWatcher.d.ts +39 -0
  71. package/build/watchers/NativeWatcher.js +156 -0
  72. package/build/watchers/RecrawlWarning.d.ts +18 -0
  73. package/build/watchers/RecrawlWarning.js +59 -0
  74. package/build/watchers/WatchmanWatcher.d.ts +22 -0
  75. package/build/watchers/WatchmanWatcher.js +263 -0
  76. package/build/watchers/common.d.ts +39 -0
  77. package/build/watchers/common.js +60 -0
  78. package/build/worker.d.ts +24 -0
  79. package/build/worker.js +80 -0
  80. package/build/workerExclusionList.d.ts +8 -0
  81. package/build/workerExclusionList.js +57 -0
  82. package/package.json +54 -0
@@ -0,0 +1,42 @@
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
+ import type { FileMapPluginWorker, FileMetadata, PerfLogger } from '../types';
8
+ interface ProcessFileRequest {
9
+ /**
10
+ * Populate metadata[H.SHA1] with the SHA1 of the file's contents.
11
+ */
12
+ readonly computeSha1: boolean;
13
+ /**
14
+ * Only if processing has already required reading the file's contents, return
15
+ * the contents as a Buffer - null otherwise. Not supported for batches.
16
+ */
17
+ readonly maybeReturnContent: boolean;
18
+ }
19
+ interface MaybeCodedError extends Error {
20
+ code?: string;
21
+ }
22
+ export declare class FileProcessor {
23
+ #private;
24
+ constructor(opts: Readonly<{
25
+ maxFilesPerWorker?: number | null;
26
+ maxWorkers: number;
27
+ pluginWorkers?: readonly FileMapPluginWorker[] | null;
28
+ perfLogger?: PerfLogger | null;
29
+ rootDir: string;
30
+ }>);
31
+ processBatch(files: readonly [relativePath: string, FileMetadata][], req: ProcessFileRequest): Promise<{
32
+ errors: {
33
+ normalFilePath: string;
34
+ error: MaybeCodedError;
35
+ }[];
36
+ }>;
37
+ processRegularFile(normalPath: string, fileMetadata: FileMetadata, req: ProcessFileRequest): Promise<{
38
+ content: Buffer | undefined | null;
39
+ } | null>;
40
+ end(): Promise<void>;
41
+ }
42
+ export {};
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FileProcessor = void 0;
13
+ const jest_worker_1 = require("jest-worker");
14
+ const path_1 = require("path");
15
+ const constants_1 = __importDefault(require("../constants"));
16
+ const worker_1 = require("../worker");
17
+ const RootPathUtils_1 = require("./RootPathUtils");
18
+ const debug = require('debug')('Metro:FileMap');
19
+ const NODE_MODULES_SEP = 'node_modules' + path_1.sep;
20
+ const MAX_FILES_PER_WORKER = 100;
21
+ class FileProcessor {
22
+ #maxFilesPerWorker;
23
+ #maxWorkers;
24
+ #perfLogger;
25
+ #pluginWorkers;
26
+ #inBandWorker;
27
+ #rootPathUtils;
28
+ constructor(opts) {
29
+ this.#maxFilesPerWorker = opts.maxFilesPerWorker ?? MAX_FILES_PER_WORKER;
30
+ this.#maxWorkers = opts.maxWorkers;
31
+ this.#pluginWorkers = opts.pluginWorkers ?? [];
32
+ this.#inBandWorker = new worker_1.Worker({
33
+ plugins: this.#pluginWorkers.map((plugin) => plugin.worker),
34
+ });
35
+ this.#perfLogger = opts.perfLogger;
36
+ this.#rootPathUtils = new RootPathUtils_1.RootPathUtils(opts.rootDir);
37
+ }
38
+ async processBatch(files, req) {
39
+ const errors = [];
40
+ const workerJobs = files
41
+ .map(([normalFilePath, fileMetadata]) => {
42
+ const maybeWorkerInput = this.#getWorkerInput(normalFilePath, fileMetadata, req);
43
+ if (!maybeWorkerInput) {
44
+ return null;
45
+ }
46
+ return [maybeWorkerInput, fileMetadata];
47
+ })
48
+ .filter((x) => x != null);
49
+ const numWorkers = Math.min(this.#maxWorkers, Math.ceil(workerJobs.length / this.#maxFilesPerWorker));
50
+ const batchWorker = this.#getBatchWorker(numWorkers);
51
+ if (req.maybeReturnContent) {
52
+ throw new Error('Batch processing does not support returning file contents');
53
+ }
54
+ await Promise.all(workerJobs.map(([workerInput, fileMetadata]) => {
55
+ return batchWorker
56
+ .processFile(workerInput)
57
+ .then((reply) => processWorkerReply(reply, workerInput.pluginsToRun, fileMetadata))
58
+ .catch((error) => errors.push({
59
+ normalFilePath: this.#rootPathUtils.absoluteToNormal(workerInput.filePath),
60
+ error: normalizeWorkerError(error),
61
+ }));
62
+ }));
63
+ await batchWorker.end();
64
+ return { errors };
65
+ }
66
+ async processRegularFile(normalPath, fileMetadata, req) {
67
+ const workerInput = this.#getWorkerInput(normalPath, fileMetadata, req);
68
+ return workerInput
69
+ ? {
70
+ content: processWorkerReply(await this.#inBandWorker.processFile(workerInput), workerInput.pluginsToRun, fileMetadata),
71
+ }
72
+ : null;
73
+ }
74
+ #getWorkerInput(normalPath, fileMetadata, req) {
75
+ if (fileMetadata[constants_1.default.SYMLINK] !== 0) {
76
+ // Only process regular files
77
+ return null;
78
+ }
79
+ const computeSha1 = req.computeSha1 && fileMetadata[constants_1.default.SHA1] == null;
80
+ const { maybeReturnContent } = req;
81
+ const nodeModulesIdx = normalPath.indexOf(NODE_MODULES_SEP);
82
+ // Path may begin 'node_modules/' or contain '/node_modules/'.
83
+ const isNodeModules = nodeModulesIdx === 0 || (nodeModulesIdx > 0 && normalPath[nodeModulesIdx - 1] === path_1.sep);
84
+ // Indices of plugins with a passing filter
85
+ const pluginsToRun = this.#pluginWorkers?.reduce((prev, plugin, idx) => {
86
+ if (plugin.filter({ isNodeModules, normalPath })) {
87
+ prev.push(idx);
88
+ }
89
+ return prev;
90
+ }, []) ?? [];
91
+ if (!computeSha1 && pluginsToRun.length === 0) {
92
+ // Nothing to process
93
+ return null;
94
+ }
95
+ // Use a cheaper worker configuration for node_modules files, because
96
+ // they may never be Haste modules or packages.
97
+ //
98
+ // Note that we'd only expect node_modules files to reach this point if
99
+ // retainAllFiles is true, or they're touched during watch mode.
100
+ if (isNodeModules) {
101
+ if (computeSha1) {
102
+ return {
103
+ computeSha1: true,
104
+ filePath: this.#rootPathUtils.normalToAbsolute(normalPath),
105
+ maybeReturnContent,
106
+ pluginsToRun,
107
+ };
108
+ }
109
+ return null;
110
+ }
111
+ return {
112
+ computeSha1,
113
+ filePath: this.#rootPathUtils.normalToAbsolute(normalPath),
114
+ maybeReturnContent,
115
+ pluginsToRun,
116
+ };
117
+ }
118
+ /**
119
+ * Creates workers or parses files and extracts metadata in-process.
120
+ */
121
+ #getBatchWorker(numWorkers) {
122
+ if (numWorkers <= 1) {
123
+ // In-band worker with the same interface as a Jest worker farm
124
+ return {
125
+ processFile: async (message) => this.#inBandWorker.processFile(message),
126
+ end: async () => { },
127
+ };
128
+ }
129
+ const workerPath = require.resolve('../worker');
130
+ debug('Creating worker farm of %d worker threads', numWorkers);
131
+ this.#perfLogger?.point('initWorkers_start');
132
+ const jestWorker = new jest_worker_1.Worker(workerPath, {
133
+ exposedMethods: ['processFile'],
134
+ maxRetries: 3,
135
+ numWorkers,
136
+ enableWorkerThreads: true,
137
+ forkOptions: {
138
+ // Don't pass Node arguments down to workers. In particular, avoid
139
+ // unnecessarily registering Babel when we're running Metro from
140
+ // source (our worker is plain CommonJS).
141
+ execArgv: [],
142
+ },
143
+ setupArgs: [
144
+ {
145
+ plugins: this.#pluginWorkers.map((plugin) => plugin.worker),
146
+ },
147
+ ],
148
+ });
149
+ this.#perfLogger?.point('initWorkers_end');
150
+ // Only log worker init once
151
+ this.#perfLogger = null;
152
+ return jestWorker;
153
+ }
154
+ async end() { }
155
+ }
156
+ exports.FileProcessor = FileProcessor;
157
+ function processWorkerReply(metadata, pluginsRun, fileMetadata) {
158
+ fileMetadata[constants_1.default.VISITED] = 1;
159
+ const pluginData = metadata.pluginData;
160
+ if (pluginData) {
161
+ for (const [i, pluginIdx] of pluginsRun.entries()) {
162
+ fileMetadata[constants_1.default.PLUGINDATA + pluginIdx] = pluginData[i];
163
+ }
164
+ }
165
+ if (metadata.sha1 != null) {
166
+ fileMetadata[constants_1.default.SHA1] = metadata.sha1;
167
+ }
168
+ return metadata.content;
169
+ }
170
+ function normalizeWorkerError(mixedError) {
171
+ if (mixedError == null ||
172
+ typeof mixedError !== 'object' ||
173
+ mixedError.message == null ||
174
+ mixedError.stack == null) {
175
+ const error = new Error(mixedError);
176
+ error.stack = ''; // Remove stack for stack-less errors.
177
+ return error;
178
+ }
179
+ return mixedError;
180
+ }
@@ -0,0 +1,18 @@
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
+ import type { CanonicalPath, FileMetadata, FileSystemListener, ReadonlyFileSystemChanges } from '../types';
8
+ export declare class FileSystemChangeAggregator implements FileSystemListener {
9
+ #private;
10
+ directoryAdded(canonicalPath: CanonicalPath): void;
11
+ directoryRemoved(canonicalPath: CanonicalPath): void;
12
+ fileAdded(canonicalPath: CanonicalPath, data: FileMetadata): void;
13
+ fileModified(canonicalPath: CanonicalPath, oldData: FileMetadata, newData: FileMetadata): void;
14
+ fileRemoved(canonicalPath: CanonicalPath, data: FileMetadata): void;
15
+ getSize(): number;
16
+ getView(): ReadonlyFileSystemChanges<FileMetadata>;
17
+ getMappedView<T>(metadataMapFn: (metadata: FileMetadata) => T): ReadonlyFileSystemChanges<T>;
18
+ }
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.FileSystemChangeAggregator = void 0;
10
+ class FileSystemChangeAggregator {
11
+ // Mutually exclusive with removedDirectories
12
+ #addedDirectories = new Set();
13
+ // Mutually exclusive with addedDirectories
14
+ #removedDirectories = new Set();
15
+ // Mutually exclusive with modified and removed files
16
+ #addedFiles = new Map();
17
+ // Mutually exclusive with added and removed files
18
+ #modifiedFiles = new Map();
19
+ // Mutually exclusive with added and modified files
20
+ #removedFiles = new Map();
21
+ // Removed files must be paired with the file's metadata the last time it was
22
+ // observable by consumers - ie, immediately *before* this batch. To report
23
+ // this accurately with minimal overhead, we'll note the current metadata of
24
+ // a file the first time it is modified or removed within a batch. If it is
25
+ // re-added, modified and removed again, we still have the initial metadata.
26
+ // This is particularly important if, say, a regular file is replaced by a
27
+ // symlink, or vice-versa.
28
+ #initialMetadata = new Map();
29
+ directoryAdded(canonicalPath) {
30
+ // Only add to newDirectories if this directory wasn't previously removed
31
+ // (i.e., it's truly new). If it was removed and re-added, the net effect
32
+ // is no directory change.
33
+ if (!this.#removedDirectories.delete(canonicalPath)) {
34
+ this.#addedDirectories.add(canonicalPath);
35
+ }
36
+ }
37
+ directoryRemoved(canonicalPath) {
38
+ if (!this.#addedDirectories.delete(canonicalPath)) {
39
+ this.#removedDirectories.add(canonicalPath);
40
+ }
41
+ }
42
+ fileAdded(canonicalPath, data) {
43
+ if (this.#removedFiles.delete(canonicalPath)) {
44
+ // File was removed then re-added in the same batch - treat as modification
45
+ this.#modifiedFiles.set(canonicalPath, data);
46
+ }
47
+ else {
48
+ // New file
49
+ this.#addedFiles.set(canonicalPath, data);
50
+ }
51
+ }
52
+ fileModified(canonicalPath, oldData, newData) {
53
+ if (this.#addedFiles.has(canonicalPath)) {
54
+ // File did not exist before this batch. Further modification only
55
+ // updates metadata
56
+ this.#addedFiles.set(canonicalPath, newData);
57
+ }
58
+ else {
59
+ if (!this.#initialMetadata.has(canonicalPath)) {
60
+ this.#initialMetadata.set(canonicalPath, oldData);
61
+ }
62
+ this.#modifiedFiles.set(canonicalPath, newData);
63
+ }
64
+ }
65
+ fileRemoved(canonicalPath, data) {
66
+ // Check if this file was added in the same batch
67
+ if (!this.#addedFiles.delete(canonicalPath)) {
68
+ let initialData = this.#initialMetadata.get(canonicalPath);
69
+ if (!initialData) {
70
+ initialData = data;
71
+ this.#initialMetadata.set(canonicalPath, initialData);
72
+ }
73
+ // File was not added in this batch, so add to removed with last metadata
74
+ this.#modifiedFiles.delete(canonicalPath);
75
+ this.#removedFiles.set(canonicalPath, initialData);
76
+ }
77
+ // else: File was added then removed in the same batch - no net change
78
+ }
79
+ getSize() {
80
+ return (this.#addedDirectories.size +
81
+ this.#removedDirectories.size +
82
+ this.#addedFiles.size +
83
+ this.#modifiedFiles.size +
84
+ this.#removedFiles.size);
85
+ }
86
+ getView() {
87
+ return {
88
+ addedDirectories: this.#addedDirectories,
89
+ removedDirectories: this.#removedDirectories,
90
+ addedFiles: this.#addedFiles,
91
+ modifiedFiles: this.#modifiedFiles,
92
+ removedFiles: this.#removedFiles,
93
+ };
94
+ }
95
+ getMappedView(metadataMapFn) {
96
+ return {
97
+ addedDirectories: this.#addedDirectories,
98
+ removedDirectories: this.#removedDirectories,
99
+ addedFiles: mapIterable(this.#addedFiles, metadataMapFn),
100
+ modifiedFiles: mapIterable(this.#modifiedFiles, metadataMapFn),
101
+ removedFiles: mapIterable(this.#removedFiles, metadataMapFn),
102
+ };
103
+ }
104
+ }
105
+ exports.FileSystemChangeAggregator = FileSystemChangeAggregator;
106
+ function mapIterable(map, metadataMapFn) {
107
+ return {
108
+ *[Symbol.iterator]() {
109
+ for (const [path, metadata] of map) {
110
+ yield [path, metadataMapFn(metadata)];
111
+ }
112
+ },
113
+ };
114
+ }
@@ -0,0 +1,24 @@
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
+ export declare class RootPathUtils {
8
+ #private;
9
+ constructor(rootDir: string);
10
+ getBasenameOfNthAncestor(n: number): string;
11
+ getParts(): readonly string[];
12
+ absoluteToNormal(absolutePath: string): string;
13
+ normalToAbsolute(normalPath: string): string;
14
+ relativeToNormal(relativePath: string): string;
15
+ resolveSymlinkToNormal(symlinkNormalPath: string, readlinkResult: string): string;
16
+ getAncestorOfRootIdx(normalPath: string): number | null;
17
+ joinNormalToRelative(normalPath: string, relativePath: string): {
18
+ normalPath: string;
19
+ collapsedSegments: number;
20
+ };
21
+ relative(from: string, to: string): string;
22
+ }
23
+ export declare function getAncestorOfRootIdx(normalPath: string): number;
24
+ export declare function pathsToPattern(paths: readonly string[], pathUtils: RootPathUtils): RegExp | null;