index.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  4. var path = require('path');
  5. var builtinList = _interopDefault(require('builtin-modules'));
  6. var deepMerge = _interopDefault(require('deepmerge'));
  7. var isModule = _interopDefault(require('is-module'));
  8. var fs = require('fs');
  9. var fs__default = _interopDefault(fs);
  10. var util = require('util');
  11. var pluginutils = require('@rollup/pluginutils');
  12. var resolveModule = _interopDefault(require('resolve'));
  13. const exists = util.promisify(fs__default.exists);
  14. const readFile = util.promisify(fs__default.readFile);
  15. const realpath = util.promisify(fs__default.realpath);
  16. const stat = util.promisify(fs__default.stat);
  17. const onError = (error) => {
  18. if (error.code === 'ENOENT') {
  19. return false;
  20. }
  21. throw error;
  22. };
  23. const makeCache = (fn) => {
  24. const cache = new Map();
  25. const wrapped = async (param, done) => {
  26. if (cache.has(param) === false) {
  27. cache.set(
  28. param,
  29. fn(param).catch((err) => {
  30. cache.delete(param);
  31. throw err;
  32. })
  33. );
  34. }
  35. try {
  36. const result = cache.get(param);
  37. const value = await result;
  38. return done(null, value);
  39. } catch (error) {
  40. return done(error);
  41. }
  42. };
  43. wrapped.clear = () => cache.clear();
  44. return wrapped;
  45. };
  46. const isDirCached = makeCache(async (file) => {
  47. try {
  48. const stats = await stat(file);
  49. return stats.isDirectory();
  50. } catch (error) {
  51. return onError(error);
  52. }
  53. });
  54. const isFileCached = makeCache(async (file) => {
  55. try {
  56. const stats = await stat(file);
  57. return stats.isFile();
  58. } catch (error) {
  59. return onError(error);
  60. }
  61. });
  62. const readCachedFile = makeCache(readFile);
  63. const resolveId = util.promisify(resolveModule);
  64. // returns the imported package name for bare module imports
  65. function getPackageName(id) {
  66. if (id.startsWith('.') || id.startsWith('/')) {
  67. return null;
  68. }
  69. const split = id.split('/');
  70. // @my-scope/my-package/foo.js -> @my-scope/my-package
  71. // @my-scope/my-package -> @my-scope/my-package
  72. if (split[0][0] === '@') {
  73. return `${split[0]}/${split[1]}`;
  74. }
  75. // my-package/foo.js -> my-package
  76. // my-package -> my-package
  77. return split[0];
  78. }
  79. function getMainFields(options) {
  80. let mainFields;
  81. if (options.mainFields) {
  82. ({ mainFields } = options);
  83. } else {
  84. mainFields = ['module', 'main'];
  85. }
  86. if (options.browser && mainFields.indexOf('browser') === -1) {
  87. return ['browser'].concat(mainFields);
  88. }
  89. if (!mainFields.length) {
  90. throw new Error('Please ensure at least one `mainFields` value is specified');
  91. }
  92. return mainFields;
  93. }
  94. function getPackageInfo(options) {
  95. const { cache, extensions, pkg, mainFields, preserveSymlinks, useBrowserOverrides } = options;
  96. let { pkgPath } = options;
  97. if (cache.has(pkgPath)) {
  98. return cache.get(pkgPath);
  99. }
  100. // browserify/resolve doesn't realpath paths returned in its packageFilter callback
  101. if (!preserveSymlinks) {
  102. pkgPath = fs.realpathSync(pkgPath);
  103. }
  104. const pkgRoot = path.dirname(pkgPath);
  105. const packageInfo = {
  106. // copy as we are about to munge the `main` field of `pkg`.
  107. packageJson: Object.assign({}, pkg),
  108. // path to package.json file
  109. packageJsonPath: pkgPath,
  110. // directory containing the package.json
  111. root: pkgRoot,
  112. // which main field was used during resolution of this module (main, module, or browser)
  113. resolvedMainField: 'main',
  114. // whether the browser map was used to resolve the entry point to this module
  115. browserMappedMain: false,
  116. // the entry point of the module with respect to the selected main field and any
  117. // relevant browser mappings.
  118. resolvedEntryPoint: ''
  119. };
  120. let overriddenMain = false;
  121. for (let i = 0; i < mainFields.length; i++) {
  122. const field = mainFields[i];
  123. if (typeof pkg[field] === 'string') {
  124. pkg.main = pkg[field];
  125. packageInfo.resolvedMainField = field;
  126. overriddenMain = true;
  127. break;
  128. }
  129. }
  130. const internalPackageInfo = {
  131. cachedPkg: pkg,
  132. hasModuleSideEffects: () => null,
  133. hasPackageEntry: overriddenMain !== false || mainFields.indexOf('main') !== -1,
  134. packageBrowserField:
  135. useBrowserOverrides &&
  136. typeof pkg.browser === 'object' &&
  137. Object.keys(pkg.browser).reduce((browser, key) => {
  138. let resolved = pkg.browser[key];
  139. if (resolved && resolved[0] === '.') {
  140. resolved = path.resolve(pkgRoot, resolved);
  141. }
  142. /* eslint-disable no-param-reassign */
  143. browser[key] = resolved;
  144. if (key[0] === '.') {
  145. const absoluteKey = path.resolve(pkgRoot, key);
  146. browser[absoluteKey] = resolved;
  147. if (!path.extname(key)) {
  148. extensions.reduce((subBrowser, ext) => {
  149. subBrowser[absoluteKey + ext] = subBrowser[key];
  150. return subBrowser;
  151. }, browser);
  152. }
  153. }
  154. return browser;
  155. }, {}),
  156. packageInfo
  157. };
  158. const browserMap = internalPackageInfo.packageBrowserField;
  159. if (
  160. useBrowserOverrides &&
  161. typeof pkg.browser === 'object' &&
  162. // eslint-disable-next-line no-prototype-builtins
  163. browserMap.hasOwnProperty(pkg.main)
  164. ) {
  165. packageInfo.resolvedEntryPoint = browserMap[pkg.main];
  166. packageInfo.browserMappedMain = true;
  167. } else {
  168. // index.node is technically a valid default entrypoint as well...
  169. packageInfo.resolvedEntryPoint = path.resolve(pkgRoot, pkg.main || 'index.js');
  170. packageInfo.browserMappedMain = false;
  171. }
  172. const packageSideEffects = pkg.sideEffects;
  173. if (typeof packageSideEffects === 'boolean') {
  174. internalPackageInfo.hasModuleSideEffects = () => packageSideEffects;
  175. } else if (Array.isArray(packageSideEffects)) {
  176. internalPackageInfo.hasModuleSideEffects = pluginutils.createFilter(packageSideEffects, null, {
  177. resolve: pkgRoot
  178. });
  179. }
  180. cache.set(pkgPath, internalPackageInfo);
  181. return internalPackageInfo;
  182. }
  183. function normalizeInput(input) {
  184. if (Array.isArray(input)) {
  185. return input;
  186. } else if (typeof input === 'object') {
  187. return Object.values(input);
  188. }
  189. // otherwise it's a string
  190. return [input];
  191. }
  192. // Resolve module specifiers in order. Promise resolves to the first module that resolves
  193. // successfully, or the error that resulted from the last attempted module resolution.
  194. function resolveImportSpecifiers(importSpecifierList, resolveOptions) {
  195. let promise = Promise.resolve();
  196. for (let i = 0; i < importSpecifierList.length; i++) {
  197. promise = promise.then((value) => {
  198. // if we've already resolved to something, just return it.
  199. if (value) {
  200. return value;
  201. }
  202. return resolveId(importSpecifierList[i], resolveOptions).then((result) => {
  203. if (!resolveOptions.preserveSymlinks) {
  204. result = fs.realpathSync(result);
  205. }
  206. return result;
  207. });
  208. });
  209. if (i < importSpecifierList.length - 1) {
  210. // swallow MODULE_NOT_FOUND errors from all but the last resolution
  211. promise = promise.catch((error) => {
  212. if (error.code !== 'MODULE_NOT_FOUND') {
  213. throw error;
  214. }
  215. });
  216. }
  217. }
  218. return promise;
  219. }
  220. /* eslint-disable no-param-reassign, no-shadow, no-undefined */
  221. const builtins = new Set(builtinList);
  222. const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js';
  223. const nullFn = () => null;
  224. const deepFreeze = (object) => {
  225. Object.freeze(object);
  226. for (const value of Object.values(object)) {
  227. if (typeof value === 'object' && !Object.isFrozen(value)) {
  228. deepFreeze(value);
  229. }
  230. }
  231. return object;
  232. };
  233. const defaults = {
  234. customResolveOptions: {},
  235. dedupe: [],
  236. // It's important that .mjs is listed before .js so that Rollup will interpret npm modules
  237. // which deploy both ESM .mjs and CommonJS .js files as ESM.
  238. extensions: ['.mjs', '.js', '.json', '.node'],
  239. resolveOnly: []
  240. };
  241. const DEFAULTS = deepFreeze(deepMerge({}, defaults));
  242. function nodeResolve(opts = {}) {
  243. const options = Object.assign({}, defaults, opts);
  244. const { customResolveOptions, extensions, jail } = options;
  245. const warnings = [];
  246. const packageInfoCache = new Map();
  247. const idToPackageInfo = new Map();
  248. const mainFields = getMainFields(options);
  249. const useBrowserOverrides = mainFields.indexOf('browser') !== -1;
  250. const isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false;
  251. const preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true;
  252. const rootDir = options.rootDir || process.cwd();
  253. let { dedupe } = options;
  254. let rollupOptions;
  255. if (options.only) {
  256. warnings.push('node-resolve: The `only` options is deprecated, please use `resolveOnly`');
  257. options.resolveOnly = options.only;
  258. }
  259. if (typeof dedupe !== 'function') {
  260. dedupe = (importee) =>
  261. options.dedupe.includes(importee) || options.dedupe.includes(getPackageName(importee));
  262. }
  263. const resolveOnly = options.resolveOnly.map((pattern) => {
  264. if (pattern instanceof RegExp) {
  265. return pattern;
  266. }
  267. const normalized = pattern.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
  268. return new RegExp(`^${normalized}$`);
  269. });
  270. const browserMapCache = new Map();
  271. let preserveSymlinks;
  272. return {
  273. name: 'node-resolve',
  274. buildStart(options) {
  275. rollupOptions = options;
  276. for (const warning of warnings) {
  277. this.warn(warning);
  278. }
  279. ({ preserveSymlinks } = options);
  280. },
  281. generateBundle() {
  282. readCachedFile.clear();
  283. isFileCached.clear();
  284. isDirCached.clear();
  285. },
  286. async resolveId(importee, importer) {
  287. if (importee === ES6_BROWSER_EMPTY) {
  288. return importee;
  289. }
  290. // ignore IDs with null character, these belong to other plugins
  291. if (/\0/.test(importee)) return null;
  292. // strip hash and query params from import
  293. const [withoutHash, hash] = importee.split('#');
  294. const [importPath, params] = withoutHash.split('?');
  295. const importSuffix = `${params ? `?${params}` : ''}${hash ? `#${hash}` : ''}`;
  296. importee = importPath;
  297. const basedir = !importer || dedupe(importee) ? rootDir : path.dirname(importer);
  298. // https://github.com/defunctzombie/package-browser-field-spec
  299. const browser = browserMapCache.get(importer);
  300. if (useBrowserOverrides && browser) {
  301. const resolvedImportee = path.resolve(basedir, importee);
  302. if (browser[importee] === false || browser[resolvedImportee] === false) {
  303. return ES6_BROWSER_EMPTY;
  304. }
  305. const browserImportee =
  306. browser[importee] ||
  307. browser[resolvedImportee] ||
  308. browser[`${resolvedImportee}.js`] ||
  309. browser[`${resolvedImportee}.json`];
  310. if (browserImportee) {
  311. importee = browserImportee;
  312. }
  313. }
  314. const parts = importee.split(/[/\\]/);
  315. let id = parts.shift();
  316. let isRelativeImport = false;
  317. if (id[0] === '@' && parts.length > 0) {
  318. // scoped packages
  319. id += `/${parts.shift()}`;
  320. } else if (id[0] === '.') {
  321. // an import relative to the parent dir of the importer
  322. id = path.resolve(basedir, importee);
  323. isRelativeImport = true;
  324. }
  325. if (
  326. !isRelativeImport &&
  327. resolveOnly.length &&
  328. !resolveOnly.some((pattern) => pattern.test(id))
  329. ) {
  330. if (normalizeInput(rollupOptions.input).includes(importee)) {
  331. return null;
  332. }
  333. return false;
  334. }
  335. let hasModuleSideEffects = nullFn;
  336. let hasPackageEntry = true;
  337. let packageBrowserField = false;
  338. let packageInfo;
  339. const filter = (pkg, pkgPath) => {
  340. const info = getPackageInfo({
  341. cache: packageInfoCache,
  342. extensions,
  343. pkg,
  344. pkgPath,
  345. mainFields,
  346. preserveSymlinks,
  347. useBrowserOverrides
  348. });
  349. ({ packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = info);
  350. return info.cachedPkg;
  351. };
  352. let resolveOptions = {
  353. basedir,
  354. packageFilter: filter,
  355. readFile: readCachedFile,
  356. isFile: isFileCached,
  357. isDirectory: isDirCached,
  358. extensions
  359. };
  360. if (preserveSymlinks !== undefined) {
  361. resolveOptions.preserveSymlinks = preserveSymlinks;
  362. }
  363. const importSpecifierList = [];
  364. if (importer === undefined && !importee[0].match(/^\.?\.?\//)) {
  365. // For module graph roots (i.e. when importer is undefined), we
  366. // need to handle 'path fragments` like `foo/bar` that are commonly
  367. // found in rollup config files. If importee doesn't look like a
  368. // relative or absolute path, we make it relative and attempt to
  369. // resolve it. If we don't find anything, we try resolving it as we
  370. // got it.
  371. importSpecifierList.push(`./${importee}`);
  372. }
  373. const importeeIsBuiltin = builtins.has(importee);
  374. if (importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet)) {
  375. // The `resolve` library will not resolve packages with the same
  376. // name as a node built-in module. If we're resolving something
  377. // that's a builtin, and we don't prefer to find built-ins, we
  378. // first try to look up a local module with that name. If we don't
  379. // find anything, we resolve the builtin which just returns back
  380. // the built-in's name.
  381. importSpecifierList.push(`${importee}/`);
  382. }
  383. // TypeScript files may import '.js' to refer to either '.ts' or '.tsx'
  384. if (importer && importee.endsWith('.js')) {
  385. for (const ext of ['.ts', '.tsx']) {
  386. if (importer.endsWith(ext) && extensions.includes(ext)) {
  387. importSpecifierList.push(importee.replace(/.js$/, ext));
  388. }
  389. }
  390. }
  391. importSpecifierList.push(importee);
  392. resolveOptions = Object.assign(resolveOptions, customResolveOptions);
  393. try {
  394. let resolved = await resolveImportSpecifiers(importSpecifierList, resolveOptions);
  395. if (resolved && packageBrowserField) {
  396. if (Object.prototype.hasOwnProperty.call(packageBrowserField, resolved)) {
  397. if (!packageBrowserField[resolved]) {
  398. browserMapCache.set(resolved, packageBrowserField);
  399. return ES6_BROWSER_EMPTY;
  400. }
  401. resolved = packageBrowserField[resolved];
  402. }
  403. browserMapCache.set(resolved, packageBrowserField);
  404. }
  405. if (hasPackageEntry && !preserveSymlinks && resolved) {
  406. const fileExists = await exists(resolved);
  407. if (fileExists) {
  408. resolved = await realpath(resolved);
  409. }
  410. }
  411. idToPackageInfo.set(resolved, packageInfo);
  412. if (hasPackageEntry) {
  413. if (builtins.has(resolved) && preferBuiltins && isPreferBuiltinsSet) {
  414. return null;
  415. } else if (importeeIsBuiltin && preferBuiltins) {
  416. if (!isPreferBuiltinsSet) {
  417. this.warn(
  418. `preferring built-in module '${importee}' over local alternative at '${resolved}', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning`
  419. );
  420. }
  421. return null;
  422. } else if (jail && resolved.indexOf(path.normalize(jail.trim(path.sep))) !== 0) {
  423. return null;
  424. }
  425. }
  426. if (resolved && options.modulesOnly) {
  427. const code = await readFile(resolved, 'utf-8');
  428. if (isModule(code)) {
  429. return {
  430. id: `${resolved}${importSuffix}`,
  431. moduleSideEffects: hasModuleSideEffects(resolved)
  432. };
  433. }
  434. return null;
  435. }
  436. const result = {
  437. id: `${resolved}${importSuffix}`,
  438. moduleSideEffects: hasModuleSideEffects(resolved)
  439. };
  440. return result;
  441. } catch (error) {
  442. return null;
  443. }
  444. },
  445. load(importee) {
  446. if (importee === ES6_BROWSER_EMPTY) {
  447. return 'export default {};';
  448. }
  449. return null;
  450. },
  451. getPackageInfoForId(id) {
  452. return idToPackageInfo.get(id);
  453. }
  454. };
  455. }
  456. exports.DEFAULTS = DEFAULTS;
  457. exports.default = nodeResolve;
  458. exports.nodeResolve = nodeResolve;