UNPKG

@brendonovich/kobalte__solidbase

Version:

Fully featured, fully customisable static site generation for SolidStart

98 lines (86 loc) 2.86 kB
import type LRUCache from "@alloc/quick-lru"; import type { Root, RootContent } from "mdast"; import type { Processor, Transformer } from "unified"; import type { Node } from "unist"; import type { ImportMap } from "./ImportMap.js"; const importRE = /^import ['"](.+)['"]\s*$/; const mdxRE = /\.mdx?$/; export type MdxAstCache = LRUCache<string, RootContent[]>; export function remarkTransclusion({ resolve, readFile, getCompiler, importMap, astCache, }: { resolve(id: string, importer?: string): Promise<string | undefined>; readFile(filePath: string): Promise<string>; getCompiler(filePath: string): Processor; importMap?: ImportMap; astCache?: MdxAstCache; }): () => Transformer { return () => async (ast, file) => { if (!isRootNode(ast)) return; const importer = file.path!; importMap?.deleteImporter(importer); const imports = findMdxImports(ast); if (imports.length) { type Splice = [index: number, deleteCount: number, inserted: any[]]; const splices = await Promise.all( imports.map(async ({ id, index }): Promise<Splice> => { const importedPath = await resolve(id, importer); if (!importedPath) { // Strip unresolved imports. return [index, 1, []]; } importMap?.addImport(importedPath, importer); let ast = astCache?.get(importedPath); if (!ast) { const importedFile = { path: importedPath, contents: await readFile(importedPath), }; const compiler = getCompiler(importedPath); const parsedFile = compiler.parse(importedFile); const compiledFile = await compiler.run(parsedFile, importedFile); ast = (compiledFile as Root).children; astCache?.set(importedPath, ast); } // Inject the AST of the imported markdown. return [index, 1, ast]; }), ); // Apply splices in reverse to ensure preceding indices are stable. let { children } = ast; for (const [index, deleteCount, inserted] of splices.reverse()) children = children .slice(0, index) .concat(inserted, children.slice(index + deleteCount)); ast.children = children; } }; } interface ParsedImport { id: string; node: Node; index: number; } function findMdxImports(ast: import("mdast").Root) { const imports: ParsedImport[] = []; ast.children.forEach((node: Node, index) => { // "import" type is used by @mdx-js/mdx@2.0.0-next.8 and under if (node.type === "mdxjsEsm" || node.type === "import") { // mdx ast nodes indeed have a value prop: // https://github.com/mdx-js/specification#import // but @types/unist doesn't declare it const id = importRE.exec((node as any).value as string)?.[1]; if (id && mdxRE.test(id)) { imports.push({ id, node, index }); } } }); return imports; } function isRootNode(node: Node): node is import("mdast").Root { return node.type === "root"; }