191 lines
6.1 KiB
JavaScript
191 lines
6.1 KiB
JavaScript
// 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
|
|
};
|