191 lines
6.1 KiB
JavaScript
Raw Permalink Normal View History

2026-05-31 13:21:13 +02:00
// node/resolver.ts
import * as fs from "node:fs";
import { dirname, join, relative, resolve } from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
import { parseNi, run } from "@antfu/ni";
import { ensurePrefix, slash } from "@antfu/utils";
import globalDirs from "global-directory";
import { underline, yellow } from "kolorist";
import { resolvePath } from "mlly";
import prompts from "prompts";
import { resolveGlobal } from "resolve-global";
import { findClosestPkgJsonPath, findDepPkgJsonPath } from "vitefu";
var cliRoot = fileURLToPath(new URL("..", import.meta.url));
var isInstalledGlobally = {};
async function resolveImportUrl(id) {
return toAtFS(await resolveImportPath(id, true));
}
function toAtFS(path) {
return `/@fs${ensurePrefix("/", slash(path))}`;
}
async function resolveImportPath(importName, ensure = false) {
try {
return await resolvePath(importName, {
url: import.meta.url
});
} catch {
}
if (isInstalledGlobally.value) {
try {
return resolveGlobal(importName);
} catch {
}
}
if (ensure)
throw new Error(`Failed to resolve package "${importName}"`);
}
async function findPkgRoot(dep, parent, ensure = false) {
const pkgJsonPath = await findDepPkgJsonPath(dep, parent);
const path = pkgJsonPath ? dirname(pkgJsonPath) : isInstalledGlobally.value ? await findGlobalPkgRoot(dep, false) : void 0;
if (ensure && !path)
throw new Error(`Failed to resolve package "${dep}"`);
return path;
}
async function findGlobalPkgRoot(name, ensure = false) {
const yarnPath = join(globalDirs.yarn.packages, name);
if (fs.existsSync(`${yarnPath}/package.json`))
return yarnPath;
const npmPath = join(globalDirs.npm.packages, name);
if (fs.existsSync(`${npmPath}/package.json`))
return npmPath;
if (ensure)
throw new Error(`Failed to resolve global package "${name}"`);
}
async function resolveEntry(entryRaw) {
if (!fs.existsSync(entryRaw) && !entryRaw.endsWith(".md") && !/[/\\]/.test(entryRaw))
entryRaw += ".md";
const entry = resolve(entryRaw);
if (!fs.existsSync(entry)) {
const { create } = await prompts({
name: "create",
type: "confirm",
initial: "Y",
message: `Entry file ${yellow(`"${entry}"`)} does not exist, do you want to create it?`
});
if (create)
fs.copyFileSync(resolve(cliRoot, "template.md"), entry);
else
process.exit(0);
}
return slash(entry);
}
function createResolver(type, officials) {
async function promptForInstallation(pkgName) {
const { confirm } = await prompts({
name: "confirm",
initial: "Y",
type: "confirm",
message: `The ${type} "${pkgName}" was not found ${underline(isInstalledGlobally.value ? "globally" : "in your project")}, do you want to install it now?`
});
if (!confirm)
process.exit(1);
if (isInstalledGlobally.value)
await run(parseNi, ["-g", pkgName]);
else
await run(parseNi, [pkgName]);
}
return async function(name, importer) {
const { userRoot } = await getRoots();
if (name === "none")
return ["", null];
if (name[0] === "/")
return [name, name];
if (name.startsWith("@/"))
return [name, resolve(userRoot, name.slice(2))];
if (name[0] === "." || name[0] !== "@" && name.includes("/"))
return [name, resolve(dirname(importer), name)];
if (name.startsWith(`@slidev/${type}-`) || name.startsWith(`slidev-${type}-`)) {
const pkgRoot = await findPkgRoot(name, importer);
if (!pkgRoot)
await promptForInstallation(name);
return [name, await findPkgRoot(name, importer, true)];
}
{
const possiblePkgNames = [
`@slidev/${type}-${name}`,
`slidev-${type}-${name}`,
name
];
for (const pkgName2 of possiblePkgNames) {
const pkgRoot = await findPkgRoot(pkgName2, importer);
if (pkgRoot)
return [pkgName2, pkgRoot];
}
}
const pkgName = officials[name] ?? (name[0] === "@" ? name : `slidev-${type}-${name}`);
await promptForInstallation(pkgName);
return [pkgName, await findPkgRoot(pkgName, importer, true)];
};
}
function getUserPkgJson(userRoot) {
const path = resolve(userRoot, "package.json");
if (fs.existsSync(path))
return JSON.parse(fs.readFileSync(path, "utf-8"));
return {};
}
function hasWorkspacePackageJSON(root) {
const path = join(root, "package.json");
try {
fs.accessSync(path, fs.constants.R_OK);
} catch {
return false;
}
const content = JSON.parse(fs.readFileSync(path, "utf-8")) || {};
return !!content.workspaces;
}
function hasRootFile(root) {
const ROOT_FILES = [
// '.git',
// https://pnpm.js.org/workspaces/
"pnpm-workspace.yaml"
// https://rushjs.io/pages/advanced/config_files/
// 'rush.json',
// https://nx.dev/latest/react/getting-started/nx-setup
// 'workspace.json',
// 'nx.json'
];
return ROOT_FILES.some((file) => fs.existsSync(join(root, file)));
}
function searchForWorkspaceRoot(current, root = current) {
if (hasRootFile(current))
return current;
if (hasWorkspacePackageJSON(current))
return current;
const dir = dirname(current);
if (!dir || dir === current)
return root;
return searchForWorkspaceRoot(dir, root);
}
var rootsInfo = null;
async function getRoots(entry) {
if (rootsInfo)
return rootsInfo;
if (!entry)
throw new Error("[slidev] Cannot find roots without entry");
const userRoot = dirname(entry);
isInstalledGlobally.value = slash(relative(userRoot, process.argv[1])).includes("/.pnpm/") || (await import("is-installed-globally")).default;
const clientRoot = await findPkgRoot("@slidev/client", cliRoot, true);
const closestPkgRoot = dirname(await findClosestPkgJsonPath(userRoot) || userRoot);
const userPkgJson = getUserPkgJson(closestPkgRoot);
const userWorkspaceRoot = searchForWorkspaceRoot(closestPkgRoot);
rootsInfo = {
cliRoot,
clientRoot,
userRoot,
userPkgJson,
userWorkspaceRoot
};
return rootsInfo;
}
export {
isInstalledGlobally,
resolveImportUrl,
toAtFS,
resolveImportPath,
resolveEntry,
createResolver,
getRoots
};