Skip to content

Commit 9fc9bf0

Browse files
robhoganfacebook-github-bot
authored andcommitted
Resolution: Replace context.unstable_getRealPath with context.unstable_fileSystemLookup
Summary: Replace `unstable_getRealPath`, which was introduced to bring symlink support to the resolver, with the more powerful `unstable_fileSystemLookup`. We're going to need API(s) that can - Check existence of a file or directory - Get the real path, to allow resolvers to return real paths. This API aims to roll everything into one to reduce multiple lookups as much as possible. (I plan to deprecate `context.fileExists` for that reason, because currently using it in practice necessitates a second lookup to determine the real path for a correct resolution.) This mirrors some previous underlying implementation changes in D52255863 and D52390401 and brings the context API more in line, without exposing more than necessary. As with D52255863, we use `{exists: false}` rather than a `null` return to allow for extended information in a non-breaking change in future - in particular whether the lookup goes outside a watched folder. Changelog: Internal Reviewed By: huntie Differential Revision: D59003947 fbshipit-source-id: 02db458be7701fb8c5fd5feac8eff109ebc6bf1a
1 parent 349ac23 commit 9fc9bf0

File tree

10 files changed

+90
-30
lines changed

10 files changed

+90
-30
lines changed

packages/metro-file-map/types/flow-types.d.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ export interface FileSystem {
162162
getAllFiles(): Path[];
163163
getDependencies(file: Path): string[] | null;
164164
getModuleName(file: Path): string | null;
165-
getRealPath(file: Path): string | null;
166165
getSerializableSnapshot(): FileData;
167166
getSha1(file: Path): string | null;
168167

@@ -208,6 +207,12 @@ export interface FileSystem {
208207
*/
209208
linkStats(file: Path): FileStats | null;
210209

210+
/**
211+
* Return information about the given path, whether a directory or file.
212+
* Always follow symlinks, and return a real path if it exists.
213+
*/
214+
lookup(mixedPath: Path): LookupResult;
215+
211216
matchFiles(opts: {
212217
/* Filter relative paths against a pattern. */
213218
filter?: RegExp | null;
@@ -226,6 +231,29 @@ export interface FileSystem {
226231

227232
export type Glob = string;
228233

234+
export type LookupResult =
235+
| {
236+
// The node is missing from the FileSystem implementation (note this
237+
// could indicate an unwatched path, or a directory containing no watched
238+
// files).
239+
exists: false;
240+
// The real, normal, absolute paths of any symlinks traversed.
241+
links: ReadonlySet<string>;
242+
// The real, normal, absolute path of the first path segment
243+
// encountered that does not exist, or cannot be navigated through.
244+
missing: string;
245+
}
246+
| {
247+
exists: true;
248+
// The real, normal, absolute paths of any symlinks traversed.
249+
links: ReadonlySet<string>;
250+
// The real, normal, absolute path of the file or directory.
251+
realPath: string;
252+
// Currently lookup always follows symlinks, so can only return
253+
// directories or regular files, but this may be extended.
254+
type: 'd' | 'f';
255+
};
256+
229257
export interface HasteMap {
230258
getModule(
231259
name: string,

packages/metro-resolver/src/PackageExportsResolve.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ export function resolvePackageTargetFromExports(
105105
}
106106
}
107107

108-
if (context.unstable_getRealPath != null) {
109-
const maybeRealPath = context.unstable_getRealPath(filePath);
110-
if (maybeRealPath != null) {
108+
if (context.unstable_fileSystemLookup != null) {
109+
const lookupResult = context.unstable_fileSystemLookup(filePath);
110+
if (lookupResult.exists && lookupResult.type === 'f') {
111111
return {
112112
type: 'sourceFile',
113-
filePath: maybeRealPath,
113+
filePath: lookupResult.realPath,
114114
};
115115
}
116116
} else if (context.doesFileExist(filePath)) {

packages/metro-resolver/src/__tests__/package-exports-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('with package exports resolution disabled', () => {
3434
}),
3535
originModulePath: '/root/src/main.js',
3636
unstable_enablePackageExports: false,
37-
unstable_getRealPath: null,
37+
unstable_fileSystemLookup: null,
3838
};
3939

4040
expect(Resolver.resolve(context, 'test-pkg', null)).toEqual({

packages/metro-resolver/src/__tests__/utils.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,20 @@ export function createResolutionContext(
5656
web: ['browser'],
5757
},
5858
unstable_enablePackageExports: false,
59-
unstable_getRealPath: filePath =>
60-
typeof fileMap[filePath] === 'string'
61-
? filePath
62-
: fileMap[filePath]?.realPath,
59+
unstable_fileSystemLookup: filePath => {
60+
const candidate = fileMap[filePath];
61+
if (typeof candidate === 'string') {
62+
return {exists: true, type: 'f', realPath: filePath};
63+
}
64+
if (candidate == null || candidate.realPath == null) {
65+
return {exists: false};
66+
}
67+
return {
68+
exists: true,
69+
type: 'f',
70+
realPath: candidate.realPath,
71+
};
72+
},
6373
unstable_logWarning: () => {},
6474
...createPackageAccessors(fileMap),
6575
};

packages/metro-resolver/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export type {
2020
FileAndDirCandidates,
2121
FileCandidates,
2222
FileResolution,
23-
GetRealPath,
23+
FileSystemLookup,
2424
ResolutionContext,
2525
Resolution,
2626
ResolveAsset,

packages/metro-resolver/src/resolve.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -500,10 +500,10 @@ function resolveSourceFileForExt(
500500
if (redirectedPath === false) {
501501
return {type: 'empty'};
502502
}
503-
if (context.unstable_getRealPath) {
504-
const maybeRealPath = context.unstable_getRealPath(redirectedPath);
505-
if (maybeRealPath != null) {
506-
return maybeRealPath;
503+
if (context.unstable_fileSystemLookup) {
504+
const lookupResult = context.unstable_fileSystemLookup(redirectedPath);
505+
if (lookupResult.exists && lookupResult.type === 'f') {
506+
return lookupResult.realPath;
507507
}
508508
} else if (context.doesFileExist(redirectedPath)) {
509509
return redirectedPath;

packages/metro-resolver/src/types.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,15 @@ export type PackageForModule = $ReadOnly<{
9797
* Check existence of a single file.
9898
*/
9999
export type DoesFileExist = (filePath: string) => boolean;
100-
export type GetRealPath = (path: string) => ?string;
100+
101+
/**
102+
* Performs a lookup against an absolute or project-relative path to determine
103+
* whether it exists as a file or directory. Follows any symlinks, and returns
104+
* a real absolute path on existence.
105+
*/
106+
export type FileSystemLookup = (
107+
absoluteOrProjectRelativePath: string,
108+
) => {exists: false} | {exists: true, type: 'f' | 'd', realPath: string};
101109

102110
/**
103111
* Given a directory path and the base asset name, return a list of all the
@@ -181,7 +189,7 @@ export type ResolutionContext = $ReadOnly<{
181189
[platform: string]: $ReadOnlyArray<string>,
182190
}>,
183191
unstable_enablePackageExports: boolean,
184-
unstable_getRealPath?: ?GetRealPath,
192+
unstable_fileSystemLookup?: ?FileSystemLookup,
185193
unstable_logWarning: (message: string) => void,
186194
}>;
187195

packages/metro-resolver/types/types.d.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,15 @@ export interface PackageForModule extends PackageInfo {
7474
* Check existence of a single file.
7575
*/
7676
export type DoesFileExist = (filePath: string) => boolean;
77-
export type GetRealPath = (path: string) => string | null;
7877
export type IsAssetFile = (fileName: string) => boolean;
78+
/**
79+
* Performs a lookup against an absolute or project-relative path to determine
80+
* whether it exists as a file or directory. Follows any symlinks, and returns
81+
* a real absolute path on existence.
82+
*/
83+
export type FileSystemLookup = (
84+
absoluteOrProjectRelativePath: string,
85+
) => {exists: false} | {exists: true; type: 'f' | 'd'; realPath: string};
7986

8087
/**
8188
* Given a directory path and the base asset name, return a list of all the
@@ -158,7 +165,7 @@ export interface ResolutionContext {
158165
[platform: string]: ReadonlyArray<string>;
159166
}>;
160167
unstable_enablePackageExports: boolean;
161-
unstable_getRealPath?: GetRealPath | null;
168+
unstable_fileSystemLookup?: FileSystemLookup | null;
162169
unstable_logWarning: (message: string) => void;
163170
}
164171

packages/metro/src/node-haste/DependencyGraph.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,16 @@ class DependencyGraph extends EventEmitter {
160160
}
161161

162162
_createModuleResolver() {
163-
const getRealPathIfFile = (path: string) => {
163+
const fileSystemLookup = (path: string) => {
164164
const result = this._fileSystem.lookup(path);
165-
return result.exists && result.type === 'f' ? result.realPath : null;
165+
if (result.exists) {
166+
return {
167+
exists: true,
168+
realPath: result.realPath,
169+
type: result.type,
170+
};
171+
}
172+
return {exists: false};
166173
};
167174

168175
this._moduleResolver = new ModuleResolver({
@@ -190,14 +197,14 @@ class DependencyGraph extends EventEmitter {
190197
reporter: this._config.reporter,
191198
resolveAsset: (dirPath: string, assetName: string, extension: string) => {
192199
const basePath = dirPath + path.sep + assetName;
193-
let assets = [
200+
const assets = [
194201
basePath + extension,
195202
...this._config.resolver.assetResolutions.map(
196203
resolution => basePath + '@' + resolution + 'x' + extension,
197204
),
198-
];
199-
200-
assets = assets.map(getRealPathIfFile).filter(Boolean);
205+
]
206+
.map(assetPath => fileSystemLookup(assetPath).realPath)
207+
.filter(Boolean);
201208

202209
return assets.length ? assets : null;
203210
},
@@ -208,7 +215,7 @@ class DependencyGraph extends EventEmitter {
208215
this._config.resolver.unstable_conditionsByPlatform,
209216
unstable_enablePackageExports:
210217
this._config.resolver.unstable_enablePackageExports,
211-
unstable_getRealPath: getRealPathIfFile,
218+
unstable_fileSystemLookup: fileSystemLookup,
212219
});
213220
}
214221

packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type {
2121
CustomResolver,
2222
DoesFileExist,
2323
FileCandidates,
24-
GetRealPath,
24+
FileSystemLookup,
2525
Resolution,
2626
ResolveAsset,
2727
} from 'metro-resolver';
@@ -82,7 +82,7 @@ type Options<TPackage> = $ReadOnly<{
8282
[platform: string]: $ReadOnlyArray<string>,
8383
}>,
8484
unstable_enablePackageExports: boolean,
85-
unstable_getRealPath: ?GetRealPath,
85+
unstable_fileSystemLookup: ?FileSystemLookup,
8686
}>;
8787

8888
class ModuleResolver<TPackage: Packageish> {
@@ -151,7 +151,7 @@ class ModuleResolver<TPackage: Packageish> {
151151
unstable_conditionNames,
152152
unstable_conditionsByPlatform,
153153
unstable_enablePackageExports,
154-
unstable_getRealPath,
154+
unstable_fileSystemLookup,
155155
} = this._options;
156156

157157
try {
@@ -173,7 +173,7 @@ class ModuleResolver<TPackage: Packageish> {
173173
unstable_conditionNames,
174174
unstable_conditionsByPlatform,
175175
unstable_enablePackageExports,
176-
unstable_getRealPath,
176+
unstable_fileSystemLookup,
177177
unstable_logWarning: this._logWarning,
178178
customResolverOptions: resolverOptions.customResolverOptions ?? {},
179179
originModulePath: fromModule.path,

0 commit comments

Comments
 (0)