1'use strict';
2
3const {
4  ArrayIsArray,
5  ArrayPrototypeJoin,
6  ArrayPrototypeShift,
7  JSONStringify,
8  ObjectGetOwnPropertyNames,
9  ObjectPrototypeHasOwnProperty,
10  RegExp,
11  RegExpPrototypeExec,
12  RegExpPrototypeSymbolReplace,
13  SafeMap,
14  SafeSet,
15  String,
16  StringPrototypeEndsWith,
17  StringPrototypeIncludes,
18  StringPrototypeIndexOf,
19  StringPrototypeLastIndexOf,
20  StringPrototypeReplace,
21  StringPrototypeSlice,
22  StringPrototypeSplit,
23  StringPrototypeStartsWith,
24} = primordials;
25const internalFS = require('internal/fs/utils');
26const { BuiltinModule } = require('internal/bootstrap/realm');
27const { realpathSync } = require('fs');
28const { getOptionValue } = require('internal/options');
29const pendingDeprecation = getOptionValue('--pending-deprecation');
30// Do not eagerly grab .manifest, it may be in TDZ
31const policy = getOptionValue('--experimental-policy') ?
32  require('internal/process/policy') :
33  null;
34const { sep, relative, resolve, toNamespacedPath } = require('path');
35const preserveSymlinks = getOptionValue('--preserve-symlinks');
36const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
37const experimentalNetworkImports =
38  getOptionValue('--experimental-network-imports');
39const inputTypeFlag = getOptionValue('--input-type');
40const { URL, pathToFileURL, fileURLToPath, isURL, toPathIfFileURL } = require('internal/url');
41const { getCWDURL } = require('internal/util');
42const { canParse: URLCanParse } = internalBinding('url');
43const {
44  ERR_INPUT_TYPE_NOT_ALLOWED,
45  ERR_INVALID_ARG_TYPE,
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_NETWORK_IMPORT_DISALLOWED,
55} = require('internal/errors').codes;
56
57const { Module: CJSModule } = require('internal/modules/cjs/loader');
58const { getPackageScopeConfig } = require('internal/modules/esm/package_config');
59const { getConditionsSet } = require('internal/modules/esm/utils');
60const packageJsonReader = require('internal/modules/package_json_reader');
61const { internalModuleStat } = internalBinding('fs');
62
63/**
64 * @typedef {import('internal/modules/esm/package_config.js').PackageConfig} PackageConfig
65 */
66
67
68const emittedPackageWarnings = new SafeSet();
69
70/**
71 * Emits a deprecation warning for the use of a deprecated trailing slash pattern mapping in the "exports" field
72 * module resolution of a package.
73 * @param {string} match - The deprecated trailing slash pattern mapping.
74 * @param {string} pjsonUrl - The URL of the package.json file.
75 * @param {string} base - The URL of the module that imported the package.
76 */
77function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) {
78  const pjsonPath = fileURLToPath(pjsonUrl);
79  if (emittedPackageWarnings.has(pjsonPath + '|' + match)) { return; }
80  emittedPackageWarnings.add(pjsonPath + '|' + match);
81  process.emitWarning(
82    `Use of deprecated trailing slash pattern mapping "${match}" in the ` +
83    `"exports" field module resolution of the package at ${pjsonPath}${
84      base ? ` imported from ${fileURLToPath(base)}` :
85        ''}. Mapping specifiers ending in "/" is no longer supported.`,
86    'DeprecationWarning',
87    'DEP0155',
88  );
89}
90
91const doubleSlashRegEx = /[/\\][/\\]/;
92
93/**
94 * Emits a deprecation warning for invalid segment in module resolution.
95 * @param {string} target - The target module.
96 * @param {string} request - The requested module.
97 * @param {string} match - The matched module.
98 * @param {string} pjsonUrl - The package.json URL.
99 * @param {boolean} internal - Whether the module is in the "imports" or "exports" field.
100 * @param {string} base - The base URL.
101 * @param {boolean} isTarget - Whether the target is a module.
102 */
103function emitInvalidSegmentDeprecation(target, request, match, pjsonUrl, internal, base, isTarget) {
104  if (!pendingDeprecation) { return; }
105  const pjsonPath = fileURLToPath(pjsonUrl);
106  const double = RegExpPrototypeExec(doubleSlashRegEx, isTarget ? target : request) !== null;
107  process.emitWarning(
108    `Use of deprecated ${double ? 'double slash' :
109      'leading or trailing slash matching'} resolving "${target}" for module ` +
110      `request "${request}" ${request !== match ? `matched to "${match}" ` : ''
111      }in the "${internal ? 'imports' : 'exports'}" field module resolution of the package at ${
112        pjsonPath}${base ? ` imported from ${fileURLToPath(base)}` : ''}.`,
113    'DeprecationWarning',
114    'DEP0166',
115  );
116}
117
118/**
119 * Emits a deprecation warning if the given URL is a module and
120 * the package.json file does not define a "main" or "exports" field.
121 * @param {URL} url - The URL of the module being resolved.
122 * @param {URL} packageJSONUrl - The URL of the package.json file for the module.
123 * @param {string | URL} [base] - The base URL for the module being resolved.
124 * @param {string} [main] - The "main" field from the package.json file.
125 */
126function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
127  const format = defaultGetFormatWithoutErrors(url);
128  if (format !== 'module') { return; }
129  const path = fileURLToPath(url);
130  const pkgPath = fileURLToPath(new URL('.', packageJSONUrl));
131  const basePath = fileURLToPath(base);
132  if (!main) {
133    process.emitWarning(
134      `No "main" or "exports" field defined in the package.json for ${pkgPath
135      } resolving the main entry point "${
136        StringPrototypeSlice(path, pkgPath.length)}", imported from ${basePath
137      }.\nDefault "index" lookups for the main are deprecated for ES modules.`,
138      'DeprecationWarning',
139      'DEP0151',
140    );
141  } else if (resolve(pkgPath, main) !== path) {
142    process.emitWarning(
143      `Package ${pkgPath} has a "main" field set to "${main}", ` +
144      `excluding the full filename and extension to the resolved file at "${
145        StringPrototypeSlice(path, pkgPath.length)}", imported from ${
146        basePath}.\n Automatic extension resolution of the "main" field is ` +
147      'deprecated for ES modules.',
148      'DeprecationWarning',
149      'DEP0151',
150    );
151  }
152}
153
154const realpathCache = new SafeMap();
155
156/**
157 * @param {string | URL} url
158 * @returns {boolean}
159 */
160function fileExists(url) {
161  return internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0;
162}
163
164/**
165 * Legacy CommonJS main resolution:
166 * 1. let M = pkg_url + (json main field)
167 * 2. TRY(M, M.js, M.json, M.node)
168 * 3. TRY(M/index.js, M/index.json, M/index.node)
169 * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
170 * 5. NOT_FOUND
171 * @param {URL} packageJSONUrl
172 * @param {PackageConfig} packageConfig
173 * @param {string | URL | undefined} base
174 * @returns {URL}
175 */
176function legacyMainResolve(packageJSONUrl, packageConfig, base) {
177  let guess;
178  if (packageConfig.main !== undefined) {
179    // Note: fs check redundances will be handled by Descriptor cache here.
180    if (fileExists(guess = new URL(`./${packageConfig.main}`, packageJSONUrl))) {
181      return guess;
182    } else if (fileExists(guess = new URL(`./${packageConfig.main}.js`, packageJSONUrl))) {
183      // Handled below.
184    } else if (fileExists(guess = new URL(`./${packageConfig.main}.json`, packageJSONUrl))) {
185      // Handled below.
186    } else if (fileExists(guess = new URL(`./${packageConfig.main}.node`, packageJSONUrl))) {
187      // Handled below.
188    } else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`, packageJSONUrl))) {
189      // Handled below.
190    } else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`, packageJSONUrl))) {
191      // Handled below.
192    } else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`, packageJSONUrl))) {
193      // Handled below.
194    } else {
195      guess = undefined;
196    }
197    if (guess) {
198      emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
199                                 packageConfig.main);
200      return guess;
201    }
202    // Fallthrough.
203  }
204  if (fileExists(guess = new URL('./index.js', packageJSONUrl))) {
205    // Handled below.
206  } else if (fileExists(guess = new URL('./index.json', packageJSONUrl))) {
207    // Handled below.
208  } else if (fileExists(guess = new URL('./index.node', packageJSONUrl))) {
209    // Handled below.
210  } else {
211    guess = undefined;
212  }
213  if (guess) {
214    emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
215    return guess;
216  }
217  // Not found.
218  throw new ERR_MODULE_NOT_FOUND(
219    fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
220}
221
222/**
223 * @param {URL} search
224 * @returns {URL | undefined}
225 */
226function resolveExtensionsWithTryExactName(search) {
227  if (fileExists(search)) { return search; }
228  return resolveExtensions(search);
229}
230
231const extensions = ['.js', '.json', '.node', '.mjs'];
232
233/**
234 * @param {URL} search
235 * @returns {URL | undefined}
236 */
237function resolveExtensions(search) {
238  for (let i = 0; i < extensions.length; i++) {
239    const extension = extensions[i];
240    const guess = new URL(`${search.pathname}${extension}`, search);
241    if (fileExists(guess)) { return guess; }
242  }
243  return undefined;
244}
245
246/**
247 * @param {URL} search
248 * @returns {URL | undefined}
249 */
250function resolveDirectoryEntry(search) {
251  const dirPath = fileURLToPath(search);
252  const pkgJsonPath = resolve(dirPath, 'package.json');
253  if (fileExists(pkgJsonPath)) {
254    const pkgJson = packageJsonReader.read(pkgJsonPath);
255    if (pkgJson.exists) {
256      const { main } = pkgJson;
257      if (main != null) {
258        const mainUrl = pathToFileURL(resolve(dirPath, main));
259        return resolveExtensionsWithTryExactName(mainUrl);
260      }
261    }
262  }
263  return resolveExtensions(new URL('index', search));
264}
265
266const encodedSepRegEx = /%2F|%5C/i;
267/**
268 * Finalizes the resolution of a module specifier by checking if the resolved pathname contains encoded "/" or "\\"
269 * characters, checking if the resolved pathname is a directory or file, and resolving any symlinks if necessary.
270 * @param {URL} resolved - The resolved URL object.
271 * @param {string | URL | undefined} base - The base URL object.
272 * @param {boolean} preserveSymlinks - Whether to preserve symlinks or not.
273 * @returns {URL} - The finalized URL object.
274 * @throws {ERR_INVALID_MODULE_SPECIFIER} - If the resolved pathname contains encoded "/" or "\\" characters.
275 * @throws {ERR_UNSUPPORTED_DIR_IMPORT} - If the resolved pathname is a directory.
276 * @throws {ERR_MODULE_NOT_FOUND} - If the resolved pathname is not a file.
277 */
278function finalizeResolution(resolved, base, preserveSymlinks) {
279  if (RegExpPrototypeExec(encodedSepRegEx, resolved.pathname) !== null) {
280    throw new ERR_INVALID_MODULE_SPECIFIER(
281      resolved.pathname, 'must not include encoded "/" or "\\" characters',
282      fileURLToPath(base));
283  }
284
285  let path;
286  try {
287    path = fileURLToPath(resolved);
288  } catch (err) {
289    const { setOwnProperty } = require('internal/util');
290    setOwnProperty(err, 'input', `${resolved}`);
291    setOwnProperty(err, 'module', `${base}`);
292    throw err;
293  }
294
295  if (getOptionValue('--experimental-specifier-resolution') === 'node') {
296    let file = resolveExtensionsWithTryExactName(resolved);
297
298    // Directory
299    if (file === undefined) {
300      file = StringPrototypeEndsWith(path, '/') ?
301        (resolveDirectoryEntry(resolved) || resolved) : resolveDirectoryEntry(new URL(`${resolved}/`));
302
303      if (file === resolved) { return file; }
304
305      if (file === undefined) {
306        throw new ERR_MODULE_NOT_FOUND(
307          resolved.pathname, fileURLToPath(base), 'module');
308      }
309    }
310    // If `preserveSymlinks` is false, `resolved` is returned and `path`
311    // is used only to check that the resolved path exists.
312    resolved = file;
313    path = fileURLToPath(resolved);
314  }
315
316  const stats = internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ?
317    StringPrototypeSlice(path, -1) : path));
318
319  // Check for stats.isDirectory()
320  if (stats === 1) {
321    throw new ERR_UNSUPPORTED_DIR_IMPORT(path, fileURLToPath(base), String(resolved));
322  } else if (stats !== 0) {
323    // Check for !stats.isFile()
324    if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) {
325      process.send({ 'watch:require': [path || resolved.pathname] });
326    }
327    throw new ERR_MODULE_NOT_FOUND(
328      path || resolved.pathname, base && fileURLToPath(base), resolved);
329  }
330
331  if (!preserveSymlinks) {
332    const real = realpathSync(path, {
333      [internalFS.realpathCacheKey]: realpathCache,
334    });
335    const { search, hash } = resolved;
336    resolved =
337        pathToFileURL(real + (StringPrototypeEndsWith(path, sep) ? '/' : ''));
338    resolved.search = search;
339    resolved.hash = hash;
340  }
341
342  return resolved;
343}
344
345/**
346 * Returns an error object indicating that the specified import is not defined.
347 * @param {string} specifier - The import specifier that is not defined.
348 * @param {URL} packageJSONUrl - The URL of the package.json file, or null if not available.
349 * @param {string | URL | undefined} base - The base URL to use for resolving relative URLs.
350 * @returns {ERR_PACKAGE_IMPORT_NOT_DEFINED} - The error object.
351 */
352function importNotDefined(specifier, packageJSONUrl, base) {
353  return new ERR_PACKAGE_IMPORT_NOT_DEFINED(
354    specifier, packageJSONUrl && fileURLToPath(new URL('.', packageJSONUrl)),
355    fileURLToPath(base));
356}
357
358/**
359 * Returns an error object indicating that the specified subpath was not exported by the package.
360 * @param {string} subpath - The subpath that was not exported.
361 * @param {URL} packageJSONUrl - The URL of the package.json file.
362 * @param {string | URL | undefined} [base] - The base URL to use for resolving the subpath.
363 * @returns {ERR_PACKAGE_PATH_NOT_EXPORTED} - The error object.
364 */
365function exportsNotFound(subpath, packageJSONUrl, base) {
366  return new ERR_PACKAGE_PATH_NOT_EXPORTED(
367    fileURLToPath(new URL('.', packageJSONUrl)), subpath,
368    base && fileURLToPath(base));
369}
370
371/**
372 * Throws an error indicating that the given request is not a valid subpath match for the specified pattern.
373 * @param {string} request - The request that failed to match the pattern.
374 * @param {string} match - The pattern that the request was compared against.
375 * @param {URL} packageJSONUrl - The URL of the package.json file being resolved.
376 * @param {boolean} internal - Whether the resolution is for an "imports" or "exports" field in package.json.
377 * @param {string | URL | undefined} base - The base URL for the resolution.
378 * @throws {ERR_INVALID_MODULE_SPECIFIER} When the request is not a valid match for the pattern.
379 */
380function throwInvalidSubpath(request, match, packageJSONUrl, internal, base) {
381  const reason = `request is not a valid match in pattern "${match}" for the "${
382    internal ? 'imports' : 'exports'}" resolution of ${
383    fileURLToPath(packageJSONUrl)}`;
384  throw new ERR_INVALID_MODULE_SPECIFIER(request, reason,
385                                         base && fileURLToPath(base));
386}
387
388/**
389 * Creates an error object for an invalid package target.
390 * @param {string} subpath - The subpath.
391 * @param {import('internal/modules/esm/package_config.js').PackageTarget} target - The target.
392 * @param {URL} packageJSONUrl - The URL of the package.json file.
393 * @param {boolean} internal - Whether the package is internal.
394 * @param {string | URL | undefined} base - The base URL.
395 * @returns {ERR_INVALID_PACKAGE_TARGET} - The error object.
396 */
397function invalidPackageTarget(
398  subpath, target, packageJSONUrl, internal, base) {
399  if (typeof target === 'object' && target !== null) {
400    target = JSONStringify(target, null, '');
401  } else {
402    target = `${target}`;
403  }
404  return new ERR_INVALID_PACKAGE_TARGET(
405    fileURLToPath(new URL('.', packageJSONUrl)), subpath, target,
406    internal, base && fileURLToPath(base));
407}
408
409const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i;
410const deprecatedInvalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i;
411const invalidPackageNameRegEx = /^\.|%|\\/;
412const patternRegEx = /\*/g;
413
414/**
415 * Resolves the package target string to a URL object.
416 * @param {string} target - The target string to resolve.
417 * @param {string} subpath - The subpath to append to the resolved URL.
418 * @param {RegExpMatchArray} match - The matched string array from the import statement.
419 * @param {string} packageJSONUrl - The URL of the package.json file.
420 * @param {string} base - The base URL to resolve the target against.
421 * @param {RegExp} pattern - The pattern to replace in the target string.
422 * @param {boolean} internal - Whether the target is internal to the package.
423 * @param {boolean} isPathMap - Whether the target is a path map.
424 * @param {string[]} conditions - The import conditions.
425 * @returns {URL} - The resolved URL object.
426 * @throws {ERR_INVALID_PACKAGE_TARGET} - If the target is invalid.
427 * @throws {ERR_INVALID_SUBPATH} - If the subpath is invalid.
428 */
429function resolvePackageTargetString(
430  target,
431  subpath,
432  match,
433  packageJSONUrl,
434  base,
435  pattern,
436  internal,
437  isPathMap,
438  conditions,
439) {
440
441  if (subpath !== '' && !pattern && target[target.length - 1] !== '/') {
442    throw invalidPackageTarget(match, target, packageJSONUrl, internal, base);
443  }
444
445  if (!StringPrototypeStartsWith(target, './')) {
446    if (internal && !StringPrototypeStartsWith(target, '../') &&
447        !StringPrototypeStartsWith(target, '/')) {
448      // No need to convert target to string, since it's already presumed to be
449      if (!URLCanParse(target)) {
450        const exportTarget = pattern ?
451          RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) :
452          target + subpath;
453        return packageResolve(
454          exportTarget, packageJSONUrl, conditions);
455      }
456    }
457    throw invalidPackageTarget(match, target, packageJSONUrl, internal, base);
458  }
459
460  if (RegExpPrototypeExec(invalidSegmentRegEx, StringPrototypeSlice(target, 2)) !== null) {
461    if (RegExpPrototypeExec(deprecatedInvalidSegmentRegEx, StringPrototypeSlice(target, 2)) === null) {
462      if (!isPathMap) {
463        const request = pattern ?
464          StringPrototypeReplace(match, '*', () => subpath) :
465          match + subpath;
466        const resolvedTarget = pattern ?
467          RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) :
468          target;
469        emitInvalidSegmentDeprecation(resolvedTarget, request, match, packageJSONUrl, internal, base, true);
470      }
471    } else {
472      throw invalidPackageTarget(match, target, packageJSONUrl, internal, base);
473    }
474  }
475
476  const resolved = new URL(target, packageJSONUrl);
477  const resolvedPath = resolved.pathname;
478  const packagePath = new URL('.', packageJSONUrl).pathname;
479
480  if (!StringPrototypeStartsWith(resolvedPath, packagePath)) {
481    throw invalidPackageTarget(match, target, packageJSONUrl, internal, base);
482  }
483
484  if (subpath === '') { return resolved; }
485
486  if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) {
487    const request = pattern ? StringPrototypeReplace(match, '*', () => subpath) : match + subpath;
488    if (RegExpPrototypeExec(deprecatedInvalidSegmentRegEx, subpath) === null) {
489      if (!isPathMap) {
490        const resolvedTarget = pattern ?
491          RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) :
492          target;
493        emitInvalidSegmentDeprecation(resolvedTarget, request, match, packageJSONUrl, internal, base, false);
494      }
495    } else {
496      throwInvalidSubpath(request, match, packageJSONUrl, internal, base);
497    }
498  }
499
500  if (pattern) {
501    return new URL(
502      RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath),
503    );
504  }
505
506  return new URL(subpath, resolved);
507}
508
509/**
510 * Checks if the given key is a valid array index.
511 * @param {string} key - The key to check.
512 * @returns {boolean} - Returns `true` if the key is a valid array index, else `false`.
513 */
514function isArrayIndex(key) {
515  const keyNum = +key;
516  if (`${keyNum}` !== key) { return false; }
517  return keyNum >= 0 && keyNum < 0xFFFF_FFFF;
518}
519
520/**
521 * Resolves the target of a package based on the provided parameters.
522 * @param {string} packageJSONUrl - The URL of the package.json file.
523 * @param {import('internal/modules/esm/package_config.js').PackageTarget} target - The target to resolve.
524 * @param {string} subpath - The subpath to resolve.
525 * @param {string} packageSubpath - The subpath of the package to resolve.
526 * @param {string} base - The base path to resolve.
527 * @param {RegExp} pattern - The pattern to match.
528 * @param {boolean} internal - Whether the package is internal.
529 * @param {boolean} isPathMap - Whether the package is a path map.
530 * @param {Set<string>} conditions - The conditions to match.
531 * @returns {URL | null | undefined} - The resolved target, or null if not found, or undefined if not resolvable.
532 */
533function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
534                              base, pattern, internal, isPathMap, conditions) {
535  if (typeof target === 'string') {
536    return resolvePackageTargetString(
537      target, subpath, packageSubpath, packageJSONUrl, base, pattern, internal,
538      isPathMap, conditions);
539  } else if (ArrayIsArray(target)) {
540    if (target.length === 0) {
541      return null;
542    }
543
544    let lastException;
545    for (let i = 0; i < target.length; i++) {
546      const targetItem = target[i];
547      let resolveResult;
548      try {
549        resolveResult = resolvePackageTarget(
550          packageJSONUrl, targetItem, subpath, packageSubpath, base, pattern,
551          internal, isPathMap, conditions);
552      } catch (e) {
553        lastException = e;
554        if (e.code === 'ERR_INVALID_PACKAGE_TARGET') {
555          continue;
556        }
557        throw e;
558      }
559      if (resolveResult === undefined) {
560        continue;
561      }
562      if (resolveResult === null) {
563        lastException = null;
564        continue;
565      }
566      return resolveResult;
567    }
568    if (lastException === undefined || lastException === null) {
569      return lastException;
570    }
571    throw lastException;
572  } else if (typeof target === 'object' && target !== null) {
573    const keys = ObjectGetOwnPropertyNames(target);
574    for (let i = 0; i < keys.length; i++) {
575      const key = keys[i];
576      if (isArrayIndex(key)) {
577        throw new ERR_INVALID_PACKAGE_CONFIG(
578          fileURLToPath(packageJSONUrl), base,
579          '"exports" cannot contain numeric property keys.');
580      }
581    }
582    for (let i = 0; i < keys.length; i++) {
583      const key = keys[i];
584      if (key === 'default' || conditions.has(key)) {
585        const conditionalTarget = target[key];
586        const resolveResult = resolvePackageTarget(
587          packageJSONUrl, conditionalTarget, subpath, packageSubpath, base,
588          pattern, internal, isPathMap, conditions);
589        if (resolveResult === undefined) { continue; }
590        return resolveResult;
591      }
592    }
593    return undefined;
594  } else if (target === null) {
595    return null;
596  }
597  throw invalidPackageTarget(packageSubpath, target, packageJSONUrl, internal,
598                             base);
599}
600
601/**
602 * Is the given exports object using the shorthand syntax?
603 * @param {import('internal/modules/esm/package_config.js').PackageConfig['exports']} exports
604 * @param {URL} packageJSONUrl The URL of the package.json file.
605 * @param {string | URL | undefined} base The base URL.
606 */
607function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
608  if (typeof exports === 'string' || ArrayIsArray(exports)) { return true; }
609  if (typeof exports !== 'object' || exports === null) { return false; }
610
611  const keys = ObjectGetOwnPropertyNames(exports);
612  let isConditionalSugar = false;
613  let i = 0;
614  for (let j = 0; j < keys.length; j++) {
615    const key = keys[j];
616    const curIsConditionalSugar = key === '' || key[0] !== '.';
617    if (i++ === 0) {
618      isConditionalSugar = curIsConditionalSugar;
619    } else if (isConditionalSugar !== curIsConditionalSugar) {
620      throw new ERR_INVALID_PACKAGE_CONFIG(
621        fileURLToPath(packageJSONUrl), base,
622        '"exports" cannot contain some keys starting with \'.\' and some not.' +
623        ' The exports object must either be an object of package subpath keys' +
624        ' or an object of main entry condition name keys only.');
625    }
626  }
627  return isConditionalSugar;
628}
629
630/**
631 * Resolves the exports of a package.
632 * @param {URL} packageJSONUrl - The URL of the package.json file.
633 * @param {string} packageSubpath - The subpath of the package to resolve.
634 * @param {import('internal/modules/esm/package_config.js').PackageConfig} packageConfig - The package metadata.
635 * @param {string | URL | undefined} base - The base path to resolve from.
636 * @param {Set<string>} conditions - An array of conditions to match.
637 * @returns {URL} - The resolved package target.
638 */
639function packageExportsResolve(
640  packageJSONUrl, packageSubpath, packageConfig, base, conditions) {
641  let exports = packageConfig.exports;
642  if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
643    exports = { '.': exports };
644  }
645
646  if (ObjectPrototypeHasOwnProperty(exports, packageSubpath) &&
647      !StringPrototypeIncludes(packageSubpath, '*') &&
648      !StringPrototypeEndsWith(packageSubpath, '/')) {
649    const target = exports[packageSubpath];
650    const resolveResult = resolvePackageTarget(
651      packageJSONUrl, target, '', packageSubpath, base, false, false, false,
652      conditions,
653    );
654
655    if (resolveResult == null) {
656      throw exportsNotFound(packageSubpath, packageJSONUrl, base);
657    }
658
659    return resolveResult;
660  }
661
662  let bestMatch = '';
663  let bestMatchSubpath;
664  const keys = ObjectGetOwnPropertyNames(exports);
665  for (let i = 0; i < keys.length; i++) {
666    const key = keys[i];
667    const patternIndex = StringPrototypeIndexOf(key, '*');
668    if (patternIndex !== -1 &&
669        StringPrototypeStartsWith(packageSubpath,
670                                  StringPrototypeSlice(key, 0, patternIndex))) {
671      // When this reaches EOL, this can throw at the top of the whole function:
672      //
673      // if (StringPrototypeEndsWith(packageSubpath, '/'))
674      //   throwInvalidSubpath(packageSubpath)
675      //
676      // To match "imports" and the spec.
677      if (StringPrototypeEndsWith(packageSubpath, '/')) {
678        emitTrailingSlashPatternDeprecation(packageSubpath, packageJSONUrl,
679                                            base);
680      }
681      const patternTrailer = StringPrototypeSlice(key, patternIndex + 1);
682      if (packageSubpath.length >= key.length &&
683          StringPrototypeEndsWith(packageSubpath, patternTrailer) &&
684          patternKeyCompare(bestMatch, key) === 1 &&
685          StringPrototypeLastIndexOf(key, '*') === patternIndex) {
686        bestMatch = key;
687        bestMatchSubpath = StringPrototypeSlice(
688          packageSubpath, patternIndex,
689          packageSubpath.length - patternTrailer.length);
690      }
691    }
692  }
693
694  if (bestMatch) {
695    const target = exports[bestMatch];
696    const resolveResult = resolvePackageTarget(
697      packageJSONUrl,
698      target,
699      bestMatchSubpath,
700      bestMatch,
701      base,
702      true,
703      false,
704      StringPrototypeEndsWith(packageSubpath, '/'),
705      conditions);
706
707    if (resolveResult == null) {
708      throw exportsNotFound(packageSubpath, packageJSONUrl, base);
709    }
710    return resolveResult;
711  }
712
713  throw exportsNotFound(packageSubpath, packageJSONUrl, base);
714}
715
716/**
717 * Compares two strings that may contain a wildcard character ('*') and returns a value indicating their order.
718 * @param {string} a - The first string to compare.
719 * @param {string} b - The second string to compare.
720 * @returns {number} - A negative number if `a` should come before `b`, a positive number if `a` should come after `b`,
721 * or 0 if they are equal.
722 */
723function patternKeyCompare(a, b) {
724  const aPatternIndex = StringPrototypeIndexOf(a, '*');
725  const bPatternIndex = StringPrototypeIndexOf(b, '*');
726  const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
727  const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
728  if (baseLenA > baseLenB) { return -1; }
729  if (baseLenB > baseLenA) { return 1; }
730  if (aPatternIndex === -1) { return 1; }
731  if (bPatternIndex === -1) { return -1; }
732  if (a.length > b.length) { return -1; }
733  if (b.length > a.length) { return 1; }
734  return 0;
735}
736
737/**
738 * Resolves the given import name for a package.
739 * @param {string} name - The name of the import to resolve.
740 * @param {string | URL | undefined} base - The base URL to resolve the import from.
741 * @param {Set<string>} conditions - An object containing the import conditions.
742 * @throws {ERR_INVALID_MODULE_SPECIFIER} If the import name is not valid.
743 * @throws {ERR_PACKAGE_IMPORT_NOT_DEFINED} If the import name cannot be resolved.
744 * @returns {URL} The resolved import URL.
745 */
746function packageImportsResolve(name, base, conditions) {
747  if (name === '#' || StringPrototypeStartsWith(name, '#/') ||
748      StringPrototypeEndsWith(name, '/')) {
749    const reason = 'is not a valid internal imports specifier name';
750    throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base));
751  }
752  let packageJSONUrl;
753  const packageConfig = getPackageScopeConfig(base);
754  if (packageConfig.exists) {
755    packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
756    const imports = packageConfig.imports;
757    if (imports) {
758      if (ObjectPrototypeHasOwnProperty(imports, name) &&
759          !StringPrototypeIncludes(name, '*')) {
760        const resolveResult = resolvePackageTarget(
761          packageJSONUrl, imports[name], '', name, base, false, true, false,
762          conditions,
763        );
764        if (resolveResult != null) {
765          return resolveResult;
766        }
767      } else {
768        let bestMatch = '';
769        let bestMatchSubpath;
770        const keys = ObjectGetOwnPropertyNames(imports);
771        for (let i = 0; i < keys.length; i++) {
772          const key = keys[i];
773          const patternIndex = StringPrototypeIndexOf(key, '*');
774          if (patternIndex !== -1 &&
775              StringPrototypeStartsWith(name,
776                                        StringPrototypeSlice(key, 0,
777                                                             patternIndex))) {
778            const patternTrailer = StringPrototypeSlice(key, patternIndex + 1);
779            if (name.length >= key.length &&
780                StringPrototypeEndsWith(name, patternTrailer) &&
781                patternKeyCompare(bestMatch, key) === 1 &&
782                StringPrototypeLastIndexOf(key, '*') === patternIndex) {
783              bestMatch = key;
784              bestMatchSubpath = StringPrototypeSlice(
785                name, patternIndex, name.length - patternTrailer.length);
786            }
787          }
788        }
789
790        if (bestMatch) {
791          const target = imports[bestMatch];
792          const resolveResult = resolvePackageTarget(packageJSONUrl, target,
793                                                     bestMatchSubpath,
794                                                     bestMatch, base, true,
795                                                     true, false, conditions);
796          if (resolveResult != null) {
797            return resolveResult;
798          }
799        }
800      }
801    }
802  }
803  throw importNotDefined(name, packageJSONUrl, base);
804}
805
806/**
807 * Returns the package type for a given URL.
808 * @param {URL} url - The URL to get the package type for.
809 */
810function getPackageType(url) {
811  const packageConfig = getPackageScopeConfig(url);
812  return packageConfig.type;
813}
814
815/**
816 * Parse a package name from a specifier.
817 * @param {string} specifier - The import specifier.
818 * @param {string | URL | undefined} base - The parent URL.
819 */
820function parsePackageName(specifier, base) {
821  let separatorIndex = StringPrototypeIndexOf(specifier, '/');
822  let validPackageName = true;
823  let isScoped = false;
824  if (specifier[0] === '@') {
825    isScoped = true;
826    if (separatorIndex === -1 || specifier.length === 0) {
827      validPackageName = false;
828    } else {
829      separatorIndex = StringPrototypeIndexOf(
830        specifier, '/', separatorIndex + 1);
831    }
832  }
833
834  const packageName = separatorIndex === -1 ?
835    specifier : StringPrototypeSlice(specifier, 0, separatorIndex);
836
837  // Package name cannot have leading . and cannot have percent-encoding or
838  // \\ separators.
839  if (RegExpPrototypeExec(invalidPackageNameRegEx, packageName) !== null) {
840    validPackageName = false;
841  }
842
843  if (!validPackageName) {
844    throw new ERR_INVALID_MODULE_SPECIFIER(
845      specifier, 'is not a valid package name', fileURLToPath(base));
846  }
847
848  const packageSubpath = '.' + (separatorIndex === -1 ? '' :
849    StringPrototypeSlice(specifier, separatorIndex));
850
851  return { packageName, packageSubpath, isScoped };
852}
853
854/**
855 * Resolves a package specifier to a URL.
856 * @param {string} specifier - The package specifier to resolve.
857 * @param {string | URL | undefined} base - The base URL to use for resolution.
858 * @param {Set<string>} conditions - An object containing the conditions for resolution.
859 * @returns {URL} - The resolved URL.
860 */
861function packageResolve(specifier, base, conditions) {
862  if (BuiltinModule.canBeRequiredWithoutScheme(specifier)) {
863    return new URL('node:' + specifier);
864  }
865
866  const { packageName, packageSubpath, isScoped } =
867    parsePackageName(specifier, base);
868
869  // ResolveSelf
870  const packageConfig = getPackageScopeConfig(base);
871  if (packageConfig.exists) {
872    const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
873    if (packageConfig.exports != null && packageConfig.name === packageName) {
874      return packageExportsResolve(
875        packageJSONUrl, packageSubpath, packageConfig, base, conditions);
876    }
877  }
878
879  let packageJSONUrl =
880    new URL('./node_modules/' + packageName + '/package.json', base);
881  let packageJSONPath = fileURLToPath(packageJSONUrl);
882  let lastPath;
883  do {
884    const stat = internalModuleStat(toNamespacedPath(StringPrototypeSlice(packageJSONPath, 0,
885                                                                          packageJSONPath.length - 13)));
886    // Check for !stat.isDirectory()
887    if (stat !== 1) {
888      lastPath = packageJSONPath;
889      packageJSONUrl = new URL((isScoped ?
890        '../../../../node_modules/' : '../../../node_modules/') +
891        packageName + '/package.json', packageJSONUrl);
892      packageJSONPath = fileURLToPath(packageJSONUrl);
893      continue;
894    }
895
896    // Package match.
897    const packageConfig = packageJsonReader.read(packageJSONPath, { __proto__: null, specifier, base, isESM: true });
898    if (packageConfig.exports != null) {
899      return packageExportsResolve(
900        packageJSONUrl, packageSubpath, packageConfig, base, conditions);
901    }
902    if (packageSubpath === '.') {
903      return legacyMainResolve(
904        packageJSONUrl,
905        packageConfig,
906        base,
907      );
908    }
909
910    return new URL(packageSubpath, packageJSONUrl);
911    // Cross-platform root check.
912  } while (packageJSONPath.length !== lastPath.length);
913
914  // eslint can't handle the above code.
915  // eslint-disable-next-line no-unreachable
916  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
917}
918
919/**
920 * Checks if a specifier is a bare specifier.
921 * @param {string} specifier - The specifier to check.
922 */
923function isBareSpecifier(specifier) {
924  return specifier[0] && specifier[0] !== '/' && specifier[0] !== '.';
925}
926
927/**
928 * Determines whether a specifier is a relative path.
929 * @param {string} specifier - The specifier to check.
930 */
931function isRelativeSpecifier(specifier) {
932  if (specifier[0] === '.') {
933    if (specifier.length === 1 || specifier[1] === '/') { return true; }
934    if (specifier[1] === '.') {
935      if (specifier.length === 2 || specifier[2] === '/') { return true; }
936    }
937  }
938  return false;
939}
940
941/**
942 * Determines whether a specifier should be treated as a relative or absolute path.
943 * @param {string} specifier - The specifier to check.
944 */
945function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
946  if (specifier === '') { return false; }
947  if (specifier[0] === '/') { return true; }
948  return isRelativeSpecifier(specifier);
949}
950
951/**
952 * Resolves a module specifier to a URL.
953 * @param {string} specifier - The module specifier to resolve.
954 * @param {string | URL | undefined} base - The base URL to resolve against.
955 * @param {Set<string>} conditions - An object containing environment conditions.
956 * @param {boolean} preserveSymlinks - Whether to preserve symlinks in the resolved URL.
957 */
958function moduleResolve(specifier, base, conditions, preserveSymlinks) {
959  const isRemote = base.protocol === 'http:' ||
960    base.protocol === 'https:';
961  // Order swapped from spec for minor perf gain.
962  // Ok since relative URLs cannot parse as URLs.
963  let resolved;
964  if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
965    resolved = new URL(specifier, base);
966  } else if (!isRemote && specifier[0] === '#') {
967    resolved = packageImportsResolve(specifier, base, conditions);
968  } else {
969    try {
970      resolved = new URL(specifier);
971    } catch {
972      if (!isRemote) {
973        resolved = packageResolve(specifier, base, conditions);
974      }
975    }
976  }
977  if (resolved.protocol !== 'file:') {
978    return resolved;
979  }
980  return finalizeResolution(resolved, base, preserveSymlinks);
981}
982
983/**
984 * Try to resolve an import as a CommonJS module.
985 * @param {string} specifier - The specifier to resolve.
986 * @param {string} parentURL - The base URL.
987 */
988function resolveAsCommonJS(specifier, parentURL) {
989  try {
990    const parent = fileURLToPath(parentURL);
991    const tmpModule = new CJSModule(parent, null);
992    tmpModule.paths = CJSModule._nodeModulePaths(parent);
993
994    let found = CJSModule._resolveFilename(specifier, tmpModule, false);
995
996    // If it is a relative specifier return the relative path
997    // to the parent
998    if (isRelativeSpecifier(specifier)) {
999      found = relative(parent, found);
1000      // Add '.separator if the path does not start with '..separator'
1001      // This should be a safe assumption because when loading
1002      // esm modules there should be always a file specified so
1003      // there should not be a specifier like '..' or '.'
1004      if (!StringPrototypeStartsWith(found, `..${sep}`)) {
1005        found = `.${sep}${found}`;
1006      }
1007    } else if (isBareSpecifier(specifier)) {
1008      // If it is a bare specifier return the relative path within the
1009      // module
1010      const pkg = StringPrototypeSplit(specifier, '/')[0];
1011      const index = StringPrototypeIndexOf(found, pkg);
1012      if (index !== -1) {
1013        found = StringPrototypeSlice(found, index);
1014      }
1015    }
1016    // Normalize the path separator to give a valid suggestion
1017    // on Windows
1018    if (process.platform === 'win32') {
1019      found = RegExpPrototypeSymbolReplace(new RegExp(`\\${sep}`, 'g'),
1020                                           found, '/');
1021    }
1022    return found;
1023  } catch {
1024    return false;
1025  }
1026}
1027
1028/**
1029 * Throw an error if an import is not allowed.
1030 * TODO(@JakobJingleheimer): de-dupe `specifier` & `parsed`
1031 * @param {string} specifier - The import specifier.
1032 * @param {URL} parsed - The parsed URL of the import specifier.
1033 * @param {URL} parsedParentURL - The parsed URL of the parent module.
1034 * @throws {ERR_NETWORK_IMPORT_DISALLOWED} - If the import is disallowed.
1035 */
1036function checkIfDisallowedImport(specifier, parsed, parsedParentURL) {
1037  if (parsedParentURL) {
1038    // Avoid accessing the `protocol` property due to the lazy getters.
1039    const parentProtocol = parsedParentURL.protocol;
1040    if (
1041      parentProtocol === 'http:' ||
1042      parentProtocol === 'https:'
1043    ) {
1044      if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
1045        // Avoid accessing the `protocol` property due to the lazy getters.
1046        const parsedProtocol = parsed?.protocol;
1047        // data: and blob: disallowed due to allowing file: access via
1048        // indirection
1049        if (parsedProtocol &&
1050          parsedProtocol !== 'https:' &&
1051          parsedProtocol !== 'http:'
1052        ) {
1053          throw new ERR_NETWORK_IMPORT_DISALLOWED(
1054            specifier,
1055            parsedParentURL,
1056            'remote imports cannot import from a local location.',
1057          );
1058        }
1059
1060        return { url: parsed.href };
1061      }
1062      if (BuiltinModule.canBeRequiredWithoutScheme(specifier)) {
1063        throw new ERR_NETWORK_IMPORT_DISALLOWED(
1064          specifier,
1065          parsedParentURL,
1066          'remote imports cannot import from a local location.',
1067        );
1068      }
1069
1070      throw new ERR_NETWORK_IMPORT_DISALLOWED(
1071        specifier,
1072        parsedParentURL,
1073        'only relative and absolute specifiers are supported.',
1074      );
1075    }
1076  }
1077}
1078
1079/**
1080 * Validate user-input in `context` supplied by a custom loader.
1081 * @param {string | URL | undefined} parentURL - The parent URL.
1082 */
1083function throwIfInvalidParentURL(parentURL) {
1084  if (parentURL === undefined) {
1085    return; // Main entry point, so no parent
1086  }
1087  if (typeof parentURL !== 'string' && !isURL(parentURL)) {
1088    throw new ERR_INVALID_ARG_TYPE('parentURL', ['string', 'URL'], parentURL);
1089  }
1090}
1091
1092/**
1093 * Resolves the given specifier using the provided context, which includes the parent URL and conditions.
1094 * Throws an error if the parent URL is invalid or if the resolution is disallowed by the policy manifest.
1095 * Otherwise, attempts to resolve the specifier and returns the resulting URL and format.
1096 * @param {string} specifier - The specifier to resolve.
1097 * @param {object} [context={}] - The context object containing the parent URL and conditions.
1098 * @param {string} [context.parentURL] - The URL of the parent module.
1099 * @param {string[]} [context.conditions] - The conditions for resolving the specifier.
1100 */
1101function defaultResolve(specifier, context = {}) {
1102  let { parentURL, conditions } = context;
1103  throwIfInvalidParentURL(parentURL);
1104  if (parentURL && policy?.manifest) {
1105    const redirects = policy.manifest.getDependencyMapper(parentURL);
1106    if (redirects) {
1107      const { resolve, reaction } = redirects;
1108      const destination = resolve(specifier, new SafeSet(conditions));
1109      let missing = true;
1110      if (destination === true) {
1111        missing = false;
1112      } else if (destination) {
1113        const href = destination.href;
1114        return { url: href };
1115      }
1116      if (missing) {
1117        // Prevent network requests from firing if resolution would be banned.
1118        // Network requests can extract data by doing things like putting
1119        // secrets in query params
1120        reaction(new ERR_MANIFEST_DEPENDENCY_MISSING(
1121          parentURL,
1122          specifier,
1123          ArrayPrototypeJoin([...conditions], ', ')),
1124        );
1125      }
1126    }
1127  }
1128
1129  let parsedParentURL;
1130  if (parentURL) {
1131    try {
1132      parsedParentURL = new URL(parentURL);
1133    } catch {
1134      // Ignore exception
1135    }
1136  }
1137
1138  let parsed;
1139  try {
1140    if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
1141      parsed = new URL(specifier, parsedParentURL);
1142    } else {
1143      parsed = new URL(specifier);
1144    }
1145
1146    // Avoid accessing the `protocol` property due to the lazy getters.
1147    const protocol = parsed.protocol;
1148    if (protocol === 'data:' ||
1149      (experimentalNetworkImports &&
1150        (
1151          protocol === 'https:' ||
1152          protocol === 'http:'
1153        )
1154      )
1155    ) {
1156      return { __proto__: null, url: parsed.href };
1157    }
1158  } catch {
1159    // Ignore exception
1160  }
1161
1162  // There are multiple deep branches that can either throw or return; instead
1163  // of duplicating that deeply nested logic for the possible returns, DRY and
1164  // check for a return. This seems the least gnarly.
1165  const maybeReturn = checkIfDisallowedImport(
1166    specifier,
1167    parsed,
1168    parsedParentURL,
1169  );
1170
1171  if (maybeReturn) { return maybeReturn; }
1172
1173  // This must come after checkIfDisallowedImport
1174  if (parsed && parsed.protocol === 'node:') { return { __proto__: null, url: specifier }; }
1175
1176
1177  const isMain = parentURL === undefined;
1178  if (isMain) {
1179    parentURL = getCWDURL().href;
1180
1181    // This is the initial entry point to the program, and --input-type has
1182    // been passed as an option; but --input-type can only be used with
1183    // --eval, --print or STDIN string input. It is not allowed with file
1184    // input, to avoid user confusion over how expansive the effect of the
1185    // flag should be (i.e. entry point only, package scope surrounding the
1186    // entry point, etc.).
1187    if (inputTypeFlag) { throw new ERR_INPUT_TYPE_NOT_ALLOWED(); }
1188  }
1189
1190  conditions = getConditionsSet(conditions);
1191  let url;
1192  try {
1193    url = moduleResolve(
1194      specifier,
1195      parentURL,
1196      conditions,
1197      isMain ? preserveSymlinksMain : preserveSymlinks,
1198    );
1199  } catch (error) {
1200    // Try to give the user a hint of what would have been the
1201    // resolved CommonJS module
1202    if (error.code === 'ERR_MODULE_NOT_FOUND' ||
1203        error.code === 'ERR_UNSUPPORTED_DIR_IMPORT') {
1204      if (StringPrototypeStartsWith(specifier, 'file://')) {
1205        specifier = fileURLToPath(specifier);
1206      }
1207      decorateErrorWithCommonJSHints(error, specifier, parentURL);
1208    }
1209    throw error;
1210  }
1211
1212  return {
1213    // Do NOT cast `url` to a string: that will work even when there are real
1214    // problems, silencing them
1215    url: url.href,
1216    format: defaultGetFormatWithoutErrors(url, context),
1217  };
1218}
1219
1220/**
1221 * Decorates the given error with a hint for CommonJS modules.
1222 * @param {Error} error - The error to decorate.
1223 * @param {string} specifier - The specifier that was attempted to be imported.
1224 * @param {string} parentURL - The URL of the parent module.
1225 */
1226function decorateErrorWithCommonJSHints(error, specifier, parentURL) {
1227  const found = resolveAsCommonJS(specifier, parentURL);
1228  if (found) {
1229    // Modify the stack and message string to include the hint
1230    const lines = StringPrototypeSplit(error.stack, '\n');
1231    const hint = `Did you mean to import ${found}?`;
1232    error.stack =
1233      ArrayPrototypeShift(lines) + '\n' +
1234      hint + '\n' +
1235      ArrayPrototypeJoin(lines, '\n');
1236    error.message += `\n${hint}`;
1237  }
1238}
1239
1240module.exports = {
1241  decorateErrorWithCommonJSHints,
1242  defaultResolve,
1243  encodedSepRegEx,
1244  getPackageScopeConfig,
1245  getPackageType,
1246  packageExportsResolve,
1247  packageImportsResolve,
1248  throwIfInvalidParentURL,
1249};
1250
1251// cycle
1252const {
1253  defaultGetFormatWithoutErrors,
1254} = require('internal/modules/esm/get_format');
1255
1256if (policy) {
1257  const $defaultResolve = defaultResolve;
1258  module.exports.defaultResolve = function defaultResolve(
1259    specifier,
1260    context,
1261  ) {
1262    const ret = $defaultResolve(specifier, context);
1263    // This is a preflight check to avoid data exfiltration by query params etc.
1264    policy.manifest.mightAllow(ret.url, () =>
1265      new ERR_MANIFEST_DEPENDENCY_MISSING(
1266        context.parentURL,
1267        specifier,
1268        context.conditions,
1269      ),
1270    );
1271    return ret;
1272  };
1273}
1274