Son CV dans un terminal web en Javascript! https://terminal-cv.gregandev.fr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2436 lines
73 KiB

// @flow strict-local
import NodeResolver from '../src/NodeResolver';
import path from 'path';
import assert from 'assert';
import nullthrows from 'nullthrows';
import {ncp, overlayFS, outputFS} from '@parcel/test-utils';
import {loadConfig as configCache} from '@parcel/utils';
import {createEnvironment} from '@parcel/core/src/Environment';
import Environment from '@parcel/core/src/public/Environment';
import {DEFAULT_OPTIONS} from '@parcel/core/test/test-utils';
const rootDir = path.join(__dirname, 'fixture');
const NODE_ENV = new Environment(
createEnvironment({
context: 'node',
includeNodeModules: false,
}),
DEFAULT_OPTIONS,
);
const NODE_INCLUDE_ENV = new Environment(
createEnvironment({
context: 'node',
includeNodeModules: true,
}),
DEFAULT_OPTIONS,
);
const BROWSER_ENV = new Environment(
createEnvironment({
context: 'browser',
includeNodeModules: true,
}),
DEFAULT_OPTIONS,
);
describe('resolver', function () {
let resolver;
beforeEach(async function () {
await overlayFS.mkdirp(rootDir);
await ncp(rootDir, rootDir);
// Create the symlinks here to prevent cross platform and git issues
await outputFS.symlink(
path.join(rootDir, 'packages/source'),
path.join(rootDir, 'node_modules/source'),
);
await outputFS.symlink(
path.join(rootDir, 'packages/source-alias'),
path.join(rootDir, 'node_modules/source-alias'),
);
await outputFS.symlink(
path.join(rootDir, 'packages/source-alias-glob'),
path.join(rootDir, 'node_modules/source-alias-glob'),
);
await outputFS.symlink(
path.join(rootDir, 'bar.js'),
path.join(rootDir, 'baz.js'),
);
await outputFS.symlink(
path.join(rootDir, 'nested'),
path.join(rootDir, 'symlinked-nested'),
);
resolver = new NodeResolver({
fs: overlayFS,
projectRoot: rootDir,
mainFields: ['browser', 'source', 'module', 'main'],
extensions: ['.js', '.json'],
});
configCache.clear();
});
describe('file paths', function () {
it('should resolve a relative path with an extension', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './bar.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve a relative path without an extension', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './bar',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve an absolute path from the root module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'nested', 'test.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve an absolute path from a node_modules folder', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'node_modules', 'foo', 'index.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve a tilde path from the root module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '~/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'nested', 'test.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve a tilde path from the root module without a slash', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '~bar',
specifierType: 'esm',
parent: path.join(rootDir, 'nested', 'test.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve a tilde path from a node_modules folder', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '~/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'node_modules', 'foo', 'nested', 'baz.js'),
});
assert.equal(
nullthrows(resolved).filePath,
path.join(rootDir, 'node_modules', 'foo', 'bar.js'),
);
});
it('should resolve an index file in a directory', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './nested',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(resolved).filePath,
path.join(rootDir, 'nested', 'index.js'),
);
});
it('should not resolve an index file in a directory for URL specifiers', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './nested',
specifierType: 'url',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(nullthrows(resolved).diagnostics, [
{message: "Cannot load file './nested' in './'.", hints: []},
]);
});
it('should resolve a file with a question mark with CommonJS specifiers', async function () {
// Windows filenames cannot contain question marks.
if (process.platform === 'win32') {
return;
}
await overlayFS.writeFile(path.join(rootDir, 'a?b.js'), '');
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './a?b.js',
specifierType: 'commonjs',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'a?b.js'));
});
it('should not resolve a file with a question mark with ESM specifiers', async function () {
// Windows filenames cannot contain question marks.
if (process.platform === 'win32') {
return;
}
await overlayFS.writeFile(path.join(rootDir, 'a?b.js'), '');
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './a?b.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(nullthrows(resolved).diagnostics, [
{message: "Cannot load file './a' in './'.", hints: []},
]);
});
it('should resolve a file with an encoded question mark with ESM specifiers', async function () {
// Windows filenames cannot contain question marks.
if (process.platform === 'win32') {
return;
}
await overlayFS.writeFile(path.join(rootDir, 'a?b.js'), '');
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './a%3Fb.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'a?b.js'));
});
it('should not support percent encoding in CommonJS specifiers', async function () {
// Windows filenames cannot contain question marks.
if (process.platform === 'win32') {
return;
}
await overlayFS.writeFile(path.join(rootDir, 'a?b.js'), '');
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './a%3Fb.js',
specifierType: 'commonjs',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(nullthrows(resolved).diagnostics, [
{
message: "Cannot load file './a%3Fb.js' in './'.",
hints: ["Did you mean '__./a?b.js__'?"],
},
]);
});
it('should support query params for ESM specifiers', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './nested?foo=bar',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(resolved).filePath,
path.join(rootDir, 'nested', 'index.js'),
);
assert.deepEqual(nullthrows(resolved).query?.toString(), 'foo=bar');
});
it('should not support query params for CommonJS specifiers', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './nested?foo=bar',
specifierType: 'commonjs',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(nullthrows(resolved).diagnostics, [
{message: "Cannot load file './nested?foo=bar' in './'.", hints: []},
]);
});
});
describe('builtins', function () {
it('should resolve node builtin modules', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'zlib',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: require.resolve('browserify-zlib'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/browserify-zlib',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
require.resolve('browserify-zlib/package.json'),
],
});
});
it('Should be able to handle node: prefixes', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'node:zlib',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: require.resolve('browserify-zlib'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/browserify-zlib',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
require.resolve('browserify-zlib/package.json'),
],
});
});
it('should resolve unimplemented node builtin modules to an empty file', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'fs',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(__dirname, '..', 'src', '_empty.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(__dirname, '..', 'src', '_empty.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(__dirname, '..', 'package.json'),
],
});
});
it('should error when resolving node builtin modules with --target=node', async function () {
let resolved = await resolver.resolve({
env: NODE_ENV,
filename: 'zlib',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {isExcluded: true});
});
it('should exclude the electron module in electron environments', async function () {
let resolved = await resolver.resolve({
env: new Environment(
createEnvironment({
context: 'electron-main',
isLibrary: true,
}),
DEFAULT_OPTIONS,
),
filename: 'electron',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
sourcePath: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {isExcluded: true});
});
});
describe('node_modules', function () {
it('should resolve a node_modules index.js', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'foo',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'foo', 'index.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/foo',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'foo', 'package.json'),
],
});
});
it('should resolve a node_modules package.main', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-main',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'package-main', 'main.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-main',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-main', 'package.json'),
],
});
});
it('should resolve a node_modules package.module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-module',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-module',
'module.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-module',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-module', 'package.json'),
],
});
});
it('should resolve a node_modules package.browser main field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-browser',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser',
'browser.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-browser',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-browser', 'package.json'),
],
});
});
it('should not resolve a node_modules package.browser main field with --target=node', async function () {
let resolved = await resolver.resolve({
env: NODE_INCLUDE_ENV,
filename: 'package-browser',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser',
'main.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-browser',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-browser', 'package.json'),
],
});
});
it('should fall back to index.js when it cannot find package.main', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-fallback',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-fallback',
'index.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-fallback',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-fallback',
'main.js',
),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-fallback',
'main.js.js',
),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-fallback',
'main.js.json',
),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-fallback',
'main.js/package.json',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-fallback',
'package.json',
),
],
});
});
it('should resolve a node_module package.main pointing to a directory', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-main-directory',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-main-directory',
'nested',
'index.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-main-directory',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-main-directory',
'nested.js',
),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-main-directory',
'nested.json',
),
},
{
filePath: path.join(
rootDir,
'node_modules',
'package-main-directory',
'nested',
'package.json',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-main-directory',
'package.json',
),
],
});
});
it('should resolve a file inside a node_modules folder', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'foo/nested/baz',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'foo', 'nested', 'baz.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/foo',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'foo', 'package.json'),
],
});
});
it('should resolve a scoped module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '@scope/pkg',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.resolve(rootDir, 'node_modules/@scope/pkg/index.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/@scope/pkg',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', '@scope', 'pkg', 'package.json'),
],
});
});
it('should resolve a file inside a scoped module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '@scope/pkg/foo/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.resolve(rootDir, 'node_modules/@scope/pkg/foo/bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/@scope/pkg',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', '@scope', 'pkg', 'package.json'),
],
});
});
describe('sideEffects: false', function () {
it('should determine sideEffects correctly (file)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false/src/index.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false/src/index.js',
),
sideEffects: false,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/side-effects-false',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'side-effects-false',
'package.json',
),
],
});
});
it('should determine sideEffects correctly (extensionless file)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false/src/index',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false/src/index.js',
),
sideEffects: false,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/side-effects-false',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'side-effects-false',
'package.json',
),
],
});
});
it('should determine sideEffects correctly (sub folder)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false/src/',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false/src/index.js',
),
sideEffects: false,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/side-effects-false',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
filePath: path.join(
rootDir,
'node_modules',
'side-effects-false',
'src',
'package.json',
),
},
{
aboveFilePath: path.join(
rootDir,
'node_modules',
'side-effects-false',
'src',
'index',
),
fileName: 'package.json',
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'side-effects-false',
'package.json',
),
],
});
});
it('should determine sideEffects correctly (main field)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false/src/',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false/src/index.js',
),
sideEffects: false,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/side-effects-false',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
filePath: path.join(
rootDir,
'node_modules',
'side-effects-false',
'src',
'package.json',
),
},
{
aboveFilePath: path.join(
rootDir,
'node_modules',
'side-effects-false',
'src',
'index',
),
fileName: 'package.json',
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'side-effects-false',
'package.json',
),
],
});
});
});
describe('sideEffects: globs', function () {
it('should determine sideEffects correctly (matched)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false-glob/a/index',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(
{filePath: resolved?.filePath, sideEffects: resolved?.sideEffects},
{
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false-glob/a/index.js',
),
sideEffects: undefined,
},
);
});
it('should determine sideEffects correctly (unmatched)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false-glob/b/index.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(
{filePath: resolved?.filePath, sideEffects: resolved?.sideEffects},
{
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false-glob/b/index.js',
),
sideEffects: false,
},
);
});
it('should determine sideEffects correctly (matched dotslash)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false-glob/sub/index.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(
{filePath: resolved?.filePath, sideEffects: resolved?.sideEffects},
{
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false-glob/sub/index.js',
),
sideEffects: undefined,
},
);
});
it('should determine sideEffects correctly (unmatched, prefix in subdir)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false-glob/sub/a/index.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(
{filePath: resolved?.filePath, sideEffects: resolved?.sideEffects},
{
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false-glob/sub/a/index.js',
),
sideEffects: false,
},
);
});
it('should determine sideEffects correctly (only name)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'side-effects-false-glob/sub/index.json',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(
{filePath: resolved?.filePath, sideEffects: resolved?.sideEffects},
{
filePath: path.resolve(
rootDir,
'node_modules/side-effects-false-glob/sub/index.json',
),
sideEffects: undefined,
},
);
});
});
it('should not resolve a node module for URL dependencies', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '@scope/pkg',
specifierType: 'url',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(nullthrows(resolved).diagnostics, [
{message: "Cannot load file './@scope/pkg' in './'.", hints: []},
]);
});
it('should resolve a node module for URL dependencies with the npm: prefix', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'npm:@scope/pkg',
specifierType: 'url',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(
nullthrows(resolved).filePath,
path.join(rootDir, 'node_modules', '@scope', 'pkg', 'index.js'),
);
});
it('should support query params for bare ESM specifiers', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '@scope/pkg?foo=2',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(resolved).filePath,
path.resolve(rootDir, 'node_modules/@scope/pkg/index.js'),
);
assert.deepEqual(nullthrows(resolved).query?.toString(), 'foo=2');
});
it('should not support query params for bare CommonJS specifiers', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '@scope/pkg?foo=2',
specifierType: 'commonjs',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(nullthrows(resolved).diagnostics, [
{
message: 'Cannot find module @scope/pkg?foo=2',
hints: ["Did you mean '__@scope/pkg__'?"],
},
]);
});
it('should support query params for npm: specifiers', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'npm:@scope/pkg?foo=2',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(resolved).filePath,
path.resolve(rootDir, 'node_modules/@scope/pkg/index.js'),
);
assert.deepEqual(nullthrows(resolved).query?.toString(), 'foo=2');
});
});
describe('aliases', function () {
it('should alias the main file using the package.browser field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-browser-alias',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'browser.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-browser-alias',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-browser-alias',
'package.json',
),
],
});
});
it('should alias a sub-file using the package.browser field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-browser-alias/foo',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'bar.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-browser-alias',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-browser-alias',
'package.json',
),
],
});
});
it('should alias a relative file using the package.browser field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './foo',
specifierType: 'esm',
parent: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'browser.js',
),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'bar.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'browser.js',
),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'bar',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-browser-alias',
'package.json',
),
],
});
});
it('should not alias using the package.browser field with --target=node', async function () {
let resolved = await resolver.resolve({
env: NODE_INCLUDE_ENV,
filename: 'package-browser-alias/foo',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'foo.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-browser-alias',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-browser-alias',
'package.json',
),
],
});
});
it('should alias a deep nested relative file using the package.browser field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './nested',
specifierType: 'esm',
parent: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'browser.js',
),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'subfolder1/subfolder2/subfile.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'browser.js',
),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-browser-alias',
'nested',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-browser-alias',
'package.json',
),
],
});
});
it('should alias a sub-file using the package.alias field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-alias/foo',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'package-alias', 'bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-alias',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-alias', 'package.json'),
],
});
});
it('should alias a relative file using the package.alias field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './foo',
specifierType: 'esm',
parent: path.join(
rootDir,
'node_modules',
'package-alias',
'browser.js',
),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'package-alias', 'bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'browser.js',
),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'bar',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-alias', 'package.json'),
],
});
});
it('should alias a glob using the package.alias field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './lib/test',
specifierType: 'esm',
parent: path.join(
rootDir,
'node_modules',
'package-alias-glob',
'index.js',
),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'package-alias-glob',
'src',
'test.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias-glob',
'index.js',
),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias-glob',
'src',
'test',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-alias-glob',
'package.json',
),
],
});
});
it('should apply a module alias using the package.alias field in the root package', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliased',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'foo', 'index.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/foo',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'foo', 'package.json'),
],
});
});
it('should apply a global module alias using the package.alias field in the root package', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliased',
specifierType: 'esm',
parent: path.join(rootDir, 'node_modules', 'package-alias', 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'foo', 'index.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'foo.js',
),
},
{
fileName: 'node_modules/foo',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'foo.js',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-alias', 'package.json'),
path.join(rootDir, 'node_modules', 'foo', 'package.json'),
],
});
});
it('should apply a global module alias to a sub-file in a package', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliased/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'node_modules', 'package-alias', 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'node_modules', 'foo', 'bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'foo.js',
),
},
{
fileName: 'node_modules/foo',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'foo.js',
),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-alias', 'package.json'),
path.join(rootDir, 'node_modules', 'foo', 'package.json'),
],
});
});
it('should apply a module alias pointing to a file using the package.alias field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliased-file',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'bar.js'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply a global module alias pointing to a file using the package.alias field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliased-file',
specifierType: 'esm',
parent: path.join(rootDir, 'node_modules', 'package-alias', 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'foo.js',
),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'bar.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-alias', 'package.json'),
],
});
});
it('should apply an alias for a virtual module folder (relative to project dir)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliasedfolder/test.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'test.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested', 'test.js'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply an alias for a virtual module folder only (relative to project dir)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliasedfolder',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'index.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested'),
},
{
filePath: path.join(rootDir, 'nested.js'),
},
{
filePath: path.join(rootDir, 'nested.json'),
},
{
filePath: path.join(rootDir, 'nested', 'package.json'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply an alias for a virtual module folder (relative to root dir)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliasedabsolute/test.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'test.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested', 'test.js'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply an alias for a virtual module folder only (relative to root dir)', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'aliasedabsolute',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'index.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested'),
},
{
filePath: path.join(rootDir, 'nested.js'),
},
{
filePath: path.join(rootDir, 'nested.json'),
},
{
filePath: path.join(rootDir, 'nested', 'package.json'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply an alias for a virtual module folder sub-path', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'foo/bar',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'bar.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'bar.js'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply an alias for a virtual module folder glob sub-path', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'glob/bar/test',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'test.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested', 'test'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply an alias for a virtual module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'something',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'test.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested', 'test.js'),
},
],
invalidateOnFileChange: [path.join(rootDir, 'package.json')],
});
});
it('should apply a global alias for a virtual module', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'something',
specifierType: 'esm',
parent: path.join(rootDir, 'node_modules', 'package-alias', 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'nested', 'test.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(
rootDir,
'node_modules',
'package-alias',
'foo.js',
),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'nested', 'test.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'package-alias', 'package.json'),
],
});
});
it('should resolve to an empty file when package.browser resolves to false', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-browser-exclude',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(__dirname, '..', 'src', '_empty.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-browser-exclude',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-browser-exclude',
'package.json',
),
],
});
});
it('should resolve to an empty file when package.alias resolves to false', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-alias-exclude',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(__dirname, '..', 'src', '_empty.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/package-alias-exclude',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'package-alias-exclude',
'package.json',
),
],
});
});
});
describe('source field', function () {
it('should use the source field when symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'packages', 'source', 'source.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'source', 'package.json'),
],
});
});
it('should not use the source field when not symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-not-symlinked',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'source-not-symlinked',
'dist.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-not-symlinked',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'source-not-symlinked',
'package.json',
),
],
});
});
it('should use the source field as an alias when symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-alias/dist',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'packages', 'source-alias', 'source.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-alias',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'source-alias', 'package.json'),
],
});
});
it('should use the source field as a glob alias when symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-alias-glob',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'packages',
'source-alias-glob',
'src',
'test.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-alias-glob',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'source-alias-glob',
'package.json',
),
],
});
});
});
describe('symlinks', function () {
it('should resolve symlinked files to their realpath', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './baz.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(nullthrows(resolved).filePath, path.join(rootDir, 'bar.js'));
});
it('should resolve symlinked directories to their realpath', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: './symlinked-nested',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(resolved).filePath,
path.join(rootDir, 'nested', 'index.js'),
);
});
});
describe('error handling', function () {
it('should return diagnostics when package.module does not exist', async function () {
let result = await resolver.resolve({
env: BROWSER_ENV,
filename: 'package-module-fallback',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(nullthrows(result).diagnostics)[0].message,
`Could not load './module.js' from module 'package-module-fallback' found in package.json#module`,
);
});
it('should throw when a relative path cannot be resolved', async function () {
let result = await resolver.resolve({
env: BROWSER_ENV,
filename: './xyz.js',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.equal(
nullthrows(nullthrows(result).diagnostics)[0].message,
`Cannot load file './xyz.js' in './'.`,
);
});
it('should throw when a node_module cannot be resolved', async function () {
assert.strictEqual(
null,
await resolver.resolve({
env: BROWSER_ENV,
filename: 'xyz',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
}),
);
});
it('should throw when a subfile of a node_module cannot be resolved', async function () {
assert.strictEqual(
null,
await resolver.resolve({
env: BROWSER_ENV,
filename: 'xyz/test/file',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
}),
);
});
it('should error when a library is missing an external dependency', async function () {
let result = await resolver.resolve({
env: new Environment(
createEnvironment({
context: 'browser',
isLibrary: true,
includeNodeModules: false,
}),
DEFAULT_OPTIONS,
),
filename: 'test',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
sourcePath: path.join(rootDir, 'foo.js'),
});
assert.equal(
result?.diagnostics?.[0].message,
'External dependency "test" is not declared in package.json.',
);
});
it('should not error when external dependencies are declared', async function () {
let result = await resolver.resolve({
env: new Environment(
createEnvironment({
context: 'browser',
isLibrary: true,
includeNodeModules: false,
}),
DEFAULT_OPTIONS,
),
filename: 'foo',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
sourcePath: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(result, {isExcluded: true});
});
it('should not error when external dependencies are declared in peerDependencies', async function () {
let result = await resolver.resolve({
env: new Environment(
createEnvironment({
context: 'browser',
isLibrary: true,
includeNodeModules: false,
}),
DEFAULT_OPTIONS,
),
filename: 'bar',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
sourcePath: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(result, {isExcluded: true});
});
it('should not error on missing dependencies for environment builtins', async function () {
let result = await resolver.resolve({
env: new Environment(
createEnvironment({
context: 'browser',
isLibrary: true,
includeNodeModules: false,
}),
DEFAULT_OPTIONS,
),
filename: 'atom',
specifierType: 'esm',
parent: path.join(rootDir, 'env-dep/foo.js'),
sourcePath: path.join(rootDir, 'env-dep/foo.js'),
});
assert.deepEqual(result, {isExcluded: true});
});
it('should not error on builtin node modules', async function () {
let result = await resolver.resolve({
env: new Environment(
createEnvironment({
context: 'browser',
isLibrary: true,
includeNodeModules: false,
}),
DEFAULT_OPTIONS,
),
filename: 'buffer',
specifierType: 'esm',
parent: path.join(rootDir, 'env-dep/foo.js'),
sourcePath: path.join(rootDir, 'env-dep/foo.js'),
});
assert.deepEqual(result, {isExcluded: true});
});
});
describe('urls', function () {
it('should ignore protocol relative urls', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '//example.com/foo.png',
specifierType: 'url',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {isExcluded: true});
});
it('should ignore hash urls', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: '#hash',
specifierType: 'url',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {isExcluded: true});
});
it('should ignore http: urls', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'http://example.com/foo.png',
specifierType: 'url',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {isExcluded: true});
});
});
});