UNPKG

18.9 kBJavaScriptView Raw
1import { dirname, resolve, extname, normalize, sep } from 'path';
2import builtinList from 'builtin-modules';
3import deepFreeze from 'deep-freeze';
4import deepMerge from 'deepmerge';
5import isModule from 'is-module';
6import fs, { realpathSync } from 'fs';
7import { promisify } from 'util';
8import { createFilter } from '@rollup/pluginutils';
9import resolveModule from 'resolve';
10
11function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
12 try {
13 var info = gen[key](arg);
14 var value = info.value;
15 } catch (error) {
16 reject(error);
17 return;
18 }
19
20 if (info.done) {
21 resolve(value);
22 } else {
23 Promise.resolve(value).then(_next, _throw);
24 }
25}
26
27function _asyncToGenerator(fn) {
28 return function () {
29 var self = this,
30 args = arguments;
31 return new Promise(function (resolve, reject) {
32 var gen = fn.apply(self, args);
33
34 function _next(value) {
35 asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
36 }
37
38 function _throw(err) {
39 asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
40 }
41
42 _next(undefined);
43 });
44 };
45}
46
47function _unsupportedIterableToArray(o, minLen) {
48 if (!o) return;
49 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
50 var n = Object.prototype.toString.call(o).slice(8, -1);
51 if (n === "Object" && o.constructor) n = o.constructor.name;
52 if (n === "Map" || n === "Set") return Array.from(n);
53 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
54}
55
56function _arrayLikeToArray(arr, len) {
57 if (len == null || len > arr.length) len = arr.length;
58
59 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
60
61 return arr2;
62}
63
64function _createForOfIteratorHelper(o) {
65 if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
66 if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) {
67 var i = 0;
68
69 var F = function () {};
70
71 return {
72 s: F,
73 n: function () {
74 if (i >= o.length) return {
75 done: true
76 };
77 return {
78 done: false,
79 value: o[i++]
80 };
81 },
82 e: function (e) {
83 throw e;
84 },
85 f: F
86 };
87 }
88
89 throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
90 }
91
92 var it,
93 normalCompletion = true,
94 didErr = false,
95 err;
96 return {
97 s: function () {
98 it = o[Symbol.iterator]();
99 },
100 n: function () {
101 var step = it.next();
102 normalCompletion = step.done;
103 return step;
104 },
105 e: function (e) {
106 didErr = true;
107 err = e;
108 },
109 f: function () {
110 try {
111 if (!normalCompletion && it.return != null) it.return();
112 } finally {
113 if (didErr) throw err;
114 }
115 }
116 };
117}
118
119const exists = promisify(fs.exists);
120const readFile = promisify(fs.readFile);
121const realpath = promisify(fs.realpath);
122const stat = promisify(fs.stat);
123
124const onError = error => {
125 if (error.code === 'ENOENT') {
126 return false;
127 }
128
129 throw error;
130};
131
132const makeCache = fn => {
133 const cache = new Map();
134
135 const wrapped = /*#__PURE__*/function () {
136 var _ref = _asyncToGenerator(function* (param, done) {
137 if (cache.has(param) === false) {
138 cache.set(param, fn(param).catch(err => {
139 cache.delete(param);
140 throw err;
141 }));
142 }
143
144 try {
145 const result = cache.get(param);
146 const value = yield result;
147 return done(null, value);
148 } catch (error) {
149 return done(error);
150 }
151 });
152
153 return function wrapped(_x, _x2) {
154 return _ref.apply(this, arguments);
155 };
156 }();
157
158 wrapped.clear = () => cache.clear();
159
160 return wrapped;
161};
162
163const isDirCached = makeCache( /*#__PURE__*/function () {
164 var _ref2 = _asyncToGenerator(function* (file) {
165 try {
166 const stats = yield stat(file);
167 return stats.isDirectory();
168 } catch (error) {
169 return onError(error);
170 }
171 });
172
173 return function (_x3) {
174 return _ref2.apply(this, arguments);
175 };
176}());
177const isFileCached = makeCache( /*#__PURE__*/function () {
178 var _ref3 = _asyncToGenerator(function* (file) {
179 try {
180 const stats = yield stat(file);
181 return stats.isFile();
182 } catch (error) {
183 return onError(error);
184 }
185 });
186
187 return function (_x4) {
188 return _ref3.apply(this, arguments);
189 };
190}());
191const readCachedFile = makeCache(readFile);
192
193const resolveId = promisify(resolveModule); // returns the imported package name for bare module imports
194
195function getPackageName(id) {
196 if (id.startsWith('.') || id.startsWith('/')) {
197 return null;
198 }
199
200 const split = id.split('/'); // @my-scope/my-package/foo.js -> @my-scope/my-package
201 // @my-scope/my-package -> @my-scope/my-package
202
203 if (split[0][0] === '@') {
204 return `${split[0]}/${split[1]}`;
205 } // my-package/foo.js -> my-package
206 // my-package -> my-package
207
208
209 return split[0];
210}
211function getMainFields(options) {
212 let mainFields;
213
214 if (options.mainFields) {
215 mainFields = options.mainFields;
216 } else {
217 mainFields = ['module', 'main'];
218 }
219
220 if (options.browser && mainFields.indexOf('browser') === -1) {
221 return ['browser'].concat(mainFields);
222 }
223
224 if (!mainFields.length) {
225 throw new Error('Please ensure at least one `mainFields` value is specified');
226 }
227
228 return mainFields;
229}
230function getPackageInfo(options) {
231 const cache = options.cache,
232 extensions = options.extensions,
233 pkg = options.pkg,
234 mainFields = options.mainFields,
235 preserveSymlinks = options.preserveSymlinks,
236 useBrowserOverrides = options.useBrowserOverrides;
237 let pkgPath = options.pkgPath;
238
239 if (cache.has(pkgPath)) {
240 return cache.get(pkgPath);
241 } // browserify/resolve doesn't realpath paths returned in its packageFilter callback
242
243
244 if (!preserveSymlinks) {
245 pkgPath = realpathSync(pkgPath);
246 }
247
248 const pkgRoot = dirname(pkgPath);
249 const packageInfo = {
250 // copy as we are about to munge the `main` field of `pkg`.
251 packageJson: Object.assign({}, pkg),
252 // path to package.json file
253 packageJsonPath: pkgPath,
254 // directory containing the package.json
255 root: pkgRoot,
256 // which main field was used during resolution of this module (main, module, or browser)
257 resolvedMainField: 'main',
258 // whether the browser map was used to resolve the entry point to this module
259 browserMappedMain: false,
260 // the entry point of the module with respect to the selected main field and any
261 // relevant browser mappings.
262 resolvedEntryPoint: ''
263 };
264 let overriddenMain = false;
265
266 for (let i = 0; i < mainFields.length; i++) {
267 const field = mainFields[i];
268
269 if (typeof pkg[field] === 'string') {
270 pkg.main = pkg[field];
271 packageInfo.resolvedMainField = field;
272 overriddenMain = true;
273 break;
274 }
275 }
276
277 const internalPackageInfo = {
278 cachedPkg: pkg,
279 hasModuleSideEffects: () => null,
280 hasPackageEntry: overriddenMain !== false || mainFields.indexOf('main') !== -1,
281 packageBrowserField: useBrowserOverrides && typeof pkg.browser === 'object' && Object.keys(pkg.browser).reduce((browser, key) => {
282 let resolved = pkg.browser[key];
283
284 if (resolved && resolved[0] === '.') {
285 resolved = resolve(pkgRoot, resolved);
286 }
287 /* eslint-disable no-param-reassign */
288
289
290 browser[key] = resolved;
291
292 if (key[0] === '.') {
293 const absoluteKey = resolve(pkgRoot, key);
294 browser[absoluteKey] = resolved;
295
296 if (!extname(key)) {
297 extensions.reduce((subBrowser, ext) => {
298 subBrowser[absoluteKey + ext] = subBrowser[key];
299 return subBrowser;
300 }, browser);
301 }
302 }
303
304 return browser;
305 }, {}),
306 packageInfo
307 };
308 const browserMap = internalPackageInfo.packageBrowserField;
309
310 if (useBrowserOverrides && typeof pkg.browser === 'object' && // eslint-disable-next-line no-prototype-builtins
311 browserMap.hasOwnProperty(pkg.main)) {
312 packageInfo.resolvedEntryPoint = browserMap[pkg.main];
313 packageInfo.browserMappedMain = true;
314 } else {
315 // index.node is technically a valid default entrypoint as well...
316 packageInfo.resolvedEntryPoint = resolve(pkgRoot, pkg.main || 'index.js');
317 packageInfo.browserMappedMain = false;
318 }
319
320 const packageSideEffects = pkg.sideEffects;
321
322 if (typeof packageSideEffects === 'boolean') {
323 internalPackageInfo.hasModuleSideEffects = () => packageSideEffects;
324 } else if (Array.isArray(packageSideEffects)) {
325 internalPackageInfo.hasModuleSideEffects = createFilter(packageSideEffects, null, {
326 resolve: pkgRoot
327 });
328 }
329
330 cache.set(pkgPath, internalPackageInfo);
331 return internalPackageInfo;
332}
333function normalizeInput(input) {
334 if (Array.isArray(input)) {
335 return input;
336 } else if (typeof input === 'object') {
337 return Object.values(input);
338 } // otherwise it's a string
339
340
341 return [input];
342} // Resolve module specifiers in order. Promise resolves to the first module that resolves
343// successfully, or the error that resulted from the last attempted module resolution.
344
345function resolveImportSpecifiers(importSpecifierList, resolveOptions) {
346 let promise = Promise.resolve();
347
348 for (let i = 0; i < importSpecifierList.length; i++) {
349 promise = promise.then(value => {
350 // if we've already resolved to something, just return it.
351 if (value) {
352 return value;
353 }
354
355 return resolveId(importSpecifierList[i], resolveOptions).then(result => {
356 if (!resolveOptions.preserveSymlinks) {
357 result = realpathSync(result);
358 }
359
360 return result;
361 });
362 });
363
364 if (i < importSpecifierList.length - 1) {
365 // swallow MODULE_NOT_FOUND errors from all but the last resolution
366 promise = promise.catch(error => {
367 if (error.code !== 'MODULE_NOT_FOUND') {
368 throw error;
369 }
370 });
371 }
372 }
373
374 return promise;
375}
376
377const builtins = new Set(builtinList);
378const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js';
379
380const nullFn = () => null;
381
382const defaults = {
383 customResolveOptions: {},
384 dedupe: [],
385 // It's important that .mjs is listed before .js so that Rollup will interpret npm modules
386 // which deploy both ESM .mjs and CommonJS .js files as ESM.
387 extensions: ['.mjs', '.js', '.json', '.node'],
388 resolveOnly: []
389};
390const DEFAULTS = deepFreeze(deepMerge({}, defaults));
391function nodeResolve(opts = {}) {
392 const options = Object.assign({}, defaults, opts);
393 const customResolveOptions = options.customResolveOptions,
394 extensions = options.extensions,
395 jail = options.jail;
396 const warnings = [];
397 const packageInfoCache = new Map();
398 const idToPackageInfo = new Map();
399 const mainFields = getMainFields(options);
400 const useBrowserOverrides = mainFields.indexOf('browser') !== -1;
401 const isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false;
402 const preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true;
403 const rootDir = options.rootDir || process.cwd();
404 let dedupe = options.dedupe;
405 let rollupOptions;
406
407 if (options.only) {
408 warnings.push('node-resolve: The `only` options is deprecated, please use `resolveOnly`');
409 options.resolveOnly = options.only;
410 }
411
412 if (typeof dedupe !== 'function') {
413 dedupe = importee => options.dedupe.includes(importee) || options.dedupe.includes(getPackageName(importee));
414 }
415
416 const resolveOnly = options.resolveOnly.map(pattern => {
417 if (pattern instanceof RegExp) {
418 return pattern;
419 }
420
421 const normalized = pattern.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
422 return new RegExp(`^${normalized}$`);
423 });
424 const browserMapCache = new Map();
425 let preserveSymlinks;
426 return {
427 name: 'node-resolve',
428
429 buildStart(options) {
430 rollupOptions = options;
431
432 var _iterator = _createForOfIteratorHelper(warnings),
433 _step;
434
435 try {
436 for (_iterator.s(); !(_step = _iterator.n()).done;) {
437 const warning = _step.value;
438 this.warn(warning);
439 }
440 } catch (err) {
441 _iterator.e(err);
442 } finally {
443 _iterator.f();
444 }
445
446 preserveSymlinks = options.preserveSymlinks;
447 },
448
449 generateBundle() {
450 readCachedFile.clear();
451 isFileCached.clear();
452 isDirCached.clear();
453 },
454
455 resolveId(importee, importer) {
456 var _this = this;
457
458 return _asyncToGenerator(function* () {
459 if (importee === ES6_BROWSER_EMPTY) {
460 return importee;
461 } // ignore IDs with null character, these belong to other plugins
462
463
464 if (/\0/.test(importee)) return null;
465 const basedir = !importer || dedupe(importee) ? rootDir : dirname(importer); // https://github.com/defunctzombie/package-browser-field-spec
466
467 const browser = browserMapCache.get(importer);
468
469 if (useBrowserOverrides && browser) {
470 const resolvedImportee = resolve(basedir, importee);
471
472 if (browser[importee] === false || browser[resolvedImportee] === false) {
473 return ES6_BROWSER_EMPTY;
474 }
475
476 const browserImportee = browser[importee] || browser[resolvedImportee] || browser[`${resolvedImportee}.js`] || browser[`${resolvedImportee}.json`];
477
478 if (browserImportee) {
479 importee = browserImportee;
480 }
481 }
482
483 const parts = importee.split(/[/\\]/);
484 let id = parts.shift();
485 let isRelativeImport = false;
486
487 if (id[0] === '@' && parts.length > 0) {
488 // scoped packages
489 id += `/${parts.shift()}`;
490 } else if (id[0] === '.') {
491 // an import relative to the parent dir of the importer
492 id = resolve(basedir, importee);
493 isRelativeImport = true;
494 }
495
496 if (!isRelativeImport && resolveOnly.length && !resolveOnly.some(pattern => pattern.test(id))) {
497 if (normalizeInput(rollupOptions.input).includes(importee)) {
498 return null;
499 }
500
501 return false;
502 }
503
504 let hasModuleSideEffects = nullFn;
505 let hasPackageEntry = true;
506 let packageBrowserField = false;
507 let packageInfo;
508
509 const filter = (pkg, pkgPath) => {
510 const info = getPackageInfo({
511 cache: packageInfoCache,
512 extensions,
513 pkg,
514 pkgPath,
515 mainFields,
516 preserveSymlinks,
517 useBrowserOverrides
518 });
519 packageInfo = info.packageInfo;
520 hasModuleSideEffects = info.hasModuleSideEffects;
521 hasPackageEntry = info.hasPackageEntry;
522 packageBrowserField = info.packageBrowserField;
523 return info.cachedPkg;
524 };
525
526 let resolveOptions = {
527 basedir,
528 packageFilter: filter,
529 readFile: readCachedFile,
530 isFile: isFileCached,
531 isDirectory: isDirCached,
532 extensions
533 };
534
535 if (preserveSymlinks !== undefined) {
536 resolveOptions.preserveSymlinks = preserveSymlinks;
537 }
538
539 const importSpecifierList = [];
540
541 if (importer === undefined && !importee[0].match(/^\.?\.?\//)) {
542 // For module graph roots (i.e. when importer is undefined), we
543 // need to handle 'path fragments` like `foo/bar` that are commonly
544 // found in rollup config files. If importee doesn't look like a
545 // relative or absolute path, we make it relative and attempt to
546 // resolve it. If we don't find anything, we try resolving it as we
547 // got it.
548 importSpecifierList.push(`./${importee}`);
549 }
550
551 const importeeIsBuiltin = builtins.has(importee);
552
553 if (importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet)) {
554 // The `resolve` library will not resolve packages with the same
555 // name as a node built-in module. If we're resolving something
556 // that's a builtin, and we don't prefer to find built-ins, we
557 // first try to look up a local module with that name. If we don't
558 // find anything, we resolve the builtin which just returns back
559 // the built-in's name.
560 importSpecifierList.push(`${importee}/`);
561 }
562
563 importSpecifierList.push(importee);
564 resolveOptions = Object.assign(resolveOptions, customResolveOptions);
565
566 try {
567 let resolved = yield resolveImportSpecifiers(importSpecifierList, resolveOptions);
568
569 if (resolved && packageBrowserField) {
570 if (Object.prototype.hasOwnProperty.call(packageBrowserField, resolved)) {
571 if (!packageBrowserField[resolved]) {
572 browserMapCache.set(resolved, packageBrowserField);
573 return ES6_BROWSER_EMPTY;
574 }
575
576 resolved = packageBrowserField[resolved];
577 }
578
579 browserMapCache.set(resolved, packageBrowserField);
580 }
581
582 if (hasPackageEntry && !preserveSymlinks && resolved) {
583 const fileExists = yield exists(resolved);
584
585 if (fileExists) {
586 resolved = yield realpath(resolved);
587 }
588 }
589
590 idToPackageInfo.set(resolved, packageInfo);
591
592 if (hasPackageEntry) {
593 if (builtins.has(resolved) && preferBuiltins && isPreferBuiltinsSet) {
594 return null;
595 } else if (importeeIsBuiltin && preferBuiltins) {
596 if (!isPreferBuiltinsSet) {
597 _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`);
598 }
599
600 return null;
601 } else if (jail && resolved.indexOf(normalize(jail.trim(sep))) !== 0) {
602 return null;
603 }
604 }
605
606 if (resolved && options.modulesOnly) {
607 const code = yield readFile(resolved, 'utf-8');
608
609 if (isModule(code)) {
610 return {
611 id: resolved,
612 moduleSideEffects: hasModuleSideEffects(resolved)
613 };
614 }
615
616 return null;
617 }
618
619 const result = {
620 id: resolved,
621 moduleSideEffects: hasModuleSideEffects(resolved)
622 };
623 return result;
624 } catch (error) {
625 return null;
626 }
627 })();
628 },
629
630 load(importee) {
631 if (importee === ES6_BROWSER_EMPTY) {
632 return 'export default {};';
633 }
634
635 return null;
636 },
637
638 getPackageInfoForId(id) {
639 return idToPackageInfo.get(id);
640 }
641
642 };
643}
644
645export default nodeResolve;
646export { DEFAULTS, nodeResolve };