Socket
Socket
Sign inDemoInstall

@rollup/plugin-node-resolve

Package Overview
Dependencies
Maintainers
4
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rollup/plugin-node-resolve - npm Package Compare versions

Comparing version 15.2.0 to 15.2.1

603

dist/cjs/index.js

@@ -15,3 +15,3 @@ 'use strict';

var version = "15.2.0";
var version = "15.2.1";
var peerDependencies = {

@@ -25,14 +25,13 @@ rollup: "^2.78.0||^3.0.0"

const stat = util.promisify(fs.stat);
async function fileExists(filePath) {
try {
const res = await stat(filePath);
return res.isFile();
} catch {
return false;
}
try {
const res = await stat(filePath);
return res.isFile();
}
catch {
return false;
}
}
async function resolveSymlink(path) {
return (await fileExists(path)) ? realpath(path) : path;
return (await fileExists(path)) ? realpath(path) : path;
}

@@ -313,301 +312,370 @@

/* eslint-disable no-await-in-loop */
function isModuleDir(current, moduleDirs) {
return moduleDirs.some((dir) => current.endsWith(dir));
return moduleDirs.some((dir) => current.endsWith(dir));
}
async function findPackageJson(base, moduleDirs) {
const { root } = path.parse(base);
let current = base;
while (current !== root && !isModuleDir(current, moduleDirs)) {
const pkgJsonPath = path.join(current, 'package.json');
if (await fileExists(pkgJsonPath)) {
const pkgJsonString = fs.readFileSync(pkgJsonPath, 'utf-8');
return { pkgJson: JSON.parse(pkgJsonString), pkgPath: current, pkgJsonPath };
const { root } = path.parse(base);
let current = base;
while (current !== root && !isModuleDir(current, moduleDirs)) {
const pkgJsonPath = path.join(current, 'package.json');
if (await fileExists(pkgJsonPath)) {
const pkgJsonString = fs.readFileSync(pkgJsonPath, 'utf-8');
return { pkgJson: JSON.parse(pkgJsonString), pkgPath: current, pkgJsonPath };
}
current = path.resolve(current, '..');
}
current = path.resolve(current, '..');
}
return null;
return null;
}
function isUrl(str) {
try {
return !!new URL(str);
} catch (_) {
return false;
}
try {
return !!new URL(str);
}
catch (_) {
return false;
}
}
/**
* Conditions is an export object where all keys are conditions like 'node' (aka do not with '.')
*/
function isConditions(exports) {
return typeof exports === 'object' && Object.keys(exports).every((k) => !k.startsWith('.'));
return typeof exports === 'object' && Object.keys(exports).every((k) => !k.startsWith('.'));
}
/**
* Mappings is an export object where all keys start with '.
*/
function isMappings(exports) {
return typeof exports === 'object' && !isConditions(exports);
return typeof exports === 'object' && !isConditions(exports);
}
/**
* Check for mixed exports, which are exports where some keys start with '.' and some do not
*/
function isMixedExports(exports) {
const keys = Object.keys(exports);
return keys.some((k) => k.startsWith('.')) && keys.some((k) => !k.startsWith('.'));
const keys = Object.keys(exports);
return keys.some((k) => k.startsWith('.')) && keys.some((k) => !k.startsWith('.'));
}
function createBaseErrorMsg(importSpecifier, importer) {
return `Could not resolve import "${importSpecifier}" in ${importer}`;
return `Could not resolve import "${importSpecifier}" in ${importer}`;
}
function createErrorMsg(context, reason, internal) {
const { importSpecifier, importer, pkgJsonPath } = context;
const base = createBaseErrorMsg(importSpecifier, importer);
const field = internal ? 'imports' : 'exports';
return `${base} using ${field} defined in ${pkgJsonPath}.${reason ? ` ${reason}` : ''}`;
function createErrorMsg(context, reason, isImports) {
const { importSpecifier, importer, pkgJsonPath } = context;
const base = createBaseErrorMsg(importSpecifier, importer);
const field = isImports ? 'imports' : 'exports';
return `${base} using ${field} defined in ${pkgJsonPath}.${reason ? ` ${reason}` : ''}`;
}
class ResolveError extends Error {}
class ResolveError extends Error {
}
class InvalidConfigurationError extends ResolveError {
constructor(context, reason) {
super(createErrorMsg(context, `Invalid "exports" field. ${reason}`));
}
constructor(context, reason) {
super(createErrorMsg(context, `Invalid "exports" field. ${reason}`));
}
}
class InvalidModuleSpecifierError extends ResolveError {
constructor(context, internal, reason) {
super(createErrorMsg(context, reason, internal));
}
constructor(context, isImports, reason) {
super(createErrorMsg(context, reason, isImports));
}
}
class InvalidPackageTargetError extends ResolveError {
constructor(context, reason) {
super(createErrorMsg(context, reason));
}
constructor(context, reason) {
super(createErrorMsg(context, reason));
}
}
/* eslint-disable no-await-in-loop, no-undefined */
/**
* Check for invalid path segments
*/
function includesInvalidSegments(pathSegments, moduleDirs) {
return pathSegments
.split('/')
.slice(1)
.some((t) => ['.', '..', ...moduleDirs].includes(t));
const invalidSegments = ['', '.', '..', ...moduleDirs];
// contains any "", ".", "..", or "node_modules" segments, including percent encoded variants
return pathSegments.some((v) => invalidSegments.includes(v) || invalidSegments.includes(decodeURI(v)));
}
async function resolvePackageTarget(context, { target, subpath, pattern, internal }) {
if (typeof target === 'string') {
if (!pattern && subpath.length > 0 && !target.endsWith('/')) {
throw new InvalidModuleSpecifierError(context);
async function resolvePackageTarget(context, { target, patternMatch, isImports }) {
// If target is a String, then
if (typeof target === 'string') {
// If target does not start with "./", then
if (!target.startsWith('./')) {
// If isImports is false, or if target starts with "../" or "/", or if target is a valid URL, then
if (!isImports || ['/', '../'].some((p) => target.startsWith(p)) || isUrl(target)) {
// Throw an Invalid Package Target error.
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
}
// If patternMatch is a String, then
if (typeof patternMatch === 'string') {
// Return PACKAGE_RESOLVE(target with every instance of "*" replaced by patternMatch, packageURL + "/")
const result = await context.resolveId(target.replace(/\*/g, patternMatch), context.pkgURL.href);
return result ? url.pathToFileURL(result.location).href : null;
}
// Return PACKAGE_RESOLVE(target, packageURL + "/").
const result = await context.resolveId(target, context.pkgURL.href);
return result ? url.pathToFileURL(result.location).href : null;
}
// TODO: Drop if we do not support Node <= 16 anymore
// This behavior was removed in Node 17 (deprecated in Node 14), see DEP0148
if (context.allowExportsFolderMapping) {
target = target.replace(/\/$/, '/*');
}
// If target split on "/" or "\"
{
const pathSegments = target.split(/\/|\\/);
// after the first "." segment
const firstDot = pathSegments.indexOf('.');
firstDot !== -1 && pathSegments.slice(firstDot);
if (firstDot !== -1 &&
firstDot < pathSegments.length - 1 &&
includesInvalidSegments(pathSegments.slice(firstDot + 1), context.moduleDirs)) {
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
}
}
// Let resolvedTarget be the URL resolution of the concatenation of packageURL and target.
const resolvedTarget = new URL(target, context.pkgURL);
// Assert: resolvedTarget is contained in packageURL.
if (!resolvedTarget.href.startsWith(context.pkgURL.href)) {
throw new InvalidPackageTargetError(context, `Resolved to ${resolvedTarget.href} which is outside package ${context.pkgURL.href}`);
}
// If patternMatch is null, then
if (!patternMatch) {
// Return resolvedTarget.
return resolvedTarget;
}
// If patternMatch split on "/" or "\" contains invalid segments
if (includesInvalidSegments(patternMatch.split(/\/|\\/), context.moduleDirs)) {
// throw an Invalid Module Specifier error.
throw new InvalidModuleSpecifierError(context);
}
// Return the URL resolution of resolvedTarget with every instance of "*" replaced with patternMatch.
return resolvedTarget.href.replace(/\*/g, patternMatch);
}
if (!target.startsWith('./')) {
if (internal && !['/', '../'].some((p) => target.startsWith(p)) && !isUrl(target)) {
// this is a bare package import, remap it and resolve it using regular node resolve
if (pattern) {
const result = await context.resolveId(
target.replace(/\*/g, subpath),
context.pkgURL.href
);
return result ? url.pathToFileURL(result.location).href : null;
// Otherwise, if target is an Array, then
if (Array.isArray(target)) {
// If _target.length is zero, return null.
if (target.length === 0) {
return null;
}
const result = await context.resolveId(`${target}${subpath}`, context.pkgURL.href);
return result ? url.pathToFileURL(result.location).href : null;
}
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
let lastError = null;
// For each item in target, do
for (const item of target) {
// Let resolved be the result of PACKAGE_TARGET_RESOLVE of the item
// continuing the loop on any Invalid Package Target error.
try {
const resolved = await resolvePackageTarget(context, {
target: item,
patternMatch,
isImports
});
// If resolved is undefined, continue the loop.
// Else Return resolved.
if (resolved !== undefined) {
return resolved;
}
}
catch (error) {
if (!(error instanceof InvalidPackageTargetError)) {
throw error;
}
else {
lastError = error;
}
}
}
// Return or throw the last fallback resolution null return or error
if (lastError) {
throw lastError;
}
return null;
}
if (includesInvalidSegments(target, context.moduleDirs)) {
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
// Otherwise, if target is a non-null Object, then
if (target && typeof target === 'object') {
// For each property of target
for (const [key, value] of Object.entries(target)) {
// If exports contains any index property keys, as defined in ECMA-262 6.1.7 Array Index, throw an Invalid Package Configuration error.
// TODO: We do not check if the key is a number here...
// If key equals "default" or conditions contains an entry for the key, then
if (key === 'default' || context.conditions.includes(key)) {
// Let targetValue be the value of the property in target.
// Let resolved be the result of PACKAGE_TARGET_RESOLVE of the targetValue
const resolved = await resolvePackageTarget(context, {
target: value,
patternMatch,
isImports
});
// If resolved is equal to undefined, continue the loop.
// Return resolved.
if (resolved !== undefined) {
return resolved;
}
}
}
// Return undefined.
return undefined;
}
const resolvedTarget = new URL(target, context.pkgURL);
if (!resolvedTarget.href.startsWith(context.pkgURL.href)) {
throw new InvalidPackageTargetError(
context,
`Resolved to ${resolvedTarget.href} which is outside package ${context.pkgURL.href}`
);
// Otherwise, if target is null, return null.
if (target === null) {
return null;
}
// Otherwise throw an Invalid Package Target error.
throw new InvalidPackageTargetError(context, `Invalid exports field.`);
}
if (includesInvalidSegments(subpath, context.moduleDirs)) {
throw new InvalidModuleSpecifierError(context);
/* eslint-disable no-await-in-loop */
/**
* Implementation of Node's `PATTERN_KEY_COMPARE` function
*/
function nodePatternKeyCompare(keyA, keyB) {
// Let baseLengthA be the index of "*" in keyA plus one, if keyA contains "*", or the length of keyA otherwise.
const baseLengthA = keyA.includes('*') ? keyA.indexOf('*') + 1 : keyA.length;
// Let baseLengthB be the index of "*" in keyB plus one, if keyB contains "*", or the length of keyB otherwise.
const baseLengthB = keyB.includes('*') ? keyB.indexOf('*') + 1 : keyB.length;
// if baseLengthA is greater, return -1, if lower 1
const rval = baseLengthB - baseLengthA;
if (rval !== 0)
return rval;
// If keyA does not contain "*", return 1.
if (!keyA.includes('*'))
return 1;
// If keyB does not contain "*", return -1.
if (!keyB.includes('*'))
return -1;
// If the length of keyA is greater than the length of keyB, return -1.
// If the length of keyB is greater than the length of keyA, return 1.
// Else Return 0.
return keyB.length - keyA.length;
}
async function resolvePackageImportsExports(context, { matchKey, matchObj, isImports }) {
// If matchKey is a key of matchObj and does not contain "*", then
if (!matchKey.includes('*') && matchKey in matchObj) {
// Let target be the value of matchObj[matchKey].
const target = matchObj[matchKey];
// Return the result of PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions).
const resolved = await resolvePackageTarget(context, { target, patternMatch: '', isImports });
return resolved;
}
// Let expansionKeys be the list of keys of matchObj containing only a single "*"
const expansionKeys = Object.keys(matchObj)
// Assert: ends with "/" or contains only a single "*".
.filter((k) => k.endsWith('/') || k.includes('*'))
// sorted by the sorting function PATTERN_KEY_COMPARE which orders in descending order of specificity.
.sort(nodePatternKeyCompare);
// For each key expansionKey in expansionKeys, do
for (const expansionKey of expansionKeys) {
const indexOfAsterisk = expansionKey.indexOf('*');
// Let patternBase be the substring of expansionKey up to but excluding the first "*" character.
const patternBase = indexOfAsterisk === -1 ? expansionKey : expansionKey.substring(0, indexOfAsterisk);
// If matchKey starts with but is not equal to patternBase, then
if (matchKey.startsWith(patternBase) && matchKey !== patternBase) {
// Let patternTrailer be the substring of expansionKey from the index after the first "*" character.
const patternTrailer = indexOfAsterisk !== -1 ? expansionKey.substring(indexOfAsterisk + 1) : '';
// If patternTrailer has zero length,
if (patternTrailer.length === 0 ||
// or if matchKey ends with patternTrailer and the length of matchKey is greater than or equal to the length of expansionKey, then
(matchKey.endsWith(patternTrailer) && matchKey.length >= expansionKey.length)) {
// Let target be the value of matchObj[expansionKey].
const target = matchObj[expansionKey];
// Let patternMatch be the substring of matchKey starting at the index of the length of patternBase up to the length
// of matchKey minus the length of patternTrailer.
const patternMatch = matchKey.substring(patternBase.length, matchKey.length - patternTrailer.length);
// Return the result of PACKAGE_TARGET_RESOLVE
const resolved = await resolvePackageTarget(context, {
target,
patternMatch,
isImports
});
return resolved;
}
}
}
throw new InvalidModuleSpecifierError(context, isImports);
}
if (pattern) {
return resolvedTarget.href.replace(/\*/g, subpath);
/**
* Implementation of PACKAGE_EXPORTS_RESOLVE
*/
async function resolvePackageExports(context, subpath, exports) {
// If exports is an Object with both a key starting with "." and a key not starting with "."
if (isMixedExports(exports)) {
// throw an Invalid Package Configuration error.
throw new InvalidConfigurationError(context, 'All keys must either start with ./, or without one.');
}
return new URL(subpath, resolvedTarget).href;
}
if (Array.isArray(target)) {
let lastError;
for (const item of target) {
try {
const resolved = await resolvePackageTarget(context, {
target: item,
subpath,
pattern,
internal
});
// return if defined or null, but not undefined
if (resolved !== undefined) {
return resolved;
// If subpath is equal to ".", then
if (subpath === '.') {
// Let mainExport be undefined.
let mainExport;
// If exports is a String or Array, or an Object containing no keys starting with ".", then
if (typeof exports === 'string' || Array.isArray(exports) || isConditions(exports)) {
// Set mainExport to exports
mainExport = exports;
// Otherwise if exports is an Object containing a "." property, then
}
} catch (error) {
if (!(error instanceof InvalidPackageTargetError)) {
throw error;
} else {
lastError = error;
else if (isMappings(exports)) {
// Set mainExport to exports["."]
mainExport = exports['.'];
}
}
// If mainExport is not undefined, then
if (mainExport) {
// Let resolved be the result of PACKAGE_TARGET_RESOLVE with target = mainExport
const resolved = await resolvePackageTarget(context, {
target: mainExport,
patternMatch: '',
isImports: false
});
// If resolved is not null or undefined, return resolved.
if (resolved) {
return resolved;
}
}
// Otherwise, if exports is an Object and all keys of exports start with ".", then
}
if (lastError) {
throw lastError;
}
return null;
}
if (target && typeof target === 'object') {
for (const [key, value] of Object.entries(target)) {
if (key === 'default' || context.conditions.includes(key)) {
const resolved = await resolvePackageTarget(context, {
target: value,
subpath,
pattern,
internal
else if (isMappings(exports)) {
// Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE
const resolvedMatch = await resolvePackageImportsExports(context, {
matchKey: subpath,
matchObj: exports,
isImports: false
});
// return if defined or null, but not undefined
if (resolved !== undefined) {
return resolved;
// If resolved is not null or undefined, return resolved.
if (resolvedMatch) {
return resolvedMatch;
}
}
}
return undefined;
}
if (target === null) {
return null;
}
throw new InvalidPackageTargetError(context, `Invalid exports field.`);
// Throw a Package Path Not Exported error.
throw new InvalidModuleSpecifierError(context);
}
/* eslint-disable no-await-in-loop */
async function resolvePackageImportsExports(context, { matchKey, matchObj, internal }) {
if (!matchKey.endsWith('*') && matchKey in matchObj) {
const target = matchObj[matchKey];
const resolved = await resolvePackageTarget(context, { target, subpath: '', internal });
return resolved;
}
const expansionKeys = Object.keys(matchObj)
.filter((k) => k.endsWith('/') || k.endsWith('*'))
.sort((a, b) => b.length - a.length);
for (const expansionKey of expansionKeys) {
const prefix = expansionKey.substring(0, expansionKey.length - 1);
if (expansionKey.endsWith('*') && matchKey.startsWith(prefix)) {
const target = matchObj[expansionKey];
const subpath = matchKey.substring(expansionKey.length - 1);
const resolved = await resolvePackageTarget(context, {
target,
subpath,
pattern: true,
internal
});
return resolved;
async function resolvePackageImports({ importSpecifier, importer, moduleDirs, conditions, resolveId }) {
const result = await findPackageJson(importer, moduleDirs);
if (!result) {
throw new Error(`${createBaseErrorMsg(importSpecifier, importer)}. Could not find a parent package.json.`);
}
if (matchKey.startsWith(expansionKey)) {
const target = matchObj[expansionKey];
const subpath = matchKey.substring(expansionKey.length);
const resolved = await resolvePackageTarget(context, { target, subpath, internal });
return resolved;
const { pkgPath, pkgJsonPath, pkgJson } = result;
const pkgURL = url.pathToFileURL(`${pkgPath}/`);
const context = {
importer,
importSpecifier,
moduleDirs,
pkgURL,
pkgJsonPath,
conditions,
resolveId
};
// Assert: specifier begins with "#".
if (!importSpecifier.startsWith('#')) {
throw new InvalidModuleSpecifierError(context, true, 'Invalid import specifier.');
}
}
throw new InvalidModuleSpecifierError(context, internal);
}
async function resolvePackageExports(context, subpath, exports) {
if (isMixedExports(exports)) {
throw new InvalidConfigurationError(
context,
'All keys must either start with ./, or without one.'
);
}
if (subpath === '.') {
let mainExport;
// If exports is a String or Array, or an Object containing no keys starting with ".", then
if (typeof exports === 'string' || Array.isArray(exports) || isConditions(exports)) {
mainExport = exports;
} else if (isMappings(exports)) {
mainExport = exports['.'];
// If specifier is exactly equal to "#" or starts with "#/", then
if (importSpecifier === '#' || importSpecifier.startsWith('#/')) {
// Throw an Invalid Module Specifier error.
throw new InvalidModuleSpecifierError(context, true, 'Invalid import specifier.');
}
if (mainExport) {
const resolved = await resolvePackageTarget(context, { target: mainExport, subpath: '' });
if (resolved) {
return resolved;
}
const { imports } = pkgJson;
if (!imports) {
throw new InvalidModuleSpecifierError(context, true);
}
} else if (isMappings(exports)) {
const resolvedMatch = await resolvePackageImportsExports(context, {
matchKey: subpath,
matchObj: exports
// Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
// If packageURL is not null, then
return resolvePackageImportsExports(context, {
matchKey: importSpecifier,
matchObj: imports,
isImports: true
});
if (resolvedMatch) {
return resolvedMatch;
}
}
throw new InvalidModuleSpecifierError(context);
}
async function resolvePackageImports({
importSpecifier,
importer,
moduleDirs,
conditions,
resolveId
}) {
const result = await findPackageJson(importer, moduleDirs);
if (!result) {
throw new Error(createBaseErrorMsg('. Could not find a parent package.json.'));
}
const { pkgPath, pkgJsonPath, pkgJson } = result;
const pkgURL = url.pathToFileURL(`${pkgPath}/`);
const context = {
importer,
importSpecifier,
moduleDirs,
pkgURL,
pkgJsonPath,
conditions,
resolveId
};
const { imports } = pkgJson;
if (!imports) {
throw new InvalidModuleSpecifierError(context, true);
}
if (importSpecifier === '#' || importSpecifier.startsWith('#/')) {
throw new InvalidModuleSpecifierError(context, true, 'Invalid import specifier.');
}
return resolvePackageImportsExports(context, {
matchKey: importSpecifier,
matchObj: imports,
internal: true
});
}
const resolveImportPath = util.promisify(resolve);

@@ -715,3 +783,4 @@ const readFile = util.promisify(fs.readFile);

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping
}) {

@@ -805,2 +874,3 @@ if (importSpecifier.startsWith('#')) {

pkgJsonPath,
allowExportsFolderMapping,
conditions: exportConditions

@@ -886,3 +956,4 @@ };

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping
}) {

@@ -903,3 +974,4 @@ try {

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping
});

@@ -991,3 +1063,5 @@ if (exportMapRes) return exportMapRes;

moduleDirectories: ['node_modules'],
ignoreSideEffectsForRoot: false
ignoreSideEffectsForRoot: false,
// TODO: set to false in next major release or remove
allowExportsFolderMapping: true
};

@@ -1138,3 +1212,4 @@ const DEFAULTS = deepFreeze(deepMerge({}, defaults));

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping: options.allowExportsFolderMapping
});

@@ -1141,0 +1216,0 @@

@@ -11,3 +11,3 @@ import path, { dirname, resolve, extname, normalize, sep } from 'path';

var version = "15.2.0";
var version = "15.2.1";
var peerDependencies = {

@@ -21,14 +21,13 @@ rollup: "^2.78.0||^3.0.0"

const stat = promisify(fs.stat);
async function fileExists(filePath) {
try {
const res = await stat(filePath);
return res.isFile();
} catch {
return false;
}
try {
const res = await stat(filePath);
return res.isFile();
}
catch {
return false;
}
}
async function resolveSymlink(path) {
return (await fileExists(path)) ? realpath(path) : path;
return (await fileExists(path)) ? realpath(path) : path;
}

@@ -309,301 +308,370 @@

/* eslint-disable no-await-in-loop */
function isModuleDir(current, moduleDirs) {
return moduleDirs.some((dir) => current.endsWith(dir));
return moduleDirs.some((dir) => current.endsWith(dir));
}
async function findPackageJson(base, moduleDirs) {
const { root } = path.parse(base);
let current = base;
while (current !== root && !isModuleDir(current, moduleDirs)) {
const pkgJsonPath = path.join(current, 'package.json');
if (await fileExists(pkgJsonPath)) {
const pkgJsonString = fs.readFileSync(pkgJsonPath, 'utf-8');
return { pkgJson: JSON.parse(pkgJsonString), pkgPath: current, pkgJsonPath };
const { root } = path.parse(base);
let current = base;
while (current !== root && !isModuleDir(current, moduleDirs)) {
const pkgJsonPath = path.join(current, 'package.json');
if (await fileExists(pkgJsonPath)) {
const pkgJsonString = fs.readFileSync(pkgJsonPath, 'utf-8');
return { pkgJson: JSON.parse(pkgJsonString), pkgPath: current, pkgJsonPath };
}
current = path.resolve(current, '..');
}
current = path.resolve(current, '..');
}
return null;
return null;
}
function isUrl(str) {
try {
return !!new URL(str);
} catch (_) {
return false;
}
try {
return !!new URL(str);
}
catch (_) {
return false;
}
}
/**
* Conditions is an export object where all keys are conditions like 'node' (aka do not with '.')
*/
function isConditions(exports) {
return typeof exports === 'object' && Object.keys(exports).every((k) => !k.startsWith('.'));
return typeof exports === 'object' && Object.keys(exports).every((k) => !k.startsWith('.'));
}
/**
* Mappings is an export object where all keys start with '.
*/
function isMappings(exports) {
return typeof exports === 'object' && !isConditions(exports);
return typeof exports === 'object' && !isConditions(exports);
}
/**
* Check for mixed exports, which are exports where some keys start with '.' and some do not
*/
function isMixedExports(exports) {
const keys = Object.keys(exports);
return keys.some((k) => k.startsWith('.')) && keys.some((k) => !k.startsWith('.'));
const keys = Object.keys(exports);
return keys.some((k) => k.startsWith('.')) && keys.some((k) => !k.startsWith('.'));
}
function createBaseErrorMsg(importSpecifier, importer) {
return `Could not resolve import "${importSpecifier}" in ${importer}`;
return `Could not resolve import "${importSpecifier}" in ${importer}`;
}
function createErrorMsg(context, reason, internal) {
const { importSpecifier, importer, pkgJsonPath } = context;
const base = createBaseErrorMsg(importSpecifier, importer);
const field = internal ? 'imports' : 'exports';
return `${base} using ${field} defined in ${pkgJsonPath}.${reason ? ` ${reason}` : ''}`;
function createErrorMsg(context, reason, isImports) {
const { importSpecifier, importer, pkgJsonPath } = context;
const base = createBaseErrorMsg(importSpecifier, importer);
const field = isImports ? 'imports' : 'exports';
return `${base} using ${field} defined in ${pkgJsonPath}.${reason ? ` ${reason}` : ''}`;
}
class ResolveError extends Error {}
class ResolveError extends Error {
}
class InvalidConfigurationError extends ResolveError {
constructor(context, reason) {
super(createErrorMsg(context, `Invalid "exports" field. ${reason}`));
}
constructor(context, reason) {
super(createErrorMsg(context, `Invalid "exports" field. ${reason}`));
}
}
class InvalidModuleSpecifierError extends ResolveError {
constructor(context, internal, reason) {
super(createErrorMsg(context, reason, internal));
}
constructor(context, isImports, reason) {
super(createErrorMsg(context, reason, isImports));
}
}
class InvalidPackageTargetError extends ResolveError {
constructor(context, reason) {
super(createErrorMsg(context, reason));
}
constructor(context, reason) {
super(createErrorMsg(context, reason));
}
}
/* eslint-disable no-await-in-loop, no-undefined */
/**
* Check for invalid path segments
*/
function includesInvalidSegments(pathSegments, moduleDirs) {
return pathSegments
.split('/')
.slice(1)
.some((t) => ['.', '..', ...moduleDirs].includes(t));
const invalidSegments = ['', '.', '..', ...moduleDirs];
// contains any "", ".", "..", or "node_modules" segments, including percent encoded variants
return pathSegments.some((v) => invalidSegments.includes(v) || invalidSegments.includes(decodeURI(v)));
}
async function resolvePackageTarget(context, { target, subpath, pattern, internal }) {
if (typeof target === 'string') {
if (!pattern && subpath.length > 0 && !target.endsWith('/')) {
throw new InvalidModuleSpecifierError(context);
async function resolvePackageTarget(context, { target, patternMatch, isImports }) {
// If target is a String, then
if (typeof target === 'string') {
// If target does not start with "./", then
if (!target.startsWith('./')) {
// If isImports is false, or if target starts with "../" or "/", or if target is a valid URL, then
if (!isImports || ['/', '../'].some((p) => target.startsWith(p)) || isUrl(target)) {
// Throw an Invalid Package Target error.
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
}
// If patternMatch is a String, then
if (typeof patternMatch === 'string') {
// Return PACKAGE_RESOLVE(target with every instance of "*" replaced by patternMatch, packageURL + "/")
const result = await context.resolveId(target.replace(/\*/g, patternMatch), context.pkgURL.href);
return result ? pathToFileURL(result.location).href : null;
}
// Return PACKAGE_RESOLVE(target, packageURL + "/").
const result = await context.resolveId(target, context.pkgURL.href);
return result ? pathToFileURL(result.location).href : null;
}
// TODO: Drop if we do not support Node <= 16 anymore
// This behavior was removed in Node 17 (deprecated in Node 14), see DEP0148
if (context.allowExportsFolderMapping) {
target = target.replace(/\/$/, '/*');
}
// If target split on "/" or "\"
{
const pathSegments = target.split(/\/|\\/);
// after the first "." segment
const firstDot = pathSegments.indexOf('.');
firstDot !== -1 && pathSegments.slice(firstDot);
if (firstDot !== -1 &&
firstDot < pathSegments.length - 1 &&
includesInvalidSegments(pathSegments.slice(firstDot + 1), context.moduleDirs)) {
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
}
}
// Let resolvedTarget be the URL resolution of the concatenation of packageURL and target.
const resolvedTarget = new URL(target, context.pkgURL);
// Assert: resolvedTarget is contained in packageURL.
if (!resolvedTarget.href.startsWith(context.pkgURL.href)) {
throw new InvalidPackageTargetError(context, `Resolved to ${resolvedTarget.href} which is outside package ${context.pkgURL.href}`);
}
// If patternMatch is null, then
if (!patternMatch) {
// Return resolvedTarget.
return resolvedTarget;
}
// If patternMatch split on "/" or "\" contains invalid segments
if (includesInvalidSegments(patternMatch.split(/\/|\\/), context.moduleDirs)) {
// throw an Invalid Module Specifier error.
throw new InvalidModuleSpecifierError(context);
}
// Return the URL resolution of resolvedTarget with every instance of "*" replaced with patternMatch.
return resolvedTarget.href.replace(/\*/g, patternMatch);
}
if (!target.startsWith('./')) {
if (internal && !['/', '../'].some((p) => target.startsWith(p)) && !isUrl(target)) {
// this is a bare package import, remap it and resolve it using regular node resolve
if (pattern) {
const result = await context.resolveId(
target.replace(/\*/g, subpath),
context.pkgURL.href
);
return result ? pathToFileURL(result.location).href : null;
// Otherwise, if target is an Array, then
if (Array.isArray(target)) {
// If _target.length is zero, return null.
if (target.length === 0) {
return null;
}
const result = await context.resolveId(`${target}${subpath}`, context.pkgURL.href);
return result ? pathToFileURL(result.location).href : null;
}
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
let lastError = null;
// For each item in target, do
for (const item of target) {
// Let resolved be the result of PACKAGE_TARGET_RESOLVE of the item
// continuing the loop on any Invalid Package Target error.
try {
const resolved = await resolvePackageTarget(context, {
target: item,
patternMatch,
isImports
});
// If resolved is undefined, continue the loop.
// Else Return resolved.
if (resolved !== undefined) {
return resolved;
}
}
catch (error) {
if (!(error instanceof InvalidPackageTargetError)) {
throw error;
}
else {
lastError = error;
}
}
}
// Return or throw the last fallback resolution null return or error
if (lastError) {
throw lastError;
}
return null;
}
if (includesInvalidSegments(target, context.moduleDirs)) {
throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
// Otherwise, if target is a non-null Object, then
if (target && typeof target === 'object') {
// For each property of target
for (const [key, value] of Object.entries(target)) {
// If exports contains any index property keys, as defined in ECMA-262 6.1.7 Array Index, throw an Invalid Package Configuration error.
// TODO: We do not check if the key is a number here...
// If key equals "default" or conditions contains an entry for the key, then
if (key === 'default' || context.conditions.includes(key)) {
// Let targetValue be the value of the property in target.
// Let resolved be the result of PACKAGE_TARGET_RESOLVE of the targetValue
const resolved = await resolvePackageTarget(context, {
target: value,
patternMatch,
isImports
});
// If resolved is equal to undefined, continue the loop.
// Return resolved.
if (resolved !== undefined) {
return resolved;
}
}
}
// Return undefined.
return undefined;
}
const resolvedTarget = new URL(target, context.pkgURL);
if (!resolvedTarget.href.startsWith(context.pkgURL.href)) {
throw new InvalidPackageTargetError(
context,
`Resolved to ${resolvedTarget.href} which is outside package ${context.pkgURL.href}`
);
// Otherwise, if target is null, return null.
if (target === null) {
return null;
}
// Otherwise throw an Invalid Package Target error.
throw new InvalidPackageTargetError(context, `Invalid exports field.`);
}
if (includesInvalidSegments(subpath, context.moduleDirs)) {
throw new InvalidModuleSpecifierError(context);
/* eslint-disable no-await-in-loop */
/**
* Implementation of Node's `PATTERN_KEY_COMPARE` function
*/
function nodePatternKeyCompare(keyA, keyB) {
// Let baseLengthA be the index of "*" in keyA plus one, if keyA contains "*", or the length of keyA otherwise.
const baseLengthA = keyA.includes('*') ? keyA.indexOf('*') + 1 : keyA.length;
// Let baseLengthB be the index of "*" in keyB plus one, if keyB contains "*", or the length of keyB otherwise.
const baseLengthB = keyB.includes('*') ? keyB.indexOf('*') + 1 : keyB.length;
// if baseLengthA is greater, return -1, if lower 1
const rval = baseLengthB - baseLengthA;
if (rval !== 0)
return rval;
// If keyA does not contain "*", return 1.
if (!keyA.includes('*'))
return 1;
// If keyB does not contain "*", return -1.
if (!keyB.includes('*'))
return -1;
// If the length of keyA is greater than the length of keyB, return -1.
// If the length of keyB is greater than the length of keyA, return 1.
// Else Return 0.
return keyB.length - keyA.length;
}
async function resolvePackageImportsExports(context, { matchKey, matchObj, isImports }) {
// If matchKey is a key of matchObj and does not contain "*", then
if (!matchKey.includes('*') && matchKey in matchObj) {
// Let target be the value of matchObj[matchKey].
const target = matchObj[matchKey];
// Return the result of PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions).
const resolved = await resolvePackageTarget(context, { target, patternMatch: '', isImports });
return resolved;
}
// Let expansionKeys be the list of keys of matchObj containing only a single "*"
const expansionKeys = Object.keys(matchObj)
// Assert: ends with "/" or contains only a single "*".
.filter((k) => k.endsWith('/') || k.includes('*'))
// sorted by the sorting function PATTERN_KEY_COMPARE which orders in descending order of specificity.
.sort(nodePatternKeyCompare);
// For each key expansionKey in expansionKeys, do
for (const expansionKey of expansionKeys) {
const indexOfAsterisk = expansionKey.indexOf('*');
// Let patternBase be the substring of expansionKey up to but excluding the first "*" character.
const patternBase = indexOfAsterisk === -1 ? expansionKey : expansionKey.substring(0, indexOfAsterisk);
// If matchKey starts with but is not equal to patternBase, then
if (matchKey.startsWith(patternBase) && matchKey !== patternBase) {
// Let patternTrailer be the substring of expansionKey from the index after the first "*" character.
const patternTrailer = indexOfAsterisk !== -1 ? expansionKey.substring(indexOfAsterisk + 1) : '';
// If patternTrailer has zero length,
if (patternTrailer.length === 0 ||
// or if matchKey ends with patternTrailer and the length of matchKey is greater than or equal to the length of expansionKey, then
(matchKey.endsWith(patternTrailer) && matchKey.length >= expansionKey.length)) {
// Let target be the value of matchObj[expansionKey].
const target = matchObj[expansionKey];
// Let patternMatch be the substring of matchKey starting at the index of the length of patternBase up to the length
// of matchKey minus the length of patternTrailer.
const patternMatch = matchKey.substring(patternBase.length, matchKey.length - patternTrailer.length);
// Return the result of PACKAGE_TARGET_RESOLVE
const resolved = await resolvePackageTarget(context, {
target,
patternMatch,
isImports
});
return resolved;
}
}
}
throw new InvalidModuleSpecifierError(context, isImports);
}
if (pattern) {
return resolvedTarget.href.replace(/\*/g, subpath);
/**
* Implementation of PACKAGE_EXPORTS_RESOLVE
*/
async function resolvePackageExports(context, subpath, exports) {
// If exports is an Object with both a key starting with "." and a key not starting with "."
if (isMixedExports(exports)) {
// throw an Invalid Package Configuration error.
throw new InvalidConfigurationError(context, 'All keys must either start with ./, or without one.');
}
return new URL(subpath, resolvedTarget).href;
}
if (Array.isArray(target)) {
let lastError;
for (const item of target) {
try {
const resolved = await resolvePackageTarget(context, {
target: item,
subpath,
pattern,
internal
});
// return if defined or null, but not undefined
if (resolved !== undefined) {
return resolved;
// If subpath is equal to ".", then
if (subpath === '.') {
// Let mainExport be undefined.
let mainExport;
// If exports is a String or Array, or an Object containing no keys starting with ".", then
if (typeof exports === 'string' || Array.isArray(exports) || isConditions(exports)) {
// Set mainExport to exports
mainExport = exports;
// Otherwise if exports is an Object containing a "." property, then
}
} catch (error) {
if (!(error instanceof InvalidPackageTargetError)) {
throw error;
} else {
lastError = error;
else if (isMappings(exports)) {
// Set mainExport to exports["."]
mainExport = exports['.'];
}
}
// If mainExport is not undefined, then
if (mainExport) {
// Let resolved be the result of PACKAGE_TARGET_RESOLVE with target = mainExport
const resolved = await resolvePackageTarget(context, {
target: mainExport,
patternMatch: '',
isImports: false
});
// If resolved is not null or undefined, return resolved.
if (resolved) {
return resolved;
}
}
// Otherwise, if exports is an Object and all keys of exports start with ".", then
}
if (lastError) {
throw lastError;
}
return null;
}
if (target && typeof target === 'object') {
for (const [key, value] of Object.entries(target)) {
if (key === 'default' || context.conditions.includes(key)) {
const resolved = await resolvePackageTarget(context, {
target: value,
subpath,
pattern,
internal
else if (isMappings(exports)) {
// Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE
const resolvedMatch = await resolvePackageImportsExports(context, {
matchKey: subpath,
matchObj: exports,
isImports: false
});
// return if defined or null, but not undefined
if (resolved !== undefined) {
return resolved;
// If resolved is not null or undefined, return resolved.
if (resolvedMatch) {
return resolvedMatch;
}
}
}
return undefined;
}
if (target === null) {
return null;
}
throw new InvalidPackageTargetError(context, `Invalid exports field.`);
// Throw a Package Path Not Exported error.
throw new InvalidModuleSpecifierError(context);
}
/* eslint-disable no-await-in-loop */
async function resolvePackageImportsExports(context, { matchKey, matchObj, internal }) {
if (!matchKey.endsWith('*') && matchKey in matchObj) {
const target = matchObj[matchKey];
const resolved = await resolvePackageTarget(context, { target, subpath: '', internal });
return resolved;
}
const expansionKeys = Object.keys(matchObj)
.filter((k) => k.endsWith('/') || k.endsWith('*'))
.sort((a, b) => b.length - a.length);
for (const expansionKey of expansionKeys) {
const prefix = expansionKey.substring(0, expansionKey.length - 1);
if (expansionKey.endsWith('*') && matchKey.startsWith(prefix)) {
const target = matchObj[expansionKey];
const subpath = matchKey.substring(expansionKey.length - 1);
const resolved = await resolvePackageTarget(context, {
target,
subpath,
pattern: true,
internal
});
return resolved;
async function resolvePackageImports({ importSpecifier, importer, moduleDirs, conditions, resolveId }) {
const result = await findPackageJson(importer, moduleDirs);
if (!result) {
throw new Error(`${createBaseErrorMsg(importSpecifier, importer)}. Could not find a parent package.json.`);
}
if (matchKey.startsWith(expansionKey)) {
const target = matchObj[expansionKey];
const subpath = matchKey.substring(expansionKey.length);
const resolved = await resolvePackageTarget(context, { target, subpath, internal });
return resolved;
const { pkgPath, pkgJsonPath, pkgJson } = result;
const pkgURL = pathToFileURL(`${pkgPath}/`);
const context = {
importer,
importSpecifier,
moduleDirs,
pkgURL,
pkgJsonPath,
conditions,
resolveId
};
// Assert: specifier begins with "#".
if (!importSpecifier.startsWith('#')) {
throw new InvalidModuleSpecifierError(context, true, 'Invalid import specifier.');
}
}
throw new InvalidModuleSpecifierError(context, internal);
}
async function resolvePackageExports(context, subpath, exports) {
if (isMixedExports(exports)) {
throw new InvalidConfigurationError(
context,
'All keys must either start with ./, or without one.'
);
}
if (subpath === '.') {
let mainExport;
// If exports is a String or Array, or an Object containing no keys starting with ".", then
if (typeof exports === 'string' || Array.isArray(exports) || isConditions(exports)) {
mainExport = exports;
} else if (isMappings(exports)) {
mainExport = exports['.'];
// If specifier is exactly equal to "#" or starts with "#/", then
if (importSpecifier === '#' || importSpecifier.startsWith('#/')) {
// Throw an Invalid Module Specifier error.
throw new InvalidModuleSpecifierError(context, true, 'Invalid import specifier.');
}
if (mainExport) {
const resolved = await resolvePackageTarget(context, { target: mainExport, subpath: '' });
if (resolved) {
return resolved;
}
const { imports } = pkgJson;
if (!imports) {
throw new InvalidModuleSpecifierError(context, true);
}
} else if (isMappings(exports)) {
const resolvedMatch = await resolvePackageImportsExports(context, {
matchKey: subpath,
matchObj: exports
// Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
// If packageURL is not null, then
return resolvePackageImportsExports(context, {
matchKey: importSpecifier,
matchObj: imports,
isImports: true
});
if (resolvedMatch) {
return resolvedMatch;
}
}
throw new InvalidModuleSpecifierError(context);
}
async function resolvePackageImports({
importSpecifier,
importer,
moduleDirs,
conditions,
resolveId
}) {
const result = await findPackageJson(importer, moduleDirs);
if (!result) {
throw new Error(createBaseErrorMsg('. Could not find a parent package.json.'));
}
const { pkgPath, pkgJsonPath, pkgJson } = result;
const pkgURL = pathToFileURL(`${pkgPath}/`);
const context = {
importer,
importSpecifier,
moduleDirs,
pkgURL,
pkgJsonPath,
conditions,
resolveId
};
const { imports } = pkgJson;
if (!imports) {
throw new InvalidModuleSpecifierError(context, true);
}
if (importSpecifier === '#' || importSpecifier.startsWith('#/')) {
throw new InvalidModuleSpecifierError(context, true, 'Invalid import specifier.');
}
return resolvePackageImportsExports(context, {
matchKey: importSpecifier,
matchObj: imports,
internal: true
});
}
const resolveImportPath = promisify(resolve$1);

@@ -711,3 +779,4 @@ const readFile = promisify(fs.readFile);

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping
}) {

@@ -801,2 +870,3 @@ if (importSpecifier.startsWith('#')) {

pkgJsonPath,
allowExportsFolderMapping,
conditions: exportConditions

@@ -882,3 +952,4 @@ };

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping
}) {

@@ -899,3 +970,4 @@ try {

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping
});

@@ -987,3 +1059,5 @@ if (exportMapRes) return exportMapRes;

moduleDirectories: ['node_modules'],
ignoreSideEffectsForRoot: false
ignoreSideEffectsForRoot: false,
// TODO: set to false in next major release or remove
allowExportsFolderMapping: true
};

@@ -1134,3 +1208,4 @@ const DEFAULTS = deepFreeze(deepMerge({}, defaults));

rootDir,
ignoreSideEffectsForRoot
ignoreSideEffectsForRoot,
allowExportsFolderMapping: options.allowExportsFolderMapping
});

@@ -1137,0 +1212,0 @@

{
"name": "@rollup/plugin-node-resolve",
"version": "15.2.0",
"version": "15.2.1",
"publishConfig": {

@@ -5,0 +5,0 @@ "access": "public"

@@ -178,2 +178,27 @@ [npm]: https://img.shields.io/npm/v/@rollup/plugin-node-resolve

### `allowExportsFolderMapping`
Older Node versions supported exports mappings of folders like
```json
{
"exports": {
"./foo/": "./dist/foo/"
}
}
```
This was deprecated with Node 14 and removed in Node 17, instead it is recommended to use exports patterns like
```json
{
"exports": {
"./foo/*": "./dist/foo/*"
}
}
```
But for backwards compatibility this behavior is still supported by enabling the `allowExportsFolderMapping` (defaults to `true`).
The default value might change in a futur major release.
## Preserving symlinks

@@ -180,0 +205,0 @@

@@ -99,2 +99,10 @@ import type { Plugin } from 'rollup';

rootDir?: string;
/**
* Allow folder mappings in package exports (trailing /)
* This was deprecated in Node 14 and removed with Node 17, see DEP0148.
* So this option might be changed to default to `false` in a future release.
* @default true
*/
allowExportsFolderMapping?: boolean;
}

@@ -101,0 +109,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc