You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

773 lines
24 KiB

// Copied from https://raw.githubusercontent.com/nodejs/node/v13.12.0/lib/internal/modules/esm/resolve.js
// Then modified to suite our needs.
// Formatting is intentionally bad to keep the diff as small as possible, to make it easier to merge
// upstream changes and understand our modifications.
'use strict';
const {
ArrayIsArray,
JSONParse,
JSONStringify,
ObjectGetOwnPropertyNames,
ObjectPrototypeHasOwnProperty,
SafeMap,
StringPrototypeEndsWith,
StringPrototypeIncludes,
StringPrototypeIndexOf,
StringPrototypeSlice,
StringPrototypeStartsWith,
StringPrototypeSubstr,
} = {
ArrayIsArray: Array.isArray,
JSONParse: JSON.parse,
JSONStringify: JSON.stringify,
ObjectGetOwnPropertyNames: Object.getOwnPropertyNames,
ObjectPrototypeHasOwnProperty: (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop),
SafeMap: Map,
StringPrototypeEndsWith: (str, ...rest) => String.prototype.endsWith.apply(str, rest),
StringPrototypeIncludes: (str, ...rest) => String.prototype.includes.apply(str, rest),
StringPrototypeIndexOf: (str, ...rest) => String.prototype.indexOf.apply(str, rest),
StringPrototypeSlice: (str, ...rest) => String.prototype.slice.apply(str, rest),
StringPrototypeStartsWith: (str, ...rest) => String.prototype.startsWith.apply(str, rest),
StringPrototypeSubstr: (str, ...rest) => String.prototype.substr.apply(str, rest),
} // node pulls from `primordials` object
// const internalFS = require('internal/fs/utils');
// const { NativeModule } = require('internal/bootstrap/loaders');
const Module = require('module')
const NativeModule = {
canBeRequiredByUsers(specifier) {
return Module.builtinModules.includes(specifier)
}
}
const {
closeSync,
fstatSync,
openSync,
readFileSync,
realpathSync,
statSync,
Stats,
} = require('fs');
// const { getOptionValue } = require('internal/options');
const { getOptionValue } = (() => {
let options;
function parseOptions() {
if (!options) {
options = {
'--preserve-symlinks': false,
'--preserve-symlinks-main': false,
'--input-type': undefined,
'--experimental-specifier-resolution': 'explicit',
...parseExecArgv()
}
}
};
function parseExecArgv () {
return require('arg')({
'--preserve-symlinks': Boolean,
'--preserve-symlinks-main': Boolean,
'--input-type': String,
'--experimental-specifier-resolution': String
}, {
argv: process.execArgv,
permissive: true
});
}
return {
getOptionValue: (opt) => {
parseOptions();
return options[opt];
}
};
})();
const { sep } = require('path');
const preserveSymlinks = getOptionValue('--preserve-symlinks');
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
const typeFlag = getOptionValue('--input-type');
// const { URL, pathToFileURL, fileURLToPath } = require('internal/url');
const { URL, pathToFileURL, fileURLToPath } = require('url');
const {
ERR_INPUT_TYPE_NOT_ALLOWED,
ERR_INVALID_MODULE_SPECIFIER,
ERR_INVALID_PACKAGE_CONFIG,
ERR_INVALID_PACKAGE_TARGET,
ERR_MODULE_NOT_FOUND,
ERR_PACKAGE_PATH_NOT_EXPORTED,
ERR_UNSUPPORTED_ESM_URL_SCHEME,
// } = require('internal/errors').codes;
} = {
ERR_INPUT_TYPE_NOT_ALLOWED: createErrorCtor('ERR_INPUT_TYPE_NOT_ALLOWED'),
ERR_INVALID_MODULE_SPECIFIER: createErrorCtor('ERR_INVALID_MODULE_SPECIFIER'),
ERR_INVALID_PACKAGE_CONFIG: createErrorCtor('ERR_INVALID_PACKAGE_CONFIG'),
ERR_INVALID_PACKAGE_TARGET: createErrorCtor('ERR_INVALID_PACKAGE_TARGET'),
ERR_MODULE_NOT_FOUND: createErrorCtor('ERR_MODULE_NOT_FOUND'),
ERR_PACKAGE_PATH_NOT_EXPORTED: createErrorCtor('ERR_PACKAGE_PATH_NOT_EXPORTED'),
ERR_UNSUPPORTED_ESM_URL_SCHEME: createErrorCtor('ERR_UNSUPPORTED_ESM_URL_SCHEME'),
}
function createErrorCtor(name) {
return class CustomError extends Error {
constructor(...args) {
super([name, ...args].join(' '))
}
}
}
function createResolve(opts) {
// TODO receive cached fs implementations here
const {tsExtensions, jsExtensions, preferTsExts} = opts;
const realpathCache = new SafeMap();
const packageJSONCache = new SafeMap(); /* string -> PackageConfig */
function tryStatSync(path) {
try {
return statSync(path);
} catch {
return new Stats();
}
}
function readIfFile(path) {
let fd;
try {
fd = openSync(path, 'r');
} catch {
return undefined;
}
try {
if (!fstatSync(fd).isFile()) return undefined;
return readFileSync(fd, 'utf8');
} finally {
closeSync(fd);
}
}
function getPackageConfig(path, base) {
const existing = packageJSONCache.get(path);
if (existing !== undefined) {
if (!existing.isValid) {
throw new ERR_INVALID_PACKAGE_CONFIG(path, fileURLToPath(base), false);
}
return existing;
}
const source = readIfFile(path);
if (source === undefined) {
const packageConfig = {
exists: false,
main: undefined,
name: undefined,
isValid: true,
type: 'none',
exports: undefined
};
packageJSONCache.set(path, packageConfig);
return packageConfig;
}
let packageJSON;
try {
packageJSON = JSONParse(source);
} catch {
const packageConfig = {
exists: true,
main: undefined,
name: undefined,
isValid: false,
type: 'none',
exports: undefined
};
packageJSONCache.set(path, packageConfig);
return packageConfig;
}
let { main, name, type } = packageJSON;
const { exports } = packageJSON;
if (typeof main !== 'string') main = undefined;
if (typeof name !== 'string') name = undefined;
// Ignore unknown types for forwards compatibility
if (type !== 'module' && type !== 'commonjs') type = 'none';
const packageConfig = {
exists: true,
main,
name,
isValid: true,
type,
exports
};
packageJSONCache.set(path, packageConfig);
return packageConfig;
}
function getPackageScopeConfig(resolved, base) {
let packageJSONUrl = new URL('./package.json', resolved);
while (true) {
const packageJSONPath = packageJSONUrl.pathname;
if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json'))
break;
const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), base);
if (packageConfig.exists) return packageConfig;
const lastPackageJSONUrl = packageJSONUrl;
packageJSONUrl = new URL('../package.json', packageJSONUrl);
// Terminates at root where ../package.json equals ../../package.json
// (can't just check "/package.json" for Windows support).
if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) break;
}
const packageConfig = {
exists: false,
main: undefined,
name: undefined,
isValid: true,
type: 'none',
exports: undefined
};
packageJSONCache.set(fileURLToPath(packageJSONUrl), packageConfig);
return packageConfig;
}
/*
* Legacy CommonJS main resolution:
* 1. let M = pkg_url + (json main field)
* 2. TRY(M, M.js, M.json, M.node)
* 3. TRY(M/index.js, M/index.json, M/index.node)
* 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
* 5. NOT_FOUND
*/
function fileExists(url) {
return tryStatSync(fileURLToPath(url)).isFile();
}
function legacyMainResolve(packageJSONUrl, packageConfig) {
let guess;
if (packageConfig.main !== undefined) {
// Note: fs check redundances will be handled by Descriptor cache here.
if (fileExists(guess = new URL(`./${packageConfig.main}`,
packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
packageJSONUrl))) {
return guess;
}
// Fallthrough.
}
if (fileExists(guess = new URL('./index.js', packageJSONUrl))) {
return guess;
}
// So fs.
if (fileExists(guess = new URL('./index.json', packageJSONUrl))) {
return guess;
}
if (fileExists(guess = new URL('./index.node', packageJSONUrl))) {
return guess;
}
// Not found.
return undefined;
}
function resolveExtensionsWithTryExactName(search) {
if (fileExists(search)) return search;
const resolvedReplacementExtension = resolveReplacementExtensions(search);
if(resolvedReplacementExtension) return resolvedReplacementExtension;
return resolveExtensions(search);
}
const extensions = Array.from(new Set([
...(preferTsExts ? tsExtensions : []),
'.js',
...jsExtensions,
'.json', '.node', '.mjs',
...tsExtensions
]));
function resolveExtensions(search) {
for (let i = 0; i < extensions.length; i++) {
const extension = extensions[i];
const guess = new URL(`${search.pathname}${extension}`, search);
if (fileExists(guess)) return guess;
}
return undefined;
}
/**
* TS's resolver can resolve foo.js to foo.ts, by replacing .js extension with several source extensions.
* IMPORTANT: preserve ordering according to preferTsExts; this affects resolution behavior!
*/
const replacementExtensions = extensions.filter(ext => ['.js', '.jsx', '.ts', '.tsx'].includes(ext));
function resolveReplacementExtensions(search) {
if (search.pathname.match(/\.js$/)) {
const pathnameWithoutExtension = search.pathname.slice(0, search.pathname.length - 3);
for (let i = 0; i < replacementExtensions.length; i++) {
const extension = replacementExtensions[i];
const guess = new URL(`${pathnameWithoutExtension}${extension}`, search);
if (fileExists(guess)) return guess;
}
}
return undefined;
}
function resolveIndex(search) {
return resolveExtensions(new URL('index', search));
}
function finalizeResolution(resolved, base) {
if (getOptionValue('--experimental-specifier-resolution') === 'node') {
let file = resolveExtensionsWithTryExactName(resolved);
if (file !== undefined) return file;
if (!StringPrototypeEndsWith(resolved.pathname, '/')) {
file = resolveIndex(new URL(`${resolved.pathname}/`, base));
} else {
file = resolveIndex(resolved);
}
if (file !== undefined) return file;
throw new ERR_MODULE_NOT_FOUND(
resolved.pathname, fileURLToPath(base), 'module');
}
if (StringPrototypeEndsWith(resolved.pathname, '/')) return resolved;
const file = resolveReplacementExtensions(resolved) || resolved;
const path = fileURLToPath(file);
if (!tryStatSync(path).isFile()) {
throw new ERR_MODULE_NOT_FOUND(
path || resolved.pathname, fileURLToPath(base), 'module');
}
return file;
}
function throwExportsNotFound(subpath, packageJSONUrl, base) {
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
fileURLToPath(packageJSONUrl), subpath, fileURLToPath(base));
}
function throwSubpathInvalid(subpath, packageJSONUrl, base) {
throw new ERR_INVALID_MODULE_SPECIFIER(
fileURLToPath(packageJSONUrl), subpath, fileURLToPath(base));
}
function throwExportsInvalid(
subpath, target, packageJSONUrl, base) {
if (typeof target === 'object' && target !== null) {
target = JSONStringify(target, null, '');
} else if (ArrayIsArray(target)) {
target = `[${target}]`;
} else {
target = `${target}`;
}
throw new ERR_INVALID_PACKAGE_TARGET(
fileURLToPath(packageJSONUrl), null, subpath, target, fileURLToPath(base));
}
function resolveExportsTargetString(
target, subpath, match, packageJSONUrl, base) {
if (target[0] !== '.' || target[1] !== '/' ||
(subpath !== '' && target[target.length - 1] !== '/')) {
throwExportsInvalid(match, target, packageJSONUrl, base);
}
const resolved = new URL(target, packageJSONUrl);
const resolvedPath = resolved.pathname;
const packagePath = new URL('.', packageJSONUrl).pathname;
if (!StringPrototypeStartsWith(resolvedPath, packagePath) ||
StringPrototypeIncludes(
resolvedPath, '/node_modules/', packagePath.length - 1)) {
throwExportsInvalid(match, target, packageJSONUrl, base);
}
if (subpath === '') return resolved;
const subpathResolved = new URL(subpath, resolved);
const subpathResolvedPath = subpathResolved.pathname;
if (!StringPrototypeStartsWith(subpathResolvedPath, resolvedPath) ||
StringPrototypeIncludes(subpathResolvedPath,
'/node_modules/', packagePath.length - 1)) {
throwSubpathInvalid(match + subpath, packageJSONUrl, base);
}
return subpathResolved;
}
function isArrayIndex(key /* string */) { /* -> boolean */
const keyNum = +key;
if (`${keyNum}` !== key) return false;
return keyNum >= 0 && keyNum < 0xFFFF_FFFF;
}
function resolveExportsTarget(
packageJSONUrl, target, subpath, packageSubpath, base) {
if (typeof target === 'string') {
const resolved = resolveExportsTargetString(
target, subpath, packageSubpath, packageJSONUrl, base);
return finalizeResolution(resolved, base);
} else if (ArrayIsArray(target)) {
if (target.length === 0)
throwExportsInvalid(packageSubpath, target, packageJSONUrl, base);
let lastException;
for (let i = 0; i < target.length; i++) {
const targetItem = target[i];
let resolved;
try {
resolved = resolveExportsTarget(
packageJSONUrl, targetItem, subpath, packageSubpath, base);
} catch (e) {
lastException = e;
if (e.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED' ||
e.code === 'ERR_INVALID_PACKAGE_TARGET') {
continue;
}
throw e;
}
return finalizeResolution(resolved, base);
}
throw lastException;
} else if (typeof target === 'object' && target !== null) {
const keys = ObjectGetOwnPropertyNames(target);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (isArrayIndex(key)) {
throw new ERR_INVALID_PACKAGE_CONFIG(
fileURLToPath(packageJSONUrl),
'"exports" cannot contain numeric property keys');
}
}
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (key === 'node' || key === 'import' || key === 'default') {
const conditionalTarget = target[key];
try {
return resolveExportsTarget(
packageJSONUrl, conditionalTarget, subpath, packageSubpath, base);
} catch (e) {
if (e.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') continue;
throw e;
}
}
}
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
}
throwExportsInvalid(packageSubpath, target, packageJSONUrl, base);
}
function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
if (typeof exports === 'string' || ArrayIsArray(exports)) return true;
if (typeof exports !== 'object' || exports === null) return false;
const keys = ObjectGetOwnPropertyNames(exports);
let isConditionalSugar = false;
let i = 0;
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
const curIsConditionalSugar = key === '' || key[0] !== '.';
if (i++ === 0) {
isConditionalSugar = curIsConditionalSugar;
} else if (isConditionalSugar !== curIsConditionalSugar) {
throw new ERR_INVALID_PACKAGE_CONFIG(
fileURLToPath(packageJSONUrl),
'"exports" cannot contain some keys starting with \'.\' and some not.' +
' The exports object must either be an object of package subpath keys' +
' or an object of main entry condition name keys only.');
}
}
return isConditionalSugar;
}
function packageMainResolve(packageJSONUrl, packageConfig, base) {
if (packageConfig.exists) {
const exports = packageConfig.exports;
if (exports !== undefined) {
if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
return resolveExportsTarget(packageJSONUrl, exports, '', '', base);
} else if (typeof exports === 'object' && exports !== null) {
const target = exports['.'];
if (target !== undefined)
return resolveExportsTarget(packageJSONUrl, target, '', '', base);
}
throw new ERR_PACKAGE_PATH_NOT_EXPORTED(packageJSONUrl, '.');
}
if (packageConfig.main !== undefined) {
const resolved = new URL(packageConfig.main, packageJSONUrl);
const path = fileURLToPath(resolved);
if (tryStatSync(path).isFile()) return resolved;
}
if (getOptionValue('--experimental-specifier-resolution') === 'node') {
if (packageConfig.main !== undefined) {
return finalizeResolution(
new URL(packageConfig.main, packageJSONUrl), base);
} else {
return finalizeResolution(
new URL('index', packageJSONUrl), base);
}
}
if (packageConfig.type !== 'module') {
return legacyMainResolve(packageJSONUrl, packageConfig);
}
}
throw new ERR_MODULE_NOT_FOUND(
fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
}
function packageExportsResolve(
packageJSONUrl, packageSubpath, packageConfig, base) /* -> URL */ {
const exports = packageConfig.exports;
if (exports === undefined ||
isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
}
if (ObjectPrototypeHasOwnProperty(exports, packageSubpath)) {
const target = exports[packageSubpath];
const resolved = resolveExportsTarget(
packageJSONUrl, target, '', packageSubpath, base);
return finalizeResolution(resolved, base);
}
let bestMatch = '';
const keys = ObjectGetOwnPropertyNames(exports);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (key[key.length - 1] !== '/') continue;
if (StringPrototypeStartsWith(packageSubpath, key) &&
key.length > bestMatch.length) {
bestMatch = key;
}
}
if (bestMatch) {
const target = exports[bestMatch];
const subpath = StringPrototypeSubstr(packageSubpath, bestMatch.length);
const resolved = resolveExportsTarget(
packageJSONUrl, target, subpath, packageSubpath, base);
return finalizeResolution(resolved, base);
}
throwExportsNotFound(packageSubpath, packageJSONUrl, base);
}
function getPackageType(url) {
const packageConfig = getPackageScopeConfig(url, url);
return packageConfig.type;
}
function packageResolve(specifier /* string */, base /* URL */) { /* -> URL */
let separatorIndex = StringPrototypeIndexOf(specifier, '/');
let validPackageName = true;
let isScoped = false;
if (specifier[0] === '@') {
isScoped = true;
if (separatorIndex === -1 || specifier.length === 0) {
validPackageName = false;
} else {
separatorIndex = StringPrototypeIndexOf(
specifier, '/', separatorIndex + 1);
}
}
const packageName = separatorIndex === -1 ?
specifier : StringPrototypeSlice(specifier, 0, separatorIndex);
// Package name cannot have leading . and cannot have percent-encoding or
// separators.
for (let i = 0; i < packageName.length; i++) {
if (packageName[i] === '%' || packageName[i] === '\\') {
validPackageName = false;
break;
}
}
if (!validPackageName) {
throw new ERR_INVALID_MODULE_SPECIFIER(
specifier, undefined, fileURLToPath(base));
}
const packageSubpath = separatorIndex === -1 ?
'' : '.' + StringPrototypeSlice(specifier, separatorIndex);
// ResolveSelf
const packageConfig = getPackageScopeConfig(base, base);
if (packageConfig.exists) {
// TODO(jkrems): Find a way to forward the pair/iterator already generated
// while executing GetPackageScopeConfig
let packageJSONUrl;
for (const [ filename, packageConfigCandidate ] of packageJSONCache) {
if (packageConfig === packageConfigCandidate) {
packageJSONUrl = pathToFileURL(filename);
break;
}
}
if (packageJSONUrl !== undefined &&
packageConfig.name === packageName &&
packageConfig.exports !== undefined) {
if (packageSubpath === './') {
return new URL('./', packageJSONUrl);
} else if (packageSubpath === '') {
return packageMainResolve(packageJSONUrl, packageConfig, base);
} else {
return packageExportsResolve(
packageJSONUrl, packageSubpath, packageConfig, base);
}
}
}
let packageJSONUrl =
new URL('./node_modules/' + packageName + '/package.json', base);
let packageJSONPath = fileURLToPath(packageJSONUrl);
let lastPath;
do {
const stat = tryStatSync(
StringPrototypeSlice(packageJSONPath, 0, packageJSONPath.length - 13));
if (!stat.isDirectory()) {
lastPath = packageJSONPath;
packageJSONUrl = new URL((isScoped ?
'../../../../node_modules/' : '../../../node_modules/') +
packageName + '/package.json', packageJSONUrl);
packageJSONPath = fileURLToPath(packageJSONUrl);
continue;
}
// Package match.
const packageConfig = getPackageConfig(packageJSONPath, base);
if (packageSubpath === './') {
return new URL('./', packageJSONUrl);
} else if (packageSubpath === '') {
return packageMainResolve(packageJSONUrl, packageConfig, base);
} else if (packageConfig.exports !== undefined) {
return packageExportsResolve(
packageJSONUrl, packageSubpath, packageConfig, base);
} else {
return finalizeResolution(
new URL(packageSubpath, packageJSONUrl), base);
}
// Cross-platform root check.
} while (packageJSONPath.length !== lastPath.length);
// eslint can't handle the above code.
// eslint-disable-next-line no-unreachable
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base));
}
function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
if (specifier === '') return false;
if (specifier[0] === '/') return true;
if (specifier[0] === '.') {
if (specifier.length === 1 || specifier[1] === '/') return true;
if (specifier[1] === '.') {
if (specifier.length === 2 || specifier[2] === '/') return true;
}
}
return false;
}
function moduleResolve(specifier /* string */, base /* URL */) { /* -> URL */
// Order swapped from spec for minor perf gain.
// Ok since relative URLs cannot parse as URLs.
let resolved;
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
resolved = new URL(specifier, base);
} else {
try {
resolved = new URL(specifier);
} catch {
return packageResolve(specifier, base);
}
}
return finalizeResolution(resolved, base);
}
function defaultResolve(specifier, { parentURL } = {}, defaultResolveUnused) {
let parsed;
try {
parsed = new URL(specifier);
if (parsed.protocol === 'data:') {
return {
url: specifier
};
}
} catch {}
if (parsed && parsed.protocol === 'nodejs:')
return { url: specifier };
if (parsed && parsed.protocol !== 'file:' && parsed.protocol !== 'data:')
throw new ERR_UNSUPPORTED_ESM_URL_SCHEME();
if (NativeModule.canBeRequiredByUsers(specifier)) {
return {
url: 'nodejs:' + specifier
};
}
if (parentURL && StringPrototypeStartsWith(parentURL, 'data:')) {
// This is gonna blow up, we want the error
new URL(specifier, parentURL);
}
const isMain = parentURL === undefined;
if (isMain) {
parentURL = pathToFileURL(`${process.cwd()}/`).href;
// This is the initial entry point to the program, and --input-type has
// been passed as an option; but --input-type can only be used with
// --eval, --print or STDIN string input. It is not allowed with file
// input, to avoid user confusion over how expansive the effect of the
// flag should be (i.e. entry point only, package scope surrounding the
// entry point, etc.).
if (typeFlag)
throw new ERR_INPUT_TYPE_NOT_ALLOWED();
}
let url = moduleResolve(specifier, new URL(parentURL));
if (isMain ? !preserveSymlinksMain : !preserveSymlinks) {
const urlPath = fileURLToPath(url);
const real = realpathSync(urlPath, {
// [internalFS.realpathCacheKey]: realpathCache
});
const old = url;
url = pathToFileURL(real + (urlPath.endsWith(sep) ? '/' : ''));
url.search = old.search;
url.hash = old.hash;
}
return { url: `${url}` };
}
return {
defaultResolve,
getPackageType
};
}
module.exports = {
createResolve
}