mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 23:49:51 +00:00
MDX: Support postprocess.includeMDAST option
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-mdx': patch
|
||||
---
|
||||
|
||||
Support `postprocess.includeMDAST` option
|
||||
@@ -16,8 +16,8 @@
|
||||
"@ai-sdk/react": "^2.0.66",
|
||||
"@fumadocs/mdx-remote": "workspace:*",
|
||||
"@mixedbread/sdk": "^0.34.0",
|
||||
"@orama/orama": "^3.1.15",
|
||||
"@orama/core": "^1.2.13",
|
||||
"@orama/orama": "^3.1.15",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-hover-card": "^1.1.15",
|
||||
"@radix-ui/react-presence": "^1.1.5",
|
||||
@@ -30,6 +30,8 @@
|
||||
"ai": "^5.0.66",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"d3-force": "^3.0.0",
|
||||
"estree-util-build-jsx": "^3.0.1",
|
||||
"estree-util-to-js": "^2.0.0",
|
||||
"feed": "^5.1.0",
|
||||
"fumadocs-core": "workspace:*",
|
||||
"fumadocs-docgen": "workspace:^",
|
||||
@@ -64,6 +66,7 @@
|
||||
"zod": "^4.1.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/estree": "^1.0.8",
|
||||
"@fumadocs/cli": "workspace:*",
|
||||
"@next/bundle-analyzer": "16.0.0-beta.0",
|
||||
"@next/env": "16.0.0-beta.0",
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
"estree-util-value-to-estree": "^3.4.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lru-cache": "^11.2.2",
|
||||
"unist-util-remove-position": "^5.0.0",
|
||||
"mdast-util-to-markdown": "^2.1.2",
|
||||
"picocolors": "^1.1.1",
|
||||
"remark-mdx": "^3.1.1",
|
||||
@@ -105,7 +106,6 @@
|
||||
"remark-stringify": "^11.0.0",
|
||||
"rollup": "^4.52.4",
|
||||
"tsconfig": "workspace:*",
|
||||
"unist-util-remove-position": "^5.0.0",
|
||||
"vfile": "^6.0.3",
|
||||
"vite": "^7.1.9",
|
||||
"webpack": "^5.102.1"
|
||||
|
||||
@@ -48,6 +48,7 @@ export interface CompiledMDXProperties<Frontmatter = Record<string, unknown>> {
|
||||
lastModified?: Date;
|
||||
extractedReferences?: ExtractedReference[];
|
||||
_markdown?: string;
|
||||
_mdast?: string;
|
||||
}
|
||||
|
||||
export interface FumadocsDataMap {
|
||||
@@ -115,6 +116,7 @@ export async function buildMDX(
|
||||
'frontmatter',
|
||||
'lastModified',
|
||||
'_markdown',
|
||||
'_mdast',
|
||||
],
|
||||
} satisfies PostprocessOptions,
|
||||
],
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Root, RootContent } from 'mdast';
|
||||
import { visit } from 'unist-util-visit';
|
||||
import { toMarkdown } from 'mdast-util-to-markdown';
|
||||
import { valueToEstree } from 'estree-util-value-to-estree';
|
||||
import { removePosition } from 'unist-util-remove-position';
|
||||
|
||||
export interface ExtractedReference {
|
||||
href: string;
|
||||
@@ -18,6 +19,15 @@ export interface PostprocessOptions {
|
||||
* stringify MDAST and export via `_markdown`.
|
||||
*/
|
||||
includeProcessedMarkdown?: boolean;
|
||||
|
||||
/**
|
||||
* store MDAST and export via `_mdast`.
|
||||
*/
|
||||
includeMDAST?:
|
||||
| boolean
|
||||
| {
|
||||
removePosition?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,6 +38,7 @@ export function remarkPostprocess(
|
||||
this: Processor,
|
||||
{
|
||||
includeProcessedMarkdown = false,
|
||||
includeMDAST = false,
|
||||
valueToExport = [],
|
||||
}: PostprocessOptions = {},
|
||||
): Transformer<Root, Root> {
|
||||
@@ -65,6 +76,14 @@ export function remarkPostprocess(
|
||||
});
|
||||
}
|
||||
|
||||
if (includeMDAST) {
|
||||
const options = includeMDAST === true ? {} : includeMDAST;
|
||||
|
||||
file.data._mdast = JSON.stringify(
|
||||
options.removePosition ? removePosition(structuredClone(tree)) : tree,
|
||||
);
|
||||
}
|
||||
|
||||
for (const { name, value } of file.data['mdx-export'] ?? []) {
|
||||
tree.children.unshift(getMdastExport(name, value));
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import { buildMDX, CompiledMDXProperties } from '@/loaders/mdx/build-mdx';
|
||||
import type { ProcessorOptions } from '@mdx-js/mdx';
|
||||
import { executeMdx } from '@fumadocs/mdx-remote/client';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { type DocData, missingProcessedMarkdown } from '@/runtime/shared';
|
||||
import { createDocMethods, type DocData } from '@/runtime/shared';
|
||||
import type { DocCollection } from '@/config';
|
||||
import { readFileWithCache } from '@/next/map/file-cache';
|
||||
import { fumaMatter } from '@/utils/fuma-matter';
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
function getDocCollection(config: LoadedConfig, collection: string) {
|
||||
const col = config.collections.get(collection);
|
||||
@@ -36,7 +36,8 @@ export const _runtimeAsync: RuntimeAsync = {
|
||||
async function compileAndLoad() {
|
||||
if (cachedResult) return cachedResult;
|
||||
const mdxOptions = await initMdxOptions;
|
||||
const raw = await readFileWithCache(info.fullPath);
|
||||
const raw = (await fs.readFile(info.fullPath)).toString();
|
||||
|
||||
const { content } = fumaMatter(raw);
|
||||
const compiled = await buildMDX(collectionName, content, {
|
||||
...mdxOptions,
|
||||
@@ -57,16 +58,7 @@ export const _runtimeAsync: RuntimeAsync = {
|
||||
|
||||
return {
|
||||
...data,
|
||||
info,
|
||||
async getText(type) {
|
||||
if (type === 'raw') {
|
||||
return readFileWithCache(info.fullPath);
|
||||
}
|
||||
|
||||
const out = await compileAndLoad();
|
||||
if (typeof out._markdown !== 'string') missingProcessedMarkdown();
|
||||
return out._markdown;
|
||||
},
|
||||
...createDocMethods(info, () => compileAndLoad()),
|
||||
async load() {
|
||||
const out = await compileAndLoad();
|
||||
|
||||
|
||||
@@ -6,17 +6,14 @@ import {
|
||||
} from 'fumadocs-core/source';
|
||||
import type { DocOut, MetaOut, Runtime } from './types';
|
||||
import type { CompiledMDXProperties } from '@/loaders/mdx/build-mdx';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import { type FileInfo, missingProcessedMarkdown } from '@/runtime/shared';
|
||||
import { createDocMethods, type FileInfo } from '@/runtime/shared';
|
||||
|
||||
export const _runtime: Runtime = {
|
||||
doc(files) {
|
||||
return files.map((file) => {
|
||||
const data = file.data as unknown as CompiledMDXProperties;
|
||||
const filePath = file.info.fullPath;
|
||||
|
||||
return {
|
||||
info: file.info,
|
||||
_exports: data as unknown as Record<string, unknown>,
|
||||
body: data.default,
|
||||
lastModified: data.lastModified,
|
||||
@@ -24,14 +21,7 @@ export const _runtime: Runtime = {
|
||||
structuredData: data.structuredData,
|
||||
extractedReferences: data.extractedReferences,
|
||||
...data.frontmatter,
|
||||
async getText(type) {
|
||||
if (type === 'raw') {
|
||||
return (await fs.readFile(filePath)).toString();
|
||||
}
|
||||
|
||||
if (typeof data._markdown !== 'string') missingProcessedMarkdown();
|
||||
return data._markdown;
|
||||
},
|
||||
...createDocMethods(file.info, () => Promise.resolve(data)),
|
||||
} satisfies DocOut;
|
||||
}) as any;
|
||||
},
|
||||
|
||||
@@ -2,6 +2,9 @@ import type { StructuredData } from 'fumadocs-core/mdx-plugins';
|
||||
import type { TOCItemType } from 'fumadocs-core/toc';
|
||||
import type { MDXContent } from 'mdx/types';
|
||||
import type { ExtractedReference } from '@/loaders/mdx/remark-postprocess';
|
||||
import type { Root } from 'mdast';
|
||||
import type { CompiledMDXProperties } from '@/loaders/mdx/build-mdx';
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
export interface FileInfo {
|
||||
/**
|
||||
@@ -62,6 +65,8 @@ export interface DocMethods {
|
||||
* - `type: processed` - get the processed Markdown content, only available when `includeProcessedMarkdown` is enabled on collection config.
|
||||
*/
|
||||
getText: (type: 'raw' | 'processed') => Promise<string>;
|
||||
|
||||
getMDAST: () => Promise<Root>;
|
||||
}
|
||||
|
||||
export type MetaCollectionEntry<Data> = Data & {
|
||||
@@ -79,8 +84,32 @@ export type AsyncDocCollectionEntry<Frontmatter> = DocMethods & {
|
||||
load: () => Promise<DocData>;
|
||||
} & Frontmatter;
|
||||
|
||||
export function missingProcessedMarkdown(): never {
|
||||
throw new Error(
|
||||
"getText('processed') requires `includeProcessedMarkdown` to be enabled in your collection config.",
|
||||
);
|
||||
export function createDocMethods(
|
||||
info: FileInfo,
|
||||
load: () => Promise<CompiledMDXProperties<any>>,
|
||||
): DocMethods {
|
||||
return {
|
||||
info,
|
||||
async getText(type) {
|
||||
if (type === 'raw') {
|
||||
return (await fs.readFile(info.fullPath)).toString();
|
||||
}
|
||||
|
||||
const data = await load();
|
||||
if (typeof data._markdown !== 'string')
|
||||
throw new Error(
|
||||
"getText('processed') requires `includeProcessedMarkdown` to be enabled in your collection config.",
|
||||
);
|
||||
return data._markdown;
|
||||
},
|
||||
async getMDAST() {
|
||||
const data = await load();
|
||||
|
||||
if (!data._mdast)
|
||||
throw new Error(
|
||||
'getMDAST() requires `includeMDAST` to be enabled in your collection config.',
|
||||
);
|
||||
return JSON.parse(data._mdast);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,13 +15,12 @@ import {
|
||||
import * as path from 'node:path';
|
||||
import {
|
||||
type AsyncDocCollectionEntry,
|
||||
createDocMethods,
|
||||
type DocCollectionEntry,
|
||||
type DocData,
|
||||
type FileInfo,
|
||||
type MetaCollectionEntry,
|
||||
missingProcessedMarkdown,
|
||||
} from '@/runtime/shared';
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
export * from './base';
|
||||
|
||||
@@ -73,16 +72,8 @@ export function fromConfig<Config>(): ServerCreate<Config> {
|
||||
): DocCollectionEntry<Frontmatter> {
|
||||
return {
|
||||
...mapDocData(entry),
|
||||
info,
|
||||
async getText(type) {
|
||||
if (type === 'raw') {
|
||||
return (await fs.readFile(info.fullPath)).toString();
|
||||
}
|
||||
|
||||
if (typeof entry._markdown !== 'string') missingProcessedMarkdown();
|
||||
return entry._markdown;
|
||||
},
|
||||
...entry.frontmatter,
|
||||
...createDocMethods(info, async () => entry),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -93,19 +84,10 @@ export function fromConfig<Config>(): ServerCreate<Config> {
|
||||
): AsyncDocCollectionEntry<Frontmatter> {
|
||||
return {
|
||||
...head,
|
||||
info,
|
||||
...createDocMethods(info, content),
|
||||
async load() {
|
||||
return mapDocData(await content());
|
||||
},
|
||||
async getText(type) {
|
||||
if (type === 'raw') {
|
||||
return (await fs.readFile(info.fullPath)).toString();
|
||||
}
|
||||
|
||||
const entry = await content();
|
||||
if (typeof entry._markdown !== 'string') missingProcessedMarkdown();
|
||||
return entry._markdown;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Generated
+12
-3
@@ -113,6 +113,12 @@ importers:
|
||||
d3-force:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
estree-util-build-jsx:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1
|
||||
estree-util-to-js:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
feed:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0
|
||||
@@ -228,6 +234,9 @@ importers:
|
||||
'@types/d3-force':
|
||||
specifier: ^3.0.10
|
||||
version: 3.0.10
|
||||
'@types/estree':
|
||||
specifier: ^1.0.8
|
||||
version: 1.0.8
|
||||
'@types/hast':
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4
|
||||
@@ -1573,6 +1582,9 @@ importers:
|
||||
unified:
|
||||
specifier: ^11.0.5
|
||||
version: 11.0.5
|
||||
unist-util-remove-position:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
unist-util-visit:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
@@ -1634,9 +1646,6 @@ importers:
|
||||
tsconfig:
|
||||
specifier: workspace:*
|
||||
version: link:../tsconfig
|
||||
unist-util-remove-position:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
vfile:
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3
|
||||
|
||||
Reference in New Issue
Block a user