Skip to content

Commit 1385905

Browse files
committed
check export map before calling resolve
1 parent 915bb50 commit 1385905

File tree

1 file changed

+65
-35
lines changed

1 file changed

+65
-35
lines changed

Diff for: packages/jest-resolve/src/defaultResolver.ts

+65-35
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import {isAbsolute} from 'path';
8+
import {dirname, isAbsolute, resolve as pathResolve} from 'path';
99
import pnpResolver from 'jest-pnp-resolver';
1010
import {sync as resolveSync} from 'resolve';
1111
import {
1212
Options as ResolveExportsOptions,
1313
resolve as resolveExports,
1414
} from 'resolve.exports';
15-
import slash = require('slash');
1615
import {
1716
PkgJson,
1817
isDirectory,
@@ -45,6 +44,62 @@ declare global {
4544
}
4645
}
4746

47+
function getPathInModule(path: string, options: ResolverOptions): string {
48+
if (isAbsolute(path) || path.startsWith('.')) {
49+
return path;
50+
}
51+
52+
const segments = path.split('/');
53+
54+
let moduleName = segments.shift();
55+
56+
if (moduleName) {
57+
// TODO: handle `#` here: https://github.com/facebook/jest/issues/12270
58+
if (moduleName.startsWith('@')) {
59+
moduleName = `${moduleName}/${segments.shift()}`;
60+
}
61+
62+
let packageJsonPath = '';
63+
64+
try {
65+
packageJsonPath = resolveSync(`${moduleName}/package.json`, {
66+
...options,
67+
isDirectory,
68+
isFile,
69+
preserveSymlinks: false,
70+
readPackageSync,
71+
realpathSync,
72+
});
73+
} catch {
74+
// ignore if package.json cannot be found
75+
}
76+
77+
if (packageJsonPath && isFile(packageJsonPath)) {
78+
const pkg = readPackageCached(packageJsonPath);
79+
80+
if (pkg.exports) {
81+
// we need to make sure resolve ignores `main`
82+
delete pkg.main;
83+
84+
const subpath = segments.join('/') || '.';
85+
86+
const resolved = resolveExports(
87+
pkg,
88+
subpath,
89+
createResolveOptions(options.conditions),
90+
);
91+
92+
// TODO: should we throw if not?
93+
if (resolved) {
94+
return pathResolve(dirname(packageJsonPath), resolved);
95+
}
96+
}
97+
}
98+
}
99+
100+
return path;
101+
}
102+
48103
export default function defaultResolver(
49104
path: string,
50105
options: ResolverOptions,
@@ -55,12 +110,13 @@ export default function defaultResolver(
55110
return pnpResolver(path, options);
56111
}
57112

58-
const result = resolveSync(path, {
113+
const pathToResolve = getPathInModule(path, options);
114+
115+
const result = resolveSync(pathToResolve, {
59116
...options,
60117
isDirectory,
61118
isFile,
62-
packageFilter: createPackageFilter(path, options.packageFilter),
63-
pathFilter: createPathFilter(path, options.conditions, options.pathFilter),
119+
packageFilter: createPackageFilter(pathToResolve, options.packageFilter),
64120
preserveSymlinks: false,
65121
readPackageSync,
66122
realpathSync,
@@ -107,39 +163,13 @@ function createPackageFilter(
107163
};
108164
}
109165

110-
function createPathFilter(
111-
originalPath: string,
112-
conditions?: Array<string>,
113-
userFilter?: ResolverOptions['pathFilter'],
114-
): ResolverOptions['pathFilter'] {
115-
if (shouldIgnoreRequestForExports(originalPath)) {
116-
return userFilter;
117-
}
118-
119-
const options: ResolveExportsOptions = conditions
166+
function createResolveOptions(
167+
conditions: Array<string> | undefined,
168+
): ResolveExportsOptions {
169+
return conditions
120170
? {conditions, unsafe: true}
121171
: // no conditions were passed - let's assume this is Jest internal and it should be `require`
122172
{browser: false, require: true};
123-
124-
return function pathFilter(pkg, path, relativePath, ...rest) {
125-
let pathToUse = relativePath;
126-
127-
if (userFilter) {
128-
pathToUse = userFilter(pkg, path, relativePath, ...rest);
129-
}
130-
131-
if (pkg.exports == null) {
132-
return pathToUse;
133-
}
134-
135-
// this `index` thing can backfire, but `resolve` adds it: https://github.com/browserify/resolve/blob/f1b51848ecb7f56f77bfb823511d032489a13eab/lib/sync.js#L192
136-
const isRootRequire =
137-
pathToUse === 'index' && !originalPath.endsWith('/index');
138-
139-
const newPath = isRootRequire ? '.' : slash(pathToUse);
140-
141-
return resolveExports(pkg, newPath, options) || pathToUse;
142-
};
143173
}
144174

145175
// if it's a relative import or an absolute path, exports are ignored

0 commit comments

Comments
 (0)