jsdom-context-require
Version:
Allows you to require files in a jsdom window context.
225 lines (224 loc) • 6.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolve = void 0;
const fs = require("fs");
const path = require("path");
const resolveExports = require("resolve.exports");
const modulePartsReg = /^((?:@[^/]+\/)?[^/]+)(\/.*)?$/;
const noopModule = path.join(__dirname, "../noop.js");
const resolveExportsOptions = {
unsafe: true,
browser: true,
require: true,
conditions: ["default", "require", "browser"],
};
function resolve(id, from, extensions) {
switch (id[0]) {
case ".": {
return tryRealPath(resolveFile(path.join(from, id), extensions));
}
case "#": {
const pkg = tryReadPackage(from);
if (pkg) {
const resolvedImport = resolveExports.imports(pkg, id, resolveExportsOptions);
if (resolvedImport) {
const resolved = path.join(from, resolvedImport[0]);
if (tryStat(resolved)?.isFile()) {
return tryRealPath(resolved);
}
}
}
return;
}
default:
return tryRealPath(resolvePackage(id, from, extensions));
}
}
exports.resolve = resolve;
function resolvePackage(id, from, extensions) {
const [, name, subPath = ""] = modulePartsReg.exec(id);
for (const modulesDir of getNodeModulesPaths(from)) {
const moduleDir = path.join(modulesDir, name);
const pkg = tryReadPackage(moduleDir);
if (pkg) {
return resolveWithPackage(pkg, moduleDir, `.${subPath}`, extensions);
}
}
}
function resolveWithPackage(pkg, moduleDir, id, extensions) {
if (pkg.exports) {
const resolvedExports = resolveExports.exports(pkg, id, resolveExportsOptions);
if (resolvedExports) {
const resolved = path.join(moduleDir, resolvedExports[0]);
return tryStat(resolved)?.isFile() ? resolved : undefined;
}
return;
}
const resolvedLegacy = resolveLegacyPackage(id, pkg, extensions);
if (resolvedLegacy) {
return resolveFile(path.join(moduleDir, resolvedLegacy), extensions);
}
else if (resolvedLegacy === false) {
return noopModule;
}
else {
return resolveFile(path.join(moduleDir, id), extensions);
}
}
function resolveLegacyPackage(id, pkg, extensions) {
if (pkg.browser) {
const pkgBrowser = pkg.browser;
let curId = id;
if (typeof pkgBrowser === "string") {
switch (curId) {
case ".":
case "./":
return pkgBrowser;
default:
return curId;
}
}
let replacement = pkgBrowser[curId];
if (replacement !== undefined) {
return replacement;
}
if (curId === ".") {
// Check `.` and `./`
curId = "./";
replacement = pkgBrowser[curId];
if (replacement !== undefined) {
return replacement;
}
}
const isFolder = curId[curId.length - 1] === "/";
if (isFolder) {
// If we're definitely matching a folder we'll try adding `index` to the
// end first.
curId += "index";
replacement = pkgBrowser[curId];
if (replacement !== undefined) {
return replacement;
}
}
for (const ext of extensions) {
replacement = pkgBrowser[curId + ext];
if (replacement !== undefined) {
return replacement;
}
}
if (!isFolder) {
// If we're not matching a folder we'll try adding `/index` to the end.
curId += "/index";
replacement = pkgBrowser[curId];
if (replacement !== undefined) {
return replacement;
}
for (const ext of extensions) {
replacement = pkgBrowser[curId + ext];
if (replacement !== undefined) {
return replacement;
}
}
}
}
switch (id) {
case ".":
case "./":
return pkg.main || "./index";
}
return id;
}
function resolveFile(file, extensions) {
const stat = tryStat(file);
return stat?.isFile()
? file
: resolveExtensions(file, extensions) ||
(stat?.isDirectory() ? resolveDir(file, extensions) : undefined);
}
function resolveDir(dir, extensions) {
const pkg = tryReadPackage(dir);
return ((pkg && resolveWithPackage(pkg, dir, ".", extensions)) ||
resolveExtensions(path.join(dir, "index"), extensions));
}
function resolveExtensions(file, extensions) {
for (const ext of extensions) {
const resolved = file + ext;
if (tryStat(resolved)?.isFile()) {
return resolved;
}
}
}
function tryRealPath(file) {
if (file) {
try {
return fs.realpathSync(file);
}
catch {
return;
}
}
}
function tryStat(file) {
try {
return fs.statSync(file);
}
catch {
return;
}
}
function tryReadPackage(dir) {
try {
return JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf-8"));
}
catch {
return;
}
}
// // unix
// getNodeModulesPaths("/")
// getNodeModulesPaths("/a")
// getNodeModulesPaths("/a/")
// getNodeModulesPaths("/a/b")
// getNodeModulesPaths("/a/b/")
// getNodeModulesPaths("/Users")
// getNodeModulesPaths("/Users/")
// getNodeModulesPaths("/Users/src")
// getNodeModulesPaths("/Users/src/")
// // windows
// getNodeModulesPaths("C:")
// getNodeModulesPaths("C:\\")
// getNodeModulesPaths("C:\\a")
// getNodeModulesPaths("C:\\a\\")
// getNodeModulesPaths("C:\\a\\b")
// getNodeModulesPaths("C:\\a\\b\\")
// getNodeModulesPaths("C:\\Users")
// getNodeModulesPaths("C:\\Users\\")
// getNodeModulesPaths("C:\\Users\\src")
// getNodeModulesPaths("C:\\Users\\src\\")
// getNodeModulesPaths("\\\\")
// getNodeModulesPaths("\\\\a")
// getNodeModulesPaths("\\\\a\\")
// getNodeModulesPaths("\\\\a\\b")
// getNodeModulesPaths("\\\\a\\b\\")
// getNodeModulesPaths("\\\\Users")
// getNodeModulesPaths("\\\\Users\\")
// getNodeModulesPaths("\\\\Users\\src")
// getNodeModulesPaths("\\\\Users\\src\\")
function getNodeModulesPaths(fromDir) {
const sep = fromDir[0] === "/" ? "/" : "\\";
let sepIndex = fromDir.length - 1;
let curDir = fromDir;
if (curDir[sepIndex] !== sep) {
curDir += sep;
sepIndex++;
}
const modulePaths = [`${curDir}node_modules`];
while (0 < --sepIndex) {
sepIndex = curDir.lastIndexOf(sep, sepIndex);
if (sepIndex === -1)
break;
curDir = curDir.slice(0, sepIndex + 1);
modulePaths.push(`${curDir}node_modules`);
}
return modulePaths;
}