@rollup/plugin-node-resolve
Advanced tools
Comparing version 10.0.0 to 11.0.0
# @rollup/plugin-node-resolve ChangeLog | ||
## v11.0.0 | ||
_2020-11-30_ | ||
### Breaking Changes | ||
- refactor!: simplify builtins and remove `customResolveOptions` (#656) | ||
- feat!: Mark built-ins as external (#627) | ||
- feat!: support package entry points (#540) | ||
### Bugfixes | ||
- fix: refactor handling builtins, do not log warning if no local version (#637) | ||
### Updates | ||
- docs: fix import statements in examples in README.md (#646) | ||
## v10.0.0 | ||
@@ -4,0 +22,0 @@ |
@@ -11,7 +11,8 @@ 'use strict'; | ||
var util = require('util'); | ||
var resolve = require('resolve'); | ||
var pluginutils = require('@rollup/pluginutils'); | ||
var resolveModule = require('resolve'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var path__default = /*#__PURE__*/_interopDefaultLegacy(path); | ||
var builtinList__default = /*#__PURE__*/_interopDefaultLegacy(builtinList); | ||
@@ -21,3 +22,3 @@ var deepMerge__default = /*#__PURE__*/_interopDefaultLegacy(deepMerge); | ||
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); | ||
var resolveModule__default = /*#__PURE__*/_interopDefaultLegacy(resolveModule); | ||
var resolve__default = /*#__PURE__*/_interopDefaultLegacy(resolve); | ||
@@ -83,4 +84,2 @@ const exists = util.promisify(fs__default['default'].exists); | ||
const resolveId = util.promisify(resolveModule__default['default']); | ||
// returns the imported package name for bare module imports | ||
@@ -138,3 +137,3 @@ function getPackageName(id) { | ||
// copy as we are about to munge the `main` field of `pkg`. | ||
packageJson: Object.assign({}, pkg), | ||
packageJson: { ...pkg }, | ||
@@ -237,33 +236,302 @@ // path to package.json file | ||
// Resolve module specifiers in order. Promise resolves to the first module that resolves | ||
// successfully, or the error that resulted from the last attempted module resolution. | ||
function resolveImportSpecifiers(importSpecifierList, resolveOptions) { | ||
let promise = Promise.resolve(); | ||
const resolveImportPath = util.promisify(resolve__default['default']); | ||
const readFile$1 = util.promisify(fs__default['default'].readFile); | ||
for (let i = 0; i < importSpecifierList.length; i++) { | ||
// eslint-disable-next-line no-loop-func | ||
promise = promise.then(async (value) => { | ||
// if we've already resolved to something, just return it. | ||
if (value) { | ||
return value; | ||
const pathNotFoundError = (subPath, pkgPath) => | ||
new Error(`Package subpath '${subPath}' is not defined by "exports" in ${pkgPath}`); | ||
function findExportKeyMatch(exportMap, subPath) { | ||
for (const key of Object.keys(exportMap)) { | ||
if (key.endsWith('*')) { | ||
// star match: "./foo/*": "./foo/*.js" | ||
const keyWithoutStar = key.substring(0, key.length - 1); | ||
if (subPath.startsWith(keyWithoutStar)) { | ||
return key; | ||
} | ||
} | ||
let result = await resolveId(importSpecifierList[i], resolveOptions); | ||
if (!resolveOptions.preserveSymlinks) { | ||
if (await exists(result)) { | ||
result = await realpath(result); | ||
} | ||
if (key.endsWith('/') && subPath.startsWith(key)) { | ||
// directory match (deprecated by node): "./foo/": "./foo/.js" | ||
return key; | ||
} | ||
if (key === subPath) { | ||
// literal match | ||
return key; | ||
} | ||
} | ||
return null; | ||
} | ||
function mapSubPath(pkgJsonPath, subPath, key, value) { | ||
if (typeof value === 'string') { | ||
if (typeof key === 'string' && key.endsWith('*')) { | ||
// star match: "./foo/*": "./foo/*.js" | ||
const keyWithoutStar = key.substring(0, key.length - 1); | ||
const subPathAfterKey = subPath.substring(keyWithoutStar.length); | ||
return value.replace(/\*/g, subPathAfterKey); | ||
} | ||
if (value.endsWith('/')) { | ||
// directory match (deprecated by node): "./foo/": "./foo/.js" | ||
return `${value}${subPath.substring(key.length)}`; | ||
} | ||
// mapping is a string, for example { "./foo": "./dist/foo.js" } | ||
return value; | ||
} | ||
if (Array.isArray(value)) { | ||
// mapping is an array with fallbacks, for example { "./foo": ["foo:bar", "./dist/foo.js"] } | ||
return value.find((v) => v.startsWith('./')); | ||
} | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
function findEntrypoint(pkgJsonPath, subPath, exportMap, conditions, key) { | ||
if (typeof exportMap !== 'object') { | ||
return mapSubPath(pkgJsonPath, subPath, key, exportMap); | ||
} | ||
// iterate conditions recursively, find the first that matches all conditions | ||
for (const [condition, subExportMap] of Object.entries(exportMap)) { | ||
if (conditions.includes(condition)) { | ||
const mappedSubPath = findEntrypoint(pkgJsonPath, subPath, subExportMap, conditions, key); | ||
if (mappedSubPath) { | ||
return mappedSubPath; | ||
} | ||
return result; | ||
} | ||
} | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
function findEntrypointTopLevel(pkgJsonPath, subPath, exportMap, conditions) { | ||
if (typeof exportMap !== 'object') { | ||
// the export map shorthand, for example { exports: "./index.js" } | ||
if (subPath !== '.') { | ||
// shorthand only supports a main entrypoint | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
return mapSubPath(pkgJsonPath, subPath, null, exportMap); | ||
} | ||
// export map is an object, the top level can be either conditions or sub path mappings | ||
const keys = Object.keys(exportMap); | ||
const isConditions = keys.every((k) => !k.startsWith('.')); | ||
const isMappings = keys.every((k) => k.startsWith('.')); | ||
if (!isConditions && !isMappings) { | ||
throw new Error( | ||
`Invalid package config ${pkgJsonPath}, "exports" cannot contain some keys starting with '.'` + | ||
' and some not. The exports object must either be an object of package subpath keys or an object of main entry' + | ||
' condition name keys only.' | ||
); | ||
} | ||
let key = null; | ||
let exportMapForSubPath; | ||
if (isConditions) { | ||
// top level is conditions, for example { "import": ..., "require": ..., "module": ... } | ||
if (subPath !== '.') { | ||
// package with top level conditions means it only supports a main entrypoint | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
exportMapForSubPath = exportMap; | ||
} else { | ||
// top level is sub path mappings, for example { ".": ..., "./foo": ..., "./bar": ... } | ||
key = findExportKeyMatch(exportMap, subPath); | ||
if (!key) { | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
exportMapForSubPath = exportMap[key]; | ||
} | ||
return findEntrypoint(pkgJsonPath, subPath, exportMapForSubPath, conditions, key); | ||
} | ||
async function resolveId({ | ||
importPath, | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}) { | ||
let hasModuleSideEffects = () => null; | ||
let hasPackageEntry = true; | ||
let packageBrowserField = false; | ||
let packageInfo; | ||
const filter = (pkg, pkgPath) => { | ||
const info = getPackageInfo({ | ||
cache: packageInfoCache, | ||
extensions, | ||
pkg, | ||
pkgPath, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides | ||
}); | ||
// swallow MODULE_NOT_FOUND errors | ||
promise = promise.catch((error) => { | ||
({ packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = info); | ||
return info.cachedPkg; | ||
}; | ||
const resolveOptions = { | ||
basedir: baseDir, | ||
readFile: readCachedFile, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions, | ||
includeCoreModules: false, | ||
moduleDirectory: moduleDirectories, | ||
preserveSymlinks, | ||
packageFilter: filter | ||
}; | ||
let location; | ||
const pkgName = getPackageName(importPath); | ||
if (pkgName) { | ||
let pkgJsonPath; | ||
let pkgJson; | ||
try { | ||
pkgJsonPath = await resolveImportPath(`${pkgName}/package.json`, resolveOptions); | ||
pkgJson = JSON.parse(await readFile$1(pkgJsonPath, 'utf-8')); | ||
} catch (_) { | ||
// if there is no package.json we defer to regular resolve behavior | ||
} | ||
if (pkgJsonPath && pkgJson && pkgJson.exports) { | ||
try { | ||
const packageSubPath = | ||
pkgName === importPath ? '.' : `.${importPath.substring(pkgName.length)}`; | ||
const mappedSubPath = findEntrypointTopLevel( | ||
pkgJsonPath, | ||
packageSubPath, | ||
pkgJson.exports, | ||
exportConditions | ||
); | ||
const pkgDir = path__default['default'].dirname(pkgJsonPath); | ||
location = path__default['default'].join(pkgDir, mappedSubPath); | ||
} catch (error) { | ||
warn(error); | ||
return null; | ||
} | ||
} | ||
} | ||
if (!location) { | ||
try { | ||
location = await resolveImportPath(importPath, resolveOptions); | ||
} catch (error) { | ||
if (error.code !== 'MODULE_NOT_FOUND') { | ||
throw error; | ||
} | ||
return null; | ||
} | ||
} | ||
if (!preserveSymlinks) { | ||
if (await exists(location)) { | ||
location = await realpath(location); | ||
} | ||
} | ||
return { | ||
location, | ||
hasModuleSideEffects, | ||
hasPackageEntry, | ||
packageBrowserField, | ||
packageInfo | ||
}; | ||
} | ||
// Resolve module specifiers in order. Promise resolves to the first module that resolves | ||
// successfully, or the error that resulted from the last attempted module resolution. | ||
async function resolveImportSpecifiers({ | ||
importSpecifierList, | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}) { | ||
for (let i = 0; i < importSpecifierList.length; i++) { | ||
// eslint-disable-next-line no-await-in-loop | ||
const resolved = await resolveId({ | ||
importPath: importSpecifierList[i], | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}); | ||
if (resolved) { | ||
return resolved; | ||
} | ||
} | ||
return null; | ||
} | ||
return promise; | ||
function handleDeprecatedOptions(opts) { | ||
const warnings = []; | ||
if (opts.customResolveOptions) { | ||
const { customResolveOptions } = opts; | ||
if (customResolveOptions.moduleDirectory) { | ||
// eslint-disable-next-line no-param-reassign | ||
opts.moduleDirectories = Array.isArray(customResolveOptions.moduleDirectory) | ||
? customResolveOptions.moduleDirectory | ||
: [customResolveOptions.moduleDirectory]; | ||
warnings.push( | ||
'node-resolve: The `customResolveOptions.moduleDirectory` option has been deprecated. Use `moduleDirectories`, which must be an array.' | ||
); | ||
} | ||
if (customResolveOptions.preserveSymlinks) { | ||
throw new Error( | ||
'node-resolve: `customResolveOptions.preserveSymlinks` is no longer an option. We now always use the rollup `preserveSymlinks` option.' | ||
); | ||
} | ||
[ | ||
'basedir', | ||
'package', | ||
'extensions', | ||
'includeCoreModules', | ||
'readFile', | ||
'isFile', | ||
'isDirectory', | ||
'realpath', | ||
'packageFilter', | ||
'pathFilter', | ||
'paths', | ||
'packageIterator' | ||
].forEach((resolveOption) => { | ||
if (customResolveOptions[resolveOption]) { | ||
throw new Error( | ||
`node-resolve: \`customResolveOptions.${resolveOption}\` is no longer an option. If you need this, please open an issue.` | ||
); | ||
} | ||
}); | ||
} | ||
return { warnings }; | ||
} | ||
@@ -275,3 +543,2 @@ | ||
const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js'; | ||
const nullFn = () => null; | ||
const deepFreeze = (object) => { | ||
@@ -288,4 +555,7 @@ Object.freeze(object); | ||
}; | ||
const baseConditions = ['default', 'module']; | ||
const baseConditionsEsm = [...baseConditions, 'import']; | ||
const baseConditionsCjs = [...baseConditions, 'require']; | ||
const defaults = { | ||
customResolveOptions: {}, | ||
dedupe: [], | ||
@@ -295,3 +565,4 @@ // It's important that .mjs is listed before .js so that Rollup will interpret npm modules | ||
extensions: ['.mjs', '.js', '.json', '.node'], | ||
resolveOnly: [] | ||
resolveOnly: [], | ||
moduleDirectories: ['node_modules'] | ||
}; | ||
@@ -301,5 +572,8 @@ const DEFAULTS = deepFreeze(deepMerge__default['default']({}, defaults)); | ||
function nodeResolve(opts = {}) { | ||
const options = Object.assign({}, defaults, opts); | ||
const { customResolveOptions, extensions, jail } = options; | ||
const warnings = []; | ||
const { warnings } = handleDeprecatedOptions(opts); | ||
const options = { ...defaults, ...opts }; | ||
const { extensions, jail, moduleDirectories } = options; | ||
const conditionsEsm = [...baseConditionsEsm, ...(options.exportConditions || [])]; | ||
const conditionsCjs = [...baseConditionsCjs, ...(options.exportConditions || [])]; | ||
const packageInfoCache = new Map(); | ||
@@ -315,7 +589,2 @@ const idToPackageInfo = new Map(); | ||
if (options.only) { | ||
warnings.push('node-resolve: The `only` options is deprecated, please use `resolveOnly`'); | ||
options.resolveOnly = options.only; | ||
} | ||
if (typeof dedupe !== 'function') { | ||
@@ -356,3 +625,3 @@ dedupe = (importee) => | ||
async resolveId(importee, importer) { | ||
async resolveId(importee, importer, opts) { | ||
if (importee === ES6_BROWSER_EMPTY) { | ||
@@ -373,3 +642,3 @@ return importee; | ||
const basedir = !importer || dedupe(importee) ? rootDir : path.dirname(importer); | ||
const baseDir = !importer || dedupe(importee) ? rootDir : path.dirname(importer); | ||
@@ -379,3 +648,3 @@ // https://github.com/defunctzombie/package-browser-field-spec | ||
if (useBrowserOverrides && browser) { | ||
const resolvedImportee = path.resolve(basedir, importee); | ||
const resolvedImportee = path.resolve(baseDir, importee); | ||
if (browser[importee] === false || browser[resolvedImportee] === false) { | ||
@@ -403,3 +672,3 @@ return ES6_BROWSER_EMPTY; | ||
// an import relative to the parent dir of the importer | ||
id = path.resolve(basedir, importee); | ||
id = path.resolve(baseDir, importee); | ||
isRelativeImport = true; | ||
@@ -419,36 +688,2 @@ } | ||
let hasModuleSideEffects = nullFn; | ||
let hasPackageEntry = true; | ||
let packageBrowserField = false; | ||
let packageInfo; | ||
const filter = (pkg, pkgPath) => { | ||
const info = getPackageInfo({ | ||
cache: packageInfoCache, | ||
extensions, | ||
pkg, | ||
pkgPath, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides | ||
}); | ||
({ packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = info); | ||
return info.cachedPkg; | ||
}; | ||
let resolveOptions = { | ||
basedir, | ||
packageFilter: filter, | ||
readFile: readCachedFile, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions | ||
}; | ||
if (preserveSymlinks !== undefined) { | ||
resolveOptions.preserveSymlinks = preserveSymlinks; | ||
} | ||
const importSpecifierList = []; | ||
@@ -468,3 +703,3 @@ | ||
if (importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet)) { | ||
if (importeeIsBuiltin) { | ||
// The `resolve` library will not resolve packages with the same | ||
@@ -489,5 +724,30 @@ // name as a node built-in module. If we're resolving something | ||
importSpecifierList.push(importee); | ||
resolveOptions = Object.assign(resolveOptions, customResolveOptions); | ||
let resolved = await resolveImportSpecifiers(importSpecifierList, resolveOptions); | ||
const warn = (...args) => this.warn(...args); | ||
const isRequire = | ||
opts && opts.custom && opts.custom['node-resolve'] && opts.custom['node-resolve'].isRequire; | ||
const exportConditions = isRequire ? conditionsCjs : conditionsEsm; | ||
const resolvedWithoutBuiltins = await resolveImportSpecifiers({ | ||
importSpecifierList, | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}); | ||
const resolved = | ||
importeeIsBuiltin && preferBuiltins | ||
? { | ||
packageInfo: undefined, | ||
hasModuleSideEffects: () => null, | ||
hasPackageEntry: true, | ||
packageBrowserField: false | ||
} | ||
: resolvedWithoutBuiltins; | ||
if (!resolved) { | ||
@@ -497,43 +757,43 @@ return null; | ||
const { packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = resolved; | ||
let { location } = resolved; | ||
if (packageBrowserField) { | ||
if (Object.prototype.hasOwnProperty.call(packageBrowserField, resolved)) { | ||
if (!packageBrowserField[resolved]) { | ||
browserMapCache.set(resolved, packageBrowserField); | ||
if (Object.prototype.hasOwnProperty.call(packageBrowserField, location)) { | ||
if (!packageBrowserField[location]) { | ||
browserMapCache.set(location, packageBrowserField); | ||
return ES6_BROWSER_EMPTY; | ||
} | ||
resolved = packageBrowserField[resolved]; | ||
location = packageBrowserField[location]; | ||
} | ||
browserMapCache.set(resolved, packageBrowserField); | ||
browserMapCache.set(location, packageBrowserField); | ||
} | ||
if (hasPackageEntry && !preserveSymlinks) { | ||
const fileExists = await exists(resolved); | ||
const fileExists = await exists(location); | ||
if (fileExists) { | ||
resolved = await realpath(resolved); | ||
location = await realpath(location); | ||
} | ||
} | ||
idToPackageInfo.set(resolved, packageInfo); | ||
idToPackageInfo.set(location, packageInfo); | ||
if (hasPackageEntry) { | ||
if (builtins.has(resolved) && preferBuiltins && isPreferBuiltinsSet) { | ||
return null; | ||
} else if (importeeIsBuiltin && preferBuiltins) { | ||
if (!isPreferBuiltinsSet) { | ||
if (importeeIsBuiltin && preferBuiltins) { | ||
if (!isPreferBuiltinsSet && resolvedWithoutBuiltins && resolved !== importee) { | ||
this.warn( | ||
`preferring built-in module '${importee}' over local alternative at '${resolved}', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning` | ||
`preferring built-in module '${importee}' over local alternative at '${resolvedWithoutBuiltins.location}', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning` | ||
); | ||
} | ||
return false; | ||
} else if (jail && location.indexOf(path.normalize(jail.trim(path.sep))) !== 0) { | ||
return null; | ||
} else if (jail && resolved.indexOf(path.normalize(jail.trim(path.sep))) !== 0) { | ||
return null; | ||
} | ||
} | ||
if (options.modulesOnly && (await exists(resolved))) { | ||
const code = await readFile(resolved, 'utf-8'); | ||
if (options.modulesOnly && (await exists(location))) { | ||
const code = await readFile(location, 'utf-8'); | ||
if (isModule__default['default'](code)) { | ||
return { | ||
id: `${resolved}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(resolved) | ||
id: `${location}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(location) | ||
}; | ||
@@ -544,4 +804,4 @@ } | ||
const result = { | ||
id: `${resolved}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(resolved) | ||
id: `${location}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(location) | ||
}; | ||
@@ -548,0 +808,0 @@ return result; |
@@ -1,2 +0,2 @@ | ||
import { dirname, resolve, extname, normalize, sep } from 'path'; | ||
import path, { dirname, resolve, extname, normalize, sep } from 'path'; | ||
import builtinList from 'builtin-modules'; | ||
@@ -7,4 +7,4 @@ import deepMerge from 'deepmerge'; | ||
import { promisify } from 'util'; | ||
import resolve$1 from 'resolve'; | ||
import { createFilter } from '@rollup/pluginutils'; | ||
import resolveModule from 'resolve'; | ||
@@ -70,4 +70,2 @@ const exists = promisify(fs.exists); | ||
const resolveId = promisify(resolveModule); | ||
// returns the imported package name for bare module imports | ||
@@ -125,3 +123,3 @@ function getPackageName(id) { | ||
// copy as we are about to munge the `main` field of `pkg`. | ||
packageJson: Object.assign({}, pkg), | ||
packageJson: { ...pkg }, | ||
@@ -224,33 +222,302 @@ // path to package.json file | ||
// Resolve module specifiers in order. Promise resolves to the first module that resolves | ||
// successfully, or the error that resulted from the last attempted module resolution. | ||
function resolveImportSpecifiers(importSpecifierList, resolveOptions) { | ||
let promise = Promise.resolve(); | ||
const resolveImportPath = promisify(resolve$1); | ||
const readFile$1 = promisify(fs.readFile); | ||
for (let i = 0; i < importSpecifierList.length; i++) { | ||
// eslint-disable-next-line no-loop-func | ||
promise = promise.then(async (value) => { | ||
// if we've already resolved to something, just return it. | ||
if (value) { | ||
return value; | ||
const pathNotFoundError = (subPath, pkgPath) => | ||
new Error(`Package subpath '${subPath}' is not defined by "exports" in ${pkgPath}`); | ||
function findExportKeyMatch(exportMap, subPath) { | ||
for (const key of Object.keys(exportMap)) { | ||
if (key.endsWith('*')) { | ||
// star match: "./foo/*": "./foo/*.js" | ||
const keyWithoutStar = key.substring(0, key.length - 1); | ||
if (subPath.startsWith(keyWithoutStar)) { | ||
return key; | ||
} | ||
} | ||
let result = await resolveId(importSpecifierList[i], resolveOptions); | ||
if (!resolveOptions.preserveSymlinks) { | ||
if (await exists(result)) { | ||
result = await realpath(result); | ||
} | ||
if (key.endsWith('/') && subPath.startsWith(key)) { | ||
// directory match (deprecated by node): "./foo/": "./foo/.js" | ||
return key; | ||
} | ||
if (key === subPath) { | ||
// literal match | ||
return key; | ||
} | ||
} | ||
return null; | ||
} | ||
function mapSubPath(pkgJsonPath, subPath, key, value) { | ||
if (typeof value === 'string') { | ||
if (typeof key === 'string' && key.endsWith('*')) { | ||
// star match: "./foo/*": "./foo/*.js" | ||
const keyWithoutStar = key.substring(0, key.length - 1); | ||
const subPathAfterKey = subPath.substring(keyWithoutStar.length); | ||
return value.replace(/\*/g, subPathAfterKey); | ||
} | ||
if (value.endsWith('/')) { | ||
// directory match (deprecated by node): "./foo/": "./foo/.js" | ||
return `${value}${subPath.substring(key.length)}`; | ||
} | ||
// mapping is a string, for example { "./foo": "./dist/foo.js" } | ||
return value; | ||
} | ||
if (Array.isArray(value)) { | ||
// mapping is an array with fallbacks, for example { "./foo": ["foo:bar", "./dist/foo.js"] } | ||
return value.find((v) => v.startsWith('./')); | ||
} | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
function findEntrypoint(pkgJsonPath, subPath, exportMap, conditions, key) { | ||
if (typeof exportMap !== 'object') { | ||
return mapSubPath(pkgJsonPath, subPath, key, exportMap); | ||
} | ||
// iterate conditions recursively, find the first that matches all conditions | ||
for (const [condition, subExportMap] of Object.entries(exportMap)) { | ||
if (conditions.includes(condition)) { | ||
const mappedSubPath = findEntrypoint(pkgJsonPath, subPath, subExportMap, conditions, key); | ||
if (mappedSubPath) { | ||
return mappedSubPath; | ||
} | ||
return result; | ||
} | ||
} | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
function findEntrypointTopLevel(pkgJsonPath, subPath, exportMap, conditions) { | ||
if (typeof exportMap !== 'object') { | ||
// the export map shorthand, for example { exports: "./index.js" } | ||
if (subPath !== '.') { | ||
// shorthand only supports a main entrypoint | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
return mapSubPath(pkgJsonPath, subPath, null, exportMap); | ||
} | ||
// export map is an object, the top level can be either conditions or sub path mappings | ||
const keys = Object.keys(exportMap); | ||
const isConditions = keys.every((k) => !k.startsWith('.')); | ||
const isMappings = keys.every((k) => k.startsWith('.')); | ||
if (!isConditions && !isMappings) { | ||
throw new Error( | ||
`Invalid package config ${pkgJsonPath}, "exports" cannot contain some keys starting with '.'` + | ||
' and some not. The exports object must either be an object of package subpath keys or an object of main entry' + | ||
' condition name keys only.' | ||
); | ||
} | ||
let key = null; | ||
let exportMapForSubPath; | ||
if (isConditions) { | ||
// top level is conditions, for example { "import": ..., "require": ..., "module": ... } | ||
if (subPath !== '.') { | ||
// package with top level conditions means it only supports a main entrypoint | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
exportMapForSubPath = exportMap; | ||
} else { | ||
// top level is sub path mappings, for example { ".": ..., "./foo": ..., "./bar": ... } | ||
key = findExportKeyMatch(exportMap, subPath); | ||
if (!key) { | ||
throw pathNotFoundError(subPath, pkgJsonPath); | ||
} | ||
exportMapForSubPath = exportMap[key]; | ||
} | ||
return findEntrypoint(pkgJsonPath, subPath, exportMapForSubPath, conditions, key); | ||
} | ||
async function resolveId({ | ||
importPath, | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}) { | ||
let hasModuleSideEffects = () => null; | ||
let hasPackageEntry = true; | ||
let packageBrowserField = false; | ||
let packageInfo; | ||
const filter = (pkg, pkgPath) => { | ||
const info = getPackageInfo({ | ||
cache: packageInfoCache, | ||
extensions, | ||
pkg, | ||
pkgPath, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides | ||
}); | ||
// swallow MODULE_NOT_FOUND errors | ||
promise = promise.catch((error) => { | ||
({ packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = info); | ||
return info.cachedPkg; | ||
}; | ||
const resolveOptions = { | ||
basedir: baseDir, | ||
readFile: readCachedFile, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions, | ||
includeCoreModules: false, | ||
moduleDirectory: moduleDirectories, | ||
preserveSymlinks, | ||
packageFilter: filter | ||
}; | ||
let location; | ||
const pkgName = getPackageName(importPath); | ||
if (pkgName) { | ||
let pkgJsonPath; | ||
let pkgJson; | ||
try { | ||
pkgJsonPath = await resolveImportPath(`${pkgName}/package.json`, resolveOptions); | ||
pkgJson = JSON.parse(await readFile$1(pkgJsonPath, 'utf-8')); | ||
} catch (_) { | ||
// if there is no package.json we defer to regular resolve behavior | ||
} | ||
if (pkgJsonPath && pkgJson && pkgJson.exports) { | ||
try { | ||
const packageSubPath = | ||
pkgName === importPath ? '.' : `.${importPath.substring(pkgName.length)}`; | ||
const mappedSubPath = findEntrypointTopLevel( | ||
pkgJsonPath, | ||
packageSubPath, | ||
pkgJson.exports, | ||
exportConditions | ||
); | ||
const pkgDir = path.dirname(pkgJsonPath); | ||
location = path.join(pkgDir, mappedSubPath); | ||
} catch (error) { | ||
warn(error); | ||
return null; | ||
} | ||
} | ||
} | ||
if (!location) { | ||
try { | ||
location = await resolveImportPath(importPath, resolveOptions); | ||
} catch (error) { | ||
if (error.code !== 'MODULE_NOT_FOUND') { | ||
throw error; | ||
} | ||
return null; | ||
} | ||
} | ||
if (!preserveSymlinks) { | ||
if (await exists(location)) { | ||
location = await realpath(location); | ||
} | ||
} | ||
return { | ||
location, | ||
hasModuleSideEffects, | ||
hasPackageEntry, | ||
packageBrowserField, | ||
packageInfo | ||
}; | ||
} | ||
// Resolve module specifiers in order. Promise resolves to the first module that resolves | ||
// successfully, or the error that resulted from the last attempted module resolution. | ||
async function resolveImportSpecifiers({ | ||
importSpecifierList, | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}) { | ||
for (let i = 0; i < importSpecifierList.length; i++) { | ||
// eslint-disable-next-line no-await-in-loop | ||
const resolved = await resolveId({ | ||
importPath: importSpecifierList[i], | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}); | ||
if (resolved) { | ||
return resolved; | ||
} | ||
} | ||
return null; | ||
} | ||
return promise; | ||
function handleDeprecatedOptions(opts) { | ||
const warnings = []; | ||
if (opts.customResolveOptions) { | ||
const { customResolveOptions } = opts; | ||
if (customResolveOptions.moduleDirectory) { | ||
// eslint-disable-next-line no-param-reassign | ||
opts.moduleDirectories = Array.isArray(customResolveOptions.moduleDirectory) | ||
? customResolveOptions.moduleDirectory | ||
: [customResolveOptions.moduleDirectory]; | ||
warnings.push( | ||
'node-resolve: The `customResolveOptions.moduleDirectory` option has been deprecated. Use `moduleDirectories`, which must be an array.' | ||
); | ||
} | ||
if (customResolveOptions.preserveSymlinks) { | ||
throw new Error( | ||
'node-resolve: `customResolveOptions.preserveSymlinks` is no longer an option. We now always use the rollup `preserveSymlinks` option.' | ||
); | ||
} | ||
[ | ||
'basedir', | ||
'package', | ||
'extensions', | ||
'includeCoreModules', | ||
'readFile', | ||
'isFile', | ||
'isDirectory', | ||
'realpath', | ||
'packageFilter', | ||
'pathFilter', | ||
'paths', | ||
'packageIterator' | ||
].forEach((resolveOption) => { | ||
if (customResolveOptions[resolveOption]) { | ||
throw new Error( | ||
`node-resolve: \`customResolveOptions.${resolveOption}\` is no longer an option. If you need this, please open an issue.` | ||
); | ||
} | ||
}); | ||
} | ||
return { warnings }; | ||
} | ||
@@ -262,3 +529,2 @@ | ||
const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js'; | ||
const nullFn = () => null; | ||
const deepFreeze = (object) => { | ||
@@ -275,4 +541,7 @@ Object.freeze(object); | ||
}; | ||
const baseConditions = ['default', 'module']; | ||
const baseConditionsEsm = [...baseConditions, 'import']; | ||
const baseConditionsCjs = [...baseConditions, 'require']; | ||
const defaults = { | ||
customResolveOptions: {}, | ||
dedupe: [], | ||
@@ -282,3 +551,4 @@ // It's important that .mjs is listed before .js so that Rollup will interpret npm modules | ||
extensions: ['.mjs', '.js', '.json', '.node'], | ||
resolveOnly: [] | ||
resolveOnly: [], | ||
moduleDirectories: ['node_modules'] | ||
}; | ||
@@ -288,5 +558,8 @@ const DEFAULTS = deepFreeze(deepMerge({}, defaults)); | ||
function nodeResolve(opts = {}) { | ||
const options = Object.assign({}, defaults, opts); | ||
const { customResolveOptions, extensions, jail } = options; | ||
const warnings = []; | ||
const { warnings } = handleDeprecatedOptions(opts); | ||
const options = { ...defaults, ...opts }; | ||
const { extensions, jail, moduleDirectories } = options; | ||
const conditionsEsm = [...baseConditionsEsm, ...(options.exportConditions || [])]; | ||
const conditionsCjs = [...baseConditionsCjs, ...(options.exportConditions || [])]; | ||
const packageInfoCache = new Map(); | ||
@@ -302,7 +575,2 @@ const idToPackageInfo = new Map(); | ||
if (options.only) { | ||
warnings.push('node-resolve: The `only` options is deprecated, please use `resolveOnly`'); | ||
options.resolveOnly = options.only; | ||
} | ||
if (typeof dedupe !== 'function') { | ||
@@ -343,3 +611,3 @@ dedupe = (importee) => | ||
async resolveId(importee, importer) { | ||
async resolveId(importee, importer, opts) { | ||
if (importee === ES6_BROWSER_EMPTY) { | ||
@@ -360,3 +628,3 @@ return importee; | ||
const basedir = !importer || dedupe(importee) ? rootDir : dirname(importer); | ||
const baseDir = !importer || dedupe(importee) ? rootDir : dirname(importer); | ||
@@ -366,3 +634,3 @@ // https://github.com/defunctzombie/package-browser-field-spec | ||
if (useBrowserOverrides && browser) { | ||
const resolvedImportee = resolve(basedir, importee); | ||
const resolvedImportee = resolve(baseDir, importee); | ||
if (browser[importee] === false || browser[resolvedImportee] === false) { | ||
@@ -390,3 +658,3 @@ return ES6_BROWSER_EMPTY; | ||
// an import relative to the parent dir of the importer | ||
id = resolve(basedir, importee); | ||
id = resolve(baseDir, importee); | ||
isRelativeImport = true; | ||
@@ -406,36 +674,2 @@ } | ||
let hasModuleSideEffects = nullFn; | ||
let hasPackageEntry = true; | ||
let packageBrowserField = false; | ||
let packageInfo; | ||
const filter = (pkg, pkgPath) => { | ||
const info = getPackageInfo({ | ||
cache: packageInfoCache, | ||
extensions, | ||
pkg, | ||
pkgPath, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides | ||
}); | ||
({ packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = info); | ||
return info.cachedPkg; | ||
}; | ||
let resolveOptions = { | ||
basedir, | ||
packageFilter: filter, | ||
readFile: readCachedFile, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions | ||
}; | ||
if (preserveSymlinks !== undefined) { | ||
resolveOptions.preserveSymlinks = preserveSymlinks; | ||
} | ||
const importSpecifierList = []; | ||
@@ -455,3 +689,3 @@ | ||
if (importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet)) { | ||
if (importeeIsBuiltin) { | ||
// The `resolve` library will not resolve packages with the same | ||
@@ -476,5 +710,30 @@ // name as a node built-in module. If we're resolving something | ||
importSpecifierList.push(importee); | ||
resolveOptions = Object.assign(resolveOptions, customResolveOptions); | ||
let resolved = await resolveImportSpecifiers(importSpecifierList, resolveOptions); | ||
const warn = (...args) => this.warn(...args); | ||
const isRequire = | ||
opts && opts.custom && opts.custom['node-resolve'] && opts.custom['node-resolve'].isRequire; | ||
const exportConditions = isRequire ? conditionsCjs : conditionsEsm; | ||
const resolvedWithoutBuiltins = await resolveImportSpecifiers({ | ||
importSpecifierList, | ||
exportConditions, | ||
warn, | ||
packageInfoCache, | ||
extensions, | ||
mainFields, | ||
preserveSymlinks, | ||
useBrowserOverrides, | ||
baseDir, | ||
moduleDirectories | ||
}); | ||
const resolved = | ||
importeeIsBuiltin && preferBuiltins | ||
? { | ||
packageInfo: undefined, | ||
hasModuleSideEffects: () => null, | ||
hasPackageEntry: true, | ||
packageBrowserField: false | ||
} | ||
: resolvedWithoutBuiltins; | ||
if (!resolved) { | ||
@@ -484,43 +743,43 @@ return null; | ||
const { packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = resolved; | ||
let { location } = resolved; | ||
if (packageBrowserField) { | ||
if (Object.prototype.hasOwnProperty.call(packageBrowserField, resolved)) { | ||
if (!packageBrowserField[resolved]) { | ||
browserMapCache.set(resolved, packageBrowserField); | ||
if (Object.prototype.hasOwnProperty.call(packageBrowserField, location)) { | ||
if (!packageBrowserField[location]) { | ||
browserMapCache.set(location, packageBrowserField); | ||
return ES6_BROWSER_EMPTY; | ||
} | ||
resolved = packageBrowserField[resolved]; | ||
location = packageBrowserField[location]; | ||
} | ||
browserMapCache.set(resolved, packageBrowserField); | ||
browserMapCache.set(location, packageBrowserField); | ||
} | ||
if (hasPackageEntry && !preserveSymlinks) { | ||
const fileExists = await exists(resolved); | ||
const fileExists = await exists(location); | ||
if (fileExists) { | ||
resolved = await realpath(resolved); | ||
location = await realpath(location); | ||
} | ||
} | ||
idToPackageInfo.set(resolved, packageInfo); | ||
idToPackageInfo.set(location, packageInfo); | ||
if (hasPackageEntry) { | ||
if (builtins.has(resolved) && preferBuiltins && isPreferBuiltinsSet) { | ||
return null; | ||
} else if (importeeIsBuiltin && preferBuiltins) { | ||
if (!isPreferBuiltinsSet) { | ||
if (importeeIsBuiltin && preferBuiltins) { | ||
if (!isPreferBuiltinsSet && resolvedWithoutBuiltins && resolved !== importee) { | ||
this.warn( | ||
`preferring built-in module '${importee}' over local alternative at '${resolved}', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning` | ||
`preferring built-in module '${importee}' over local alternative at '${resolvedWithoutBuiltins.location}', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning` | ||
); | ||
} | ||
return false; | ||
} else if (jail && location.indexOf(normalize(jail.trim(sep))) !== 0) { | ||
return null; | ||
} else if (jail && resolved.indexOf(normalize(jail.trim(sep))) !== 0) { | ||
return null; | ||
} | ||
} | ||
if (options.modulesOnly && (await exists(resolved))) { | ||
const code = await readFile(resolved, 'utf-8'); | ||
if (options.modulesOnly && (await exists(location))) { | ||
const code = await readFile(location, 'utf-8'); | ||
if (isModule(code)) { | ||
return { | ||
id: `${resolved}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(resolved) | ||
id: `${location}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(location) | ||
}; | ||
@@ -531,4 +790,4 @@ } | ||
const result = { | ||
id: `${resolved}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(resolved) | ||
id: `${location}${importSuffix}`, | ||
moduleSideEffects: hasModuleSideEffects(location) | ||
}; | ||
@@ -535,0 +794,0 @@ return result; |
{ | ||
"name": "@rollup/plugin-node-resolve", | ||
"version": "10.0.0", | ||
"version": "11.0.0", | ||
"publishConfig": { | ||
@@ -62,3 +62,3 @@ "access": "public" | ||
"is-module": "^1.0.0", | ||
"resolve": "^1.17.0" | ||
"resolve": "^1.19.0" | ||
}, | ||
@@ -69,3 +69,3 @@ "devDependencies": { | ||
"@rollup/plugin-babel": "^5.1.0", | ||
"@rollup/plugin-commonjs": "^14.0.0", | ||
"@rollup/plugin-commonjs": "^16.0.0", | ||
"@rollup/plugin-json": "^4.1.0", | ||
@@ -72,0 +72,0 @@ "es5-ext": "^0.10.53", |
@@ -47,2 +47,13 @@ [npm]: https://img.shields.io/npm/v/@rollup/plugin-node-resolve | ||
### `exportConditions` | ||
Type: `Array[...String]`<br> | ||
Default: `[]` | ||
Additional conditions of the package.json exports field to match when resolving modules. By default, this plugin looks for the `['default', 'module', 'import']` conditions when resolving imports. | ||
When using `@rollup/plugin-commonjs` v16 or higher, this plugin will use the `['default', 'module', 'require']` conditions when resolving require statements. | ||
Setting this option will add extra conditions on top of the default conditions. See https://nodejs.org/api/packages.html#packages_conditional_exports for more information. | ||
### `browser` | ||
@@ -55,15 +66,9 @@ | ||
### `customResolveOptions` | ||
### `moduleDirectories` | ||
Type: `Object`<br> | ||
Default: `null` | ||
Type: `Array[...String]`<br> | ||
Default: `['node_modules']` | ||
An `Object` that specifies additional options that should be passed through to [`resolve`](https://www.npmjs.com/package/resolve). | ||
One or more directories in which to recursively look for modules. | ||
``` | ||
customResolveOptions: { | ||
moduleDirectory: 'js_modules' | ||
} | ||
``` | ||
### `dedupe` | ||
@@ -106,3 +111,3 @@ | ||
Locks the module search within specified path (e.g. chroot). Modules defined outside this path will be marked as external. | ||
Locks the module search within specified path (e.g. chroot). Modules defined outside this path will be ignored by this plugin. | ||
@@ -117,10 +122,6 @@ ### `mainFields` | ||
### `only` | ||
DEPRECATED: use "resolveOnly" instead | ||
### `preferBuiltins` | ||
Type: `Boolean`<br> | ||
Default: `true` | ||
Default: `true` (with warnings if a builtin module is used over a local version. Set to `true` to disable warning.) | ||
@@ -157,2 +158,6 @@ If `true`, the plugin will prefer built-in modules (e.g. `fs`, `path`). If `false`, the plugin will look for locally installed modules of the same name. | ||
## Preserving symlinks | ||
This plugin honours the rollup [`preserveSymlinks`](https://rollupjs.org/guide/en/#preservesymlinks) option. | ||
## Using with @rollup/plugin-commonjs | ||
@@ -164,3 +169,3 @@ | ||
// rollup.config.js | ||
import resolve from '@rollup/plugin-node-resolve'; | ||
import { nodeResolve } from '@rollup/plugin-node-resolve'; | ||
import commonjs from '@rollup/plugin-commonjs'; | ||
@@ -175,3 +180,3 @@ | ||
}, | ||
plugins: [resolve(), commonjs()] | ||
plugins: [nodeResolve(), commonjs()] | ||
}; | ||
@@ -182,12 +187,14 @@ ``` | ||
This plugin won't resolve any builtins (e.g. `fs`). If you need to resolve builtins you can install local modules and set `preferBuiltins` to `false`, or install a plugin like [rollup-plugin-node-polyfills](https://github.com/ionic-team/rollup-plugin-node-polyfills) which provides stubbed versions of these methods. | ||
By default this plugin will prefer built-ins over local modules, marking them as external. | ||
If you want to silence warnings about builtins, you can add the list of builtins to the `externals` option; like so: | ||
See [`preferBuiltins`](#preferbuiltins). | ||
To provide stubbed versions of Node built-ins, yse a plugin like [rollup-plugin-node-polyfills](https://github.com/ionic-team/rollup-plugin-node-polyfills) or use [`builtin-modules`](https://github.com/sindresorhus/builtin-modules) with `external`, and set `preferBuiltins` to `false`. e.g. | ||
```js | ||
import resolve from '@rollup/plugin-node-resolve'; | ||
import { nodeResolve } from '@rollup/plugin-node-resolve'; | ||
import builtins from 'builtin-modules' | ||
export default ({ | ||
input: ..., | ||
plugins: [resolve()], | ||
plugins: [nodeResolve()], | ||
external: builtins, | ||
@@ -198,2 +205,15 @@ output: ... | ||
## Resolving require statements | ||
According to [NodeJS module resolution](https://nodejs.org/api/packages.html#packages_package_entry_points) `require` statements should resolve using the `require` condition in the package exports field, while es modules should use the `import` condition. | ||
The node resolve plugin uses `import` by default, you can opt into using the `require` semantics by passing an extra option to the resolve function: | ||
```js | ||
this.resolve(importee, importer, { | ||
skipSelf: true, | ||
custom: { 'node-resolve': { isRequire: true } } | ||
}); | ||
``` | ||
## Meta | ||
@@ -200,0 +220,0 @@ |
@@ -1,4 +0,1 @@ | ||
import { Plugin } from 'rollup'; | ||
import { AsyncOpts } from 'resolve'; | ||
export const DEFAULTS: { | ||
@@ -13,2 +10,14 @@ customResolveOptions: {}; | ||
/** | ||
* Additional conditions of the package.json exports field to match when resolving modules. | ||
* By default, this plugin looks for the `'default', 'module', 'import']` conditions when resolving imports. | ||
* | ||
* When using `@rollup/plugin-commonjs` v16 or higher, this plugin will use the | ||
* `['default', 'module', 'import']` conditions when resolving require statements. | ||
* | ||
* Setting this option will add extra conditions on top of the default conditions. | ||
* See https://nodejs.org/api/packages.html#packages_conditional_exports for more information. | ||
*/ | ||
exportConditions?: string[]; | ||
/** | ||
* If `true`, instructs the plugin to use the `"browser"` property in `package.json` | ||
@@ -24,5 +33,6 @@ * files to specify alternative files to load for bundling. This is useful when | ||
/** | ||
* An `Object` that specifies additional options that should be passed through to `node-resolve`. | ||
* One or more directories in which to recursively look for modules. | ||
* @default ['node_modules'] | ||
*/ | ||
customResolveOptions?: AsyncOpts; | ||
moduleDirectories?: string[]; | ||
@@ -63,8 +73,2 @@ /** | ||
/** | ||
* @deprecated use "resolveOnly" instead | ||
* @default null | ||
*/ | ||
only?: ReadonlyArray<string | RegExp> | null; | ||
/** | ||
* If `true`, the plugin will prefer built-in modules (e.g. `fs`, `path`). If `false`, | ||
@@ -71,0 +75,0 @@ * the plugin will look for locally installed modules of the same name. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
71321
1466
215
Updatedresolve@^1.19.0