/
utils.js
125 lines (112 loc) 路 3.58 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {ResolutionContext} from '../index';
import type {PackageJson} from '../types';
import path from 'path';
/**
* Data structure approximating a file tree. Should be populated with complete
* paths mapping to file contents.
*/
type MockFileMap = $ReadOnly<{
[path: string]: ?(string | $ReadOnly<{realPath: ?string}>),
}>;
/**
* Create a new partial `ResolutionContext` object given a mock file structure.
* Includes defaults closely matching metro-config, which can be overridden by
* consuming tests.
*/
export function createResolutionContext(
fileMap: MockFileMap,
{enableSymlinks}: $ReadOnly<{enableSymlinks?: boolean}> = {},
): $Diff<ResolutionContext, {originModulePath: string}> {
return {
allowHaste: true,
customResolverOptions: {},
disableHierarchicalLookup: false,
extraNodeModules: null,
isAssetFile: () => false,
mainFields: ['browser', 'main'],
nodeModulesPaths: [],
preferNativePlatform: false,
redirectModulePath: (filePath: string) => filePath,
resolveAsset: (filePath: string) => null,
resolveHasteModule: (name: string) => null,
resolveHastePackage: (name: string) => null,
sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx'],
unstable_conditionNames: ['import', 'require'],
unstable_conditionsByPlatform: {
web: ['browser'],
},
unstable_enablePackageExports: false,
unstable_logWarning: () => {},
...createPackageAccessors(fileMap),
...(enableSymlinks === true
? {
doesFileExist: (filePath: string) =>
// Should return false unless realpath(filePath) exists. We mock shallow
// dereferencing.
fileMap[filePath] != null &&
(typeof fileMap[filePath] === 'string' ||
typeof fileMap[filePath].realPath === 'string'),
unstable_getRealPath: filePath =>
typeof fileMap[filePath] === 'string'
? filePath
: fileMap[filePath]?.realPath,
}
: {
doesFileExist: (filePath: string) =>
typeof fileMap[filePath] === 'string',
unstable_getRealPath: null,
}),
};
}
/**
* Create `getPackage` and `getPackageForModule` accessor properties on
* `ResolutionContext` based on the input mock file/package.json map.
*/
export function createPackageAccessors(
fileOrPackageJsonMap: MockFileMap | {[path: string]: PackageJson},
): $ReadOnly<{
getPackage: ResolutionContext['getPackage'],
getPackageForModule: ResolutionContext['getPackageForModule'],
}> {
const getPackage = (packageJsonPath: string) => {
const contents = fileOrPackageJsonMap[packageJsonPath];
if (typeof contents === 'string') {
return JSON.parse(contents);
}
if (contents != null) {
return contents;
}
return null;
};
const getPackageForModule = (modulePath: string) => {
const parsedPath = path.parse(modulePath);
const root = parsedPath.root;
let dir = path.join(parsedPath.dir, parsedPath.name);
do {
const candidate = path.join(dir, 'package.json');
const packageJson = getPackage(candidate);
if (packageJson != null) {
return {
rootPath: dir,
packageJson,
};
}
dir = path.dirname(dir);
} while (dir !== '.' && dir !== root);
return null;
};
return {
getPackage,
getPackageForModule,
};
}