UNPKG

@alauda/doom

Version:

Doctor Doom making docs.

108 lines (107 loc) 3.66 kB
import fs from 'node:fs/promises'; import path from 'node:path'; import { logger } from '@rspress/core'; import { isProduction } from '@rspress/shared'; import ejs from 'ejs'; import { red } from 'yoctocolors'; import { resolveRepo } from "../../utils/index.js"; import { parseToc } from "./parse-toc.js"; import { getFrontmatterNode, mdProcessor, mdxProcessor } from "./utils.js"; const refCache = new Map(); const resolveReference_ = async (localBasePath, localPublicBase, items, refName, force) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!items[refName]) { logger.error(`Reference \`${red(refName)}\` not found`); return; } const source = items[refName]; let publicBase; let sourcePath = source.path; if (source.repo) { const repoFolder = await resolveRepo(source.repo, force, source.branch); if (!repoFolder) { return; } publicBase = path.resolve(repoFolder, source.publicBase ?? 'docs/public'); sourcePath = path.resolve(repoFolder, sourcePath); } else { publicBase = localPublicBase; sourcePath = path.resolve(localBasePath, sourcePath); } let found = false; try { const stat = await fs.stat(sourcePath); found = stat.isFile(); } catch { // } if (!found) { logger.error(`Reference path \`${red(source.path)}\` for \`${red(source.name)}\` not found`); return; } let content = await fs.readFile(sourcePath, 'utf8'); for (const processor of source.processors ?? []) { switch (processor.type) { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition case 'ejsTemplate': { content = await ejs.render(content, { data: processor.data }, { async: true }); break; } } } const processor = (sourcePath.endsWith('.ejs') ? sourcePath.slice(0, -4) : sourcePath).endsWith('.mdx') ? mdxProcessor : mdProcessor; const root = processor.parse(content); const sourceBase = path.dirname(sourcePath); if (!source.anchor) { return { publicBase, sourceBase, contents: root.children, }; } const frontmatterNode = getFrontmatterNode(root); const { toc } = parseToc(root, true); const active = toc.find((it) => it.id === source.anchor) ?? toc.find((it) => it.text === source.anchor); if (!active) { logger.error(`Anchor \`${red(source.anchor)}\` not found in \`${red(source.name)}\``); return; } const nodes = frontmatterNode ? [frontmatterNode] : []; for (let i = active.index, n = root.children.length; i < n; i++) { if (i === active.index && (source.ignoreHeading ?? active.depth === 1)) { continue; } const node = root.children[i]; if (node.type === 'heading' && node.depth <= active.depth && i > active.index) { break; } nodes.push(node); } return { publicBase, sourceBase, contents: nodes, }; }; export const resolveReference = async (localBasePath, localPublicBase, items, refName, force) => { if (refCache.has(refName)) { return refCache.get(refName); } const resolving = resolveReference_(localBasePath, localPublicBase, items, refName, force); refCache.set(refName, resolving); if (!isProduction()) { setTimeout(() => { refCache.delete(refName); }, 5_000); } return resolving; };