metro-file-map 0.76.0 → 0.76.2
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 +2 -3
- package/src/ModuleMap.d.ts +33 -0
- package/src/Watcher.d.ts +24 -0
- package/src/Watcher.js +2 -0
- package/src/Watcher.js.flow +5 -0
- package/src/cache/DiskCacheManager.d.ts +37 -0
- package/src/crawlers/node/index.js +9 -1
- package/src/crawlers/node/index.js.flow +12 -1
- package/src/crawlers/watchman/index.js +5 -2
- package/src/crawlers/watchman/index.js.flow +7 -3
- package/src/flow-types.d.ts +272 -0
- package/src/flow-types.js.flow +1 -0
- package/src/index.d.ts +94 -0
- package/src/index.js +16 -20
- package/src/index.js.flow +23 -20
- package/src/lib/DuplicateHasteCandidatesError.d.ts +24 -0
- package/src/lib/TreeFS.js +170 -111
- package/src/lib/TreeFS.js.flow +170 -98
- package/src/HasteFS.js +0 -220
- package/src/HasteFS.js.flow +0 -216
package/src/lib/TreeFS.js.flow
CHANGED
|
@@ -26,6 +26,13 @@ type FileNode = FileMetaData;
|
|
|
26
26
|
type LinkNode = string;
|
|
27
27
|
type AnyNode = FileNode | DirectoryNode | LinkNode;
|
|
28
28
|
|
|
29
|
+
// Terminology:
|
|
30
|
+
//
|
|
31
|
+
// mixedPath - a root-relative or absolute path
|
|
32
|
+
// relativePath - a root-relative path
|
|
33
|
+
// normalPath - a root-relative, normalised path (no extraneous '.' or '..')
|
|
34
|
+
// canonicalPath - a root-relative, normalised, real path (no symlinks in dirname)
|
|
35
|
+
|
|
29
36
|
export default class TreeFS implements MutableFileSystem {
|
|
30
37
|
+#rootDir: Path;
|
|
31
38
|
+#files: FileData;
|
|
@@ -46,18 +53,18 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
46
53
|
);
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
getModuleName(
|
|
50
|
-
const fileMetadata = this._getFileData(
|
|
56
|
+
getModuleName(mixedPath: Path): ?string {
|
|
57
|
+
const fileMetadata = this._getFileData(mixedPath);
|
|
51
58
|
return (fileMetadata && fileMetadata[H.ID]) ?? null;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
getSize(
|
|
55
|
-
const fileMetadata = this._getFileData(
|
|
61
|
+
getSize(mixedPath: Path): ?number {
|
|
62
|
+
const fileMetadata = this._getFileData(mixedPath);
|
|
56
63
|
return (fileMetadata && fileMetadata[H.SIZE]) ?? null;
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
getDependencies(
|
|
60
|
-
const fileMetadata = this._getFileData(
|
|
66
|
+
getDependencies(mixedPath: Path): ?Array<string> {
|
|
67
|
+
const fileMetadata = this._getFileData(mixedPath);
|
|
61
68
|
|
|
62
69
|
if (fileMetadata) {
|
|
63
70
|
return fileMetadata[H.DEPENDENCIES]
|
|
@@ -68,13 +75,13 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
|
|
71
|
-
getSha1(
|
|
72
|
-
const fileMetadata = this._getFileData(
|
|
78
|
+
getSha1(mixedPath: Path): ?string {
|
|
79
|
+
const fileMetadata = this._getFileData(mixedPath);
|
|
73
80
|
return (fileMetadata && fileMetadata[H.SHA1]) ?? null;
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
exists(
|
|
77
|
-
const result = this._getFileData(
|
|
83
|
+
exists(mixedPath: Path): boolean {
|
|
84
|
+
const result = this._getFileData(mixedPath);
|
|
78
85
|
return result != null;
|
|
79
86
|
}
|
|
80
87
|
|
|
@@ -84,8 +91,8 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
84
91
|
);
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
linkStats(
|
|
88
|
-
const fileMetadata = this._getFileData(
|
|
94
|
+
linkStats(mixedPath: Path): ?FileStats {
|
|
95
|
+
const fileMetadata = this._getFileData(mixedPath, {followLeaf: false});
|
|
89
96
|
if (fileMetadata == null) {
|
|
90
97
|
return null;
|
|
91
98
|
}
|
|
@@ -133,7 +140,7 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
133
140
|
if (!contextRootResult) {
|
|
134
141
|
return [];
|
|
135
142
|
}
|
|
136
|
-
const {
|
|
143
|
+
const {canonicalPath: rootRealPath, node: contextRoot} = contextRootResult;
|
|
137
144
|
if (!(contextRoot instanceof Map)) {
|
|
138
145
|
return [];
|
|
139
146
|
}
|
|
@@ -171,30 +178,72 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
171
178
|
return files;
|
|
172
179
|
}
|
|
173
180
|
|
|
174
|
-
getRealPath(
|
|
175
|
-
const normalPath = this._normalizePath(
|
|
181
|
+
getRealPath(mixedPath: Path): ?string {
|
|
182
|
+
const normalPath = this._normalizePath(mixedPath);
|
|
176
183
|
const metadata = this.#files.get(normalPath);
|
|
177
184
|
if (metadata && metadata[H.SYMLINK] === 0) {
|
|
178
185
|
return fastPath.resolve(this.#rootDir, normalPath);
|
|
179
186
|
}
|
|
180
|
-
const result = this._lookupByNormalPath(normalPath, {
|
|
187
|
+
const result = this._lookupByNormalPath(normalPath, {followLeaf: true});
|
|
181
188
|
if (!result || result.node instanceof Map) {
|
|
182
189
|
return null;
|
|
183
190
|
}
|
|
184
|
-
return fastPath.resolve(this.#rootDir, result.
|
|
191
|
+
return fastPath.resolve(this.#rootDir, result.canonicalPath);
|
|
185
192
|
}
|
|
186
193
|
|
|
187
|
-
addOrModify(
|
|
188
|
-
const normalPath = this._normalizePath(
|
|
189
|
-
|
|
194
|
+
addOrModify(mixedPath: Path, metadata: FileMetaData): void {
|
|
195
|
+
const normalPath = this._normalizePath(mixedPath);
|
|
196
|
+
// Walk the tree to find the *real* path of the parent node, creating
|
|
197
|
+
// directories as we need.
|
|
198
|
+
const parentDirNode = this._lookupByNormalPath(path.dirname(normalPath), {
|
|
199
|
+
makeDirectories: true,
|
|
200
|
+
});
|
|
201
|
+
if (!parentDirNode) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`TreeFS: Failed to make parent directory entry for ${mixedPath}`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
// Normalize the resulting path to account for the parent node being root.
|
|
207
|
+
const canonicalPath = this._normalizePath(
|
|
208
|
+
parentDirNode.canonicalPath + path.sep + path.basename(normalPath),
|
|
209
|
+
);
|
|
210
|
+
this.bulkAddOrModify(new Map([[canonicalPath, metadata]]));
|
|
190
211
|
}
|
|
191
212
|
|
|
192
213
|
bulkAddOrModify(addedOrModifiedFiles: FileData): void {
|
|
214
|
+
const files = this.#files;
|
|
215
|
+
|
|
216
|
+
// Optimisation: Bulk FileData are typically clustered by directory, so we
|
|
217
|
+
// optimise for that case by remembering the last directory we looked up.
|
|
218
|
+
// Experiments with large result sets show this to be significantly (~30%)
|
|
219
|
+
// faster than caching all lookups in a Map, and 70% faster than no cache.
|
|
220
|
+
let lastDir: ?string;
|
|
221
|
+
let directoryNode: DirectoryNode;
|
|
222
|
+
|
|
193
223
|
for (const [normalPath, metadata] of addedOrModifiedFiles) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
224
|
+
if (addedOrModifiedFiles !== files) {
|
|
225
|
+
files.set(normalPath, metadata);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const lastSepIdx = normalPath.lastIndexOf(path.sep);
|
|
229
|
+
const dirname = lastSepIdx === -1 ? '' : normalPath.slice(0, lastSepIdx);
|
|
230
|
+
const basename =
|
|
231
|
+
lastSepIdx === -1 ? normalPath : normalPath.slice(lastSepIdx + 1);
|
|
232
|
+
|
|
233
|
+
if (directoryNode == null || dirname !== lastDir) {
|
|
234
|
+
const lookup = this._lookupByNormalPath(dirname, {
|
|
235
|
+
followLeaf: false,
|
|
236
|
+
makeDirectories: true,
|
|
237
|
+
});
|
|
238
|
+
if (!(lookup?.node instanceof Map)) {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`TreeFS: Could not add directory ${dirname} when adding files`,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
lastDir = dirname;
|
|
244
|
+
directoryNode = lookup.node;
|
|
245
|
+
}
|
|
246
|
+
|
|
198
247
|
if (metadata[H.SYMLINK] !== 0) {
|
|
199
248
|
const symlinkTarget = metadata[H.SYMLINK];
|
|
200
249
|
invariant(
|
|
@@ -219,73 +268,116 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
219
268
|
}
|
|
220
269
|
}
|
|
221
270
|
|
|
222
|
-
remove(
|
|
223
|
-
const normalPath = this._normalizePath(
|
|
224
|
-
const
|
|
225
|
-
if (
|
|
271
|
+
remove(mixedPath: Path): ?FileMetaData {
|
|
272
|
+
const normalPath = this._normalizePath(mixedPath);
|
|
273
|
+
const result = this._lookupByNormalPath(normalPath, {followLeaf: false});
|
|
274
|
+
if (!result || result.node instanceof Map) {
|
|
226
275
|
return null;
|
|
227
276
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
277
|
+
const {parentNode, canonicalPath, node} = result;
|
|
278
|
+
|
|
279
|
+
// If node is a symlink, get its metadata from the file map. Otherwise, we
|
|
280
|
+
// already have it in the lookup result.
|
|
281
|
+
const fileMetadata =
|
|
282
|
+
typeof node === 'string' ? this.#files.get(canonicalPath) : node;
|
|
283
|
+
if (fileMetadata == null) {
|
|
284
|
+
throw new Error(`TreeFS: Missing metadata for ${mixedPath}`);
|
|
285
|
+
}
|
|
286
|
+
if (parentNode == null) {
|
|
287
|
+
throw new Error(`TreeFS: Missing parent node for ${mixedPath}`);
|
|
288
|
+
}
|
|
289
|
+
this.#files.delete(canonicalPath);
|
|
290
|
+
parentNode.delete(path.basename(canonicalPath));
|
|
233
291
|
return fileMetadata;
|
|
234
292
|
}
|
|
235
293
|
|
|
236
294
|
_lookupByNormalPath(
|
|
237
|
-
|
|
295
|
+
requestedNormalPath: string,
|
|
238
296
|
opts: {
|
|
239
297
|
// Like lstat vs stat, whether to follow a symlink at the basename of
|
|
240
298
|
// the given path, or return the details of the symlink itself.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
): ?
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
let
|
|
252
|
-
|
|
253
|
-
|
|
299
|
+
followLeaf?: boolean,
|
|
300
|
+
makeDirectories?: boolean,
|
|
301
|
+
} = {followLeaf: true, makeDirectories: false},
|
|
302
|
+
): ?(
|
|
303
|
+
| {canonicalPath: string, node: AnyNode, parentNode: DirectoryNode}
|
|
304
|
+
| {canonicalPath: string, node: DirectoryNode, parentNode: null}
|
|
305
|
+
) {
|
|
306
|
+
// We'll update the target if we hit a symlink.
|
|
307
|
+
let targetNormalPath = requestedNormalPath;
|
|
308
|
+
// Lazy-initialised set of seen target paths, to detect symlink cycles.
|
|
309
|
+
let seen: ?Set<string>;
|
|
310
|
+
// Pointer to the first character of the current path segment in
|
|
311
|
+
// targetNormalPath.
|
|
312
|
+
let fromIdx = 0;
|
|
313
|
+
// The parent of the current segment
|
|
314
|
+
let parentNode = this.#rootNode;
|
|
315
|
+
|
|
316
|
+
while (targetNormalPath.length > fromIdx) {
|
|
317
|
+
const nextSepIdx = targetNormalPath.indexOf(path.sep, fromIdx);
|
|
318
|
+
const isLastSegment = nextSepIdx === -1;
|
|
319
|
+
const segmentName = isLastSegment
|
|
320
|
+
? targetNormalPath.slice(fromIdx)
|
|
321
|
+
: targetNormalPath.slice(fromIdx, nextSepIdx);
|
|
322
|
+
fromIdx = !isLastSegment ? nextSepIdx + 1 : targetNormalPath.length;
|
|
323
|
+
|
|
324
|
+
if (segmentName === '.') {
|
|
254
325
|
continue;
|
|
255
326
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
327
|
+
|
|
328
|
+
let segmentNode = parentNode.get(segmentName);
|
|
329
|
+
if (segmentNode == null) {
|
|
330
|
+
if (opts.makeDirectories !== true) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
segmentNode = new Map();
|
|
334
|
+
parentNode.set(segmentName, segmentNode);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// If there are no more '/' to come, we're done unless this is a symlink
|
|
338
|
+
// we must follow.
|
|
339
|
+
if (
|
|
340
|
+
isLastSegment &&
|
|
341
|
+
(typeof segmentNode !== 'string' || opts.followLeaf === false)
|
|
342
|
+
) {
|
|
343
|
+
return {
|
|
344
|
+
canonicalPath: targetNormalPath,
|
|
345
|
+
node: segmentNode,
|
|
346
|
+
parentNode,
|
|
347
|
+
};
|
|
259
348
|
}
|
|
260
|
-
|
|
349
|
+
|
|
350
|
+
// If the next node is a directory, go into it
|
|
351
|
+
if (segmentNode instanceof Map) {
|
|
352
|
+
parentNode = segmentNode;
|
|
353
|
+
} else if (Array.isArray(segmentNode)) {
|
|
261
354
|
// Regular file in a directory path
|
|
262
355
|
return null;
|
|
263
|
-
} else if (typeof
|
|
264
|
-
|
|
356
|
+
} else if (typeof segmentNode === 'string') {
|
|
357
|
+
// segmentNode is a normalised symlink target. Append any subsequent
|
|
358
|
+
// path segments to the symlink target, and reset with our new target.
|
|
359
|
+
targetNormalPath = isLastSegment
|
|
360
|
+
? segmentNode
|
|
361
|
+
: segmentNode + path.sep + targetNormalPath.slice(fromIdx);
|
|
362
|
+
if (seen == null) {
|
|
363
|
+
// Optimisation: set this lazily only when we've encountered a symlink
|
|
364
|
+
seen = new Set([requestedNormalPath]);
|
|
365
|
+
}
|
|
366
|
+
if (seen.has(targetNormalPath)) {
|
|
265
367
|
// TODO: Warn `Symlink cycle detected: ${[...seen, node].join(' -> ')}`
|
|
266
368
|
return null;
|
|
267
369
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
seen,
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
node = nextNode;
|
|
275
|
-
}
|
|
276
|
-
const basenameNode = node.get(basename);
|
|
277
|
-
if (typeof basenameNode === 'string') {
|
|
278
|
-
// basenameNode is a symlink target
|
|
279
|
-
if (!opts.follow) {
|
|
280
|
-
return {normalPath: relativePath, node: basenameNode};
|
|
281
|
-
}
|
|
282
|
-
if (seen.has(basenameNode)) {
|
|
283
|
-
// TODO: Warn `Symlink cycle detected: ${[...seen, target].join(' -> ')}`
|
|
284
|
-
return null;
|
|
370
|
+
seen.add(targetNormalPath);
|
|
371
|
+
fromIdx = 0;
|
|
372
|
+
parentNode = this.#rootNode;
|
|
285
373
|
}
|
|
286
|
-
return this._lookupByNormalPath(basenameNode, opts, seen);
|
|
287
374
|
}
|
|
288
|
-
|
|
375
|
+
invariant(parentNode === this.#rootNode, 'Unexpectedly escaped traversal');
|
|
376
|
+
return {
|
|
377
|
+
canonicalPath: targetNormalPath,
|
|
378
|
+
node: this.#rootNode,
|
|
379
|
+
parentNode: null,
|
|
380
|
+
};
|
|
289
381
|
}
|
|
290
382
|
|
|
291
383
|
_normalizePath(relativeOrAbsolutePath: Path): string {
|
|
@@ -366,39 +458,19 @@ export default class TreeFS implements MutableFileSystem {
|
|
|
366
458
|
|
|
367
459
|
_getFileData(
|
|
368
460
|
filePath: Path,
|
|
369
|
-
opts: {
|
|
461
|
+
opts: {followLeaf: boolean} = {followLeaf: true},
|
|
370
462
|
): ?FileMetaData {
|
|
371
463
|
const normalPath = this._normalizePath(filePath);
|
|
372
464
|
const metadata = this.#files.get(normalPath);
|
|
373
|
-
if (metadata && (!opts.
|
|
465
|
+
if (metadata && (!opts.followLeaf || metadata[H.SYMLINK] === 0)) {
|
|
374
466
|
return metadata;
|
|
375
467
|
}
|
|
376
|
-
const result = this._lookupByNormalPath(normalPath,
|
|
468
|
+
const result = this._lookupByNormalPath(normalPath, {
|
|
469
|
+
followLeaf: opts.followLeaf,
|
|
470
|
+
});
|
|
377
471
|
if (!result || result.node instanceof Map) {
|
|
378
472
|
return null;
|
|
379
473
|
}
|
|
380
|
-
return this.#files.get(result.
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
_mkdirp(directoryParts: $ReadOnlyArray<string>): DirectoryNode {
|
|
384
|
-
let node = this.#rootNode;
|
|
385
|
-
for (const directoryPart of directoryParts) {
|
|
386
|
-
if (directoryPart === '.') {
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
let nextNode = node.get(directoryPart);
|
|
390
|
-
if (nextNode == null) {
|
|
391
|
-
nextNode = new Map();
|
|
392
|
-
node.set(directoryPart, nextNode);
|
|
393
|
-
}
|
|
394
|
-
invariant(
|
|
395
|
-
nextNode instanceof Map,
|
|
396
|
-
'%s in %s is a file, directory expected',
|
|
397
|
-
directoryPart,
|
|
398
|
-
directoryParts,
|
|
399
|
-
);
|
|
400
|
-
node = nextNode;
|
|
401
|
-
}
|
|
402
|
-
return node;
|
|
474
|
+
return this.#files.get(result.canonicalPath);
|
|
403
475
|
}
|
|
404
476
|
}
|
package/src/HasteFS.js
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true,
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var _constants = _interopRequireDefault(require("./constants"));
|
|
8
|
-
var fastPath = _interopRequireWildcard(require("./lib/fast_path"));
|
|
9
|
-
var _invariant = _interopRequireDefault(require("invariant"));
|
|
10
|
-
var path = _interopRequireWildcard(require("path"));
|
|
11
|
-
var _jestUtil = require("jest-util");
|
|
12
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
13
|
-
if (typeof WeakMap !== "function") return null;
|
|
14
|
-
var cacheBabelInterop = new WeakMap();
|
|
15
|
-
var cacheNodeInterop = new WeakMap();
|
|
16
|
-
return (_getRequireWildcardCache = function (nodeInterop) {
|
|
17
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
18
|
-
})(nodeInterop);
|
|
19
|
-
}
|
|
20
|
-
function _interopRequireWildcard(obj, nodeInterop) {
|
|
21
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
22
|
-
return obj;
|
|
23
|
-
}
|
|
24
|
-
if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
|
|
25
|
-
return { default: obj };
|
|
26
|
-
}
|
|
27
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
28
|
-
if (cache && cache.has(obj)) {
|
|
29
|
-
return cache.get(obj);
|
|
30
|
-
}
|
|
31
|
-
var newObj = {};
|
|
32
|
-
var hasPropertyDescriptor =
|
|
33
|
-
Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
34
|
-
for (var key in obj) {
|
|
35
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
36
|
-
var desc = hasPropertyDescriptor
|
|
37
|
-
? Object.getOwnPropertyDescriptor(obj, key)
|
|
38
|
-
: null;
|
|
39
|
-
if (desc && (desc.get || desc.set)) {
|
|
40
|
-
Object.defineProperty(newObj, key, desc);
|
|
41
|
-
} else {
|
|
42
|
-
newObj[key] = obj[key];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
newObj.default = obj;
|
|
47
|
-
if (cache) {
|
|
48
|
-
cache.set(obj, newObj);
|
|
49
|
-
}
|
|
50
|
-
return newObj;
|
|
51
|
-
}
|
|
52
|
-
function _interopRequireDefault(obj) {
|
|
53
|
-
return obj && obj.__esModule ? obj : { default: obj };
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
57
|
-
*
|
|
58
|
-
* This source code is licensed under the MIT license found in the
|
|
59
|
-
* LICENSE file in the root directory of this source tree.
|
|
60
|
-
*
|
|
61
|
-
* @format
|
|
62
|
-
*
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
class HasteFS {
|
|
66
|
-
#rootDir;
|
|
67
|
-
#files;
|
|
68
|
-
constructor({ rootDir, files }) {
|
|
69
|
-
this.#rootDir = rootDir;
|
|
70
|
-
this.#files = files;
|
|
71
|
-
}
|
|
72
|
-
_normalizePath(relativeOrAbsolutePath) {
|
|
73
|
-
return path.isAbsolute(relativeOrAbsolutePath)
|
|
74
|
-
? fastPath.relative(this.#rootDir, relativeOrAbsolutePath)
|
|
75
|
-
: path.normalize(relativeOrAbsolutePath);
|
|
76
|
-
}
|
|
77
|
-
remove(filePath) {
|
|
78
|
-
const normalPath = this._normalizePath(filePath);
|
|
79
|
-
const fileMetadata = this.#files.get(normalPath);
|
|
80
|
-
if (!fileMetadata) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
this.#files.delete(normalPath);
|
|
84
|
-
return fileMetadata;
|
|
85
|
-
}
|
|
86
|
-
bulkAddOrModify(changedFiles) {
|
|
87
|
-
for (const [relativePath, metadata] of changedFiles) {
|
|
88
|
-
this.#files.set(relativePath, metadata);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
addOrModify(filePath, metadata) {
|
|
92
|
-
this.#files.set(this._normalizePath(filePath), metadata);
|
|
93
|
-
}
|
|
94
|
-
getSerializableSnapshot() {
|
|
95
|
-
return new Map(Array.from(this.#files.entries(), ([k, v]) => [k, [...v]]));
|
|
96
|
-
}
|
|
97
|
-
getModuleName(file) {
|
|
98
|
-
const fileMetadata = this._getFileData(file);
|
|
99
|
-
return (fileMetadata && fileMetadata[_constants.default.ID]) ?? null;
|
|
100
|
-
}
|
|
101
|
-
getSize(file) {
|
|
102
|
-
const fileMetadata = this._getFileData(file);
|
|
103
|
-
return (fileMetadata && fileMetadata[_constants.default.SIZE]) ?? null;
|
|
104
|
-
}
|
|
105
|
-
getDependencies(file) {
|
|
106
|
-
const fileMetadata = this._getFileData(file);
|
|
107
|
-
if (fileMetadata) {
|
|
108
|
-
return fileMetadata[_constants.default.DEPENDENCIES]
|
|
109
|
-
? fileMetadata[_constants.default.DEPENDENCIES].split(
|
|
110
|
-
_constants.default.DEPENDENCY_DELIM
|
|
111
|
-
)
|
|
112
|
-
: [];
|
|
113
|
-
} else {
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
getSha1(file) {
|
|
118
|
-
const fileMetadata = this._getFileData(file);
|
|
119
|
-
return (fileMetadata && fileMetadata[_constants.default.SHA1]) ?? null;
|
|
120
|
-
}
|
|
121
|
-
exists(file) {
|
|
122
|
-
return this._getFileData(file) != null;
|
|
123
|
-
}
|
|
124
|
-
getAllFiles() {
|
|
125
|
-
return Array.from(this.getAbsoluteFileIterator());
|
|
126
|
-
}
|
|
127
|
-
getFileIterator() {
|
|
128
|
-
return this.#files.keys();
|
|
129
|
-
}
|
|
130
|
-
*getAbsoluteFileIterator() {
|
|
131
|
-
for (const file of this.getFileIterator()) {
|
|
132
|
-
yield fastPath.resolve(this.#rootDir, file);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
linkStats(file) {
|
|
136
|
-
const fileMetadata = this._getFileData(file);
|
|
137
|
-
if (fileMetadata == null) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
const fileType = fileMetadata[_constants.default.SYMLINK] === 0 ? "f" : "l";
|
|
141
|
-
const modifiedTime = fileMetadata[_constants.default.MTIME];
|
|
142
|
-
(0, _invariant.default)(
|
|
143
|
-
typeof modifiedTime === "number",
|
|
144
|
-
"File in HasteFS missing modified time"
|
|
145
|
-
);
|
|
146
|
-
return {
|
|
147
|
-
fileType,
|
|
148
|
-
modifiedTime,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
matchFiles(pattern) {
|
|
152
|
-
const regexpPattern =
|
|
153
|
-
pattern instanceof RegExp ? pattern : new RegExp(pattern);
|
|
154
|
-
const files = [];
|
|
155
|
-
for (const file of this.getAbsoluteFileIterator()) {
|
|
156
|
-
if (regexpPattern.test(file)) {
|
|
157
|
-
files.push(file);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return files;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Given a search context, return a list of file paths matching the query.
|
|
165
|
-
* The query matches against normalized paths which start with `./`,
|
|
166
|
-
* for example: `a/b.js` -> `./a/b.js`
|
|
167
|
-
*/
|
|
168
|
-
matchFilesWithContext(root, context) {
|
|
169
|
-
const files = [];
|
|
170
|
-
const prefix = "./";
|
|
171
|
-
for (const file of this.getAbsoluteFileIterator()) {
|
|
172
|
-
const filePath = fastPath.relative(root, file);
|
|
173
|
-
const isUnderRoot = filePath && !filePath.startsWith("..");
|
|
174
|
-
// Ignore everything outside of the provided `root`.
|
|
175
|
-
if (!isUnderRoot) {
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Prevent searching in child directories during a non-recursive search.
|
|
180
|
-
if (!context.recursive && filePath.includes(path.sep)) {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
if (
|
|
184
|
-
context.filter.test(
|
|
185
|
-
// NOTE(EvanBacon): Ensure files start with `./` for matching purposes
|
|
186
|
-
// this ensures packages work across Metro and Webpack (ex: Storybook for React DOM / React Native).
|
|
187
|
-
// `a/b.js` -> `./a/b.js`
|
|
188
|
-
prefix + filePath.replace(/\\/g, "/")
|
|
189
|
-
)
|
|
190
|
-
) {
|
|
191
|
-
files.push(file);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return files;
|
|
195
|
-
}
|
|
196
|
-
matchFilesWithGlob(globs, root) {
|
|
197
|
-
const files = new Set();
|
|
198
|
-
const matcher = (0, _jestUtil.globsToMatcher)(globs);
|
|
199
|
-
for (const file of this.getAbsoluteFileIterator()) {
|
|
200
|
-
const filePath = root != null ? fastPath.relative(root, file) : file;
|
|
201
|
-
if (matcher((0, _jestUtil.replacePathSepForGlob)(filePath))) {
|
|
202
|
-
files.add(file);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return files;
|
|
206
|
-
}
|
|
207
|
-
_getFileData(filePath) {
|
|
208
|
-
// Shortcut to avoid any file path parsing if the given path is already
|
|
209
|
-
// normalised.
|
|
210
|
-
const optimisticMetadata = this.#files.get(filePath);
|
|
211
|
-
if (optimisticMetadata) {
|
|
212
|
-
return optimisticMetadata;
|
|
213
|
-
}
|
|
214
|
-
return this.#files.get(this._normalizePath(filePath));
|
|
215
|
-
}
|
|
216
|
-
getRealPath(filePath) {
|
|
217
|
-
throw new Error("HasteFS.getRealPath() is not implemented.");
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
exports.default = HasteFS;
|