Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(resolve): use resolve.exports for imports #13777

Merged
merged 4 commits into from Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -6,7 +6,7 @@
- `[jest-config, jest-worker]` Use `os.availableParallelism` if available to calculate number of workers to spawn ([#13738](https://github.com/facebook/jest/pull/13738))
- `[@jest/globals, jest-mock]` Add `jest.replaceProperty()` that replaces property value ([#13496](https://github.com/facebook/jest/pull/13496))
- `[jest-haste-map]` ignore Sapling vcs directories (`.sl/`) ([#13674](https://github.com/facebook/jest/pull/13674))
- `[jest-resolve]` Support subpath imports ([#13705](https://github.com/facebook/jest/pull/13705), [#13723](https://github.com/facebook/jest/pull/13723))
- `[jest-resolve]` Support subpath imports ([#13705](https://github.com/facebook/jest/pull/13705), [#13723](https://github.com/facebook/jest/pull/13723)), [#13777](https://github.com/facebook/jest/pull/13777))
- `[jest-runtime]` Add `jest.isolateModulesAsync` for scoped module initialization of asynchronous functions ([#13680](https://github.com/facebook/jest/pull/13680))
- `[jest-runtime]` Add `jest.isEnvironmentTornDown` function ([#13698](https://github.com/facebook/jest/pull/13698))
- `[jest-test-result]` Added `skipped` and `focused` status to `FormattedTestResult` ([#13700](https://github.com/facebook/jest/pull/13700))
Expand Down
3 changes: 1 addition & 2 deletions packages/jest-resolve/package.json
Expand Up @@ -24,8 +24,7 @@
"jest-util": "workspace:^",
"jest-validate": "workspace:^",
"resolve": "^1.20.0",
"resolve.exports": "^1.1.1",
"resolve.imports": "^2.0.3",
"resolve.exports": "^2.0.0",
"slash": "^3.0.0"
},
"devDependencies": {
Expand Down
9 changes: 1 addition & 8 deletions packages/jest-resolve/src/__tests__/resolve.test.ts
Expand Up @@ -397,14 +397,7 @@ describe('findNodeModule', () => {
basedir: path.resolve(importsRoot, './foo-import/index.js'),
conditions: [],
});
}).toThrow(
expect.objectContaining({
code: 'ERR_PACKAGE_IMPORT_NOT_DEFINED',
message: expect.stringMatching(
/^Package import specifier "#something-else" is not defined in package/,
),
}),
);
}).toThrow('Missing "#something-else" specifier in "foo-import" package');
});
});
});
Expand Down
88 changes: 36 additions & 52 deletions packages/jest-resolve/src/defaultResolver.ts
Expand Up @@ -8,11 +8,7 @@
import {dirname, isAbsolute, resolve as pathResolve} from 'path';
import pnpResolver from 'jest-pnp-resolver';
import {SyncOpts as UpstreamResolveOptions, sync as resolveSync} from 'resolve';
import {
Options as ResolveExportsOptions,
resolve as resolveExports,
} from 'resolve.exports';
import {resolve as resolveImports} from 'resolve.imports';
import * as resolve from 'resolve.exports';
import {
findClosestPackageJson,
isDirectory,
Expand Down Expand Up @@ -148,28 +144,26 @@ function getPathInModule(

const pkg = readPackageCached(closestPackageJson);

const resolved = resolveImports(
{
base: options.basedir,
content: pkg,
path: dirname(closestPackageJson),
},
path,
createImportsResolveOptions(options.conditions),
const resolved = resolve.imports(
pkg,
path as resolve.Imports.Entry,
createResolveOptions(options.conditions),
);

if (!resolved) {
if (resolved) {
const target = resolved[0];
return target.startsWith('.')
? // internal relative filepath
pathResolve(dirname(closestPackageJson), target)
: // this is an external module, re-resolve it
defaultResolver(target, options);
}

if (pkg.imports) {
throw new Error(
'`imports` exists, but no results - this is a bug in Jest. Please report an issue',
);
}

if (resolved.startsWith('.')) {
return pathResolve(dirname(closestPackageJson), resolved);
}

// this is an external module, re-resolve it
return defaultResolver(resolved, options);
}

const segments = path.split('/');
Expand All @@ -186,22 +180,22 @@ function getPathInModule(
if (closestPackageJson) {
const pkg = readPackageCached(closestPackageJson);

if (pkg.name === moduleName && pkg.exports) {
const subpath = segments.join('/') || '.';

const resolved = resolveExports(
if (pkg.name === moduleName) {
const resolved = resolve.exports(
pkg,
subpath,
(segments.join('/') || '.') as resolve.Exports.Entry,
createResolveOptions(options.conditions),
);

if (!resolved) {
if (resolved) {
return pathResolve(dirname(closestPackageJson), resolved[0]);
}

if (pkg.exports) {
throw new Error(
'`exports` exists, but no results - this is a bug in Jest. Please report an issue',
);
}

return pathResolve(dirname(closestPackageJson), resolved);
}
}

Expand All @@ -216,22 +210,20 @@ function getPathInModule(
if (packageJsonPath && isFile(packageJsonPath)) {
const pkg = readPackageCached(packageJsonPath);

if (pkg.exports) {
const subpath = segments.join('/') || '.';

const resolved = resolveExports(
pkg,
subpath,
createResolveOptions(options.conditions),
);
const resolved = resolve.exports(
pkg,
(segments.join('/') || '.') as resolve.Exports.Entry,
createResolveOptions(options.conditions),
);

if (!resolved) {
throw new Error(
'`exports` exists, but no results - this is a bug in Jest. Please report an issue',
);
}
if (resolved) {
return pathResolve(dirname(packageJsonPath), resolved[0]);
}

return pathResolve(dirname(packageJsonPath), resolved);
if (pkg.exports) {
throw new Error(
'`exports` exists, but no results - this is a bug in Jest. Please report an issue',
);
}
}
}
Expand All @@ -241,21 +233,13 @@ function getPathInModule(

function createResolveOptions(
conditions: Array<string> | undefined,
): ResolveExportsOptions {
): resolve.Options {
return conditions
? {conditions, unsafe: true}
: // no conditions were passed - let's assume this is Jest internal and it should be `require`
{browser: false, require: true};
}

function createImportsResolveOptions(conditions: Array<string> | undefined) {
return {
conditions: conditions
? [...conditions, 'default']
: ['node', 'require', 'default'],
};
}

// if it's a relative import or an absolute path, imports/exports are ignored
const shouldIgnoreRequestForExports = (path: string) =>
path.startsWith('.') || isAbsolute(path);
27 changes: 5 additions & 22 deletions yarn.lock
Expand Up @@ -12895,8 +12895,7 @@ __metadata:
jest-util: "workspace:^"
jest-validate: "workspace:^"
resolve: ^1.20.0
resolve.exports: ^1.1.1
resolve.imports: ^2.0.3
resolve.exports: ^2.0.0
slash: ^3.0.0
tsd-lite: ^0.6.0
languageName: unknown
Expand Down Expand Up @@ -16415,13 +16414,6 @@ __metadata:
languageName: node
linkType: hard

"pattern-key-compare@npm:^2.0.0":
version: 2.0.0
resolution: "pattern-key-compare@npm:2.0.0"
checksum: cded15070cddbc5ef7b97c1b91371bcf59ff931f8afe383d2323f935891e6c4517bd76154f5edc2b1ab53c6fbeeb0711b9db43af592064482d0a9ccf03dd507c
languageName: node
linkType: hard

"pend@npm:~1.2.0":
version: 1.2.0
resolution: "pend@npm:1.2.0"
Expand Down Expand Up @@ -18359,19 +18351,10 @@ __metadata:
languageName: node
linkType: hard

"resolve.exports@npm:^1.1.1":
version: 1.1.1
resolution: "resolve.exports@npm:1.1.1"
checksum: 485aa10082eb388a569d696e17ad7b16f4186efc97dd34eadd029d95b811f21ffee13b1b733198bb4584dbb3cb296aa6f141835221fb7613b9606b84f1386655
languageName: node
linkType: hard

"resolve.imports@npm:^2.0.3":
version: 2.0.3
resolution: "resolve.imports@npm:2.0.3"
dependencies:
pattern-key-compare: ^2.0.0
checksum: 155ae4a32ccc1da7ad12b88f6c748dd1e038092838e537de1066248c32a197b42489810da6070bb2bd0dd954e8abbe841b09282c0806c5493b2e49e8f7e29632
"resolve.exports@npm:^2.0.0":
version: 2.0.0
resolution: "resolve.exports@npm:2.0.0"
checksum: d8bee3b0cc0a0ae6c8323710983505bc6a3a2574f718e96f01e048a0f0af035941434b386cc9efc7eededc5e1199726185c306ec6f6a1aa55d5fbad926fd0634
languageName: node
linkType: hard

Expand Down