rollup-plugin-node-resolve
Advanced tools
Comparing version
# rollup-plugin-node-resolve changelog | ||
## 4.2.4 (2019-05-11) | ||
* Add note on builtins to Readme ([#215](https://github.com/rollup/rollup-plugin-node-resolve/pull/215) by @keithamus) | ||
* Add issue templates ([#217](https://github.com/rollup/rollup-plugin-node-resolve/pull/217) by @mecurc) | ||
* Improve performance by caching `isDir` ([#218](https://github.com/rollup/rollup-plugin-node-resolve/pull/218) by @keithamus) | ||
## 4.2.3 (2019-04-11) | ||
* Fix ordering of jsnext:main when using the jsnext option ([#209](https://github.com/rollup/rollup-plugin-node-resolve/pull/209) by @lukastaegert) | ||
## 4.2.2 (2019-04-10) | ||
* Fix TypeScript typings (rename and export Options interface) ([#206](https://github.com/rollup/rollup-plugin-node-resolve/pull/206) by @Kocal) | ||
* Fix mainfields typing ([#207](https://github.com/rollup/rollup-plugin-node-resolve/pull/207) by @nicolashenry) | ||
## 4.2.1 (2019-04-06) | ||
* Respect setting the deprecated fields "module", "main", and "jsnext" ([#204](https://github.com/rollup/rollup-plugin-node-resolve/pull/204) by @nick-woodward) | ||
## 4.2.0 (2019-04-06) | ||
* Add new mainfields option ([#182](https://github.com/rollup/rollup-plugin-node-resolve/pull/182) by @keithamus) | ||
* Added dedupe option to prevent bundling the same package multiple times ([#201](https://github.com/rollup/rollup-plugin-node-resolve/pull/182) by @sormy) | ||
## 4.1.0 (2019-04-05) | ||
* Add TypeScript typings ([#189](https://github.com/rollup/rollup-plugin-node-resolve/pull/189) by @NotWoods) | ||
* Update dependencies ([#202](https://github.com/rollup/rollup-plugin-node-resolve/pull/202) by @lukastaegert) | ||
## 4.0.1 (2019-02-22) | ||
* Fix issue when external modules are specified in `package.browser` ([#143](https://github.com/rollup/rollup-plugin-node-resolve/pull/143) by @keithamus) | ||
* Fix `package.browser` mapping issue when `false` is specified ([#183](https://github.com/rollup/rollup-plugin-node-resolve/pull/183) by @allex) | ||
## 4.0.0 (2018-12-09) | ||
@@ -4,0 +38,0 @@ |
@@ -16,28 +16,58 @@ 'use strict'; | ||
var readFileCache = {}; | ||
var readFileAsync = function (file) { return new Promise(function (fulfil, reject) { return fs.readFile(file, function (err, contents) { return err ? reject(err) : fulfil(contents); }); }); }; | ||
var statAsync = function (file) { return new Promise(function (fulfil, reject) { return fs.stat(file, function (err, contents) { return err ? reject(err) : fulfil(contents); }); }); }; | ||
function cachedReadFile (file, cb) { | ||
if (file in readFileCache === false) { | ||
readFileCache[file] = readFileAsync(file).catch(function (err) { | ||
delete readFileCache[file]; | ||
throw err; | ||
var cache = function (fn) { | ||
var cache = new Map(); | ||
var wrapped = function (param, done) { | ||
if (cache.has(param) === false) { | ||
cache.set(param, fn(param).catch(function (err) { | ||
cache.delete(param); | ||
throw err; | ||
})); | ||
} | ||
return cache.get(param).then(function (result) { return done(null, result); }, done); | ||
}; | ||
wrapped.clear = function () { return cache.clear(); }; | ||
return wrapped; | ||
}; | ||
var ignoreENOENT = function (err) { | ||
if (err.code === 'ENOENT') { return false; } | ||
throw err; | ||
}; | ||
var readFileCached = cache(readFileAsync); | ||
var isDirCached = cache(function (file) { return statAsync(file).then(function (stat) { return stat.isDirectory(); }, ignoreENOENT); }); | ||
var isFileCached = cache(function (file) { return statAsync(file).then(function (stat) { return stat.isFile(); }, ignoreENOENT); }); | ||
function getMainFields (options) { | ||
var mainFields; | ||
if (options.mainFields) { | ||
if ('module' in options || 'main' in options || 'jsnext' in options) { | ||
throw new Error("node-resolve: do not use deprecated 'module', 'main', 'jsnext' options with 'mainFields'"); | ||
} | ||
mainFields = options.mainFields; | ||
} else { | ||
mainFields = []; | ||
[['module', 'module', true], ['jsnext', 'jsnext:main', false], ['main', 'main', true]].forEach(function (ref) { | ||
var option = ref[0]; | ||
var field = ref[1]; | ||
var defaultIncluded = ref[2]; | ||
if (option in options) { | ||
// eslint-disable-next-line no-console | ||
console.warn(("node-resolve: setting options." + option + " is deprecated, please override options.mainFields instead")); | ||
if (options[option]) { | ||
mainFields.push(field); | ||
} | ||
} else if (defaultIncluded) { | ||
mainFields.push(field); | ||
} | ||
}); | ||
} | ||
readFileCache[file].then(function (contents) { return cb(null, contents); }, cb); | ||
} | ||
var isFileCache = {}; | ||
function cachedIsFile (file, cb) { | ||
if (file in isFileCache === false) { | ||
isFileCache[file] = statAsync(file) | ||
.then( | ||
function (stat) { return stat.isFile(); }, | ||
function (err) { | ||
if (err.code == 'ENOENT') { return false; } | ||
delete isFileCache[file]; | ||
throw err; | ||
}); | ||
if (options.browser && mainFields.indexOf('browser') === -1) { | ||
return ['browser'].concat(mainFields); | ||
} | ||
isFileCache[file].then(function (contents) { return cb(null, contents); }, cb); | ||
if ( !mainFields.length ) { | ||
throw new Error( "Please ensure at least one 'mainFields' value is specified" ); | ||
} | ||
return mainFields; | ||
} | ||
@@ -50,5 +80,5 @@ | ||
var useModule = options.module !== false; | ||
var useMain = options.main !== false; | ||
var useJsnext = options.jsnext === true; | ||
var mainFields = getMainFields(options); | ||
var useBrowserOverrides = mainFields.indexOf('browser') !== -1; | ||
var dedupe = options.dedupe || []; | ||
var isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false; | ||
@@ -70,6 +100,2 @@ var preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true; | ||
if ( !useModule && !useMain && !useJsnext ) { | ||
throw new Error( "At least one of options.module, options.main or options.jsnext must be true" ); | ||
} | ||
var preserveSymlinks; | ||
@@ -85,7 +111,8 @@ | ||
generateBundle: function generateBundle () { | ||
isFileCache = {}; | ||
readFileCache = {}; | ||
readFileCached.clear(); | ||
isFileCached.clear(); | ||
isDirCached.clear(); | ||
}, | ||
resolveId: function resolveId$$1 ( importee, importer ) { | ||
resolveId: function resolveId ( importee, importer ) { | ||
var this$1 = this; | ||
@@ -97,3 +124,8 @@ | ||
if (options.browser && browserMapCache[importer]) { | ||
if (dedupe.indexOf(importee) !== -1) { | ||
importee = path.join(process.cwd(), 'node_modules', importee); | ||
} | ||
// https://github.com/defunctzombie/package-browser-field-spec | ||
if (useBrowserOverrides && browserMapCache[importer]) { | ||
var resolvedImportee = path.resolve( basedir, importee ); | ||
@@ -109,3 +141,2 @@ var browser = browserMapCache[importer]; | ||
var parts = importee.split( /[/\\]/ ); | ||
@@ -132,5 +163,8 @@ var id = parts.shift(); | ||
var pkgRoot = path.dirname( pkgPath ); | ||
if (options.browser && typeof pkg[ 'browser' ] === 'object') { | ||
if (useBrowserOverrides && typeof pkg[ 'browser' ] === 'object') { | ||
packageBrowserField = Object.keys(pkg[ 'browser' ]).reduce(function (browser, key) { | ||
var resolved = pkg[ 'browser' ][ key ] === false ? false : path.resolve( pkgRoot, pkg[ 'browser' ][ key ] ); | ||
var resolved = pkg[ 'browser' ][ key ]; | ||
if (resolved && resolved[0] === '.') { | ||
resolved = path.resolve( pkgRoot, pkg[ 'browser' ][ key ] ); | ||
} | ||
browser[ key ] = resolved; | ||
@@ -151,9 +185,12 @@ if ( key[0] === '.' ) { | ||
if (options.browser && typeof pkg[ 'browser' ] === 'string') { | ||
pkg[ 'main' ] = pkg[ 'browser' ]; | ||
} else if ( useModule && pkg[ 'module' ] ) { | ||
pkg[ 'main' ] = pkg[ 'module' ]; | ||
} else if ( useJsnext && pkg[ 'jsnext:main' ] ) { | ||
pkg[ 'main' ] = pkg[ 'jsnext:main' ]; | ||
} else if ( ( useJsnext || useModule ) && !useMain ) { | ||
var overriddenMain = false; | ||
for ( var i = 0; i < mainFields.length; i++ ) { | ||
var field = mainFields[i]; | ||
if ( typeof pkg[ field ] === 'string' ) { | ||
pkg[ 'main' ] = pkg[ field ]; | ||
overriddenMain = true; | ||
break; | ||
} | ||
} | ||
if ( overriddenMain === false && mainFields.indexOf( 'main' ) === -1 ) { | ||
disregardResult = true; | ||
@@ -163,4 +200,5 @@ } | ||
}, | ||
readFile: cachedReadFile, | ||
isFile: cachedIsFile, | ||
readFile: readFileCached, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions: extensions | ||
@@ -177,6 +215,9 @@ }; | ||
) | ||
.catch(function () { return false; }) | ||
.then(function (resolved) { | ||
if (options.browser && packageBrowserField) { | ||
if (packageBrowserField[ resolved ]) { | ||
if ( resolved && useBrowserOverrides && packageBrowserField ) { | ||
if ( packageBrowserField.hasOwnProperty(resolved) ) { | ||
if (!packageBrowserField[resolved]) { | ||
browserMapCache[resolved] = packageBrowserField; | ||
return ES6_BROWSER_EMPTY; | ||
} | ||
resolved = packageBrowserField[ resolved ]; | ||
@@ -187,3 +228,3 @@ } | ||
if ( !disregardResult && resolved !== false ) { | ||
if ( !disregardResult ) { | ||
if ( !preserveSymlinks && resolved && fs.existsSync( resolved ) ) { | ||
@@ -212,5 +253,6 @@ resolved = fs.realpathSync( resolved ); | ||
} else { | ||
return resolved === false ? null : resolved; | ||
return resolved; | ||
} | ||
}); | ||
}) | ||
.catch(function () { return null; }); | ||
} | ||
@@ -217,0 +259,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
import { dirname, extname, normalize, resolve, sep } from 'path'; | ||
import { dirname, join, resolve, normalize, sep, extname } from 'path'; | ||
import builtins from 'builtin-modules'; | ||
@@ -12,28 +12,58 @@ import resolveId from 'resolve'; | ||
var readFileCache = {}; | ||
var readFileAsync = function (file) { return new Promise(function (fulfil, reject) { return fs.readFile(file, function (err, contents) { return err ? reject(err) : fulfil(contents); }); }); }; | ||
var statAsync = function (file) { return new Promise(function (fulfil, reject) { return fs.stat(file, function (err, contents) { return err ? reject(err) : fulfil(contents); }); }); }; | ||
function cachedReadFile (file, cb) { | ||
if (file in readFileCache === false) { | ||
readFileCache[file] = readFileAsync(file).catch(function (err) { | ||
delete readFileCache[file]; | ||
throw err; | ||
var cache = function (fn) { | ||
var cache = new Map(); | ||
var wrapped = function (param, done) { | ||
if (cache.has(param) === false) { | ||
cache.set(param, fn(param).catch(function (err) { | ||
cache.delete(param); | ||
throw err; | ||
})); | ||
} | ||
return cache.get(param).then(function (result) { return done(null, result); }, done); | ||
}; | ||
wrapped.clear = function () { return cache.clear(); }; | ||
return wrapped; | ||
}; | ||
var ignoreENOENT = function (err) { | ||
if (err.code === 'ENOENT') { return false; } | ||
throw err; | ||
}; | ||
var readFileCached = cache(readFileAsync); | ||
var isDirCached = cache(function (file) { return statAsync(file).then(function (stat) { return stat.isDirectory(); }, ignoreENOENT); }); | ||
var isFileCached = cache(function (file) { return statAsync(file).then(function (stat) { return stat.isFile(); }, ignoreENOENT); }); | ||
function getMainFields (options) { | ||
var mainFields; | ||
if (options.mainFields) { | ||
if ('module' in options || 'main' in options || 'jsnext' in options) { | ||
throw new Error("node-resolve: do not use deprecated 'module', 'main', 'jsnext' options with 'mainFields'"); | ||
} | ||
mainFields = options.mainFields; | ||
} else { | ||
mainFields = []; | ||
[['module', 'module', true], ['jsnext', 'jsnext:main', false], ['main', 'main', true]].forEach(function (ref) { | ||
var option = ref[0]; | ||
var field = ref[1]; | ||
var defaultIncluded = ref[2]; | ||
if (option in options) { | ||
// eslint-disable-next-line no-console | ||
console.warn(("node-resolve: setting options." + option + " is deprecated, please override options.mainFields instead")); | ||
if (options[option]) { | ||
mainFields.push(field); | ||
} | ||
} else if (defaultIncluded) { | ||
mainFields.push(field); | ||
} | ||
}); | ||
} | ||
readFileCache[file].then(function (contents) { return cb(null, contents); }, cb); | ||
} | ||
var isFileCache = {}; | ||
function cachedIsFile (file, cb) { | ||
if (file in isFileCache === false) { | ||
isFileCache[file] = statAsync(file) | ||
.then( | ||
function (stat) { return stat.isFile(); }, | ||
function (err) { | ||
if (err.code == 'ENOENT') { return false; } | ||
delete isFileCache[file]; | ||
throw err; | ||
}); | ||
if (options.browser && mainFields.indexOf('browser') === -1) { | ||
return ['browser'].concat(mainFields); | ||
} | ||
isFileCache[file].then(function (contents) { return cb(null, contents); }, cb); | ||
if ( !mainFields.length ) { | ||
throw new Error( "Please ensure at least one 'mainFields' value is specified" ); | ||
} | ||
return mainFields; | ||
} | ||
@@ -46,5 +76,5 @@ | ||
var useModule = options.module !== false; | ||
var useMain = options.main !== false; | ||
var useJsnext = options.jsnext === true; | ||
var mainFields = getMainFields(options); | ||
var useBrowserOverrides = mainFields.indexOf('browser') !== -1; | ||
var dedupe = options.dedupe || []; | ||
var isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false; | ||
@@ -66,6 +96,2 @@ var preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true; | ||
if ( !useModule && !useMain && !useJsnext ) { | ||
throw new Error( "At least one of options.module, options.main or options.jsnext must be true" ); | ||
} | ||
var preserveSymlinks; | ||
@@ -81,7 +107,8 @@ | ||
generateBundle: function generateBundle () { | ||
isFileCache = {}; | ||
readFileCache = {}; | ||
readFileCached.clear(); | ||
isFileCached.clear(); | ||
isDirCached.clear(); | ||
}, | ||
resolveId: function resolveId$$1 ( importee, importer ) { | ||
resolveId: function resolveId ( importee, importer ) { | ||
var this$1 = this; | ||
@@ -93,3 +120,8 @@ | ||
if (options.browser && browserMapCache[importer]) { | ||
if (dedupe.indexOf(importee) !== -1) { | ||
importee = join(process.cwd(), 'node_modules', importee); | ||
} | ||
// https://github.com/defunctzombie/package-browser-field-spec | ||
if (useBrowserOverrides && browserMapCache[importer]) { | ||
var resolvedImportee = resolve( basedir, importee ); | ||
@@ -105,3 +137,2 @@ var browser = browserMapCache[importer]; | ||
var parts = importee.split( /[/\\]/ ); | ||
@@ -128,5 +159,8 @@ var id = parts.shift(); | ||
var pkgRoot = dirname( pkgPath ); | ||
if (options.browser && typeof pkg[ 'browser' ] === 'object') { | ||
if (useBrowserOverrides && typeof pkg[ 'browser' ] === 'object') { | ||
packageBrowserField = Object.keys(pkg[ 'browser' ]).reduce(function (browser, key) { | ||
var resolved = pkg[ 'browser' ][ key ] === false ? false : resolve( pkgRoot, pkg[ 'browser' ][ key ] ); | ||
var resolved = pkg[ 'browser' ][ key ]; | ||
if (resolved && resolved[0] === '.') { | ||
resolved = resolve( pkgRoot, pkg[ 'browser' ][ key ] ); | ||
} | ||
browser[ key ] = resolved; | ||
@@ -147,9 +181,12 @@ if ( key[0] === '.' ) { | ||
if (options.browser && typeof pkg[ 'browser' ] === 'string') { | ||
pkg[ 'main' ] = pkg[ 'browser' ]; | ||
} else if ( useModule && pkg[ 'module' ] ) { | ||
pkg[ 'main' ] = pkg[ 'module' ]; | ||
} else if ( useJsnext && pkg[ 'jsnext:main' ] ) { | ||
pkg[ 'main' ] = pkg[ 'jsnext:main' ]; | ||
} else if ( ( useJsnext || useModule ) && !useMain ) { | ||
var overriddenMain = false; | ||
for ( var i = 0; i < mainFields.length; i++ ) { | ||
var field = mainFields[i]; | ||
if ( typeof pkg[ field ] === 'string' ) { | ||
pkg[ 'main' ] = pkg[ field ]; | ||
overriddenMain = true; | ||
break; | ||
} | ||
} | ||
if ( overriddenMain === false && mainFields.indexOf( 'main' ) === -1 ) { | ||
disregardResult = true; | ||
@@ -159,4 +196,5 @@ } | ||
}, | ||
readFile: cachedReadFile, | ||
isFile: cachedIsFile, | ||
readFile: readFileCached, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions: extensions | ||
@@ -173,6 +211,9 @@ }; | ||
) | ||
.catch(function () { return false; }) | ||
.then(function (resolved) { | ||
if (options.browser && packageBrowserField) { | ||
if (packageBrowserField[ resolved ]) { | ||
if ( resolved && useBrowserOverrides && packageBrowserField ) { | ||
if ( packageBrowserField.hasOwnProperty(resolved) ) { | ||
if (!packageBrowserField[resolved]) { | ||
browserMapCache[resolved] = packageBrowserField; | ||
return ES6_BROWSER_EMPTY; | ||
} | ||
resolved = packageBrowserField[ resolved ]; | ||
@@ -183,3 +224,3 @@ } | ||
if ( !disregardResult && resolved !== false ) { | ||
if ( !disregardResult ) { | ||
if ( !preserveSymlinks && resolved && fs.existsSync( resolved ) ) { | ||
@@ -208,5 +249,6 @@ resolved = fs.realpathSync( resolved ); | ||
} else { | ||
return resolved === false ? null : resolved; | ||
return resolved; | ||
} | ||
}); | ||
}) | ||
.catch(function () { return null; }); | ||
} | ||
@@ -213,0 +255,0 @@ }; |
{ | ||
"name": "rollup-plugin-node-resolve", | ||
"description": "Bundle third-party dependencies in node_modules", | ||
"version": "4.0.0", | ||
"version": "4.2.4", | ||
"devDependencies": { | ||
"buble": "^0.19.6", | ||
"es5-ext": "^0.10.46", | ||
"eslint": "^5.10.0", | ||
"mocha": "^5.2.0", | ||
"rollup": "^0.67.4", | ||
"rollup-plugin-buble": "^0.19.4", | ||
"rollup-plugin-commonjs": "^9.2.0", | ||
"buble": "^0.19.7", | ||
"es5-ext": "^0.10.49", | ||
"eslint": "^5.16.0", | ||
"mocha": "^6.1.2", | ||
"rollup": "^1.9.3", | ||
"rollup-plugin-buble": "^0.19.6", | ||
"rollup-plugin-commonjs": "^9.3.4", | ||
"string-capitalize": "^1.0.1", | ||
"vlq": "^1.0.0" | ||
"typescript": "^3.4.3" | ||
}, | ||
@@ -23,3 +23,3 @@ "main": "dist/rollup-plugin-node-resolve.cjs.js", | ||
"test": "mocha", | ||
"posttest": "eslint src test/*.js", | ||
"posttest": "tsc && eslint src test/*.js", | ||
"lint": "eslint src", | ||
@@ -31,8 +31,10 @@ "prepublishOnly": "npm test", | ||
"src", | ||
"dist" | ||
"dist", | ||
"index.d.ts" | ||
], | ||
"dependencies": { | ||
"builtin-modules": "^3.0.0", | ||
"@types/resolve": "0.0.8", | ||
"builtin-modules": "^3.1.0", | ||
"is-module": "^1.0.0", | ||
"resolve": "^1.8.1" | ||
"resolve": "^1.10.0" | ||
}, | ||
@@ -39,0 +41,0 @@ "repository": "rollup/rollup-plugin-node-resolve", |
@@ -23,10 +23,18 @@ # rollup-plugin-node-resolve | ||
file: 'bundle.js', | ||
format: 'iife' | ||
format: 'iife', | ||
name: 'MyModule' | ||
}, | ||
name: 'MyModule', | ||
plugins: [ | ||
resolve({ | ||
// the fields to scan in a package.json to determine the entry point | ||
// if this list contains "browser", overrides specified in "pkg.browser" | ||
// will be used | ||
mainFields: ['module', 'main'], // Default: ['module', 'main'] | ||
// DEPRECATED: use "mainFields" instead | ||
// use "module" field for ES6 module if possible | ||
module: true, // Default: true | ||
// DEPRECATED: use "mainFields" instead | ||
// use "jsnext:main" if possible | ||
@@ -38,11 +46,12 @@ // legacy field pointing to ES6 module in third-party libraries, | ||
// DEPRECATED: use "mainFields" instead | ||
// use "main" field or index.js, even if it's not an ES6 module | ||
// (needs to be converted from CommonJS to ES6 | ||
// (needs to be converted from CommonJS to ES6) | ||
// – see https://github.com/rollup/rollup-plugin-commonjs | ||
main: true, // Default: true | ||
// some package.json files have a `browser` field which | ||
// specifies alternative files to load for people bundling | ||
// for the browser. If that's you, use this option, otherwise | ||
// pkg.browser will be ignored | ||
// some package.json files have a "browser" field which specifies | ||
// alternative files to load for people bundling for the browser. If | ||
// that's you, either use this option or add "browser" to the | ||
// "mainfields" option, otherwise pkg.browser will be ignored | ||
browser: true, // Default: false | ||
@@ -70,2 +79,7 @@ | ||
// Force resolving for these modules to root's node_modules that helps | ||
// to prevent bundling the same package multiple times if package is | ||
// imported from dependencies. | ||
dedupe: [ 'react', 'react-dom' ], // Default: [] | ||
// Any additional options that should be passed through | ||
@@ -104,5 +118,22 @@ // to node-resolve | ||
## Resolving Built-Ins (like `fs`) | ||
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-builtins](https://github.com/calvinmetcalf/rollup-plugin-node-builtins) which provides stubbed versions of these methods. | ||
If you want to silence warnings about builtins, you can add the list of builtins to the `externals` option; like so: | ||
```js | ||
import resolve from 'rollup-plugin-node-resolve'; | ||
import builtins from 'builtin-modules' | ||
export default ({ | ||
input: ..., | ||
plugins: [resolve()], | ||
externals: builtins, | ||
output: ... | ||
}) | ||
``` | ||
## License | ||
MIT |
138
src/index.js
@@ -1,2 +0,2 @@ | ||
import {dirname, extname, normalize, resolve, sep} from 'path'; | ||
import {dirname, extname, join, normalize, resolve, sep} from 'path'; | ||
import builtins from 'builtin-modules'; | ||
@@ -12,28 +12,54 @@ import resolveId from 'resolve'; | ||
let readFileCache = {}; | ||
const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, (err, contents) => err ? reject(err) : fulfil(contents))); | ||
const statAsync = file => new Promise((fulfil, reject) => fs.stat(file, (err, contents) => err ? reject(err) : fulfil(contents))); | ||
function cachedReadFile (file, cb) { | ||
if (file in readFileCache === false) { | ||
readFileCache[file] = readFileAsync(file).catch(err => { | ||
delete readFileCache[file]; | ||
throw err; | ||
const cache = fn => { | ||
const cache = new Map(); | ||
const wrapped = (param, done) => { | ||
if (cache.has(param) === false) { | ||
cache.set(param, fn(param).catch(err => { | ||
cache.delete(param); | ||
throw err; | ||
})); | ||
} | ||
return cache.get(param).then(result => done(null, result), done); | ||
}; | ||
wrapped.clear = () => cache.clear(); | ||
return wrapped; | ||
}; | ||
const ignoreENOENT = err => { | ||
if (err.code === 'ENOENT') return false; | ||
throw err; | ||
}; | ||
const readFileCached = cache(readFileAsync); | ||
const isDirCached = cache(file => statAsync(file).then(stat => stat.isDirectory(), ignoreENOENT)); | ||
const isFileCached = cache(file => statAsync(file).then(stat => stat.isFile(), ignoreENOENT)); | ||
function getMainFields (options) { | ||
let mainFields; | ||
if (options.mainFields) { | ||
if ('module' in options || 'main' in options || 'jsnext' in options) { | ||
throw new Error(`node-resolve: do not use deprecated 'module', 'main', 'jsnext' options with 'mainFields'`); | ||
} | ||
mainFields = options.mainFields; | ||
} else { | ||
mainFields = []; | ||
[['module', 'module', true], ['jsnext', 'jsnext:main', false], ['main', 'main', true]].forEach(([option, field, defaultIncluded]) => { | ||
if (option in options) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`node-resolve: setting options.${option} is deprecated, please override options.mainFields instead`); | ||
if (options[option]) { | ||
mainFields.push(field); | ||
} | ||
} else if (defaultIncluded) { | ||
mainFields.push(field); | ||
} | ||
}); | ||
} | ||
readFileCache[file].then(contents => cb(null, contents), cb); | ||
} | ||
let isFileCache = {}; | ||
function cachedIsFile (file, cb) { | ||
if (file in isFileCache === false) { | ||
isFileCache[file] = statAsync(file) | ||
.then( | ||
stat => stat.isFile(), | ||
err => { | ||
if (err.code == 'ENOENT') return false; | ||
delete isFileCache[file]; | ||
throw err; | ||
}); | ||
if (options.browser && mainFields.indexOf('browser') === -1) { | ||
return ['browser'].concat(mainFields); | ||
} | ||
isFileCache[file].then(contents => cb(null, contents), cb); | ||
if ( !mainFields.length ) { | ||
throw new Error( `Please ensure at least one 'mainFields' value is specified` ); | ||
} | ||
return mainFields; | ||
} | ||
@@ -44,5 +70,5 @@ | ||
export default function nodeResolve ( options = {} ) { | ||
const useModule = options.module !== false; | ||
const useMain = options.main !== false; | ||
const useJsnext = options.jsnext === true; | ||
const mainFields = getMainFields(options); | ||
const useBrowserOverrides = mainFields.indexOf('browser') !== -1; | ||
const dedupe = options.dedupe || []; | ||
const isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false; | ||
@@ -64,6 +90,2 @@ const preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true; | ||
if ( !useModule && !useMain && !useJsnext ) { | ||
throw new Error( `At least one of options.module, options.main or options.jsnext must be true` ); | ||
} | ||
let preserveSymlinks; | ||
@@ -79,4 +101,5 @@ | ||
generateBundle () { | ||
isFileCache = {}; | ||
readFileCache = {}; | ||
readFileCached.clear(); | ||
isFileCached.clear(); | ||
isDirCached.clear(); | ||
}, | ||
@@ -89,3 +112,8 @@ | ||
if (options.browser && browserMapCache[importer]) { | ||
if (dedupe.indexOf(importee) !== -1) { | ||
importee = join(process.cwd(), 'node_modules', importee); | ||
} | ||
// https://github.com/defunctzombie/package-browser-field-spec | ||
if (useBrowserOverrides && browserMapCache[importer]) { | ||
const resolvedImportee = resolve( basedir, importee ); | ||
@@ -101,3 +129,2 @@ const browser = browserMapCache[importer]; | ||
const parts = importee.split( /[/\\]/ ); | ||
@@ -124,5 +151,8 @@ let id = parts.shift(); | ||
const pkgRoot = dirname( pkgPath ); | ||
if (options.browser && typeof pkg[ 'browser' ] === 'object') { | ||
if (useBrowserOverrides && typeof pkg[ 'browser' ] === 'object') { | ||
packageBrowserField = Object.keys(pkg[ 'browser' ]).reduce((browser, key) => { | ||
const resolved = pkg[ 'browser' ][ key ] === false ? false : resolve( pkgRoot, pkg[ 'browser' ][ key ] ); | ||
let resolved = pkg[ 'browser' ][ key ]; | ||
if (resolved && resolved[0] === '.') { | ||
resolved = resolve( pkgRoot, pkg[ 'browser' ][ key ] ); | ||
} | ||
browser[ key ] = resolved; | ||
@@ -143,9 +173,12 @@ if ( key[0] === '.' ) { | ||
if (options.browser && typeof pkg[ 'browser' ] === 'string') { | ||
pkg[ 'main' ] = pkg[ 'browser' ]; | ||
} else if ( useModule && pkg[ 'module' ] ) { | ||
pkg[ 'main' ] = pkg[ 'module' ]; | ||
} else if ( useJsnext && pkg[ 'jsnext:main' ] ) { | ||
pkg[ 'main' ] = pkg[ 'jsnext:main' ]; | ||
} else if ( ( useJsnext || useModule ) && !useMain ) { | ||
let overriddenMain = false; | ||
for ( let i = 0; i < mainFields.length; i++ ) { | ||
const field = mainFields[i]; | ||
if ( typeof pkg[ field ] === 'string' ) { | ||
pkg[ 'main' ] = pkg[ field ]; | ||
overriddenMain = true; | ||
break; | ||
} | ||
} | ||
if ( overriddenMain === false && mainFields.indexOf( 'main' ) === -1 ) { | ||
disregardResult = true; | ||
@@ -155,4 +188,5 @@ } | ||
}, | ||
readFile: cachedReadFile, | ||
isFile: cachedIsFile, | ||
readFile: readFileCached, | ||
isFile: isFileCached, | ||
isDirectory: isDirCached, | ||
extensions: extensions | ||
@@ -169,6 +203,9 @@ }; | ||
) | ||
.catch(() => false) | ||
.then(resolved => { | ||
if (options.browser && packageBrowserField) { | ||
if (packageBrowserField[ resolved ]) { | ||
if ( resolved && useBrowserOverrides && packageBrowserField ) { | ||
if ( packageBrowserField.hasOwnProperty(resolved) ) { | ||
if (!packageBrowserField[resolved]) { | ||
browserMapCache[resolved] = packageBrowserField; | ||
return ES6_BROWSER_EMPTY; | ||
} | ||
resolved = packageBrowserField[ resolved ]; | ||
@@ -179,3 +216,3 @@ } | ||
if ( !disregardResult && resolved !== false ) { | ||
if ( !disregardResult ) { | ||
if ( !preserveSymlinks && resolved && fs.existsSync( resolved ) ) { | ||
@@ -204,7 +241,8 @@ resolved = fs.realpathSync( resolved ); | ||
} else { | ||
return resolved === false ? null : resolved; | ||
return resolved; | ||
} | ||
}); | ||
}) | ||
.catch(() => null); | ||
} | ||
}; | ||
} |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
39794
35.14%8
14.29%735
40%136
29.52%0
-100%4
33.33%+ Added
+ Added
+ Added
+ Added
Updated
Updated