@docubook/core 1.8.2 → 2.0.0-alpha.1
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.
- package/README.md +100 -385
- package/dist/chunk-J7CN2VUH.js +188 -0
- package/dist/chunk-J7CN2VUH.js.map +1 -0
- package/dist/index.d.ts +76 -72
- package/dist/index.js +125 -177
- package/dist/index.js.map +1 -1
- package/dist/mdx-compiler/serialize.d.ts +53 -0
- package/dist/mdx-compiler/serialize.js +7 -0
- package/dist/mdx-compiler/serialize.js.map +1 -0
- package/package.json +22 -5
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// src/mdx-compiler/serialize.ts
|
|
2
|
+
import { compile } from "@mdx-js/mdx";
|
|
3
|
+
import { VFile } from "vfile";
|
|
4
|
+
import { matter } from "vfile-matter";
|
|
5
|
+
|
|
6
|
+
// src/mdx-compiler/format-mdx-error.ts
|
|
7
|
+
function createFormattedMDXError(error, _source) {
|
|
8
|
+
return new Error(`[mdx] error compiling MDX:
|
|
9
|
+
${error?.message ?? error}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/mdx-compiler/plugins/remove-imports-exports.ts
|
|
13
|
+
import { remove } from "unist-util-remove";
|
|
14
|
+
function removeImportsExportsPlugin() {
|
|
15
|
+
return (tree) => remove(tree, "mdxjsEsm");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/mdx-compiler/plugins/remove-javascript-expressions.ts
|
|
19
|
+
import { visit, SKIP } from "unist-util-visit";
|
|
20
|
+
var removeJavaScriptExpressions = () => {
|
|
21
|
+
return (tree) => {
|
|
22
|
+
visit(tree, (node, index, parent) => {
|
|
23
|
+
if (node.type === "mdxFlowExpression" || node.type === "mdxTextExpression") {
|
|
24
|
+
if (parent && typeof index === "number") {
|
|
25
|
+
parent.children.splice(index, 1);
|
|
26
|
+
return [SKIP, index];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
|
|
30
|
+
const el = node;
|
|
31
|
+
if (el.attributes) {
|
|
32
|
+
el.attributes = el.attributes.filter((attr) => {
|
|
33
|
+
if (attr.type === "mdxJsxAttribute") {
|
|
34
|
+
return attr.value === null || typeof attr.value === "string" || attr.value && attr.value.type !== "mdxJsxAttributeValueExpression";
|
|
35
|
+
}
|
|
36
|
+
return attr.type !== "mdxJsxExpressionAttribute";
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// src/mdx-compiler/plugins/remove-dangerous-javascript-expressions.ts
|
|
45
|
+
var BLOCKED_GLOBALS = [
|
|
46
|
+
// Code execution
|
|
47
|
+
"eval",
|
|
48
|
+
"Function",
|
|
49
|
+
"AsyncFunction",
|
|
50
|
+
"GeneratorFunction",
|
|
51
|
+
// Module system
|
|
52
|
+
"require",
|
|
53
|
+
"module",
|
|
54
|
+
"exports",
|
|
55
|
+
"__dirname",
|
|
56
|
+
"__filename",
|
|
57
|
+
// Runtime
|
|
58
|
+
"process",
|
|
59
|
+
"global",
|
|
60
|
+
"globalThis",
|
|
61
|
+
"Reflect",
|
|
62
|
+
// File system / network
|
|
63
|
+
"child_process",
|
|
64
|
+
"fs",
|
|
65
|
+
"net",
|
|
66
|
+
"http",
|
|
67
|
+
"https",
|
|
68
|
+
"vm",
|
|
69
|
+
"worker_threads",
|
|
70
|
+
// Browser-like (available in Node/Deno)
|
|
71
|
+
"fetch",
|
|
72
|
+
"setTimeout",
|
|
73
|
+
"setInterval",
|
|
74
|
+
"setImmediate",
|
|
75
|
+
"queueMicrotask",
|
|
76
|
+
"XMLHttpRequest"
|
|
77
|
+
];
|
|
78
|
+
var BLOCKED_PROPERTIES = [
|
|
79
|
+
"constructor",
|
|
80
|
+
"prototype",
|
|
81
|
+
"__proto__",
|
|
82
|
+
"eval",
|
|
83
|
+
"Reflect",
|
|
84
|
+
"Function",
|
|
85
|
+
"AsyncFunction",
|
|
86
|
+
"GeneratorFunction",
|
|
87
|
+
"require"
|
|
88
|
+
];
|
|
89
|
+
function walk(node, blockedGlobals, blockedProperties) {
|
|
90
|
+
if (!node || typeof node !== "object") return;
|
|
91
|
+
if (node.type === "Identifier" && blockedGlobals.includes(node.name)) {
|
|
92
|
+
const parent = node.parent;
|
|
93
|
+
const isProperty = parent?.type === "MemberExpression" && parent.property === node && !parent.computed;
|
|
94
|
+
const isParam = parent?.type === "FunctionDeclaration" || parent?.type === "FunctionExpression";
|
|
95
|
+
if (!isProperty && !isParam) {
|
|
96
|
+
throw new Error(`Security: Access to '${node.name}' is not allowed`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (node.type === "CallExpression" && node.callee?.type === "Identifier" && blockedGlobals.includes(node.callee.name)) {
|
|
100
|
+
throw new Error(`Security: ${node.callee.name}() calls are not allowed`);
|
|
101
|
+
}
|
|
102
|
+
if (node.type === "ImportExpression") {
|
|
103
|
+
throw new Error("Security: Dynamic import() is not allowed");
|
|
104
|
+
}
|
|
105
|
+
if (node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && blockedGlobals.includes(node.tag.name)) {
|
|
106
|
+
throw new Error(`Security: ${node.tag.name}\`...\` tagged template is not allowed`);
|
|
107
|
+
}
|
|
108
|
+
if (node.type === "CallExpression" && node.callee?.type === "MemberExpression" && node.callee.computed) {
|
|
109
|
+
throw new Error("Security: Function calls via computed property access are not allowed");
|
|
110
|
+
}
|
|
111
|
+
if (node.type === "MemberExpression" && !node.computed) {
|
|
112
|
+
const prop = node.property;
|
|
113
|
+
if (prop?.type === "Identifier" && blockedProperties.includes(prop.name)) {
|
|
114
|
+
throw new Error(`Security: .${prop.name} access is not allowed`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (node.type === "NewExpression" && node.callee?.type === "Identifier" && blockedGlobals.includes(node.callee.name)) {
|
|
118
|
+
throw new Error(`Security: new ${node.callee.name}() is not allowed`);
|
|
119
|
+
}
|
|
120
|
+
for (const key in node) {
|
|
121
|
+
if (key === "parent" || key === "position") continue;
|
|
122
|
+
const value = node[key];
|
|
123
|
+
if (Array.isArray(value)) {
|
|
124
|
+
value.forEach((child) => {
|
|
125
|
+
if (child && typeof child === "object") walk(child, blockedGlobals, blockedProperties);
|
|
126
|
+
});
|
|
127
|
+
} else if (value && typeof value === "object") {
|
|
128
|
+
walk(value, blockedGlobals, blockedProperties);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
var CreateRemoveDangerousCallsPlugin = (blockedGlobals, blockedProperties) => {
|
|
133
|
+
return () => (tree) => {
|
|
134
|
+
walk(tree, blockedGlobals ?? BLOCKED_GLOBALS, blockedProperties ?? BLOCKED_PROPERTIES);
|
|
135
|
+
return tree;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/mdx-compiler/serialize.ts
|
|
140
|
+
function getCompileOptions(mdxOptions = {}, rsc = false, blockJS = true, outputFormat = "function-body", format = "mdx") {
|
|
141
|
+
const remarkPlugins = [
|
|
142
|
+
...mdxOptions?.remarkPlugins ?? [],
|
|
143
|
+
removeImportsExportsPlugin,
|
|
144
|
+
...blockJS ? [removeJavaScriptExpressions] : [],
|
|
145
|
+
// Defense-in-depth: audit remaining AST for dangerous patterns.
|
|
146
|
+
CreateRemoveDangerousCallsPlugin()
|
|
147
|
+
];
|
|
148
|
+
return {
|
|
149
|
+
...mdxOptions,
|
|
150
|
+
remarkPlugins,
|
|
151
|
+
rehypePlugins: mdxOptions?.rehypePlugins ?? [],
|
|
152
|
+
format,
|
|
153
|
+
outputFormat,
|
|
154
|
+
providerImportSource: rsc ? void 0 : "@mdx-js/react",
|
|
155
|
+
development: process.env.NODE_ENV !== "production"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async function serialize(source, {
|
|
159
|
+
scope = {},
|
|
160
|
+
mdxOptions = {},
|
|
161
|
+
parseFrontmatter = false,
|
|
162
|
+
blockJS = true,
|
|
163
|
+
outputFormat = "function-body",
|
|
164
|
+
format = "mdx"
|
|
165
|
+
} = {}, rsc = false) {
|
|
166
|
+
const vfile = new VFile(source);
|
|
167
|
+
if (parseFrontmatter) {
|
|
168
|
+
matter(vfile, { strip: true });
|
|
169
|
+
}
|
|
170
|
+
let compiledSource;
|
|
171
|
+
try {
|
|
172
|
+
compiledSource = String(
|
|
173
|
+
await compile(vfile, getCompileOptions(mdxOptions, rsc, blockJS, outputFormat, format))
|
|
174
|
+
);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
throw createFormattedMDXError(error, String(vfile));
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
compiledSource,
|
|
180
|
+
frontmatter: vfile.data.matter ?? {},
|
|
181
|
+
scope
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
serialize
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=chunk-J7CN2VUH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mdx-compiler/serialize.ts","../src/mdx-compiler/format-mdx-error.ts","../src/mdx-compiler/plugins/remove-imports-exports.ts","../src/mdx-compiler/plugins/remove-javascript-expressions.ts","../src/mdx-compiler/plugins/remove-dangerous-javascript-expressions.ts"],"sourcesContent":["// MPL-2.0 — derived from next-mdx-remote (IBM). See LICENSE-MPL-2.0.\nimport { compile } from \"@mdx-js/mdx\";\nimport { VFile } from \"vfile\";\nimport { matter } from \"vfile-matter\";\nimport { createFormattedMDXError } from \"./format-mdx-error.js\";\nimport { removeImportsExportsPlugin } from \"./plugins/remove-imports-exports.js\";\nimport { removeJavaScriptExpressions } from \"./plugins/remove-javascript-expressions.js\";\nimport { CreateRemoveDangerousCallsPlugin } from \"./plugins/remove-dangerous-javascript-expressions.js\";\nimport type { Pluggable } from \"unified\";\n\n/** @internal — re-exported from unified. */\ntype RemarkPlugins = Pluggable[];\ntype RehypePlugins = Pluggable[];\n\nexport type { MDXRemoteSerializeResult } from \"./types\";\n\nexport type SerializeOptions = {\n scope?: Record<string, unknown>;\n mdxOptions?: {\n remarkPlugins?: RemarkPlugins;\n rehypePlugins?: RehypePlugins;\n };\n parseFrontmatter?: boolean;\n /**\n * MDX compile output shape.\n * - `\"function-body\"` (default): JS function body string for `<MDXRemote>`.\n * - `\"program\"`: full ESM module source (imports + `export default MDXContent`)\n * for static bundling / hydration without `new Function`.\n * @default \"function-body\"\n */\n outputFormat?: \"function-body\" | \"program\";\n /**\n * MDX input format.\n * - `\"mdx\"` (default): JSX tags are parsed and resolve via the components map.\n * - `\"md\"`: plain markdown — authored JSX tags are NOT parsed (dropped,\n * content kept as text). Markdown directives (`:::`/`::`/`::::`) still\n * work; this is the v2 authoring contract (no JSX tags).\n * @default \"mdx\"\n */\n format?: \"mdx\" | \"md\";\n /**\n * Strip JavaScript expressions from MDX (default: true).\n * When true, removes all `{expression}` and JSX attribute expression nodes\n * before compilation. When false, expressions are preserved but a\n * security sanitizer audits the AST for dangerous patterns.\n * @default true\n */\n blockJS?: boolean;\n};\n\nexport type SerializeResult = {\n compiledSource: string;\n frontmatter: Record<string, unknown>;\n scope: Record<string, unknown>;\n};\n\nfunction getCompileOptions(\n mdxOptions: SerializeOptions[\"mdxOptions\"] = {},\n rsc = false,\n blockJS = true,\n outputFormat: NonNullable<SerializeOptions[\"outputFormat\"]> = \"function-body\",\n format: NonNullable<SerializeOptions[\"format\"]> = \"mdx\"\n) {\n const remarkPlugins = [\n ...(mdxOptions?.remarkPlugins ?? []),\n removeImportsExportsPlugin,\n ...(blockJS ? [removeJavaScriptExpressions] : []),\n // Defense-in-depth: audit remaining AST for dangerous patterns.\n CreateRemoveDangerousCallsPlugin(),\n ];\n\n return {\n ...mdxOptions,\n remarkPlugins,\n rehypePlugins: mdxOptions?.rehypePlugins ?? [],\n format,\n outputFormat,\n providerImportSource: rsc ? undefined : \"@mdx-js/react\",\n development: process.env.NODE_ENV !== \"production\",\n };\n}\n\n/**\n * Compile raw MDX string into a serialized result that can be rendered.\n */\nexport async function serialize(\n source: string,\n {\n scope = {},\n mdxOptions = {},\n parseFrontmatter = false,\n blockJS = true,\n outputFormat = \"function-body\",\n format = \"mdx\",\n }: SerializeOptions = {},\n rsc = false\n): Promise<SerializeResult> {\n const vfile = new VFile(source);\n\n if (parseFrontmatter) {\n matter(vfile, { strip: true });\n }\n\n let compiledSource: string;\n try {\n compiledSource = String(\n await compile(vfile, getCompileOptions(mdxOptions, rsc, blockJS, outputFormat, format))\n );\n } catch (error: any) {\n throw createFormattedMDXError(error, String(vfile));\n }\n\n return {\n compiledSource,\n frontmatter: (vfile.data.matter ?? {}) as Record<string, unknown>,\n scope,\n };\n}\n","// MPL-2.0 — derived from next-mdx-remote (IBM). See LICENSE-MPL-2.0.\n/**\n * Wraps raw MDX compilation errors with a clear message prefix.\n */\nexport function createFormattedMDXError(error: any, _source: string): Error {\n return new Error(`[mdx] error compiling MDX:\\n${error?.message ?? error}`);\n}\n","// MPL-2.0 — derived from next-mdx-remote (IBM). See LICENSE-MPL-2.0.\nimport { remove } from \"unist-util-remove\";\nimport type { Node } from \"unist\";\n\n/** remark plugin: strips all `mdxjsEsm` nodes (import/export statements). */\nexport function removeImportsExportsPlugin() {\n return (tree: Node) => remove(tree, \"mdxjsEsm\");\n}\n","// MPL-2.0 — derived from next-mdx-remote (IBM). See LICENSE-MPL-2.0.\nimport { visit, SKIP } from \"unist-util-visit\";\nimport type { Node } from \"unist\";\n\n/**\n * remark plugin: removes JS expression nodes ({variable}, {func()}) from MDX.\n * Preserves JSX (<Component />) and plain markdown.\n */\nexport const removeJavaScriptExpressions = () => {\n return (tree: Node) => {\n visit(tree, (node: Node, index: number | undefined, parent: Node | undefined) => {\n if (node.type === \"mdxFlowExpression\" || node.type === \"mdxTextExpression\") {\n if (parent && typeof index === \"number\") {\n (parent as any).children.splice(index, 1);\n return [SKIP, index] as const;\n }\n }\n\n if (node.type === \"mdxJsxFlowElement\" || node.type === \"mdxJsxTextElement\") {\n const el = node as any;\n if (el.attributes) {\n el.attributes = el.attributes.filter((attr: any) => {\n if (attr.type === \"mdxJsxAttribute\") {\n return (\n attr.value === null ||\n typeof attr.value === \"string\" ||\n (attr.value && attr.value.type !== \"mdxJsxAttributeValueExpression\")\n );\n }\n return attr.type !== \"mdxJsxExpressionAttribute\";\n });\n }\n }\n });\n };\n};\n","// MPL-2.0 — derived from next-mdx-remote (IBM). See LICENSE-MPL-2.0.\nimport type { Node } from \"unist\";\n\nconst BLOCKED_GLOBALS = [\n // Code execution\n \"eval\",\n \"Function\",\n \"AsyncFunction\",\n \"GeneratorFunction\",\n // Module system\n \"require\",\n \"module\",\n \"exports\",\n \"__dirname\",\n \"__filename\",\n // Runtime\n \"process\",\n \"global\",\n \"globalThis\",\n \"Reflect\",\n // File system / network\n \"child_process\",\n \"fs\",\n \"net\",\n \"http\",\n \"https\",\n \"vm\",\n \"worker_threads\",\n // Browser-like (available in Node/Deno)\n \"fetch\",\n \"setTimeout\",\n \"setInterval\",\n \"setImmediate\",\n \"queueMicrotask\",\n \"XMLHttpRequest\",\n];\n\nconst BLOCKED_PROPERTIES = [\n \"constructor\",\n \"prototype\",\n \"__proto__\",\n \"eval\",\n \"Reflect\",\n \"Function\",\n \"AsyncFunction\",\n \"GeneratorFunction\",\n \"require\",\n];\n\nfunction walk(node: any, blockedGlobals: string[], blockedProperties: string[]) {\n if (!node || typeof node !== \"object\") return;\n\n if (node.type === \"Identifier\" && blockedGlobals.includes(node.name)) {\n const parent = node.parent;\n const isProperty =\n parent?.type === \"MemberExpression\" && parent.property === node && !parent.computed;\n const isParam = parent?.type === \"FunctionDeclaration\" || parent?.type === \"FunctionExpression\";\n if (!isProperty && !isParam) {\n throw new Error(`Security: Access to '${node.name}' is not allowed`);\n }\n }\n\n // Block direct calls to blocked globals: eval(), Function(), fetch(), etc.\n if (\n node.type === \"CallExpression\" &&\n node.callee?.type === \"Identifier\" &&\n blockedGlobals.includes(node.callee.name)\n ) {\n throw new Error(`Security: ${node.callee.name}() calls are not allowed`);\n }\n\n // Block dynamic import(): import(\"node:fs\")\n if (node.type === \"ImportExpression\") {\n throw new Error(\"Security: Dynamic import() is not allowed\");\n }\n\n // Block tagged template literals on blocked globals: eval`...`\n if (\n node.type === \"TaggedTemplateExpression\" &&\n node.tag?.type === \"Identifier\" &&\n blockedGlobals.includes(node.tag.name)\n ) {\n throw new Error(`Security: ${node.tag.name}\\`...\\` tagged template is not allowed`);\n }\n\n // Block computed MemberExpression calls on any object identifier\n // Catches: Object[\"constructor\"](...), Object[\"con\"+\"structor\"](...), etc.\n if (\n node.type === \"CallExpression\" &&\n node.callee?.type === \"MemberExpression\" &&\n node.callee.computed\n ) {\n throw new Error(\"Security: Function calls via computed property access are not allowed\");\n }\n\n // Block non-computed property access to dangerous properties:\n // obj.constructor, obj.prototype, obj.__proto__\n if (node.type === \"MemberExpression\" && !node.computed) {\n const prop = node.property;\n if (prop?.type === \"Identifier\" && blockedProperties.includes(prop.name)) {\n throw new Error(`Security: .${prop.name} access is not allowed`);\n }\n }\n\n // Block new expressions: new Function(...)\n if (\n node.type === \"NewExpression\" &&\n node.callee?.type === \"Identifier\" &&\n blockedGlobals.includes(node.callee.name)\n ) {\n throw new Error(`Security: new ${node.callee.name}() is not allowed`);\n }\n\n for (const key in node) {\n if (key === \"parent\" || key === \"position\") continue;\n const value = node[key];\n if (Array.isArray(value)) {\n value.forEach((child: any) => {\n if (child && typeof child === \"object\") walk(child, blockedGlobals, blockedProperties);\n });\n } else if (value && typeof value === \"object\") {\n walk(value, blockedGlobals, blockedProperties);\n }\n }\n}\n\nexport const CreateRemoveDangerousCallsPlugin = (\n blockedGlobals?: string[],\n blockedProperties?: string[]\n) => {\n return () => (tree: Node) => {\n walk(tree, blockedGlobals ?? BLOCKED_GLOBALS, blockedProperties ?? BLOCKED_PROPERTIES);\n return tree;\n };\n};\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
1
|
export { cn, formatDate, formatDate2, parseDate, stringToDate, toIsoDateOnly } from './utils.js';
|
|
3
|
-
import { compileMDX } from '@docubook/mdx-remote/rsc';
|
|
4
|
-
import { Node } from 'unist';
|
|
5
2
|
import { Pluggable } from 'unified';
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { Node } from 'unist';
|
|
4
|
+
import { ZodType } from 'zod';
|
|
5
|
+
import { MDXComponents } from 'mdx/types.js';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { MDXRemoteSerializeResult } from './mdx-compiler/serialize.js';
|
|
8
|
+
export { SerializeOptions, SerializeResult, serialize } from './mdx-compiler/serialize.js';
|
|
8
9
|
import 'clsx';
|
|
9
10
|
|
|
10
11
|
type TocItem = {
|
|
@@ -12,32 +13,52 @@ type TocItem = {
|
|
|
12
13
|
text: string;
|
|
13
14
|
href: string;
|
|
14
15
|
};
|
|
15
|
-
type MdxCompileResult<Frontmatter> = {
|
|
16
|
-
content: ReactNode;
|
|
17
|
-
frontmatter: Frontmatter;
|
|
18
|
-
scope?: Record<string, unknown>;
|
|
19
|
-
};
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Custom merge function.
|
|
19
|
+
*/
|
|
20
|
+
type MergeComponents = (currentComponents: Readonly<MDXComponents>) => MDXComponents;
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for `MDXProvider`.
|
|
23
|
+
*/
|
|
24
|
+
type Props = {
|
|
28
25
|
/**
|
|
29
|
-
*
|
|
30
|
-
* Set to `false` when frontmatter is already extracted separately
|
|
31
|
-
* (e.g. via gray-matter) to avoid redundant parsing.
|
|
32
|
-
* Defaults to `true`.
|
|
26
|
+
* Children (optional).
|
|
33
27
|
*/
|
|
34
|
-
|
|
28
|
+
children?: React.ReactNode | null | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Additional components to use or a function that creates them (optional).
|
|
31
|
+
*/
|
|
32
|
+
components?: Readonly<MDXComponents> | MergeComponents | null | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Turn off outer component context (default: `false`).
|
|
35
|
+
*/
|
|
36
|
+
disableParentContext?: boolean | null | undefined;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** Props for the client-side `<MDXRemote>` (accepts pre-serialized result). */
|
|
40
|
+
type MDXRemoteProps = MDXRemoteSerializeResult & {
|
|
41
|
+
components?: Record<string, React.ComponentType<any>>;
|
|
42
|
+
/** Defer hydration to an idle callback */
|
|
43
|
+
lazy?: boolean;
|
|
35
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Client-side MDX renderer.
|
|
47
|
+
*
|
|
48
|
+
* Accepts a pre-compiled result from `serialize()` and renders it via
|
|
49
|
+
* `MDXProvider` for custom component injection.
|
|
50
|
+
*/
|
|
51
|
+
declare function MDXRemote({ compiledSource, frontmatter, scope, components, lazy, }: MDXRemoteProps): React.DetailedReactHTMLElement<{
|
|
52
|
+
dangerouslySetInnerHTML: {
|
|
53
|
+
__html: string;
|
|
54
|
+
};
|
|
55
|
+
suppressHydrationWarning: true;
|
|
56
|
+
}, HTMLElement> | React.FunctionComponentElement<Readonly<Props>> | React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
57
|
+
|
|
36
58
|
declare const preProcess: () => (tree: Node) => Node;
|
|
37
59
|
declare const postProcess: () => (tree: Node) => Node;
|
|
38
60
|
declare function createDefaultRehypePlugins(): Pluggable[];
|
|
39
61
|
declare function createDefaultRemarkPlugins(): Pluggable[];
|
|
40
|
-
declare function parseMdx<Frontmatter>(rawMdx: string, options?: ParseMdxOptions): Promise<MdxCompileResult<Frontmatter>>;
|
|
41
62
|
|
|
42
63
|
declare const handleCodeTitles: () => (tree: Node) => void;
|
|
43
64
|
|
|
@@ -54,65 +75,48 @@ declare const handleCodeExpandable: () => (tree: Node) => void;
|
|
|
54
75
|
*/
|
|
55
76
|
declare const rehypeMermaid: () => (tree: Node) => void;
|
|
56
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Remark plugin: convert markdown directives into MDX component elements.
|
|
80
|
+
*
|
|
81
|
+
* Contract (docubook):
|
|
82
|
+
* - `:::name{attrs} … :::` — container: EVERY component that holds content
|
|
83
|
+
* (tabs, tab, accordions, accordion, steps, step, cards, card, files,
|
|
84
|
+
* folder, note + variants). Children are the block between the opening
|
|
85
|
+
* `:::` and closing `:::` — bounded by micromark's container grammar, so
|
|
86
|
+
* a component can never trap siblings that follow it.
|
|
87
|
+
* - `::name{attrs}` — self-closing leaf (no children): file, youtube,
|
|
88
|
+
* mermaid.
|
|
89
|
+
* - `:tooltip[label]{tip="…"}` — the ONE inline (single-colon) directive.
|
|
90
|
+
* Every other text directive is rebuilt as literal text
|
|
91
|
+
* (`localhost:3000` stays intact). `::tooltip` (block leaf) is removed
|
|
92
|
+
* in v2 — tooltips are inline only.
|
|
93
|
+
*
|
|
94
|
+
* Names are PascalCased to match the components map (`file-tree` → `FileTree`).
|
|
95
|
+
* Bare attributes (`{horizontal}`) become boolean props (JSX bare attribute).
|
|
96
|
+
* Callout variants (`:::tip`, `:::info`, …) map to their own registry entries
|
|
97
|
+
* (`Tip`/`Info`/…) which wrap the `Callout` component with the type set.
|
|
98
|
+
*/
|
|
99
|
+
declare function remarkDirectiveToMdx(): (tree: Node) => Node;
|
|
100
|
+
|
|
57
101
|
declare function sluggify(text: string): string;
|
|
58
102
|
declare function extractTocsFromRawMdx(rawMdx: string): TocItem[];
|
|
59
103
|
declare function extractFrontmatter<Frontmatter>(content: string): Frontmatter;
|
|
60
104
|
/**
|
|
61
105
|
* Extract frontmatter and return both the parsed data and the content
|
|
62
|
-
* with the frontmatter block stripped. Avoids a second parse
|
|
106
|
+
* with the frontmatter block stripped. Avoids a second parse during
|
|
107
|
+
* compilation.
|
|
108
|
+
*
|
|
109
|
+
* Optionally validates the parsed frontmatter with a Zod schema.
|
|
110
|
+
* YAML coerces unquoted values (e.g. `date: 2026-06-10` → Date, `3.5` → number),
|
|
111
|
+
* so use `z.coerce.*` for fields that must remain strings.
|
|
63
112
|
*/
|
|
64
113
|
declare function extractFrontmatterWithContent<Frontmatter>(content: string): {
|
|
65
114
|
frontmatter: Frontmatter;
|
|
66
115
|
strippedContent: string;
|
|
67
116
|
};
|
|
68
|
-
|
|
69
|
-
type CacheFn = <T extends (...args: any[]) => any>(fn: T) => T;
|
|
70
|
-
type ReadMdxFileResult = {
|
|
71
|
-
content: string;
|
|
72
|
-
/** Relative path used for UI links (e.g. "docs/getting-started/index.mdx"). */
|
|
73
|
-
filePath: string;
|
|
74
|
-
/** Absolute path on disk — available when file was read by readMdxFileBySlug. */
|
|
75
|
-
absoluteFilePath?: string;
|
|
76
|
-
};
|
|
77
|
-
type ParsedMdxFile<Frontmatter, T extends TocItem = TocItem> = {
|
|
78
|
-
/** Raw content with frontmatter block stripped — ready to pass to compileMDX. */
|
|
79
|
-
content: string;
|
|
80
|
-
filePath: string;
|
|
117
|
+
declare function extractFrontmatterWithContent<Frontmatter>(content: string, schema: ZodType<Frontmatter>): {
|
|
81
118
|
frontmatter: Frontmatter;
|
|
82
|
-
|
|
83
|
-
};
|
|
84
|
-
type CompiledMdxFile<Frontmatter, T extends TocItem = TocItem> = MdxCompileResult<Frontmatter> & {
|
|
85
|
-
filePath: string;
|
|
86
|
-
tocs: T[];
|
|
87
|
-
};
|
|
88
|
-
type ReadMdxBySlugOptions = {
|
|
89
|
-
rootDir?: string;
|
|
90
|
-
docsDir?: string;
|
|
91
|
-
};
|
|
92
|
-
declare function readMdxFileBySlug(slug: string, options?: ReadMdxBySlugOptions): Promise<ReadMdxFileResult>;
|
|
93
|
-
type ParseMdxFileOptions<T extends TocItem> = {
|
|
94
|
-
tocsExtractor?: (rawMdx: string) => T[];
|
|
95
|
-
};
|
|
96
|
-
declare function parseMdxFile<Frontmatter, T extends TocItem = TocItem>(raw: ReadMdxFileResult, options?: ParseMdxFileOptions<T>): ParsedMdxFile<Frontmatter, T>;
|
|
97
|
-
declare function compileParsedMdxFile<Frontmatter, T extends TocItem = TocItem>(parsed: ParsedMdxFile<Frontmatter, T>, options?: ParseMdxOptions): Promise<CompiledMdxFile<Frontmatter, T>>;
|
|
98
|
-
type CreateMdxContentServiceOptions<Frontmatter, T extends TocItem = TocItem> = {
|
|
99
|
-
parseOptions?: ParseMdxOptions;
|
|
100
|
-
readOptions?: ReadMdxBySlugOptions;
|
|
101
|
-
tocsExtractor?: (rawMdx: string) => T[];
|
|
102
|
-
cacheFn?: CacheFn;
|
|
103
|
-
/**
|
|
104
|
-
* Optional hook to enrich or transform frontmatter after parsing.
|
|
105
|
-
* Called with the parsed frontmatter and the absolute file path.
|
|
106
|
-
* Runs at build time during static generation — ideal for injecting
|
|
107
|
-
* fallback values (e.g. git last-modified date when `date` is absent).
|
|
108
|
-
*/
|
|
109
|
-
frontmatterEnricher?: (frontmatter: Frontmatter, absoluteFilePath: string) => Frontmatter | Promise<Frontmatter>;
|
|
110
|
-
};
|
|
111
|
-
declare function createMdxContentService<Frontmatter, T extends TocItem = TocItem>(options?: CreateMdxContentServiceOptions<Frontmatter, T>): {
|
|
112
|
-
getParsedForSlug: (slug: string) => Promise<ParsedMdxFile<Frontmatter, T>>;
|
|
113
|
-
getCompiledForSlug: (slug: string) => Promise<CompiledMdxFile<Frontmatter, T>>;
|
|
114
|
-
getFrontmatterForSlug: (slug: string) => Promise<Frontmatter>;
|
|
115
|
-
getTocsForSlug: (slug: string) => Promise<T[]>;
|
|
119
|
+
strippedContent: string;
|
|
116
120
|
};
|
|
117
121
|
|
|
118
|
-
export {
|
|
122
|
+
export { MDXRemote, type MDXRemoteProps, MDXRemoteSerializeResult, type TocItem, createDefaultRehypePlugins, createDefaultRemarkPlugins, extractFrontmatter, extractFrontmatterWithContent, extractTocsFromRawMdx, handleCodeExpandable, handleCodeExpandableRemark, handleCodeTitles, postProcess, preProcess, rehypeMermaid, remarkDirectiveToMdx, sluggify };
|