-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
/
defaultResolver.ts
126 lines (110 loc) · 3.19 KB
/
defaultResolver.ts
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
126
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {resolve} from 'path';
import pnpResolver from 'jest-pnp-resolver';
import {sync as resolveSync} from 'resolve';
import {
Options as ResolveExportsOptions,
resolve as resolveExports,
} from 'resolve.exports';
import type {Config} from '@jest/types';
import {
PkgJson,
isDirectory,
isFile,
readPackageCached,
realpathSync,
} from './fileWalkers';
// copy from `resolve`'s types so we don't have their types in our definition
// files
interface ResolverOptions {
basedir: Config.Path;
browser?: boolean;
conditions?: Array<string>;
defaultResolver: typeof defaultResolver;
extensions?: Array<string>;
moduleDirectory?: Array<string>;
paths?: Array<Config.Path>;
rootDir?: Config.Path;
packageFilter?: (pkg: PkgJson, dir: string) => PkgJson;
pathFilter?: (pkg: PkgJson, path: string, relativePath: string) => string;
}
// https://github.com/facebook/jest/pull/10617
declare global {
namespace NodeJS {
export interface ProcessVersions {
pnp?: any;
}
}
}
export default function defaultResolver(
path: Config.Path,
options: ResolverOptions,
): Config.Path {
// Yarn 2 adds support to `resolve` automatically so the pnpResolver is only
// needed for Yarn 1 which implements version 1 of the pnp spec
if (process.versions.pnp === '1') {
return pnpResolver(path, options);
}
const result = resolveSync(path, {
...options,
isDirectory,
isFile,
packageFilter: createPackageFilter(
options.conditions,
options.packageFilter,
),
preserveSymlinks: false,
readPackageSync,
realpathSync,
});
// Dereference symlinks to ensure we don't create a separate
// module instance depending on how it was referenced.
return realpathSync(result);
}
/*
* helper functions
*/
function readPackageSync(_: unknown, file: Config.Path): PkgJson {
return readPackageCached(file);
}
function createPackageFilter(
conditions?: Array<string>,
userFilter?: ResolverOptions['packageFilter'],
): ResolverOptions['packageFilter'] {
function attemptExportsFallback(pkg: PkgJson) {
const options: ResolveExportsOptions = conditions
? {conditions, unsafe: true}
: // no conditions were passed - let's assume this is Jest internal and it should be `require`
{browser: false, require: true};
try {
return resolveExports(pkg, '.', options);
} catch {
return undefined;
}
}
return function packageFilter(pkg, packageDir) {
let filteredPkg = pkg;
if (userFilter) {
filteredPkg = userFilter(filteredPkg, packageDir);
}
if (filteredPkg.main != null) {
return filteredPkg;
}
const indexInRoot = resolve(packageDir, './index.js');
// if the module contains an `index.js` file in root, `resolve` will request
// that if there is no `main`. Since we don't wanna break that, add this
// check
if (isFile(indexInRoot)) {
return filteredPkg;
}
return {
...filteredPkg,
main: attemptExportsFallback(filteredPkg),
};
};
}