UNPKG

14.2 kBJavaScriptView Raw
1'use strict';
2
3function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4
5var path = require('path');
6var builtinList = _interopDefault(require('builtin-modules'));
7var resolveId = _interopDefault(require('resolve'));
8var isModule = _interopDefault(require('is-module'));
9var fs = _interopDefault(require('fs'));
10var rollupPluginutils = require('rollup-pluginutils');
11
12function _slicedToArray(arr, i) {
13 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
14}
15
16function _arrayWithHoles(arr) {
17 if (Array.isArray(arr)) return arr;
18}
19
20function _iterableToArrayLimit(arr, i) {
21 var _arr = [];
22 var _n = true;
23 var _d = false;
24 var _e = undefined;
25
26 try {
27 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
28 _arr.push(_s.value);
29
30 if (i && _arr.length === i) break;
31 }
32 } catch (err) {
33 _d = true;
34 _e = err;
35 } finally {
36 try {
37 if (!_n && _i["return"] != null) _i["return"]();
38 } finally {
39 if (_d) throw _e;
40 }
41 }
42
43 return _arr;
44}
45
46function _nonIterableRest() {
47 throw new TypeError("Invalid attempt to destructure non-iterable instance");
48}
49
50var peerDependencies = {
51 rollup: ">=1.11.0"
52};
53
54const builtins = new Set(builtinList);
55const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js'; // It is important that .mjs occur before .js so that Rollup will interpret npm modules
56// which deploy both ESM .mjs and CommonJS .js files as ESM.
57
58const DEFAULT_EXTS = ['.mjs', '.js', '.json', '.node'];
59
60const existsAsync = file => new Promise(fulfil => fs.exists(file, fulfil));
61
62const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, (err, contents) => err ? reject(err) : fulfil(contents)));
63
64const realpathAsync = file => new Promise((fulfil, reject) => fs.realpath(file, (err, contents) => err ? reject(err) : fulfil(contents)));
65
66const statAsync = file => new Promise((fulfil, reject) => fs.stat(file, (err, contents) => err ? reject(err) : fulfil(contents)));
67
68const cache = fn => {
69 const cache = new Map();
70
71 const wrapped = (param, done) => {
72 if (cache.has(param) === false) {
73 cache.set(param, fn(param).catch(err => {
74 cache.delete(param);
75 throw err;
76 }));
77 }
78
79 return cache.get(param).then(result => done(null, result), done);
80 };
81
82 wrapped.clear = () => cache.clear();
83
84 return wrapped;
85};
86
87const ignoreENOENT = err => {
88 if (err.code === 'ENOENT') return false;
89 throw err;
90};
91
92const readFileCached = cache(readFileAsync);
93const isDirCached = cache(file => statAsync(file).then(stat => stat.isDirectory(), ignoreENOENT));
94const isFileCached = cache(file => statAsync(file).then(stat => stat.isFile(), ignoreENOENT));
95
96function getMainFields(options) {
97 let mainFields;
98
99 if (options.mainFields) {
100 if ('module' in options || 'main' in options || 'jsnext' in options) {
101 throw new Error(`node-resolve: do not use deprecated 'module', 'main', 'jsnext' options with 'mainFields'`);
102 }
103
104 mainFields = options.mainFields;
105 } else {
106 mainFields = [];
107 [['module', 'module', true], ['jsnext', 'jsnext:main', false], ['main', 'main', true]].forEach(([option, field, defaultIncluded]) => {
108 if (option in options) {
109 // eslint-disable-next-line no-console
110 console.warn(`node-resolve: setting options.${option} is deprecated, please override options.mainFields instead`);
111
112 if (options[option]) {
113 mainFields.push(field);
114 }
115 } else if (defaultIncluded) {
116 mainFields.push(field);
117 }
118 });
119 }
120
121 if (options.browser && mainFields.indexOf('browser') === -1) {
122 return ['browser'].concat(mainFields);
123 }
124
125 if (!mainFields.length) {
126 throw new Error(`Please ensure at least one 'mainFields' value is specified`);
127 }
128
129 return mainFields;
130}
131
132const alwaysNull = () => null;
133
134const resolveIdAsync = (file, opts) => new Promise((fulfil, reject) => resolveId(file, opts, (err, contents) => err ? reject(err) : fulfil(contents))); // Resolve module specifiers in order. Promise resolves to the first
135// module that resolves successfully, or the error that resulted from
136// the last attempted module resolution.
137
138
139function resolveImportSpecifiers(importSpecifierList, resolveOptions) {
140 let p = Promise.resolve();
141
142 for (let i = 0; i < importSpecifierList.length; i++) {
143 p = p.then(v => {
144 // if we've already resolved to something, just return it.
145 if (v) return v;
146 return resolveIdAsync(importSpecifierList[i], resolveOptions);
147 });
148
149 if (i < importSpecifierList.length - 1) {
150 // swallow MODULE_NOT_FOUND errors from all but the last resolution
151 p = p.catch(err => {
152 if (err.code !== 'MODULE_NOT_FOUND') {
153 throw err;
154 }
155 });
156 }
157 }
158
159 return p;
160}
161
162function nodeResolve(options = {}) {
163 const mainFields = getMainFields(options);
164 const useBrowserOverrides = mainFields.indexOf('browser') !== -1;
165 const dedupe = options.dedupe || [];
166 const isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false;
167 const preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true;
168 const customResolveOptions = options.customResolveOptions || {};
169 const jail = options.jail;
170 const only = Array.isArray(options.only) ? options.only.map(o => o instanceof RegExp ? o : new RegExp('^' + String(o).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&') + '$')) : null;
171 const browserMapCache = new Map();
172
173 if (options.skip) {
174 throw new Error('options.skip is no longer supported — you should use the main Rollup `external` option instead');
175 }
176
177 const extensions = options.extensions || DEFAULT_EXTS;
178 const packageInfoCache = new Map();
179 const shouldDedupe = typeof dedupe === 'function' ? dedupe : importee => dedupe.includes(importee);
180
181 function getCachedPackageInfo(pkg, pkgPath) {
182 if (packageInfoCache.has(pkgPath)) {
183 return packageInfoCache.get(pkgPath);
184 }
185
186 const pkgRoot = path.dirname(pkgPath);
187 let overriddenMain = false;
188
189 for (let i = 0; i < mainFields.length; i++) {
190 const field = mainFields[i];
191
192 if (typeof pkg[field] === 'string') {
193 pkg['main'] = pkg[field];
194 overriddenMain = true;
195 break;
196 }
197 }
198
199 const packageInfo = {
200 cachedPkg: pkg,
201 hasModuleSideEffects: alwaysNull,
202 hasPackageEntry: overriddenMain !== false || mainFields.indexOf('main') !== -1,
203 packageBrowserField: useBrowserOverrides && typeof pkg['browser'] === 'object' && Object.keys(pkg['browser']).reduce((browser, key) => {
204 let resolved = pkg['browser'][key];
205
206 if (resolved && resolved[0] === '.') {
207 resolved = path.resolve(pkgRoot, resolved);
208 }
209
210 browser[key] = resolved;
211
212 if (key[0] === '.') {
213 const absoluteKey = path.resolve(pkgRoot, key);
214 browser[absoluteKey] = resolved;
215
216 if (!path.extname(key)) {
217 extensions.reduce((browser, ext) => {
218 browser[absoluteKey + ext] = browser[key];
219 return browser;
220 }, browser);
221 }
222 }
223
224 return browser;
225 }, {})
226 };
227 const packageSideEffects = pkg['sideEffects'];
228
229 if (typeof packageSideEffects === 'boolean') {
230 packageInfo.hasModuleSideEffects = () => packageSideEffects;
231 } else if (Array.isArray(packageSideEffects)) {
232 packageInfo.hasModuleSideEffects = rollupPluginutils.createFilter(packageSideEffects, null, {
233 resolve: pkgRoot
234 });
235 }
236
237 packageInfoCache.set(pkgPath, packageInfo);
238 return packageInfo;
239 }
240
241 let preserveSymlinks;
242 return {
243 name: 'node-resolve',
244
245 buildStart(options) {
246 preserveSymlinks = options.preserveSymlinks;
247
248 const _this$meta$rollupVers = this.meta.rollupVersion.split('.').map(Number),
249 _this$meta$rollupVers2 = _slicedToArray(_this$meta$rollupVers, 2),
250 major = _this$meta$rollupVers2[0],
251 minor = _this$meta$rollupVers2[1];
252
253 const minVersion = peerDependencies.rollup.slice(2);
254
255 const _minVersion$split$map = minVersion.split('.').map(Number),
256 _minVersion$split$map2 = _slicedToArray(_minVersion$split$map, 2),
257 minMajor = _minVersion$split$map2[0],
258 minMinor = _minVersion$split$map2[1];
259
260 if (major < minMajor || major === minMajor && minor < minMinor) {
261 this.error(`Insufficient Rollup version: "rollup-plugin-node-resolve" requires at least rollup@${minVersion} but found rollup@${this.meta.rollupVersion}.`);
262 }
263 },
264
265 generateBundle() {
266 readFileCached.clear();
267 isFileCached.clear();
268 isDirCached.clear();
269 },
270
271 resolveId(importee, importer) {
272 if (importee === ES6_BROWSER_EMPTY) {
273 return importee;
274 }
275
276 if (/\0/.test(importee)) return null; // ignore IDs with null character, these belong to other plugins
277
278 const basedir = importer ? path.dirname(importer) : process.cwd();
279
280 if (shouldDedupe(importee)) {
281 importee = path.join(process.cwd(), 'node_modules', importee);
282 } // https://github.com/defunctzombie/package-browser-field-spec
283
284
285 const browser = browserMapCache.get(importer);
286
287 if (useBrowserOverrides && browser) {
288 const resolvedImportee = path.resolve(basedir, importee);
289
290 if (browser[importee] === false || browser[resolvedImportee] === false) {
291 return ES6_BROWSER_EMPTY;
292 }
293
294 const browserImportee = browser[importee] || browser[resolvedImportee] || browser[resolvedImportee + '.js'] || browser[resolvedImportee + '.json'];
295
296 if (browserImportee) {
297 importee = browserImportee;
298 }
299 }
300
301 const parts = importee.split(/[/\\]/);
302 let id = parts.shift();
303
304 if (id[0] === '@' && parts.length > 0) {
305 // scoped packages
306 id += `/${parts.shift()}`;
307 } else if (id[0] === '.') {
308 // an import relative to the parent dir of the importer
309 id = path.resolve(basedir, importee);
310 }
311
312 if (only && !only.some(pattern => pattern.test(id))) return null;
313 let hasModuleSideEffects = alwaysNull;
314 let hasPackageEntry = true;
315 let packageBrowserField = false;
316 const resolveOptions = {
317 basedir,
318
319 packageFilter(pkg, pkgPath) {
320 let cachedPkg;
321
322 var _getCachedPackageInfo = getCachedPackageInfo(pkg, pkgPath);
323
324 cachedPkg = _getCachedPackageInfo.cachedPkg;
325 hasModuleSideEffects = _getCachedPackageInfo.hasModuleSideEffects;
326 hasPackageEntry = _getCachedPackageInfo.hasPackageEntry;
327 packageBrowserField = _getCachedPackageInfo.packageBrowserField;
328 return cachedPkg;
329 },
330
331 readFile: readFileCached,
332 isFile: isFileCached,
333 isDirectory: isDirCached,
334 extensions: extensions
335 };
336
337 if (preserveSymlinks !== undefined) {
338 resolveOptions.preserveSymlinks = preserveSymlinks;
339 }
340
341 const importSpecifierList = [];
342
343 if (importer === undefined && !importee[0].match(/^\.?\.?\//)) {
344 // For module graph roots (i.e. when importer is undefined), we
345 // need to handle 'path fragments` like `foo/bar` that are commonly
346 // found in rollup config files. If importee doesn't look like a
347 // relative or absolute path, we make it relative and attempt to
348 // resolve it. If we don't find anything, we try resolving it as we
349 // got it.
350 importSpecifierList.push('./' + importee);
351 }
352
353 const importeeIsBuiltin = builtins.has(importee);
354
355 if (importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet)) {
356 // The `resolve` library will not resolve packages with the same
357 // name as a node built-in module. If we're resolving something
358 // that's a builtin, and we don't prefer to find built-ins, we
359 // first try to look up a local module with that name. If we don't
360 // find anything, we resolve the builtin which just returns back
361 // the built-in's name.
362 importSpecifierList.push(importee + '/');
363 }
364
365 importSpecifierList.push(importee);
366 return resolveImportSpecifiers(importSpecifierList, Object.assign(resolveOptions, customResolveOptions)).then(resolved => {
367 if (resolved && packageBrowserField) {
368 if (Object.prototype.hasOwnProperty.call(packageBrowserField, resolved)) {
369 if (!packageBrowserField[resolved]) {
370 browserMapCache.set(resolved, packageBrowserField);
371 return ES6_BROWSER_EMPTY;
372 }
373
374 resolved = packageBrowserField[resolved];
375 }
376
377 browserMapCache.set(resolved, packageBrowserField);
378 }
379
380 if (hasPackageEntry && !preserveSymlinks && resolved) {
381 return existsAsync(resolved).then(exists => exists ? realpathAsync(resolved) : resolved);
382 }
383
384 return resolved;
385 }).then(resolved => {
386 if (hasPackageEntry) {
387 if (builtins.has(resolved) && preferBuiltins && isPreferBuiltinsSet) {
388 return null;
389 } else if (importeeIsBuiltin && preferBuiltins) {
390 if (!isPreferBuiltinsSet) {
391 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`);
392 }
393
394 return null;
395 } else if (jail && resolved.indexOf(path.normalize(jail.trim(path.sep))) !== 0) {
396 return null;
397 }
398 }
399
400 if (resolved && options.modulesOnly) {
401 return readFileAsync(resolved).then(code => isModule(code) ? {
402 id: resolved,
403 moduleSideEffects: hasModuleSideEffects(resolved)
404 } : null);
405 } else {
406 return {
407 id: resolved,
408 moduleSideEffects: hasModuleSideEffects(resolved)
409 };
410 }
411 }).catch(() => null);
412 },
413
414 load(importee) {
415 if (importee === ES6_BROWSER_EMPTY) {
416 return 'export default {};';
417 }
418
419 return null;
420 }
421
422 };
423}
424
425module.exports = nodeResolve;