• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  ArrayIsArray,
5  ArrayPrototypeJoin,
6  ArrayPrototypeShift,
7  JSONParse,
8  JSONStringify,
9  ObjectFreeze,
10  ObjectGetOwnPropertyNames,
11  ObjectPrototypeHasOwnProperty,
12  RegExp,
13  RegExpPrototypeTest,
14  SafeMap,
15  SafeSet,
16  String,
17  StringPrototypeEndsWith,
18  StringPrototypeIncludes,
19  StringPrototypeIndexOf,
20  StringPrototypeLastIndexOf,
21  StringPrototypeReplace,
22  StringPrototypeSlice,
23  StringPrototypeSplit,
24  StringPrototypeStartsWith,
25} = primordials;
26const internalFS = require('internal/fs/utils');
27const { NativeModule } = require('internal/bootstrap/loaders');
28const {
29  realpathSync,
30  statSync,
31  Stats,
32} = require('fs');
33const { getOptionValue } = require('internal/options');
34// Do not eagerly grab .manifest, it may be in TDZ
35const policy = getOptionValue('--experimental-policy') ?
36  require('internal/process/policy') :
37  null;
38const { sep, relative, resolve } = require('path');
39const preserveSymlinks = getOptionValue('--preserve-symlinks');
40const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
41const typeFlag = getOptionValue('--input-type');
42const { URL, pathToFileURL, fileURLToPath } = require('internal/url');
43const {
44  ERR_INPUT_TYPE_NOT_ALLOWED,
45  ERR_INVALID_ARG_VALUE,
46  ERR_INVALID_MODULE_SPECIFIER,
47  ERR_INVALID_PACKAGE_CONFIG,
48  ERR_INVALID_PACKAGE_TARGET,
49  ERR_MANIFEST_DEPENDENCY_MISSING,
50  ERR_MODULE_NOT_FOUND,
51  ERR_PACKAGE_IMPORT_NOT_DEFINED,
52  ERR_PACKAGE_PATH_NOT_EXPORTED,
53  ERR_UNSUPPORTED_DIR_IMPORT,
54  ERR_UNSUPPORTED_ESM_URL_SCHEME,
55} = require('internal/errors').codes;
56const { Module: CJSModule } = require('internal/modules/cjs/loader');
57
58const packageJsonReader = require('internal/modules/package_json_reader');
59const userConditions = getOptionValue('--conditions');
60const noAddons = getOptionValue('--no-addons');
61const addonConditions = noAddons ? [] : ['node-addons'];
62
63const DEFAULT_CONDITIONS = ObjectFreeze([
64  'node',
65  'import',
66  ...addonConditions,
67  ...userConditions,
68]);
69
70const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
71
72const pendingDeprecation = getOptionValue('--pending-deprecation');
73
74function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
75  if (!pendingDeprecation)
76    return;
77  const { format } = defaultGetFormat(url);
78  if (format !== 'module')
79    return;
80  const path = fileURLToPath(url);
81  const pkgPath = fileURLToPath(new URL('.', packageJSONUrl));
82  const basePath = fileURLToPath(base);
83  if (main)
84    process.emitWarning(
85      `Package ${pkgPath} has a "main" field set to ${JSONStringify(main)}, ` +
86      `excluding the full filename and extension to the resolved file at "${
87        StringPrototypeSlice(path, pkgPath.length)}", imported from ${
88        basePath}.\n Automatic extension resolution of the "main" field is` +
89      'deprecated for ES modules.',
90      'DeprecationWarning',
91      'DEP0151'
92    );
93  else
94    process.emitWarning(
95      `No "main" or "exports" field defined in the package.json for ${pkgPath
96      } resolving the main entry point "${
97        StringPrototypeSlice(path, pkgPath.length)}", imported from ${basePath
98      }.\nDefault "index" lookups for the main are deprecated for ES modules.`,
99      'DeprecationWarning',
100      'DEP0151'
101    );
102}
103
104function getConditionsSet(conditions) {
105  if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
106    if (!ArrayIsArray(conditions)) {
107      throw new ERR_INVALID_ARG_VALUE('conditions', conditions,
108                                      'expected an array');
109    }
110    return new SafeSet(conditions);
111  }
112  return DEFAULT_CONDITIONS_SET;
113}
114
115const realpathCache = new SafeMap();
116const packageJSONCache = new SafeMap();  /* string -> PackageConfig */
117
118const tryStatSync =
119  (path) => statSync(path, { throwIfNoEntry: false }) ?? new Stats();
120
121function getPackageConfig(path, specifier, base) {
122  const existing = packageJSONCache.get(path);
123  if (existing !== undefined) {
124    return existing;
125  }
126  const source = packageJsonReader.read(path).string;
127  if (source === undefined) {
128    const packageConfig = {
129      pjsonPath: path,
130      exists: false,
131      main: undefined,
132      name: undefined,
133      type: 'none',
134      exports: undefined,
135      imports: undefined,
136    };
137    packageJSONCache.set(path, packageConfig);
138    return packageConfig;
139  }
140
141  let packageJSON;
142  try {
143    packageJSON = JSONParse(source);
144  } catch (error) {
145    throw new ERR_INVALID_PACKAGE_CONFIG(
146      path,
147      (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier),
148      error.message
149    );
150  }
151
152  let { imports, main, name, type } = packageJSON;
153  const { exports } = packageJSON;
154  if (typeof imports !== 'object' || imports === null) imports = undefined;
155  if (typeof main !== 'string') main = undefined;
156  if (typeof name !== 'string') name = undefined;
157  // Ignore unknown types for forwards compatibility
158  if (type !== 'module' && type !== 'commonjs') type = 'none';
159
160  const packageConfig = {
161    pjsonPath: path,
162    exists: true,
163    main,
164    name,
165    type,
166    exports,
167    imports,
168  };
169  packageJSONCache.set(path, packageConfig);
170  return packageConfig;
171}
172
173function getPackageScopeConfig(resolved) {
174  let packageJSONUrl = new URL('./package.json', resolved);
175  while (true) {
176    const packageJSONPath = packageJSONUrl.pathname;
177    if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json'))
178      break;
179    const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl),
180                                           resolved);
181    if (packageConfig.exists) return packageConfig;
182
183    const lastPackageJSONUrl = packageJSONUrl;
184    packageJSONUrl = new URL('../package.json', packageJSONUrl);
185
186    // Terminates at root where ../package.json equals ../../package.json
187    // (can't just check "/package.json" for Windows support).
188    if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) break;
189  }
190  const packageJSONPath = fileURLToPath(packageJSONUrl);
191  const packageConfig = {
192    pjsonPath: packageJSONPath,
193    exists: false,
194    main: undefined,
195    name: undefined,
196    type: 'none',
197    exports: undefined,
198    imports: undefined,
199  };
200  packageJSONCache.set(packageJSONPath, packageConfig);
201  return packageConfig;
202}
203
204/**
205 * Legacy CommonJS main resolution:
206 * 1. let M = pkg_url + (json main field)
207 * 2. TRY(M, M.js, M.json, M.node)
208 * 3. TRY(M/index.js, M/index.json, M/index.node)
209 * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
210 * 5. NOT_FOUND
211 * @param {string | URL} url
212 * @returns {boolean}
213 */
214function fileExists(url) {
215  return statSync(url, { throwIfNoEntry: false })?.isFile() ?? false;
216}
217
218function legacyMainResolve(packageJSONUrl, packageConfig, base) {
219  let guess;
220  if (packageConfig.main !== undefined) {
221    // Note: fs check redundances will be handled by Descriptor cache here.
222    if (fileExists(guess = new URL(`./${packageConfig.main}`,
223                                   packageJSONUrl))) {
224      return guess;
225    } else if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
226                                          packageJSONUrl)));
227    else if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
228                                        packageJSONUrl)));
229    else if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
230                                        packageJSONUrl)));
231    else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
232                                        packageJSONUrl)));
233    else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
234                                        packageJSONUrl)));
235    else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
236                                        packageJSONUrl)));
237    else guess = undefined;
238    if (guess) {
239      emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
240                                 packageConfig.main);
241      return guess;
242    }
243    // Fallthrough.
244  }
245  if (fileExists(guess = new URL('./index.js', packageJSONUrl)));
246  // So fs.
247  else if (fileExists(guess = new URL('./index.json', packageJSONUrl)));
248  else if (fileExists(guess = new URL('./index.node', packageJSONUrl)));
249  else guess = undefined;
250  if (guess) {
251    emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
252    return guess;
253  }
254  // Not found.
255  throw new ERR_MODULE_NOT_FOUND(
256    fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
257}
258
259function resolveExtensionsWithTryExactName(search) {
260  if (fileExists(search)) return search;
261  return resolveExtensions(search);
262}
263
264const extensions = ['.js', '.json', '.node', '.mjs'];
265function resolveExtensions(search) {
266  for (let i = 0; i < extensions.length; i++) {
267    const extension = extensions[i];
268    const guess = new URL(`${search.pathname}${extension}`, search);
269    if (fileExists(guess)) return guess;
270  }
271  return undefined;
272}
273
274function resolveDirectoryEntry(search) {
275  const dirPath = fileURLToPath(search);
276  const pkgJsonPath = resolve(dirPath, 'package.json');
277  if (fileExists(pkgJsonPath)) {
278    const pkgJson = packageJsonReader.read(pkgJsonPath);
279    if (pkgJson.containsKeys) {
280      const { main } = JSONParse(pkgJson.string);
281      if (main != null) {
282        const mainUrl = pathToFileURL(resolve(dirPath, main));
283        return resolveExtensionsWithTryExactName(mainUrl);
284      }
285    }
286  }
287  return resolveExtensions(new URL('index', search));
288}
289
290const encodedSepRegEx = /%2F|%5C/i;
291function finalizeResolution(resolved, base) {
292  if (RegExpPrototypeTest(encodedSepRegEx, resolved.pathname))
293    throw new ERR_INVALID_MODULE_SPECIFIER(
294      resolved.pathname, 'must not include encoded "/" or "\\" characters',
295      fileURLToPath(base));
296
297  const path = fileURLToPath(resolved);
298  if (getOptionValue('--experimental-specifier-resolution') === 'node') {
299    let file = resolveExtensionsWithTryExactName(resolved);
300    if (file !== undefined) return file;
301    if (!StringPrototypeEndsWith(path, '/')) {
302      file = resolveDirectoryEntry(new URL(`${resolved}/`));
303      if (file !== undefined) return file;
304    } else {
305      return resolveDirectoryEntry(resolved) || resolved;
306    }
307    throw new ERR_MODULE_NOT_FOUND(
308      resolved.pathname, fileURLToPath(base), 'module');
309  }
310
311  const stats = tryStatSync(StringPrototypeEndsWith(path, '/') ?
312    StringPrototypeSlice(path, -1) : path);
313  if (stats.isDirectory()) {
314    const err = new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base));
315    err.url = String(resolved);
316    throw err;
317  } else if (!stats.isFile()) {
318    throw new ERR_MODULE_NOT_FOUND(
319      path || resolved.pathname, base && fileURLToPath(base), 'module');
320  }
321
322  return resolved;
323}
324
325function throwImportNotDefined(specifier, packageJSONUrl, base) {
326  throw new ERR_PACKAGE_IMPORT_NOT_DEFINED(
327    specifier, packageJSONUrl && fileURLToPath(new URL('.', packageJSONUrl)),
328    fileURLToPath(base));
329}
330
331function throwExportsNotFound(subpath, packageJSONUrl, base) {
332  throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
333    fileURLToPath(new URL('.', packageJSONUrl)), subpath,
334    base && fileURLToPath(base));
335}
336
337function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) {
338  const reason = `request is not a valid subpath for the "${internal ?
339    'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}`;
340  throw new ERR_INVALID_MODULE_SPECIFIER(subpath, reason,
341                                         base && fileURLToPath(base));
342}
343
344function throwInvalidPackageTarget(
345  subpath, target, packageJSONUrl, internal, base) {
346  if (typeof target === 'object' && target !== null) {
347    target = JSONStringify(target, null, '');
348  } else {
349    target = `${target}`;
350  }
351  throw new ERR_INVALID_PACKAGE_TARGET(
352    fileURLToPath(new URL('.', packageJSONUrl)), subpath, target,
353    internal, base && fileURLToPath(base));
354}
355
356const invalidSegmentRegEx = /(^|\\|\/)(\.\.?|node_modules)(\\|\/|$)/;
357const patternRegEx = /\*/g;
358
359function resolvePackageTargetString(
360  target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) {
361  if (subpath !== '' && !pattern && target[target.length - 1] !== '/')
362    throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
363
364  if (!StringPrototypeStartsWith(target, './')) {
365    if (internal && !StringPrototypeStartsWith(target, '../') &&
366        !StringPrototypeStartsWith(target, '/')) {
367      let isURL = false;
368      try {
369        new URL(target);
370        isURL = true;
371      } catch {}
372      if (!isURL) {
373        const exportTarget = pattern ?
374          StringPrototypeReplace(target, patternRegEx, subpath) :
375          target + subpath;
376        return packageResolve(exportTarget, packageJSONUrl, conditions);
377      }
378    }
379    throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
380  }
381
382  if (RegExpPrototypeTest(invalidSegmentRegEx, StringPrototypeSlice(target, 2)))
383    throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
384
385  const resolved = new URL(target, packageJSONUrl);
386  const resolvedPath = resolved.pathname;
387  const packagePath = new URL('.', packageJSONUrl).pathname;
388
389  if (!StringPrototypeStartsWith(resolvedPath, packagePath))
390    throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
391
392  if (subpath === '') return resolved;
393
394  if (RegExpPrototypeTest(invalidSegmentRegEx, subpath))
395    throwInvalidSubpath(match + subpath, packageJSONUrl, internal, base);
396
397  if (pattern)
398    return new URL(StringPrototypeReplace(resolved.href, patternRegEx,
399                                          subpath));
400  return new URL(subpath, resolved);
401}
402
403/**
404 * @param {string} key
405 * @returns {boolean}
406 */
407function isArrayIndex(key) {
408  const keyNum = +key;
409  if (`${keyNum}` !== key) return false;
410  return keyNum >= 0 && keyNum < 0xFFFF_FFFF;
411}
412
413function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
414                              base, pattern, internal, conditions) {
415  if (typeof target === 'string') {
416    return resolvePackageTargetString(
417      target, subpath, packageSubpath, packageJSONUrl, base, pattern, internal,
418      conditions);
419  } else if (ArrayIsArray(target)) {
420    if (target.length === 0)
421      return null;
422
423    let lastException;
424    for (let i = 0; i < target.length; i++) {
425      const targetItem = target[i];
426      let resolved;
427      try {
428        resolved = resolvePackageTarget(
429          packageJSONUrl, targetItem, subpath, packageSubpath, base, pattern,
430          internal, conditions);
431      } catch (e) {
432        lastException = e;
433        if (e.code === 'ERR_INVALID_PACKAGE_TARGET')
434          continue;
435        throw e;
436      }
437      if (resolved === undefined)
438        continue;
439      if (resolved === null) {
440        lastException = null;
441        continue;
442      }
443      return resolved;
444    }
445    if (lastException === undefined || lastException === null)
446      return lastException;
447    throw lastException;
448  } else if (typeof target === 'object' && target !== null) {
449    const keys = ObjectGetOwnPropertyNames(target);
450    for (let i = 0; i < keys.length; i++) {
451      const key = keys[i];
452      if (isArrayIndex(key)) {
453        throw new ERR_INVALID_PACKAGE_CONFIG(
454          fileURLToPath(packageJSONUrl), base,
455          '"exports" cannot contain numeric property keys.');
456      }
457    }
458    for (let i = 0; i < keys.length; i++) {
459      const key = keys[i];
460      if (key === 'default' || conditions.has(key)) {
461        const conditionalTarget = target[key];
462        const resolved = resolvePackageTarget(
463          packageJSONUrl, conditionalTarget, subpath, packageSubpath, base,
464          pattern, internal, conditions);
465        if (resolved === undefined)
466          continue;
467        return resolved;
468      }
469    }
470    return undefined;
471  } else if (target === null) {
472    return null;
473  }
474  throwInvalidPackageTarget(packageSubpath, target, packageJSONUrl, internal,
475                            base);
476}
477
478function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
479  if (typeof exports === 'string' || ArrayIsArray(exports)) return true;
480  if (typeof exports !== 'object' || exports === null) return false;
481
482  const keys = ObjectGetOwnPropertyNames(exports);
483  let isConditionalSugar = false;
484  let i = 0;
485  for (let j = 0; j < keys.length; j++) {
486    const key = keys[j];
487    const curIsConditionalSugar = key === '' || key[0] !== '.';
488    if (i++ === 0) {
489      isConditionalSugar = curIsConditionalSugar;
490    } else if (isConditionalSugar !== curIsConditionalSugar) {
491      throw new ERR_INVALID_PACKAGE_CONFIG(
492        fileURLToPath(packageJSONUrl), base,
493        '"exports" cannot contain some keys starting with \'.\' and some not.' +
494        ' The exports object must either be an object of package subpath keys' +
495        ' or an object of main entry condition name keys only.');
496    }
497  }
498  return isConditionalSugar;
499}
500
501/**
502 * @param {URL} packageJSONUrl
503 * @param {string} packageSubpath
504 * @param {object} packageConfig
505 * @param {string} base
506 * @param {Set<string>} conditions
507 * @returns {URL}
508 */
509function packageExportsResolve(
510  packageJSONUrl, packageSubpath, packageConfig, base, conditions) {
511  let exports = packageConfig.exports;
512  if (isConditionalExportsMainSugar(exports, packageJSONUrl, base))
513    exports = { '.': exports };
514
515  if (ObjectPrototypeHasOwnProperty(exports, packageSubpath) &&
516      !StringPrototypeIncludes(packageSubpath, '*') &&
517      !StringPrototypeEndsWith(packageSubpath, '/')) {
518    const target = exports[packageSubpath];
519    const resolved = resolvePackageTarget(
520      packageJSONUrl, target, '', packageSubpath, base, false, false, conditions
521    );
522    if (resolved === null || resolved === undefined)
523      throwExportsNotFound(packageSubpath, packageJSONUrl, base);
524    return { resolved, exact: true };
525  }
526
527  let bestMatch = '';
528  let bestMatchSubpath;
529  const keys = ObjectGetOwnPropertyNames(exports);
530  for (let i = 0; i < keys.length; i++) {
531    const key = keys[i];
532    const patternIndex = StringPrototypeIndexOf(key, '*');
533    if (patternIndex !== -1 &&
534        StringPrototypeStartsWith(packageSubpath,
535                                  StringPrototypeSlice(key, 0, patternIndex))) {
536      const patternTrailer = StringPrototypeSlice(key, patternIndex + 1);
537      if (packageSubpath.length >= key.length &&
538          StringPrototypeEndsWith(packageSubpath, patternTrailer) &&
539          patternKeyCompare(bestMatch, key) === 1 &&
540          StringPrototypeLastIndexOf(key, '*') === patternIndex) {
541        bestMatch = key;
542        bestMatchSubpath = StringPrototypeSlice(
543          packageSubpath, patternIndex,
544          packageSubpath.length - patternTrailer.length);
545      }
546    } else if (key[key.length - 1] === '/' &&
547      StringPrototypeStartsWith(packageSubpath, key) &&
548      patternKeyCompare(bestMatch, key) === 1) {
549      bestMatch = key;
550      bestMatchSubpath = StringPrototypeSlice(packageSubpath, key.length);
551    }
552  }
553
554  if (bestMatch) {
555    const target = exports[bestMatch];
556    const pattern = StringPrototypeIncludes(bestMatch, '*');
557    const resolved = resolvePackageTarget(packageJSONUrl, target,
558                                          bestMatchSubpath, bestMatch, base,
559                                          pattern, false, conditions);
560    if (resolved === null || resolved === undefined)
561      throwExportsNotFound(packageSubpath, packageJSONUrl, base);
562    return { resolved, exact: pattern };
563  }
564
565  throwExportsNotFound(packageSubpath, packageJSONUrl, base);
566}
567
568function patternKeyCompare(a, b) {
569  const aPatternIndex = StringPrototypeIndexOf(a, '*');
570  const bPatternIndex = StringPrototypeIndexOf(b, '*');
571  const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
572  const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
573  if (baseLenA > baseLenB) return -1;
574  if (baseLenB > baseLenA) return 1;
575  if (aPatternIndex === -1) return 1;
576  if (bPatternIndex === -1) return -1;
577  if (a.length > b.length) return -1;
578  if (b.length > a.length) return 1;
579  return 0;
580}
581
582function packageImportsResolve(name, base, conditions) {
583  if (name === '#' || StringPrototypeStartsWith(name, '#/')) {
584    const reason = 'is not a valid internal imports specifier name';
585    throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base));
586  }
587  let packageJSONUrl;
588  const packageConfig = getPackageScopeConfig(base);
589  if (packageConfig.exists) {
590    packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
591    const imports = packageConfig.imports;
592    if (imports) {
593      if (ObjectPrototypeHasOwnProperty(imports, name) &&
594          !StringPrototypeIncludes(name, '*') &&
595          !StringPrototypeEndsWith(name, '/')) {
596        const resolved = resolvePackageTarget(
597          packageJSONUrl, imports[name], '', name, base, false, true, conditions
598        );
599        if (resolved !== null)
600          return { resolved, exact: true };
601      } else {
602        let bestMatch = '';
603        let bestMatchSubpath;
604        const keys = ObjectGetOwnPropertyNames(imports);
605        for (let i = 0; i < keys.length; i++) {
606          const key = keys[i];
607          const patternIndex = StringPrototypeIndexOf(key, '*');
608          if (patternIndex !== -1 &&
609              StringPrototypeStartsWith(name,
610                                        StringPrototypeSlice(key, 0,
611                                                             patternIndex))) {
612            const patternTrailer = StringPrototypeSlice(key, patternIndex + 1);
613            if (name.length >= key.length &&
614                StringPrototypeEndsWith(name, patternTrailer) &&
615                patternKeyCompare(bestMatch, key) === 1 &&
616                StringPrototypeLastIndexOf(key, '*') === patternIndex) {
617              bestMatch = key;
618              bestMatchSubpath = StringPrototypeSlice(
619                name, patternIndex, name.length - patternTrailer.length);
620            }
621          } else if (key[key.length - 1] === '/' &&
622            StringPrototypeStartsWith(name, key) &&
623            patternKeyCompare(bestMatch, key) === 1) {
624            bestMatch = key;
625            bestMatchSubpath = StringPrototypeSlice(name, key.length);
626          }
627        }
628
629        if (bestMatch) {
630          const target = imports[bestMatch];
631          const pattern = StringPrototypeIncludes(bestMatch, '*');
632          const resolved = resolvePackageTarget(packageJSONUrl, target,
633                                                bestMatchSubpath, bestMatch,
634                                                base, pattern, true,
635                                                conditions);
636          if (resolved !== null)
637            return { resolved, exact: pattern };
638        }
639      }
640    }
641  }
642  throwImportNotDefined(name, packageJSONUrl, base);
643}
644
645function getPackageType(url) {
646  const packageConfig = getPackageScopeConfig(url);
647  return packageConfig.type;
648}
649
650/**
651 * @param {string} specifier
652 * @param {URL} base
653 * @param {Set<string>} conditions
654 * @returns {URL}
655 */
656function packageResolve(specifier, base, conditions) {
657  let separatorIndex = StringPrototypeIndexOf(specifier, '/');
658  let validPackageName = true;
659  let isScoped = false;
660  if (specifier[0] === '@') {
661    isScoped = true;
662    if (separatorIndex === -1 || specifier.length === 0) {
663      validPackageName = false;
664    } else {
665      separatorIndex = StringPrototypeIndexOf(
666        specifier, '/', separatorIndex + 1);
667    }
668  }
669
670  const packageName = separatorIndex === -1 ?
671    specifier : StringPrototypeSlice(specifier, 0, separatorIndex);
672
673  // Package name cannot have leading . and cannot have percent-encoding or
674  // separators.
675  for (let i = 0; i < packageName.length; i++) {
676    if (packageName[i] === '%' || packageName[i] === '\\') {
677      validPackageName = false;
678      break;
679    }
680  }
681
682  if (!validPackageName) {
683    throw new ERR_INVALID_MODULE_SPECIFIER(
684      specifier, 'is not a valid package name', fileURLToPath(base));
685  }
686
687  const packageSubpath = '.' + (separatorIndex === -1 ? '' :
688    StringPrototypeSlice(specifier, separatorIndex));
689
690  // ResolveSelf
691  const packageConfig = getPackageScopeConfig(base);
692  if (packageConfig.exists) {
693    const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
694    if (packageConfig.name === packageName &&
695        packageConfig.exports !== undefined && packageConfig.exports !== null) {
696      return packageExportsResolve(
697        packageJSONUrl, packageSubpath, packageConfig, base, conditions
698      ).resolved;
699    }
700  }
701
702  let packageJSONUrl =
703    new URL('./node_modules/' + packageName + '/package.json', base);
704  let packageJSONPath = fileURLToPath(packageJSONUrl);
705  let lastPath;
706  do {
707    const stat = tryStatSync(StringPrototypeSlice(packageJSONPath, 0,
708                                                  packageJSONPath.length - 13));
709    if (!stat.isDirectory()) {
710      lastPath = packageJSONPath;
711      packageJSONUrl = new URL((isScoped ?
712        '../../../../node_modules/' : '../../../node_modules/') +
713        packageName + '/package.json', packageJSONUrl);
714      packageJSONPath = fileURLToPath(packageJSONUrl);
715      continue;
716    }
717
718    // Package match.
719    const packageConfig = getPackageConfig(packageJSONPath, specifier, base);
720    if (packageConfig.exports !== undefined && packageConfig.exports !== null)
721      return packageExportsResolve(
722        packageJSONUrl, packageSubpath, packageConfig, base, conditions
723      ).resolved;
724    if (packageSubpath === '.')
725      return legacyMainResolve(packageJSONUrl, packageConfig, base);
726    return new URL(packageSubpath, packageJSONUrl);
727    // Cross-platform root check.
728  } while (packageJSONPath.length !== lastPath.length);
729
730  // eslint can't handle the above code.
731  // eslint-disable-next-line no-unreachable
732  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base));
733}
734
735function isBareSpecifier(specifier) {
736  return specifier[0] && specifier[0] !== '/' && specifier[0] !== '.';
737}
738
739function isRelativeSpecifier(specifier) {
740  if (specifier[0] === '.') {
741    if (specifier.length === 1 || specifier[1] === '/') return true;
742    if (specifier[1] === '.') {
743      if (specifier.length === 2 || specifier[2] === '/') return true;
744    }
745  }
746  return false;
747}
748
749function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
750  if (specifier === '') return false;
751  if (specifier[0] === '/') return true;
752  return isRelativeSpecifier(specifier);
753}
754
755/**
756 * @param {string} specifier
757 * @param {URL} base
758 * @param {Set<string>} conditions
759 * @returns {URL}
760 */
761function moduleResolve(specifier, base, conditions) {
762  // Order swapped from spec for minor perf gain.
763  // Ok since relative URLs cannot parse as URLs.
764  let resolved;
765  if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
766    resolved = new URL(specifier, base);
767  } else if (specifier[0] === '#') {
768    ({ resolved } = packageImportsResolve(specifier, base, conditions));
769  } else {
770    try {
771      resolved = new URL(specifier);
772    } catch {
773      resolved = packageResolve(specifier, base, conditions);
774    }
775  }
776  return finalizeResolution(resolved, base);
777}
778
779/**
780 * Try to resolve an import as a CommonJS module
781 * @param {string} specifier
782 * @param {string} parentURL
783 * @returns {boolean|string}
784 */
785function resolveAsCommonJS(specifier, parentURL) {
786  try {
787    const parent = fileURLToPath(parentURL);
788    const tmpModule = new CJSModule(parent, null);
789    tmpModule.paths = CJSModule._nodeModulePaths(parent);
790
791    let found = CJSModule._resolveFilename(specifier, tmpModule, false);
792
793    // If it is a relative specifier return the relative path
794    // to the parent
795    if (isRelativeSpecifier(specifier)) {
796      found = relative(parent, found);
797      // Add '.separator if the path does not start with '..separator'
798      // This should be a safe assumption because when loading
799      // esm modules there should be always a file specified so
800      // there should not be a specifier like '..' or '.'
801      if (!StringPrototypeStartsWith(found, `..${sep}`)) {
802        found = `.${sep}${found}`;
803      }
804    } else if (isBareSpecifier(specifier)) {
805      // If it is a bare specifier return the relative path within the
806      // module
807      const pkg = StringPrototypeSplit(specifier, '/')[0];
808      const index = StringPrototypeIndexOf(found, pkg);
809      if (index !== -1) {
810        found = StringPrototypeSlice(found, index);
811      }
812    }
813    // Normalize the path separator to give a valid suggestion
814    // on Windows
815    if (process.platform === 'win32') {
816      found = StringPrototypeReplace(found, new RegExp(`\\${sep}`, 'g'), '/');
817    }
818    return found;
819  } catch {
820    return false;
821  }
822}
823
824function defaultResolve(specifier, context = {}, defaultResolveUnused) {
825  let { parentURL, conditions } = context;
826  if (parentURL && policy?.manifest) {
827    const redirects = policy.manifest.getDependencyMapper(parentURL);
828    if (redirects) {
829      const { resolve, reaction } = redirects;
830      const destination = resolve(specifier, new SafeSet(conditions));
831      let missing = true;
832      if (destination === true) {
833        missing = false;
834      } else if (destination) {
835        const href = destination.href;
836        return { url: href };
837      }
838      if (missing) {
839        reaction(new ERR_MANIFEST_DEPENDENCY_MISSING(
840          parentURL,
841          specifier,
842          ArrayPrototypeJoin([...conditions], ', '))
843        );
844      }
845    }
846  }
847  let parsed;
848  try {
849    parsed = new URL(specifier);
850    if (parsed.protocol === 'data:') {
851      return {
852        url: specifier
853      };
854    }
855  } catch {}
856  if (parsed && parsed.protocol === 'node:')
857    return { url: specifier };
858  if (parsed && parsed.protocol !== 'file:' && parsed.protocol !== 'data:')
859    throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(parsed);
860  if (NativeModule.canBeRequiredByUsers(specifier)) {
861    return {
862      url: 'node:' + specifier
863    };
864  }
865  if (parentURL && StringPrototypeStartsWith(parentURL, 'data:')) {
866    // This is gonna blow up, we want the error
867    new URL(specifier, parentURL);
868  }
869
870  const isMain = parentURL === undefined;
871  if (isMain) {
872    parentURL = pathToFileURL(`${process.cwd()}/`).href;
873
874    // This is the initial entry point to the program, and --input-type has
875    // been passed as an option; but --input-type can only be used with
876    // --eval, --print or STDIN string input. It is not allowed with file
877    // input, to avoid user confusion over how expansive the effect of the
878    // flag should be (i.e. entry point only, package scope surrounding the
879    // entry point, etc.).
880    if (typeFlag)
881      throw new ERR_INPUT_TYPE_NOT_ALLOWED();
882  }
883
884  conditions = getConditionsSet(conditions);
885  let url;
886  try {
887    url = moduleResolve(specifier, parentURL, conditions);
888  } catch (error) {
889    // Try to give the user a hint of what would have been the
890    // resolved CommonJS module
891    if (error.code === 'ERR_MODULE_NOT_FOUND' ||
892        error.code === 'ERR_UNSUPPORTED_DIR_IMPORT') {
893      if (StringPrototypeStartsWith(specifier, 'file://')) {
894        specifier = fileURLToPath(specifier);
895      }
896      const found = resolveAsCommonJS(specifier, parentURL);
897      if (found) {
898        // Modify the stack and message string to include the hint
899        const lines = StringPrototypeSplit(error.stack, '\n');
900        const hint = `Did you mean to import ${found}?`;
901        error.stack =
902          ArrayPrototypeShift(lines) + '\n' +
903          hint + '\n' +
904          ArrayPrototypeJoin(lines, '\n');
905        error.message += `\n${hint}`;
906      }
907    }
908    throw error;
909  }
910
911  if (isMain ? !preserveSymlinksMain : !preserveSymlinks) {
912    const urlPath = fileURLToPath(url);
913    const real = realpathSync(urlPath, {
914      [internalFS.realpathCacheKey]: realpathCache
915    });
916    const old = url;
917    url = pathToFileURL(
918      real + (StringPrototypeEndsWith(urlPath, sep) ? '/' : ''));
919    url.search = old.search;
920    url.hash = old.hash;
921  }
922
923  return { url: `${url}` };
924}
925
926module.exports = {
927  DEFAULT_CONDITIONS,
928  defaultResolve,
929  encodedSepRegEx,
930  getPackageScopeConfig,
931  getPackageType,
932  packageExportsResolve,
933  packageImportsResolve
934};
935
936// cycle
937const { defaultGetFormat } = require('internal/modules/esm/get_format');
938