@tenphi/docs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-DStZeziu.js","names":["inside"],"sources":["../src/npm/index.ts","../src/graph/index.ts","../src/validation/index.ts","../src/content/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport {\n lstat,\n mkdir,\n mkdtemp,\n readFile,\n readdir,\n rename,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport npa from \"npm-package-arg\";\nimport pacote from \"pacote\";\nimport { glob } from \"tinyglobby\";\nimport type {\n NormalizedDocsConfig,\n PackageDiscovery,\n PackageLockSource,\n PackageManifest,\n TastyDocsLock,\n} from \"../types.js\";\n\nconst DEFAULT_REGISTRY = \"https://registry.npmjs.org/\";\nconst LOCK_FILE = \"tasty-docs.lock.json\";\n\nexport interface ResolvePackageOptions {\n registry?: string;\n cacheDir?: string;\n}\n\nexport async function resolvePackageLock(\n requested: string,\n options: ResolvePackageOptions = {},\n): Promise<PackageLockSource> {\n const parsed = npa(requested);\n if (![\"tag\", \"version\", \"range\"].includes(parsed.type)) {\n throw new Error(\n `Only npm registry package specifiers are supported (received ${parsed.type}).`,\n );\n }\n const registry = options.registry ?? DEFAULT_REGISTRY;\n const manifest = (await pacote.manifest(requested, {\n registry,\n ...(options.cacheDir ? { cache: options.cacheDir } : {}),\n fullMetadata: true,\n })) as PackageManifest;\n if (!manifest.name || !manifest.version || !manifest._integrity) {\n throw new Error(\n `Registry metadata for ${requested} did not include version and integrity.`,\n );\n }\n return {\n requested,\n resolved: `${manifest.name}@${manifest.version}`,\n registry,\n integrity: manifest._integrity,\n };\n}\n\nexport async function readDocsLock(\n root: string,\n): Promise<TastyDocsLock | undefined> {\n try {\n const value = JSON.parse(\n await readFile(join(root, LOCK_FILE), \"utf8\"),\n ) as TastyDocsLock;\n validateLock(value);\n return value;\n } catch (error) {\n if (isMissing(error)) return undefined;\n throw error;\n }\n}\n\nexport async function writeDocsLock(\n root: string,\n lock: TastyDocsLock,\n): Promise<void> {\n validateLock(lock);\n await writeFile(\n join(root, LOCK_FILE),\n `${JSON.stringify(lock, null, 2)}\\n`,\n \"utf8\",\n );\n}\n\nexport function validateLock(lock: TastyDocsLock): void {\n if (lock.schemaVersion !== 1 || !Array.isArray(lock.sources)) {\n throw new Error(\"Unsupported or invalid tasty-docs.lock.json.\");\n }\n for (const source of lock.sources) {\n if (\n !source.requested ||\n !source.resolved ||\n !source.registry ||\n !source.integrity\n ) {\n throw new Error(\n \"Every lock source requires requested, resolved, registry, and integrity.\",\n );\n }\n const parsed = npa(source.resolved);\n if (parsed.type !== \"version\") {\n throw new Error(\n `Locked source must use an exact version: ${source.resolved}.`,\n );\n }\n if (\n source.vendored &&\n (source.vendored.startsWith(\"/\") ||\n source.vendored.split(/[\\\\/]/).includes(\"..\"))\n ) {\n throw new Error(\n `Vendored package path must stay within the project: ${source.vendored}.`,\n );\n }\n }\n}\n\nexport async function materializePackage(\n source: PackageLockSource,\n config: NormalizedDocsConfig[\"build\"],\n projectRoot?: string,\n): Promise<string> {\n if (source.vendored) {\n if (!projectRoot) {\n throw new Error(\n `Vendored source ${source.resolved} requires a project root.`,\n );\n }\n const vendored = resolve(projectRoot, source.vendored);\n if (!inside(projectRoot, vendored)) {\n throw new Error(\n `Vendored package path escapes the project root: ${source.vendored}.`,\n );\n }\n const marker = (\n await readFile(join(vendored, \".tasty-docs-integrity\"), \"utf8\")\n ).trim();\n if (marker !== source.integrity) {\n throw new Error(\n `Vendored package integrity marker does not match ${source.resolved}.`,\n );\n }\n await validateExtractedTree(vendored, config);\n return vendored;\n }\n const cacheRoot = resolve(\n config.cacheDir || join(homedir(), \".cache\", \"tasty-docs\"),\n \"artifacts\",\n );\n const key = createHash(\"sha256\").update(source.integrity).digest(\"hex\");\n const destination = join(cacheRoot, key);\n const marker = join(destination, \".tasty-docs-integrity\");\n try {\n if ((await readFile(marker, \"utf8\")).trim() === source.integrity)\n return destination;\n } catch (error) {\n if (!isMissing(error)) throw error;\n }\n\n await mkdir(cacheRoot, { recursive: true });\n const temporary = await mkdtemp(join(cacheRoot, \".extract-\"));\n try {\n const tarball = await pacote.tarball(source.resolved, {\n registry: source.registry,\n integrity: source.integrity,\n cache: join(cacheRoot, \"_cacache\"),\n });\n if (tarball.byteLength > config.maxArtifactBytes) {\n throw new Error(\n `Package artifact is ${tarball.byteLength} bytes; limit is ${config.maxArtifactBytes}.`,\n );\n }\n await pacote.extract(source.resolved, temporary, {\n registry: source.registry,\n integrity: source.integrity,\n cache: join(cacheRoot, \"_cacache\"),\n });\n await validateExtractedTree(temporary, config);\n await writeFile(\n join(temporary, \".tasty-docs-integrity\"),\n `${source.integrity}\\n`,\n );\n await rm(destination, { recursive: true, force: true });\n await rename(temporary, destination);\n return destination;\n } catch (error) {\n await rm(temporary, { recursive: true, force: true });\n throw error;\n }\n}\n\nasync function validateExtractedTree(\n root: string,\n config: NormalizedDocsConfig[\"build\"],\n): Promise<void> {\n let files = 0;\n let bytes = 0;\n const pending = [root];\n while (pending.length > 0) {\n const directory = pending.pop();\n if (!directory) break;\n for (const name of await readdir(directory)) {\n if (name === \".tasty-docs-integrity\") continue;\n const path = join(directory, name);\n const info = await lstat(path);\n const rel = relative(root, path);\n if (rel.startsWith(`..${sep}`) || rel === \"..\") {\n throw new Error(`Package path escapes artifact root: ${rel}.`);\n }\n if (rel.split(sep).length > config.maxPathDepth) {\n throw new Error(`Package path exceeds maximum depth: ${rel}.`);\n }\n if (info.isSymbolicLink()) {\n throw new Error(`Package symlinks are not allowed: ${rel}.`);\n }\n if (info.isDirectory()) {\n pending.push(path);\n } else if (info.isFile()) {\n files += 1;\n bytes += info.size;\n if (info.size > config.maxAssetBytes) {\n throw new Error(`Package file exceeds maximum size: ${rel}.`);\n }\n if (files > config.maxFiles || bytes > config.maxUnpackedBytes) {\n throw new Error(\n \"Package exceeds configured file-count or unpacked-size limit.\",\n );\n }\n } else {\n throw new Error(`Unsupported package entry type: ${rel}.`);\n }\n }\n }\n}\n\nexport async function discoverPackage(root: string): Promise<PackageDiscovery> {\n const manifest = JSON.parse(\n await readFile(join(root, \"package.json\"), \"utf8\"),\n ) as PackageManifest;\n const hints = manifest.tastyDocs;\n const homeCandidates = [hints?.index, \"README.md\", \"readme.md\"].filter(\n (candidate): candidate is string => Boolean(candidate),\n );\n let home: string | undefined;\n for (const candidate of homeCandidates) {\n try {\n if ((await stat(join(root, candidate))).isFile()) {\n home = candidate;\n break;\n }\n } catch (error) {\n if (!isMissing(error)) throw error;\n }\n }\n\n const patterns = hints?.include?.length\n ? hints.include\n : [\n \"docs/**/*.{md,mdx}\",\n \"docs/**/*.{png,jpg,jpeg,gif,webp,avif,svg,pdf,txt,zip}\",\n ];\n const discovered = await glob(patterns, {\n cwd: root,\n onlyFiles: true,\n dot: false,\n ignore: hints?.exclude ?? [],\n });\n const pages = discovered.filter((path) => /\\.mdx?$/i.test(path));\n if (home && !pages.includes(home)) pages.unshift(home);\n const assets = discovered.filter((path) => !/\\.mdx?$/i.test(path));\n return { root, manifest, ...(home ? { home } : {}), pages, assets };\n}\n\nexport function packageNameFromSpecifier(specifier: string): string {\n const parsed = npa(specifier);\n if (!parsed.name)\n throw new Error(`Invalid npm package specifier: ${specifier}.`);\n return parsed.name;\n}\n\nexport function lockForSource(\n lock: TastyDocsLock | undefined,\n requested: string,\n): PackageLockSource {\n const match = lock?.sources.find(\n (source) =>\n source.requested === requested ||\n packageNameFromSpecifier(source.requested) ===\n packageNameFromSpecifier(requested),\n );\n if (!match) {\n throw new Error(\n `Package source ${requested} is not locked. Run \"tasty-docs update\" to create ${LOCK_FILE}.`,\n );\n }\n return match;\n}\n\nexport function defaultLock(sources: PackageLockSource[]): TastyDocsLock {\n return { schemaVersion: 1, sources };\n}\n\nfunction isMissing(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n );\n}\n\nfunction inside(root: string, path: string): boolean {\n const rel = relative(resolve(root), resolve(path));\n return (\n rel === \"\" ||\n (!rel.startsWith(`..${sep}`) && rel !== \"..\" && !isAbsolute(rel))\n );\n}\n","import { createHash } from \"node:crypto\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport {\n basename,\n dirname,\n extname,\n isAbsolute,\n relative,\n resolve,\n sep,\n} from \"node:path\";\nimport matter from \"gray-matter\";\nimport type { Image, Link, Root } from \"mdast\";\nimport { glob } from \"tinyglobby\";\nimport { visit } from \"unist-util-visit\";\nimport { normalizeDocsConfig } from \"../config/index.js\";\nimport {\n cloneAst,\n parseMarkdown,\n removeRenderedTitle,\n serializeMarkdown,\n stripLeadingBadgeBlock,\n} from \"../markdown/index.js\";\nimport {\n discoverPackage,\n lockForSource,\n materializePackage,\n readDocsLock,\n} from \"../npm/index.js\";\nimport type {\n CreateDocsGraphOptions,\n DocsAsset,\n DocsDiagnostic,\n DocsEntry,\n DocsFrontmatter,\n DocsGraph,\n DocsRoute,\n DocsSource,\n NavigationItem,\n NormalizedDocsConfig,\n PackageLockSource,\n} from \"../types.js\";\n\ninterface CollectedSource {\n absolutePath: string;\n sourcePath: string;\n sourceRoot: string;\n route?: string;\n title?: string;\n description?: string;\n trust: \"markdown\" | \"mdx\";\n packageLock?: PackageLockSource;\n}\n\nconst MARKDOWN_EXTENSIONS = [\".md\", \".mdx\"];\nconst FRONTMATTER_KEYS = new Set([\n \"title\",\n \"description\",\n \"slug\",\n \"draft\",\n \"sidebar\",\n \"toc\",\n \"editUrl\",\n \"prev\",\n \"next\",\n \"search\",\n \"head\",\n]);\n\nexport async function createDocsGraph(\n options: CreateDocsGraphOptions = {},\n): Promise<DocsGraph> {\n const root = resolve(options.root ?? process.cwd());\n const config = normalizeDocsConfig(options.config);\n const diagnostics: DocsDiagnostic[] = [];\n const lock = options.lock ?? (await readDocsLock(root));\n const collected = await collectSources(root, config, lock, diagnostics);\n const entries: DocsEntry[] = [];\n const routeMap = new Map<string, DocsEntry>();\n const absoluteMap = new Map<string, DocsEntry>();\n const sourceMap = new Map<string, DocsEntry>();\n\n for (const source of collected) {\n const entry = await readEntry(source, config, diagnostics);\n if (!entry) continue;\n const existing = routeMap.get(entry.route);\n if (existing) {\n diagnostics.push({\n code: \"DOCS_DUPLICATE_ROUTE\",\n severity: \"error\",\n message: `Route ${entry.route} is owned by both ${existing.sourcePath} and ${entry.sourcePath}.`,\n file: entry.sourcePath,\n related: [{ file: existing.sourcePath, message: \"First route owner.\" }],\n });\n continue;\n }\n routeMap.set(entry.route, entry);\n absoluteMap.set(normalizeFs(entry.absolutePath), entry);\n sourceMap.set(entry.sourcePath, entry);\n sourceMap.set(entry.id, entry);\n entries.push(entry);\n }\n\n for (const entry of entries) {\n await transformEntry(entry, absoluteMap, routeMap, config, diagnostics);\n }\n validateNavigation(config.navigation.items ?? [], routeMap, diagnostics);\n\n entries.sort((left, right) => left.route.localeCompare(right.route));\n const routes: DocsRoute[] = entries.map((entry) => ({\n route: entry.route,\n entryId: entry.id,\n sourcePath: entry.sourcePath,\n title: entry.title,\n }));\n const assets = entries.flatMap((entry) => entry.assets);\n return {\n root,\n config,\n entries,\n routes,\n assets,\n diagnostics,\n entryByRoute(route) {\n return routeMap.get(normalizeRoute(route));\n },\n entryBySource(sourcePath) {\n return sourceMap.get(sourcePath);\n },\n };\n}\n\nasync function collectSources(\n root: string,\n config: NormalizedDocsConfig,\n lock: CreateDocsGraphOptions[\"lock\"],\n diagnostics: DocsDiagnostic[],\n): Promise<CollectedSource[]> {\n const declarations = config.content.sources?.length\n ? config.content.sources\n : await conventionSources(root);\n const results: CollectedSource[] = [];\n const identities = new Set<string>();\n\n for (const declaration of declarations) {\n try {\n const found = await collectDeclaration(root, declaration, config, lock);\n if (found.length === 0) {\n diagnostics.push({\n code: \"DOCS_SOURCE_NOT_FOUND\",\n severity: \"error\",\n message: `Source did not match any files: ${sourceLabel(declaration)}.`,\n });\n }\n for (const source of found) {\n const identity = normalizeFs(source.absolutePath);\n if (identities.has(identity)) continue;\n identities.add(identity);\n results.push(source);\n }\n } catch (error) {\n diagnostics.push({\n code:\n error instanceof OutsideRootError\n ? \"DOCS_SOURCE_OUTSIDE_ROOT\"\n : \"DOCS_SOURCE_NOT_FOUND\",\n severity: \"error\",\n message: errorMessage(error),\n });\n }\n }\n return results;\n}\n\nasync function conventionSources(root: string): Promise<DocsSource[]> {\n const sources: DocsSource[] = [];\n if (await isFile(resolve(root, \"README.md\")))\n sources.push({ file: \"README.md\", route: \"/\" });\n const docs = resolve(root, \"docs\");\n if (await isDirectory(docs)) {\n sources.push({ glob: \"docs/**/*.{md,mdx}\", base: \"docs\" });\n }\n return sources;\n}\n\nasync function collectDeclaration(\n root: string,\n declaration: DocsSource,\n config: NormalizedDocsConfig,\n lock: CreateDocsGraphOptions[\"lock\"],\n): Promise<CollectedSource[]> {\n if (\"package\" in declaration) {\n const packageLock = lockForSource(lock, declaration.package);\n const sourceRoot = await materializePackage(\n packageLock,\n config.build,\n root,\n );\n const discovery = await discoverPackage(sourceRoot);\n const patterns = declaration.include?.length\n ? declaration.include\n : discovery.pages;\n const files = declaration.include?.length\n ? await glob(patterns, {\n cwd: sourceRoot,\n onlyFiles: true,\n ignore: declaration.exclude ?? [],\n })\n : discovery.pages.filter(\n (path) => !(declaration.exclude ?? []).includes(path),\n );\n const index = declaration.index ?? discovery.home;\n return files\n .filter((path) =>\n MARKDOWN_EXTENSIONS.includes(extname(path).toLowerCase()),\n )\n .map((path) => ({\n absolutePath: resolve(sourceRoot, path),\n sourcePath: path,\n sourceRoot,\n route:\n path === index\n ? normalizeRoute(declaration.routeBase ?? \"/\")\n : routeForPath(path, \"docs\", declaration.routeBase),\n trust: declaration.trust ?? \"markdown\",\n packageLock,\n }));\n }\n\n if (\"file\" in declaration) {\n const absolutePath = resolveSourcePath(\n root,\n declaration.file,\n config.content.allowOutsideRoot,\n );\n if (!(await isFile(absolutePath))) return [];\n return [\n {\n absolutePath,\n sourcePath: toPosix(relative(root, absolutePath)),\n sourceRoot: root,\n ...(declaration.route ? { route: declaration.route } : {}),\n ...(declaration.title ? { title: declaration.title } : {}),\n ...(declaration.description\n ? { description: declaration.description }\n : {}),\n trust: \"mdx\",\n },\n ];\n }\n\n const patterns = Array.isArray(declaration.glob)\n ? declaration.glob\n : [declaration.glob];\n const paths = await glob(patterns, {\n cwd: root,\n onlyFiles: true,\n dot: false,\n ignore: [\"**/_*/**\", \"**/_*\", ...(declaration.exclude ?? [])],\n });\n return paths.map((path) => {\n const absolutePath = resolveSourcePath(\n root,\n path,\n config.content.allowOutsideRoot,\n );\n return {\n absolutePath,\n sourcePath: toPosix(relative(root, absolutePath)),\n sourceRoot: root,\n route: routeForPath(path, declaration.base, declaration.routeBase),\n trust: \"mdx\",\n };\n });\n}\n\nasync function readEntry(\n source: CollectedSource,\n config: NormalizedDocsConfig,\n diagnostics: DocsDiagnostic[],\n): Promise<DocsEntry | undefined> {\n if (\n extname(source.sourcePath).toLowerCase() === \".mdx\" &&\n source.trust !== \"mdx\"\n ) {\n diagnostics.push({\n code: \"DOCS_UNTRUSTED_MDX\",\n severity: \"error\",\n message: `Package MDX requires trust: 'mdx': ${source.sourcePath}.`,\n file: source.sourcePath,\n hint: \"Keep package sources in Markdown-safe mode or explicitly trust this locked artifact.\",\n });\n return undefined;\n }\n const original = await readFile(source.absolutePath, \"utf8\");\n const parsedMatter = matter(original);\n const frontmatter = parsedMatter.data as DocsFrontmatter;\n for (const key of Object.keys(parsedMatter.data)) {\n if (!FRONTMATTER_KEYS.has(key)) {\n diagnostics.push({\n code: \"DOCS_FRONTMATTER_INVALID\",\n severity: \"error\",\n message: `Unknown frontmatter key \"${key}\".`,\n file: source.sourcePath,\n });\n }\n }\n const parsed = parseMarkdown(parsedMatter.content);\n const route = normalizeRoute(\n frontmatter.slug ?? source.route ?? routeForPath(source.sourcePath),\n );\n const title =\n frontmatter.title ??\n source.title ??\n parsed.firstHeading ??\n titleFromFile(source.sourcePath);\n const description =\n frontmatter.description ?? source.description ?? parsed.description;\n const duplicateTitles = new Map<string, number>();\n for (const heading of parsed.headings) {\n const count = (duplicateTitles.get(heading.text) ?? 0) + 1;\n duplicateTitles.set(heading.text, count);\n if (count > 1) {\n diagnostics.push({\n code: \"DOCS_HEADING_DUPLICATE\",\n severity: \"warning\",\n message: `Repeated heading \"${heading.text}\" receives the generated ID \"${heading.slug}\".`,\n file: source.sourcePath,\n ...(heading.line ? { line: heading.line } : {}),\n });\n }\n }\n const idPrefix = source.packageLock?.resolved ?? \"local\";\n return {\n id: `${idPrefix}:${source.sourcePath}`,\n sourcePath: source.sourcePath,\n absolutePath: source.absolutePath,\n sourceRoot: source.sourceRoot,\n route,\n title,\n ...(description ? { description } : {}),\n frontmatter,\n headings: parsed.headings,\n body: parsedMatter.content,\n transformedBody: parsedMatter.content,\n ast: parsed.ast,\n links: [],\n assets: [],\n trust: source.trust,\n ...(source.packageLock\n ? {\n package: {\n requested: source.packageLock.requested,\n resolved: source.packageLock.resolved,\n },\n }\n : {}),\n };\n}\n\nasync function transformEntry(\n entry: DocsEntry,\n absoluteMap: Map<string, DocsEntry>,\n routeMap: Map<string, DocsEntry>,\n config: NormalizedDocsConfig,\n diagnostics: DocsDiagnostic[],\n): Promise<void> {\n const ast = cloneAst(entry.ast);\n if (config.markdown.stripLeadingBadges) stripLeadingBadgeBlock(ast);\n removeRenderedTitle(ast, entry.title);\n\n visit(ast, (node) => {\n if (node.type === \"html\" && entry.trust === \"markdown\") {\n const unsafe = /<\\s*script\\b|\\son[a-z]+\\s*=|javascript:/i.test(\n node.value,\n );\n if (unsafe) {\n diagnostics.push({\n code: \"DOCS_UNSAFE_HTML\",\n severity: \"error\",\n message: \"Script-capable HTML is not allowed in package Markdown.\",\n file: entry.sourcePath,\n ...(node.position?.start.line\n ? { line: node.position.start.line }\n : {}),\n });\n node.value = \"\";\n }\n }\n });\n\n const linkTasks: Promise<void>[] = [];\n visit(ast, (node) => {\n if (node.type === \"link\") {\n linkTasks.push(\n rewriteLink(node, entry, absoluteMap, routeMap, config, diagnostics),\n );\n } else if (node.type === \"image\") {\n linkTasks.push(rewriteAsset(node, entry, config, diagnostics));\n }\n });\n await Promise.all(linkTasks);\n entry.ast = ast;\n entry.transformedBody = serializeMarkdown(ast);\n}\n\nasync function rewriteLink(\n node: Link,\n entry: DocsEntry,\n absoluteMap: Map<string, DocsEntry>,\n routeMap: Map<string, DocsEntry>,\n config: NormalizedDocsConfig,\n diagnostics: DocsDiagnostic[],\n): Promise<void> {\n const reference: import(\"../types.js\").DocsReference = {\n original: node.url,\n ...lineData(node),\n };\n entry.links.push(reference);\n if (unsafeProtocol(node.url)) {\n diagnostic(\n diagnostics,\n \"DOCS_LINK_UNSAFE\",\n `Unsafe URL protocol: ${node.url}.`,\n entry,\n node,\n );\n return;\n }\n if (isExternal(node.url) || node.url.startsWith(\"#\")) return;\n const { pathname, query, fragment } = splitReference(node.url);\n if (pathname.startsWith(\"/\")) {\n const target = routeMap.get(normalizeRoute(pathname));\n if (!target) missingLink(diagnostics, entry, node, node.url, config);\n else validateFragment(fragment, target, entry, node, diagnostics, config);\n return;\n }\n const decoded = safeDecode(pathname);\n const targetPath = resolve(dirname(entry.absolutePath), decoded);\n if (!inside(entry.sourceRoot, targetPath)) {\n diagnostic(\n diagnostics,\n \"DOCS_SOURCE_OUTSIDE_ROOT\",\n `Link escapes its allowed source root: ${node.url}.`,\n entry,\n node,\n );\n return;\n }\n const target = findDocument(targetPath, absoluteMap);\n if (!target) {\n if (await isFile(targetPath)) return;\n missingLink(diagnostics, entry, node, node.url, config);\n return;\n }\n node.url = `${withBase(target.route, config.build.base)}${query}${fragment ? `#${fragment}` : \"\"}`;\n reference.resolved = node.url;\n reference.targetSource = target.sourcePath;\n if (fragment) reference.fragment = fragment;\n validateFragment(fragment, target, entry, node, diagnostics, config);\n}\n\nasync function rewriteAsset(\n node: Image,\n entry: DocsEntry,\n config: NormalizedDocsConfig,\n diagnostics: DocsDiagnostic[],\n): Promise<void> {\n const asset: DocsAsset = {\n original: node.url,\n ...lineData(node),\n };\n entry.assets.push(asset);\n if (isExternal(node.url)) return;\n if (unsafeProtocol(node.url)) {\n diagnostic(\n diagnostics,\n \"DOCS_ASSET_UNSAFE\",\n `Unsafe asset URL: ${node.url}.`,\n entry,\n node,\n );\n return;\n }\n const { pathname, query, fragment } = splitReference(node.url);\n const absolute = resolve(dirname(entry.absolutePath), safeDecode(pathname));\n if (!inside(entry.sourceRoot, absolute)) {\n diagnostic(\n diagnostics,\n \"DOCS_SOURCE_OUTSIDE_ROOT\",\n `Asset escapes its allowed source root: ${node.url}.`,\n entry,\n node,\n );\n return;\n }\n try {\n const info = await stat(absolute);\n if (!info.isFile()) throw new Error(\"not a file\");\n if (info.size > config.build.maxAssetBytes) {\n throw new Error(`asset exceeds ${config.build.maxAssetBytes} bytes`);\n }\n const hash = createHash(\"sha256\")\n .update(await readFile(absolute))\n .digest(\"hex\")\n .slice(0, 12);\n const publicPath = withBase(\n `/_tasty-assets/${hash}-${basename(absolute)}`,\n config.build.base,\n );\n node.url = `${publicPath}${query}${fragment ? `#${fragment}` : \"\"}`;\n Object.assign(asset, {\n resolved: node.url,\n sourcePath: absolute,\n publicPath,\n hash,\n bytes: info.size,\n });\n } catch (error) {\n diagnostic(\n diagnostics,\n \"DOCS_ASSET_NOT_FOUND\",\n `Asset not found or invalid: ${node.url} (${errorMessage(error)}).`,\n entry,\n node,\n );\n }\n}\n\nfunction findDocument(\n path: string,\n absoluteMap: Map<string, DocsEntry>,\n): DocsEntry | undefined {\n const candidates = [\n path,\n ...MARKDOWN_EXTENSIONS.map((extension) => `${path}${extension}`),\n ...MARKDOWN_EXTENSIONS.map((extension) =>\n resolve(path, `README${extension}`),\n ),\n ...MARKDOWN_EXTENSIONS.map((extension) =>\n resolve(path, `index${extension}`),\n ),\n ];\n for (const candidate of candidates) {\n const entry = absoluteMap.get(normalizeFs(candidate));\n if (entry) return entry;\n }\n return undefined;\n}\n\nfunction validateFragment(\n fragment: string,\n target: DocsEntry,\n source: DocsEntry,\n node: Link,\n diagnostics: DocsDiagnostic[],\n config: NormalizedDocsConfig,\n): void {\n if (!fragment) return;\n const decoded = safeDecode(fragment);\n if (!target.headings.some((heading) => heading.slug === decoded)) {\n diagnostics.push({\n code: \"DOCS_FRAGMENT_NOT_FOUND\",\n severity: config.build.ci ? \"error\" : \"warning\",\n message: `Heading fragment #${fragment} does not exist on ${target.route}.`,\n file: source.sourcePath,\n ...lineData(node),\n hint: `Known headings: ${target.headings.map((heading) => `#${heading.slug}`).join(\", \") || \"(none)\"}.`,\n });\n }\n}\n\nfunction missingLink(\n diagnostics: DocsDiagnostic[],\n entry: DocsEntry,\n node: Link,\n url: string,\n config: NormalizedDocsConfig,\n): void {\n diagnostics.push({\n code: \"DOCS_LINK_NOT_FOUND\",\n severity: config.build.strict ? \"error\" : \"warning\",\n message: `Internal link target not found: ${url}.`,\n file: entry.sourcePath,\n ...lineData(node),\n });\n}\n\nfunction validateNavigation(\n items: NavigationItem[],\n routes: Map<string, DocsEntry>,\n diagnostics: DocsDiagnostic[],\n): void {\n for (const item of items) {\n if (typeof item === \"string\") {\n if (!routes.has(normalizeRoute(item))) {\n diagnostics.push({\n code: \"DOCS_NAV_TARGET_NOT_FOUND\",\n severity: \"error\",\n message: `Navigation target does not exist: ${item}.`,\n });\n }\n } else if (\"items\" in item) {\n validateNavigation(item.items, routes, diagnostics);\n } else if (\n \"link\" in item &&\n item.link.startsWith(\"/\") &&\n !routes.has(normalizeRoute(item.link))\n ) {\n diagnostics.push({\n code: \"DOCS_NAV_TARGET_NOT_FOUND\",\n severity: \"error\",\n message: `Navigation target does not exist: ${item.link}.`,\n });\n }\n }\n}\n\nexport function normalizeRoute(route: string): string {\n const clean =\n route\n .split(/[?#]/, 1)[0]\n ?.replace(/\\\\/g, \"/\")\n .replace(/\\/{2,}/g, \"/\") ?? \"/\";\n const segments = clean.split(\"/\").filter(Boolean);\n if (segments.some((segment) => segment === \"..\"))\n throw new Error(`Route may not contain \"..\": ${route}.`);\n const normalized = `/${segments.join(\"/\")}`;\n return normalized === \"/\" ? \"/\" : normalized.replace(/\\/$/, \"\");\n}\n\nexport function routeForPath(\n path: string,\n base?: string,\n routeBase?: string,\n): string {\n let relativePath = toPosix(path);\n if (base) {\n const normalizedBase = toPosix(base)\n .replace(/^\\.\\//, \"\")\n .replace(/\\/$/, \"\");\n if (relativePath === normalizedBase) relativePath = \"\";\n else if (relativePath.startsWith(`${normalizedBase}/`))\n relativePath = relativePath.slice(normalizedBase.length + 1);\n }\n relativePath = relativePath.replace(/\\.(md|mdx)$/i, \"\");\n relativePath = relativePath\n .replace(/(^|\\/)README$/i, \"$1\")\n .replace(/(^|\\/)index$/i, \"$1\");\n return normalizeRoute(`${routeBase ?? \"\"}/${relativePath}`);\n}\n\nfunction resolveSourcePath(\n root: string,\n path: string,\n allowOutsideRoot: boolean,\n): string {\n const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);\n if (!allowOutsideRoot && !inside(root, absolute))\n throw new OutsideRootError(path);\n return absolute;\n}\n\nfunction inside(root: string, path: string): boolean {\n const rel = relative(resolve(root), resolve(path));\n return (\n rel === \"\" ||\n (!rel.startsWith(`..${sep}`) && rel !== \"..\" && !isAbsolute(rel))\n );\n}\n\nfunction splitReference(url: string): {\n pathname: string;\n query: string;\n fragment: string;\n} {\n const hashIndex = url.indexOf(\"#\");\n const fragment = hashIndex >= 0 ? url.slice(hashIndex + 1) : \"\";\n const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;\n const queryIndex = withoutHash.indexOf(\"?\");\n return {\n pathname: queryIndex >= 0 ? withoutHash.slice(0, queryIndex) : withoutHash,\n query: queryIndex >= 0 ? withoutHash.slice(queryIndex) : \"\",\n fragment,\n };\n}\n\nfunction isExternal(url: string): boolean {\n return /^(?:[a-z][a-z\\d+.-]*:|\\/\\/)/i.test(url);\n}\n\nfunction unsafeProtocol(url: string): boolean {\n return /^(?:javascript|vbscript|data):/i.test(url.trim());\n}\n\nfunction withBase(route: string, base: string): string {\n const normalizedBase =\n base === \"/\" ? \"\" : `/${base.replace(/^\\/+|\\/+$/g, \"\")}`;\n return `${normalizedBase}${normalizeRoute(route)}` || \"/\";\n}\n\nfunction titleFromFile(path: string): string {\n const raw = basename(path, extname(path)).replace(\n /^README$/i,\n basename(dirname(path)) || \"Documentation\",\n );\n return raw\n .replace(/[-_]+/g, \" \")\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction diagnostic(\n diagnostics: DocsDiagnostic[],\n code: string,\n message: string,\n entry: DocsEntry,\n node: PositionedNode,\n): void {\n diagnostics.push({\n code,\n severity: \"error\",\n message,\n file: entry.sourcePath,\n ...lineData(node),\n });\n}\n\ntype PositionedNode = { position?: { start: { line: number } } | undefined };\n\nfunction lineOf(node: PositionedNode): number | undefined {\n return node.position?.start.line;\n}\n\nfunction lineData(\n node: PositionedNode,\n): { line: number } | Record<string, never> {\n const line = lineOf(node);\n return line === undefined ? {} : { line };\n}\n\nfunction safeDecode(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction sourceLabel(source: DocsSource): string {\n if (\"file\" in source) return source.file;\n if (\"glob\" in source)\n return Array.isArray(source.glob) ? source.glob.join(\", \") : source.glob;\n return source.package;\n}\n\nfunction normalizeFs(path: string): string {\n return resolve(path);\n}\n\nfunction toPosix(path: string): string {\n return path.split(sep).join(\"/\");\n}\n\nasync function isFile(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nclass OutsideRootError extends Error {\n constructor(path: string) {\n super(`Source path is outside the repository root: ${path}.`);\n this.name = \"OutsideRootError\";\n }\n}\n","import type { DocsDiagnostic, DocsGraph } from \"../types.js\";\n\nexport class DocsValidationError extends Error {\n readonly diagnostics: DocsDiagnostic[];\n\n constructor(diagnostics: DocsDiagnostic[]) {\n super(formatDiagnostics(diagnostics));\n this.name = \"DocsValidationError\";\n this.diagnostics = diagnostics;\n }\n}\n\nexport function validateDocs(graph: DocsGraph): DocsDiagnostic[] {\n return [...graph.diagnostics];\n}\n\nexport function assertValidDocs(graph: DocsGraph): void {\n const errors = graph.diagnostics.filter(\n (diagnostic) => diagnostic.severity === \"error\",\n );\n if (errors.length > 0) throw new DocsValidationError(errors);\n}\n\nexport function formatDiagnostics(\n diagnostics: DocsDiagnostic[],\n json = false,\n): string {\n if (json) return JSON.stringify(diagnostics, null, 2);\n return diagnostics\n .map((diagnostic) => {\n const location = diagnostic.file\n ? `${diagnostic.file}${diagnostic.line ? `:${diagnostic.line}` : \"\"}: `\n : \"\";\n const hint = diagnostic.hint ? `\\n hint: ${diagnostic.hint}` : \"\";\n return `${diagnostic.severity.toUpperCase()} ${diagnostic.code} ${location}${diagnostic.message}${hint}`;\n })\n .join(\"\\n\");\n}\n","import { createDocsGraph } from \"../graph/index.js\";\nimport { assertValidDocs } from \"../validation/index.js\";\nimport type {\n CreateDocsGraphOptions,\n DocsConfig,\n DocsEntry,\n} from \"../types.js\";\n\nexport interface DocsLoaderContext {\n store: {\n clear(): void;\n set(entry: {\n id: string;\n data: Record<string, unknown>;\n body: string;\n filePath?: string;\n }): void;\n };\n logger?: { info(message: string): void };\n parseData?: (input: {\n id: string;\n data: Record<string, unknown>;\n filePath?: string;\n }) => Promise<Record<string, unknown>>;\n}\n\nexport function createDocsLoader(\n config?: DocsConfig,\n options: Omit<CreateDocsGraphOptions, \"config\"> = {},\n) {\n return {\n name: \"@tenphi/docs\",\n async load(context: DocsLoaderContext): Promise<void> {\n const graph = await createDocsGraph({\n ...options,\n ...(config ? { config } : {}),\n });\n assertValidDocs(graph);\n context.store.clear();\n for (const entry of graph.entries) {\n const loaderEntry = toLoaderEntry(entry);\n const data = context.parseData\n ? await context.parseData({\n id: loaderEntry.id,\n data: loaderEntry.data,\n filePath: entry.sourcePath,\n })\n : loaderEntry.data;\n context.store.set({\n ...loaderEntry,\n data,\n filePath: entry.sourcePath,\n });\n }\n context.logger?.info(`Loaded ${graph.entries.length} Tasty Docs pages.`);\n },\n };\n}\n\nfunction toLoaderEntry(entry: DocsEntry): {\n id: string;\n data: Record<string, unknown>;\n body: string;\n} {\n return {\n id: entry.route === \"/\" ? \"index\" : entry.route.slice(1),\n data: {\n title: entry.title,\n draft: entry.frontmatter.draft ?? false,\n ...(entry.description ? { description: entry.description } : {}),\n ...entry.frontmatter,\n tastyDocs: {\n sourcePath: entry.sourcePath,\n route: entry.route,\n headings: entry.headings,\n },\n },\n body: entry.transformedBody,\n };\n}\n\nexport type { DocsEntry, DocsGraph, DocsRoute, DocsAsset } from \"../types.js\";\n"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { C as PackageLockSource, D as TastyDocsLock, E as SiteConfig, O as ThemeConfig, S as PackageDiscovery, T as SearchConfig, _ as MarkdownConfig, a as CreateDocsGraphOptions, b as NavigationPlacement, c as DocsConfig, d as DocsFrontmatter, f as DocsGraph, g as DocsSource, h as DocsRoute, i as ContentConfig, l as DocsDiagnostic, m as DocsReference, n as BuildConfig, o as DiagnosticSeverity, p as DocsHeading, r as ComponentsConfig, s as DocsAsset, t as BrandConfig, u as DocsEntry, v as NavigationConfig, w as PackageManifest, x as NormalizedDocsConfig, y as NavigationItem } from "./types-rjENJzWH.js";
2
+ import { DocsConfigError, defineDocsConfig, normalizeDocsConfig, validateConfig } from "./config/index.js";
3
+ import { createDocsLoader } from "./content/index.js";
4
+ //#region src/graph/index.d.ts
5
+ declare function createDocsGraph(options?: CreateDocsGraphOptions): Promise<DocsGraph>;
6
+ declare function normalizeRoute(route: string): string;
7
+ declare function routeForPath(path: string, base?: string, routeBase?: string): string;
8
+ //#endregion
9
+ //#region src/npm/index.d.ts
10
+ interface ResolvePackageOptions {
11
+ registry?: string;
12
+ cacheDir?: string;
13
+ }
14
+ declare function resolvePackageLock(requested: string, options?: ResolvePackageOptions): Promise<PackageLockSource>;
15
+ declare function readDocsLock(root: string): Promise<TastyDocsLock | undefined>;
16
+ declare function writeDocsLock(root: string, lock: TastyDocsLock): Promise<void>;
17
+ declare function validateLock(lock: TastyDocsLock): void;
18
+ declare function materializePackage(source: PackageLockSource, config: NormalizedDocsConfig["build"], projectRoot?: string): Promise<string>;
19
+ declare function discoverPackage(root: string): Promise<PackageDiscovery>;
20
+ declare function packageNameFromSpecifier(specifier: string): string;
21
+ declare function lockForSource(lock: TastyDocsLock | undefined, requested: string): PackageLockSource;
22
+ declare function defaultLock(sources: PackageLockSource[]): TastyDocsLock;
23
+ //#endregion
24
+ //#region src/validation/index.d.ts
25
+ declare class DocsValidationError extends Error {
26
+ readonly diagnostics: DocsDiagnostic[];
27
+ constructor(diagnostics: DocsDiagnostic[]);
28
+ }
29
+ declare function validateDocs(graph: DocsGraph): DocsDiagnostic[];
30
+ declare function assertValidDocs(graph: DocsGraph): void;
31
+ declare function formatDiagnostics(diagnostics: DocsDiagnostic[], json?: boolean): string;
32
+ //#endregion
33
+ export { type BrandConfig, type BuildConfig, type ComponentsConfig, type ContentConfig, type CreateDocsGraphOptions, type DiagnosticSeverity, type DocsAsset, type DocsConfig, DocsConfigError, type DocsDiagnostic, type DocsEntry, type DocsFrontmatter, type DocsGraph, type DocsHeading, type DocsReference, type DocsRoute, type DocsSource, DocsValidationError, type MarkdownConfig, type NavigationConfig, type NavigationItem, type NavigationPlacement, type NormalizedDocsConfig, type PackageDiscovery, type PackageLockSource, type PackageManifest, type SearchConfig, type SiteConfig, type TastyDocsLock, type ThemeConfig, assertValidDocs, createDocsGraph, createDocsLoader, defaultLock, defineDocsConfig, discoverPackage, formatDiagnostics, lockForSource, materializePackage, normalizeDocsConfig, normalizeRoute, packageNameFromSpecifier, readDocsLock, resolvePackageLock, routeForPath, validateConfig, validateDocs, validateLock, writeDocsLock };
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/graph/index.ts","../src/npm/index.ts","../src/validation/index.ts"],"mappings":";;;;iBAqEsB,gBACpB,UAAS,yBACR,QAAQ;iBAmiBK,eAAe;iBAaf,aACd,cACA,eACA;;;UC9lBe;EACf;EACA;;iBAGoB,mBACpB,mBACA,UAAS,wBACR,QAAQ;iBA0BW,aACpB,eACC,QAAQ;iBAaW,cACpB,cACA,MAAM,gBACL;iBASa,aAAa,MAAM;iBAiCb,mBACpB,QAAQ,mBACR,QAAQ,+BACR,uBACC;iBAkHmB,gBAAgB,eAAe,QAAQ;iBAsC7C,yBAAyB;iBAOzB,cACd,MAAM,2BACN,oBACC;iBAea,YAAY,SAAS,sBAAsB;;;cC7S9C,4BAA4B;WAC9B,aAAa;EAEtB,YAAY,aAAa;;iBAOX,aAAa,OAAO,YAAY;iBAIhC,gBAAgB,OAAO;iBAOvB,kBACd,aAAa,kBACb"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { DocsConfigError, defineDocsConfig, normalizeDocsConfig, validateConfig } from "./config/index.js";
2
+ import { _ as writeDocsLock, a as validateDocs, c as routeForPath, d as lockForSource, f as materializePackage, g as validateLock, h as resolvePackageLock, i as formatDiagnostics, l as defaultLock, m as readDocsLock, n as DocsValidationError, o as createDocsGraph, p as packageNameFromSpecifier, r as assertValidDocs, s as normalizeRoute, t as createDocsLoader, u as discoverPackage } from "./content-DStZeziu.js";
3
+ export { DocsConfigError, DocsValidationError, assertValidDocs, createDocsGraph, createDocsLoader, defaultLock, defineDocsConfig, discoverPackage, formatDiagnostics, lockForSource, materializePackage, normalizeDocsConfig, normalizeRoute, packageNameFromSpecifier, readDocsLock, resolvePackageLock, routeForPath, validateConfig, validateDocs, validateLock, writeDocsLock };
@@ -0,0 +1,19 @@
1
+ import { A as Heading, M as Paragraph, N as PhrasingContent, P as Root, j as Link, k as Content, p as DocsHeading } from "../types-rjENJzWH.js";
2
+ //#region src/markdown/index.d.ts
3
+ interface ParsedMarkdown {
4
+ ast: Root;
5
+ headings: DocsHeading[];
6
+ firstHeading?: string;
7
+ description?: string;
8
+ }
9
+ declare function parseMarkdown(body: string): ParsedMarkdown;
10
+ declare function textContent(node: Heading | Paragraph | PhrasingContent): string;
11
+ declare function serializeMarkdown(ast: Root): string;
12
+ declare function removeRenderedTitle(ast: Root, title: string): void;
13
+ declare function stripLeadingBadgeBlock(ast: Root): void;
14
+ declare function linksIn(ast: Root): Link[];
15
+ declare function cloneAst(ast: Root): Root;
16
+ declare function childrenOf(ast: Root): Content[];
17
+ //#endregion
18
+ export { ParsedMarkdown, childrenOf, cloneAst, linksIn, parseMarkdown, removeRenderedTitle, serializeMarkdown, stripLeadingBadgeBlock, textContent };
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/markdown/index.ts"],"mappings":";;UAgBiB;EACf,KAAK;EACL,UAAU;EACV;EACA;;iBAGc,cAAc,eAAe;iBA8C7B,YACd,MAAM,UAAU,YAAY;iBASd,kBAAkB,KAAK;iBAIvB,oBAAoB,KAAK,MAAM;iBAW/B,uBAAuB,KAAK;iBAgB5B,QAAQ,KAAK,OAAO;iBAMpB,SAAS,KAAK,OAAO;iBAIrB,WAAW,KAAK,OAAO"}
@@ -0,0 +1,88 @@
1
+ import { visit } from "unist-util-visit";
2
+ import GithubSlugger from "github-slugger";
3
+ import { gfmFromMarkdown, gfmToMarkdown } from "mdast-util-gfm";
4
+ import { fromMarkdown } from "mdast-util-from-markdown";
5
+ import { gfm } from "micromark-extension-gfm";
6
+ import { toMarkdown } from "mdast-util-to-markdown";
7
+ //#region src/markdown/index.ts
8
+ function parseMarkdown(body) {
9
+ const ast = fromMarkdown(body, {
10
+ extensions: [gfm()],
11
+ mdastExtensions: [gfmFromMarkdown()]
12
+ });
13
+ const slugger = new GithubSlugger();
14
+ const headings = [];
15
+ let firstHeading;
16
+ let description;
17
+ visit(ast, (node) => {
18
+ if (node.type === "heading") {
19
+ const text = textContent(node);
20
+ const slug = slugger.slug(text);
21
+ firstHeading ??= node.depth === 1 ? text : void 0;
22
+ headings.push({
23
+ depth: node.depth,
24
+ text,
25
+ slug,
26
+ ...node.position?.start.line ? { line: node.position.start.line } : {}
27
+ });
28
+ } else if (description === void 0 && node.type === "paragraph") {
29
+ const text = textContent(node).replace(/\s+/g, " ").trim();
30
+ if (isSuitableDescription(node, text)) description = text.slice(0, 240);
31
+ }
32
+ });
33
+ return {
34
+ ast,
35
+ headings,
36
+ ...firstHeading ? { firstHeading } : {},
37
+ ...description ? { description } : {}
38
+ };
39
+ }
40
+ function isSuitableDescription(node, text) {
41
+ if (text.length < 20) return false;
42
+ return !node.children.every((child) => [
43
+ "image",
44
+ "imageReference",
45
+ "link",
46
+ "linkReference",
47
+ "html"
48
+ ].includes(child.type));
49
+ }
50
+ function textContent(node) {
51
+ if ("value" in node && typeof node.value === "string") return node.value;
52
+ if ("children" in node) return node.children.map((child) => textContent(child)).join("");
53
+ if (node.type === "image") return node.alt ?? "";
54
+ return "";
55
+ }
56
+ function serializeMarkdown(ast) {
57
+ return toMarkdown(ast, { extensions: [gfmToMarkdown()] });
58
+ }
59
+ function removeRenderedTitle(ast, title) {
60
+ const first = ast.children[0];
61
+ if (first?.type === "heading" && first.depth === 1 && textContent(first) === title) ast.children.shift();
62
+ }
63
+ function stripLeadingBadgeBlock(ast) {
64
+ while (ast.children[0]?.type === "paragraph") {
65
+ if (!ast.children[0].children.every((node) => {
66
+ if (node.type === "text") return node.value.trim() === "";
67
+ if (node.type === "image" || node.type === "imageReference") return true;
68
+ if (node.type === "link") return node.children.every((child) => child.type === "image");
69
+ return false;
70
+ })) break;
71
+ ast.children.shift();
72
+ }
73
+ }
74
+ function linksIn(ast) {
75
+ const links = [];
76
+ visit(ast, "link", (node) => links.push(node));
77
+ return links;
78
+ }
79
+ function cloneAst(ast) {
80
+ return structuredClone(ast);
81
+ }
82
+ function childrenOf(ast) {
83
+ return ast.children;
84
+ }
85
+ //#endregion
86
+ export { childrenOf, cloneAst, linksIn, parseMarkdown, removeRenderedTitle, serializeMarkdown, stripLeadingBadgeBlock, textContent };
87
+
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/markdown/index.ts"],"sourcesContent":["import GithubSlugger from \"github-slugger\";\nimport { gfmFromMarkdown, gfmToMarkdown } from \"mdast-util-gfm\";\nimport { fromMarkdown } from \"mdast-util-from-markdown\";\nimport { gfm } from \"micromark-extension-gfm\";\nimport { toMarkdown } from \"mdast-util-to-markdown\";\nimport type {\n Content,\n Heading,\n Link,\n Paragraph,\n PhrasingContent,\n Root,\n} from \"mdast\";\nimport { visit } from \"unist-util-visit\";\nimport type { DocsHeading } from \"../types.js\";\n\nexport interface ParsedMarkdown {\n ast: Root;\n headings: DocsHeading[];\n firstHeading?: string;\n description?: string;\n}\n\nexport function parseMarkdown(body: string): ParsedMarkdown {\n const ast = fromMarkdown(body, {\n extensions: [gfm()],\n mdastExtensions: [gfmFromMarkdown()],\n });\n const slugger = new GithubSlugger();\n const headings: DocsHeading[] = [];\n let firstHeading: string | undefined;\n let description: string | undefined;\n\n visit(ast, (node) => {\n if (node.type === \"heading\") {\n const text = textContent(node);\n const slug = slugger.slug(text);\n firstHeading ??= node.depth === 1 ? text : undefined;\n headings.push({\n depth: node.depth,\n text,\n slug,\n ...(node.position?.start.line\n ? { line: node.position.start.line }\n : {}),\n });\n } else if (description === undefined && node.type === \"paragraph\") {\n const text = textContent(node).replace(/\\s+/g, \" \").trim();\n if (isSuitableDescription(node, text)) description = text.slice(0, 240);\n }\n });\n\n return {\n ast,\n headings,\n ...(firstHeading ? { firstHeading } : {}),\n ...(description ? { description } : {}),\n };\n}\n\nfunction isSuitableDescription(node: Paragraph, text: string): boolean {\n if (text.length < 20) return false;\n return !node.children.every((child) =>\n [\"image\", \"imageReference\", \"link\", \"linkReference\", \"html\"].includes(\n child.type,\n ),\n );\n}\n\nexport function textContent(\n node: Heading | Paragraph | PhrasingContent,\n): string {\n if (\"value\" in node && typeof node.value === \"string\") return node.value;\n if (\"children\" in node)\n return node.children.map((child) => textContent(child)).join(\"\");\n if (node.type === \"image\") return node.alt ?? \"\";\n return \"\";\n}\n\nexport function serializeMarkdown(ast: Root): string {\n return toMarkdown(ast, { extensions: [gfmToMarkdown()] });\n}\n\nexport function removeRenderedTitle(ast: Root, title: string): void {\n const first = ast.children[0];\n if (\n first?.type === \"heading\" &&\n first.depth === 1 &&\n textContent(first) === title\n ) {\n ast.children.shift();\n }\n}\n\nexport function stripLeadingBadgeBlock(ast: Root): void {\n while (ast.children[0]?.type === \"paragraph\") {\n const paragraph = ast.children[0];\n const onlyBadgeLike = paragraph.children.every((node) => {\n if (node.type === \"text\") return node.value.trim() === \"\";\n if (node.type === \"image\" || node.type === \"imageReference\") return true;\n if (node.type === \"link\") {\n return node.children.every((child) => child.type === \"image\");\n }\n return false;\n });\n if (!onlyBadgeLike) break;\n ast.children.shift();\n }\n}\n\nexport function linksIn(ast: Root): Link[] {\n const links: Link[] = [];\n visit(ast, \"link\", (node) => links.push(node));\n return links;\n}\n\nexport function cloneAst(ast: Root): Root {\n return structuredClone(ast);\n}\n\nexport function childrenOf(ast: Root): Content[] {\n return ast.children;\n}\n"],"mappings":";;;;;;;AAuBA,SAAgB,cAAc,MAA8B;CAC1D,MAAM,MAAM,aAAa,MAAM;EAC7B,YAAY,CAAC,IAAI,CAAC;EAClB,iBAAiB,CAAC,gBAAgB,CAAC;CACrC,CAAC;CACD,MAAM,UAAU,IAAI,cAAc;CAClC,MAAM,WAA0B,CAAC;CACjC,IAAI;CACJ,IAAI;CAEJ,MAAM,MAAM,SAAS;EACnB,IAAI,KAAK,SAAS,WAAW;GAC3B,MAAM,OAAO,YAAY,IAAI;GAC7B,MAAM,OAAO,QAAQ,KAAK,IAAI;GAC9B,iBAAiB,KAAK,UAAU,IAAI,OAAO,KAAA;GAC3C,SAAS,KAAK;IACZ,OAAO,KAAK;IACZ;IACA;IACA,GAAI,KAAK,UAAU,MAAM,OACrB,EAAE,MAAM,KAAK,SAAS,MAAM,KAAK,IACjC,CAAC;GACP,CAAC;EACH,OAAO,IAAI,gBAAgB,KAAA,KAAa,KAAK,SAAS,aAAa;GACjE,MAAM,OAAO,YAAY,IAAI,CAAC,CAAC,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;GACzD,IAAI,sBAAsB,MAAM,IAAI,GAAG,cAAc,KAAK,MAAM,GAAG,GAAG;EACxE;CACF,CAAC;CAED,OAAO;EACL;EACA;EACA,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;EACvC,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;CACvC;AACF;AAEA,SAAS,sBAAsB,MAAiB,MAAuB;CACrE,IAAI,KAAK,SAAS,IAAI,OAAO;CAC7B,OAAO,CAAC,KAAK,SAAS,OAAO,UAC3B;EAAC;EAAS;EAAkB;EAAQ;EAAiB;CAAM,CAAC,CAAC,SAC3D,MAAM,IACR,CACF;AACF;AAEA,SAAgB,YACd,MACQ;CACR,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU,OAAO,KAAK;CACnE,IAAI,cAAc,MAChB,OAAO,KAAK,SAAS,KAAK,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE;CACjE,IAAI,KAAK,SAAS,SAAS,OAAO,KAAK,OAAO;CAC9C,OAAO;AACT;AAEA,SAAgB,kBAAkB,KAAmB;CACnD,OAAO,WAAW,KAAK,EAAE,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;AAC1D;AAEA,SAAgB,oBAAoB,KAAW,OAAqB;CAClE,MAAM,QAAQ,IAAI,SAAS;CAC3B,IACE,OAAO,SAAS,aAChB,MAAM,UAAU,KAChB,YAAY,KAAK,MAAM,OAEvB,IAAI,SAAS,MAAM;AAEvB;AAEA,SAAgB,uBAAuB,KAAiB;CACtD,OAAO,IAAI,SAAS,EAAE,EAAE,SAAS,aAAa;EAU5C,IAAI,CATc,IAAI,SAAS,EACA,CAAC,SAAS,OAAO,SAAS;GACvD,IAAI,KAAK,SAAS,QAAQ,OAAO,KAAK,MAAM,KAAK,MAAM;GACvD,IAAI,KAAK,SAAS,WAAW,KAAK,SAAS,kBAAkB,OAAO;GACpE,IAAI,KAAK,SAAS,QAChB,OAAO,KAAK,SAAS,OAAO,UAAU,MAAM,SAAS,OAAO;GAE9D,OAAO;EACT,CACiB,GAAG;EACpB,IAAI,SAAS,MAAM;CACrB;AACF;AAEA,SAAgB,QAAQ,KAAmB;CACzC,MAAM,QAAgB,CAAC;CACvB,MAAM,KAAK,SAAS,SAAS,MAAM,KAAK,IAAI,CAAC;CAC7C,OAAO;AACT;AAEA,SAAgB,SAAS,KAAiB;CACxC,OAAO,gBAAgB,GAAG;AAC5B;AAEA,SAAgB,WAAW,KAAsB;CAC/C,OAAO,IAAI;AACb"}
@@ -0,0 +1,5 @@
1
+ //#region src/testing/index.d.ts
2
+ declare function createDocsFixture(files: Record<string, string | Uint8Array>): Promise<string>;
3
+ //#endregion
4
+ export { createDocsFixture };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/testing/index.ts"],"mappings":";iBAIsB,kBACpB,OAAO,wBAAwB,cAC9B"}
@@ -0,0 +1,17 @@
1
+ import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ //#region src/testing/index.ts
5
+ async function createDocsFixture(files) {
6
+ const root = await mkdtemp(join(tmpdir(), "tasty-docs-fixture-"));
7
+ for (const [path, contents] of Object.entries(files)) {
8
+ const target = join(root, path);
9
+ await mkdir(dirname(target), { recursive: true });
10
+ await writeFile(target, contents);
11
+ }
12
+ return root;
13
+ }
14
+ //#endregion
15
+ export { createDocsFixture };
16
+
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/testing/index.ts"],"sourcesContent":["import { mkdtemp, mkdir, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport async function createDocsFixture(\n files: Record<string, string | Uint8Array>,\n): Promise<string> {\n const root = await mkdtemp(join(tmpdir(), \"tasty-docs-fixture-\"));\n for (const [path, contents] of Object.entries(files)) {\n const target = join(root, path);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, contents);\n }\n return root;\n}\n"],"mappings":";;;;AAIA,eAAsB,kBACpB,OACiB;CACjB,MAAM,OAAO,MAAM,QAAQ,KAAK,OAAO,GAAG,qBAAqB,CAAC;CAChE,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,KAAK,GAAG;EACpD,MAAM,SAAS,KAAK,MAAM,IAAI;EAC9B,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;EAChD,MAAM,UAAU,QAAQ,QAAQ;CAClC;CACA,OAAO;AACT"}