// 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 };