@vx-oss/docs-satteri 1.0.3
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/LICENSE +21 -0
- package/dist/compile-SBpZsgmI.d.ts +42 -0
- package/dist/compile.d.ts +2 -0
- package/dist/compile.js +63 -0
- package/dist/index-AvS9vC2S.d.ts +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/local-md/client.d.ts +2 -0
- package/dist/local-md/client.js +2 -0
- package/dist/local-md/dev/react-client.d.ts +2 -0
- package/dist/local-md/dev/react-client.js +2 -0
- package/dist/local-md/dev/vite.d.ts +2 -0
- package/dist/local-md/dev/vite.js +2 -0
- package/dist/local-md/dev/ws.d.ts +2 -0
- package/dist/local-md/dev/ws.js +2 -0
- package/dist/local-md/index.d.ts +70 -0
- package/dist/local-md/index.js +104 -0
- package/dist/preset-DdTDKnqd.js +104 -0
- package/dist/preset-DzMkd76i.d.ts +35 -0
- package/dist/preset.d.ts +2 -0
- package/dist/preset.js +2 -0
- package/dist/rehype-code-CLGqDUSe.d.ts +13 -0
- package/dist/rehype-code.d.ts +2 -0
- package/dist/rehype-code.js +79 -0
- package/dist/rehype-katex-h_E-WUwT.d.ts +15 -0
- package/dist/rehype-katex.d.ts +2 -0
- package/dist/rehype-katex.js +52 -0
- package/dist/rehype-toc-wT8IcPFi.d.ts +33 -0
- package/dist/rehype-toc.d.ts +2 -0
- package/dist/rehype-toc.js +84 -0
- package/dist/remark-admonition.d.ts +13 -0
- package/dist/remark-admonition.js +79 -0
- package/dist/remark-auto-type-table.d.ts +9 -0
- package/dist/remark-auto-type-table.js +189 -0
- package/dist/remark-block-id.d.ts +18 -0
- package/dist/remark-block-id.js +46 -0
- package/dist/remark-code-tab-BYruQJUs.d.ts +15 -0
- package/dist/remark-code-tab.d.ts +2 -0
- package/dist/remark-code-tab.js +170 -0
- package/dist/remark-directive-admonition.d.ts +13 -0
- package/dist/remark-directive-admonition.js +54 -0
- package/dist/remark-feedback-block.d.ts +18 -0
- package/dist/remark-feedback-block.js +51 -0
- package/dist/remark-heading-CYhI2Dkg.d.ts +15 -0
- package/dist/remark-heading.d.ts +2 -0
- package/dist/remark-heading.js +43 -0
- package/dist/remark-image-C28nbosW.d.ts +29 -0
- package/dist/remark-image.d.ts +2 -0
- package/dist/remark-image.js +141 -0
- package/dist/remark-include.d.ts +22 -0
- package/dist/remark-include.js +336 -0
- package/dist/remark-llms.d.ts +36 -0
- package/dist/remark-llms.js +191 -0
- package/dist/remark-mdx-mermaid.d.ts +10 -0
- package/dist/remark-mdx-mermaid.js +22 -0
- package/dist/remark-npm-DdmTKhyi.d.ts +18 -0
- package/dist/remark-npm.d.ts +2 -0
- package/dist/remark-npm.js +72 -0
- package/dist/remark-steps.d.ts +14 -0
- package/dist/remark-steps.js +127 -0
- package/dist/remark-structure.d.ts +29 -0
- package/dist/remark-structure.js +94 -0
- package/dist/remark-ts2js.d.ts +25 -0
- package/dist/remark-ts2js.js +56 -0
- package/dist/renderer-BtFWPZB8.js +54 -0
- package/dist/renderer-E5KzV19n.d.ts +30 -0
- package/dist/stringifier-COIWcXys.js +130 -0
- package/dist/utils-I3DkmAkd.js +27 -0
- package/package.json +124 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MdastVisitorContext } from "satteri";
|
|
2
|
+
import { Heading } from "mdast";
|
|
3
|
+
//#region src/remark-steps.d.ts
|
|
4
|
+
interface RemarkStepsOptions {
|
|
5
|
+
steps?: string;
|
|
6
|
+
step?: string;
|
|
7
|
+
}
|
|
8
|
+
declare function remarkSteps({ steps, step }?: RemarkStepsOptions): () => {
|
|
9
|
+
name: string;
|
|
10
|
+
heading(node: Readonly<Heading>, ctx: MdastVisitorContext): undefined;
|
|
11
|
+
after(_root: Readonly<import("mdast").Root>, ctx: MdastVisitorContext): void;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { RemarkStepsOptions, remarkSteps };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { n as handleTag } from "./utils-I3DkmAkd.js";
|
|
2
|
+
import { defineMdastPlugin } from "satteri";
|
|
3
|
+
//#region src/remark-steps.ts
|
|
4
|
+
const StepRegex = /^(\d+)\.\s(.+)$/;
|
|
5
|
+
const StepTag = "[step]";
|
|
6
|
+
function remarkSteps({ steps = "fd-steps", step = "fd-step" } = {}) {
|
|
7
|
+
function convertToSteps(nodes) {
|
|
8
|
+
const depth = nodes[0].depth;
|
|
9
|
+
const children = [];
|
|
10
|
+
for (const node of nodes) if (node.type === "heading" && node.depth === depth) children.push({
|
|
11
|
+
type: "mdxJsxFlowElement",
|
|
12
|
+
name: "div",
|
|
13
|
+
attributes: [{
|
|
14
|
+
type: "mdxJsxAttribute",
|
|
15
|
+
name: "className",
|
|
16
|
+
value: step
|
|
17
|
+
}],
|
|
18
|
+
children: [node]
|
|
19
|
+
});
|
|
20
|
+
else children[children.length - 1].children.push(node);
|
|
21
|
+
return {
|
|
22
|
+
type: "mdxJsxFlowElement",
|
|
23
|
+
name: "div",
|
|
24
|
+
attributes: [{
|
|
25
|
+
type: "mdxJsxAttribute",
|
|
26
|
+
name: "className",
|
|
27
|
+
value: steps
|
|
28
|
+
}],
|
|
29
|
+
children
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function handleHeadingStep(node) {
|
|
33
|
+
const head = node.children[0];
|
|
34
|
+
if (head?.type === "text") {
|
|
35
|
+
const match = StepRegex.exec(head.value);
|
|
36
|
+
if (match) {
|
|
37
|
+
const newChildren = [...node.children];
|
|
38
|
+
newChildren[0] = {
|
|
39
|
+
...head,
|
|
40
|
+
value: match[2]
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
...node,
|
|
44
|
+
children: newChildren
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const tail = node.children[node.children.length - 1];
|
|
49
|
+
if (tail?.type === "text") {
|
|
50
|
+
const stepValue = handleTag(tail.value, StepTag);
|
|
51
|
+
if (stepValue !== false) {
|
|
52
|
+
const newChildren = [...node.children];
|
|
53
|
+
newChildren[newChildren.length - 1] = {
|
|
54
|
+
...tail,
|
|
55
|
+
value: stepValue
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
...node,
|
|
59
|
+
children: newChildren
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
function processChildren(parent, ctx) {
|
|
66
|
+
const output = [...parent.children];
|
|
67
|
+
let startIdx = -1;
|
|
68
|
+
let i = 0;
|
|
69
|
+
let currentStep = 1;
|
|
70
|
+
let changed = false;
|
|
71
|
+
const onEnd = () => {
|
|
72
|
+
if (startIdx === -1) return;
|
|
73
|
+
const nodes = output.splice(startIdx, i - startIdx);
|
|
74
|
+
output.splice(startIdx, 0, convertToSteps(nodes));
|
|
75
|
+
changed = true;
|
|
76
|
+
i = startIdx + 1;
|
|
77
|
+
startIdx = -1;
|
|
78
|
+
currentStep = 1;
|
|
79
|
+
};
|
|
80
|
+
for (; i < output.length; i++) {
|
|
81
|
+
const node = output[i];
|
|
82
|
+
if (node.type !== "heading") continue;
|
|
83
|
+
if ((node.data ?? {}).hProperties?.["data-fd-step"] !== void 0) continue;
|
|
84
|
+
if (startIdx !== -1) {
|
|
85
|
+
const startDepth = output[startIdx].depth;
|
|
86
|
+
if (node.depth !== startDepth) {
|
|
87
|
+
if (node.depth < startDepth) onEnd();
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const stepped = handleHeadingStep(node);
|
|
92
|
+
if (!stepped) {
|
|
93
|
+
onEnd();
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const steppedData = stepped.data ?? {};
|
|
97
|
+
output[i] = {
|
|
98
|
+
...stepped,
|
|
99
|
+
data: {
|
|
100
|
+
...steppedData,
|
|
101
|
+
hProperties: {
|
|
102
|
+
...steppedData.hProperties,
|
|
103
|
+
"data-fd-step": currentStep++
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
if (startIdx === -1) startIdx = i;
|
|
108
|
+
}
|
|
109
|
+
onEnd();
|
|
110
|
+
if (changed) ctx.setProperty(parent, "children", output);
|
|
111
|
+
}
|
|
112
|
+
return () => {
|
|
113
|
+
const parents = /* @__PURE__ */ new Set();
|
|
114
|
+
return defineMdastPlugin({
|
|
115
|
+
name: "remark-steps",
|
|
116
|
+
heading(node, ctx) {
|
|
117
|
+
const parent = ctx.parent(node);
|
|
118
|
+
if (parent && "children" in parent) parents.add(parent);
|
|
119
|
+
},
|
|
120
|
+
after(_root, ctx) {
|
|
121
|
+
for (const parent of parents) processChildren(parent, ctx);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { remarkSteps };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { o as ExtraPluginHooks } from "./compile-SBpZsgmI.js";
|
|
2
|
+
import { MdastPluginDefinition } from "satteri";
|
|
3
|
+
import { StructuredData } from "@vx-oss/docs-core/mdx-plugins/remark-structure";
|
|
4
|
+
import { Nodes } from "mdast";
|
|
5
|
+
//#region src/remark-structure.d.ts
|
|
6
|
+
interface StructureOptions {
|
|
7
|
+
types?: string[] | ((node: Nodes) => boolean);
|
|
8
|
+
mdxTypes?: (node: Nodes) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Include Markdown syntax in content records, sliced from the authored source.
|
|
11
|
+
*
|
|
12
|
+
* Links and JSX elements are flattened into their plain text, return `true` from
|
|
13
|
+
* `filterElement` to keep an element's syntax instead.
|
|
14
|
+
*/
|
|
15
|
+
stringify?: boolean | {
|
|
16
|
+
filterElement?: (node: Nodes & {
|
|
17
|
+
name?: string | null;
|
|
18
|
+
}) => boolean;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* export as `structuredData` (if true) or specified variable name.
|
|
22
|
+
*
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
exportAs?: string | boolean;
|
|
26
|
+
}
|
|
27
|
+
declare function remarkStructure({ types, mdxTypes, stringify, exportAs }?: StructureOptions): ExtraPluginHooks & (() => MdastPluginDefinition);
|
|
28
|
+
//#endregion
|
|
29
|
+
export { StructureOptions, type StructuredData, remarkStructure };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { t as createStringifier } from "./stringifier-COIWcXys.js";
|
|
2
|
+
//#region src/remark-structure.ts
|
|
3
|
+
const STRUCTURE_VISITORS = [
|
|
4
|
+
"heading",
|
|
5
|
+
"paragraph",
|
|
6
|
+
"blockquote",
|
|
7
|
+
"tableCell",
|
|
8
|
+
"mdxJsxFlowElement"
|
|
9
|
+
];
|
|
10
|
+
function remarkStructure({ types = [
|
|
11
|
+
"heading",
|
|
12
|
+
"paragraph",
|
|
13
|
+
"blockquote",
|
|
14
|
+
"tableCell",
|
|
15
|
+
"mdxJsxFlowElement"
|
|
16
|
+
], mdxTypes = (node) => !("children" in node) || node.children.length === 0, stringify = false, exportAs = true } = {}) {
|
|
17
|
+
const matchType = typeof types === "function" ? types : (node) => types.includes(node.type);
|
|
18
|
+
const filterElement = typeof stringify === "object" ? stringify.filterElement : void 0;
|
|
19
|
+
const plugin = () => {
|
|
20
|
+
const data = {
|
|
21
|
+
contents: [],
|
|
22
|
+
headings: []
|
|
23
|
+
};
|
|
24
|
+
const records = [];
|
|
25
|
+
let lastHeading;
|
|
26
|
+
let s;
|
|
27
|
+
function visit(node) {
|
|
28
|
+
if (stringify && (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement")) {
|
|
29
|
+
if (!filterElement?.(node)) s.flatten(node);
|
|
30
|
+
}
|
|
31
|
+
if (!matchType(node)) return;
|
|
32
|
+
if ((node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && !mdxTypes(node)) return;
|
|
33
|
+
if (node.type === "heading") {
|
|
34
|
+
const id = node.data?.hProperties?.id;
|
|
35
|
+
if (!id) return;
|
|
36
|
+
records.push({
|
|
37
|
+
node,
|
|
38
|
+
heading: void 0,
|
|
39
|
+
id
|
|
40
|
+
});
|
|
41
|
+
lastHeading = id;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
records.push({
|
|
45
|
+
node,
|
|
46
|
+
heading: lastHeading
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const definition = {
|
|
50
|
+
name: "remark-structure",
|
|
51
|
+
options: stringify ? { position: true } : void 0,
|
|
52
|
+
before(_root, ctx) {
|
|
53
|
+
ctx.data.structuredData ??= data;
|
|
54
|
+
s = createStringifier(ctx);
|
|
55
|
+
const openapiData = ctx.data.frontmatter?._openapi?.structuredData;
|
|
56
|
+
if (openapiData) {
|
|
57
|
+
data.headings.push(...openapiData.headings);
|
|
58
|
+
data.contents.push(...openapiData.contents);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
after(_root, ctx) {
|
|
62
|
+
for (const record of records) {
|
|
63
|
+
const content = (stringify && !record.id ? s.stringify(record.node) : ctx.textContent(record.node)).trim();
|
|
64
|
+
if (content.length === 0) continue;
|
|
65
|
+
if (record.id) data.headings.push({
|
|
66
|
+
id: record.id,
|
|
67
|
+
content
|
|
68
|
+
});
|
|
69
|
+
else data.contents.push({
|
|
70
|
+
heading: record.heading,
|
|
71
|
+
content
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
...Object.fromEntries(STRUCTURE_VISITORS.map((key) => [key, visit]))
|
|
76
|
+
};
|
|
77
|
+
if (stringify) Object.assign(definition, {
|
|
78
|
+
mdxJsxTextElement: visit,
|
|
79
|
+
link: (node) => s.flatten(node),
|
|
80
|
+
linkReference: (node) => s.flatten(node),
|
|
81
|
+
image: (node) => s.remove(node)
|
|
82
|
+
});
|
|
83
|
+
return definition;
|
|
84
|
+
};
|
|
85
|
+
plugin.collectExports = ({ data, addExport }) => {
|
|
86
|
+
if (exportAs) addExport(typeof exportAs === "string" ? exportAs : "structuredData", JSON.stringify(data.structuredData ?? {
|
|
87
|
+
headings: [],
|
|
88
|
+
contents: []
|
|
89
|
+
}));
|
|
90
|
+
};
|
|
91
|
+
return plugin;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { remarkStructure };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/remark-ts2js.d.ts
|
|
2
|
+
interface RemarkTs2jsOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Persist Tab value (Fumadocs UI only)
|
|
5
|
+
*
|
|
6
|
+
* @defaultValue false
|
|
7
|
+
*/
|
|
8
|
+
persist?: {
|
|
9
|
+
id: string;
|
|
10
|
+
} | false;
|
|
11
|
+
defaultValue?: 'js' | 'ts';
|
|
12
|
+
/**
|
|
13
|
+
* Transform all TypeScript codeblocks by default, without a trigger
|
|
14
|
+
*/
|
|
15
|
+
disableTrigger?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Transform TypeScript codeblocks into TS/JS tabs. Add `ts2js` to the code fence meta to enable.
|
|
19
|
+
*/
|
|
20
|
+
declare function remarkTs2js({ persist, defaultValue, disableTrigger }?: RemarkTs2jsOptions): {
|
|
21
|
+
name: string;
|
|
22
|
+
code(node: Readonly<import("mdast").Code>, ctx: import("satteri").MdastVisitorContext): Promise<undefined>;
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { RemarkTs2jsOptions, remarkTs2js };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { defineMdastPlugin } from "satteri";
|
|
2
|
+
import { generateCodeBlockTabs, parseCodeBlockAttributes } from "@vx-oss/docs-core/mdx-plugins/codeblock-utils";
|
|
3
|
+
//#region src/remark-ts2js.ts
|
|
4
|
+
/**
|
|
5
|
+
* Transform TypeScript codeblocks into TS/JS tabs. Add `ts2js` to the code fence meta to enable.
|
|
6
|
+
*/
|
|
7
|
+
function remarkTs2js({ persist = false, defaultValue = "ts", disableTrigger = false } = {}) {
|
|
8
|
+
return defineMdastPlugin({
|
|
9
|
+
name: "remark-typescript-to-javascript",
|
|
10
|
+
async code(node, ctx) {
|
|
11
|
+
const lang = node.lang;
|
|
12
|
+
if (lang !== "ts" && lang !== "tsx") return;
|
|
13
|
+
const meta = parseCodeBlockAttributes(node.meta ?? "", ["ts2js"]);
|
|
14
|
+
if (!disableTrigger && !("ts2js" in meta.attributes)) return;
|
|
15
|
+
const [{ parse }, { strip }] = await Promise.all([import("yuku-parser"), import("yuku-codegen")]);
|
|
16
|
+
const { program } = parse(node.value, { lang });
|
|
17
|
+
const result = strip(program);
|
|
18
|
+
ctx.replaceNode(node, generateCodeBlockTabs({
|
|
19
|
+
persist,
|
|
20
|
+
defaultValue,
|
|
21
|
+
triggers: [{
|
|
22
|
+
value: "ts",
|
|
23
|
+
children: [{
|
|
24
|
+
type: "text",
|
|
25
|
+
value: "TypeScript"
|
|
26
|
+
}]
|
|
27
|
+
}, {
|
|
28
|
+
value: "js",
|
|
29
|
+
children: [{
|
|
30
|
+
type: "text",
|
|
31
|
+
value: "JavaScript"
|
|
32
|
+
}]
|
|
33
|
+
}],
|
|
34
|
+
tabs: [{
|
|
35
|
+
value: "ts",
|
|
36
|
+
children: [{
|
|
37
|
+
type: "code",
|
|
38
|
+
lang: node.lang,
|
|
39
|
+
meta: meta.rest,
|
|
40
|
+
value: node.value
|
|
41
|
+
}]
|
|
42
|
+
}, {
|
|
43
|
+
value: "js",
|
|
44
|
+
children: [{
|
|
45
|
+
type: "code",
|
|
46
|
+
lang: lang === "tsx" ? "jsx" : "js",
|
|
47
|
+
meta: typeof meta.attributes.ts2js === "string" ? meta.attributes.ts2js : meta.rest,
|
|
48
|
+
value: result.code
|
|
49
|
+
}]
|
|
50
|
+
}]
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { remarkTs2js };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { asMarkdown, jsxComponents } from "@vx-oss/docs-core/server";
|
|
2
|
+
import * as JsxRuntime from "react/jsx-runtime";
|
|
3
|
+
//#region src/local-md/renderer.ts
|
|
4
|
+
const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor;
|
|
5
|
+
function fromJS(options) {
|
|
6
|
+
const { code, structuredData = {
|
|
7
|
+
headings: [],
|
|
8
|
+
contents: []
|
|
9
|
+
}, baseUrl } = options;
|
|
10
|
+
function createScope(context) {
|
|
11
|
+
const { opts, ...rest } = context ?? {};
|
|
12
|
+
return {
|
|
13
|
+
opts: {
|
|
14
|
+
...opts,
|
|
15
|
+
...JsxRuntime,
|
|
16
|
+
asMarkdown,
|
|
17
|
+
jsxComponents,
|
|
18
|
+
baseUrl
|
|
19
|
+
},
|
|
20
|
+
...rest
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function toResult(out, components) {
|
|
24
|
+
return {
|
|
25
|
+
toc: out.toc ?? [],
|
|
26
|
+
body: JsxRuntime.jsx(out.default, { components }),
|
|
27
|
+
exports: out
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
structuredData,
|
|
32
|
+
async render(components, context) {
|
|
33
|
+
const scope = createScope(context);
|
|
34
|
+
const hydrateFn = new AsyncFunction(...Object.keys(scope), code);
|
|
35
|
+
return toResult(await hydrateFn.apply(hydrateFn, Object.values(scope)), components);
|
|
36
|
+
},
|
|
37
|
+
renderSync(components, context) {
|
|
38
|
+
const scope = createScope(context);
|
|
39
|
+
const hydrateFn = new Function(...Object.keys(scope), code);
|
|
40
|
+
return toResult(hydrateFn.apply(hydrateFn, Object.values(scope)), components);
|
|
41
|
+
},
|
|
42
|
+
serialize() {
|
|
43
|
+
return {
|
|
44
|
+
type: "js",
|
|
45
|
+
...options
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function fromSerialized(options) {
|
|
51
|
+
return fromJS(options);
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { fromSerialized as n, fromJS as t };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { StructuredData } from "@vx-oss/docs-core/mdx-plugins/remark-structure";
|
|
2
|
+
import { TOCItemType } from "@vx-oss/docs-core/toc";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { MDXComponents } from "mdx/types";
|
|
5
|
+
//#region src/local-md/renderer.d.ts
|
|
6
|
+
interface MarkdownRenderer<M = Record<string, unknown>> {
|
|
7
|
+
structuredData: StructuredData;
|
|
8
|
+
render: (components?: MDXComponents, context?: Record<string, unknown>) => Promise<MarkdownRendererResult<M>>;
|
|
9
|
+
renderSync: (components?: MDXComponents, context?: Record<string, unknown>) => MarkdownRendererResult<M>;
|
|
10
|
+
/** JSON-serializable, rebuild it on the client with {@link fromSerialized} */
|
|
11
|
+
serialize: () => MarkdownRendererSerializedOptions;
|
|
12
|
+
}
|
|
13
|
+
interface MarkdownRendererResult<M = Record<string, unknown>> {
|
|
14
|
+
exports: M;
|
|
15
|
+
toc: TOCItemType[];
|
|
16
|
+
body: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
type MarkdownRendererSerializedOptions = {
|
|
19
|
+
type: 'js';
|
|
20
|
+
} & MarkdownRendererJSOptions;
|
|
21
|
+
interface MarkdownRendererJSOptions {
|
|
22
|
+
/** compiled `function-body` JavaScript. */
|
|
23
|
+
code: string;
|
|
24
|
+
filePath: string;
|
|
25
|
+
baseUrl?: string;
|
|
26
|
+
structuredData?: StructuredData;
|
|
27
|
+
}
|
|
28
|
+
declare function fromSerialized<M>(options: MarkdownRendererSerializedOptions): MarkdownRenderer<M>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { fromSerialized as i, MarkdownRendererResult as n, MarkdownRendererSerializedOptions as r, MarkdownRenderer as t };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
//#region src/stringifier.ts
|
|
2
|
+
function offsets(node) {
|
|
3
|
+
const pos = node.position;
|
|
4
|
+
if (pos?.start.offset !== void 0 && pos.end.offset !== void 0) return {
|
|
5
|
+
start: pos.start.offset,
|
|
6
|
+
end: pos.end.offset
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Record the Markdown form of generated content over an authored node's source range,
|
|
11
|
+
* for plugins that replace nodes (e.g. includes, generated type tables). Source-based
|
|
12
|
+
* Markdown output cannot see the replacement, it shows this text instead.
|
|
13
|
+
*
|
|
14
|
+
* `markdown` is only called when source positions are tracked, i.e. when a consumer
|
|
15
|
+
* of the recorded edits is present.
|
|
16
|
+
*/
|
|
17
|
+
function replaceSource(ctx, node, markdown) {
|
|
18
|
+
const pos = offsets(node);
|
|
19
|
+
if (pos) (ctx.data._sourceEdits ??= []).push({
|
|
20
|
+
start: pos.start,
|
|
21
|
+
end: pos.end,
|
|
22
|
+
text: markdown()
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Rows as an aligned Markdown table, the first row being the header.
|
|
27
|
+
* Newlines in cells are collapsed and `|` is escaped.
|
|
28
|
+
*/
|
|
29
|
+
function formatTable(rows) {
|
|
30
|
+
const cells = [];
|
|
31
|
+
const widths = [];
|
|
32
|
+
for (const row of rows) {
|
|
33
|
+
const escaped = [];
|
|
34
|
+
for (let i = 0; i < row.length; i++) {
|
|
35
|
+
const text = row[i].replace(/\s*\n\s*/g, " ").replaceAll("|", "\\|");
|
|
36
|
+
widths[i] = Math.max(widths[i] ?? 0, text.length);
|
|
37
|
+
escaped.push(text);
|
|
38
|
+
}
|
|
39
|
+
cells.push(escaped);
|
|
40
|
+
}
|
|
41
|
+
let out = "";
|
|
42
|
+
for (let r = 0; r < cells.length; r++) {
|
|
43
|
+
let line = "|";
|
|
44
|
+
for (let i = 0; i < widths.length; i++) line += ` ${(cells[r][i] ?? "").padEnd(widths[i])} |`;
|
|
45
|
+
out += `${line}\n`;
|
|
46
|
+
if (r === 0) {
|
|
47
|
+
line = "|";
|
|
48
|
+
for (const width of widths) line += ` ${"-".repeat(width)} |`;
|
|
49
|
+
out += `${line}\n`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function createStringifier(ctx) {
|
|
55
|
+
const source = ctx.source;
|
|
56
|
+
const own = [];
|
|
57
|
+
let sorted;
|
|
58
|
+
function edits() {
|
|
59
|
+
if (!sorted) {
|
|
60
|
+
sorted = ctx.data._sourceEdits ? [...ctx.data._sourceEdits, ...own] : [...own];
|
|
61
|
+
sorted.sort((a, b) => a.start - b.start);
|
|
62
|
+
}
|
|
63
|
+
return sorted;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
source,
|
|
67
|
+
get edits() {
|
|
68
|
+
return edits();
|
|
69
|
+
},
|
|
70
|
+
edit(start, end, text) {
|
|
71
|
+
own.push({
|
|
72
|
+
start,
|
|
73
|
+
end,
|
|
74
|
+
text
|
|
75
|
+
});
|
|
76
|
+
sorted = void 0;
|
|
77
|
+
},
|
|
78
|
+
remove(node) {
|
|
79
|
+
const pos = offsets(node);
|
|
80
|
+
if (pos) this.edit(pos.start, pos.end, "");
|
|
81
|
+
},
|
|
82
|
+
flatten(node) {
|
|
83
|
+
const pos = offsets(node);
|
|
84
|
+
if (pos) this.edit(pos.start, pos.end, ctx.textContent(node));
|
|
85
|
+
},
|
|
86
|
+
slice(start, end) {
|
|
87
|
+
return splice(source, start, end, edits());
|
|
88
|
+
},
|
|
89
|
+
stringify(node) {
|
|
90
|
+
const pos = offsets(node);
|
|
91
|
+
if (pos) return splice(source, pos.start, pos.end, edits());
|
|
92
|
+
const { type } = node;
|
|
93
|
+
if (type === "mdxJsxFlowElement" || type === "mdxJsxTextElement") return syntheticElement(node, ctx);
|
|
94
|
+
return ctx.textContent(node);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function splice(source, start, end, edits) {
|
|
99
|
+
let lo = 0;
|
|
100
|
+
let hi = edits.length;
|
|
101
|
+
while (lo < hi) {
|
|
102
|
+
const mid = lo + hi >> 1;
|
|
103
|
+
if (edits[mid].start < start) lo = mid + 1;
|
|
104
|
+
else hi = mid;
|
|
105
|
+
}
|
|
106
|
+
let out = "";
|
|
107
|
+
let cursor = start;
|
|
108
|
+
for (let i = lo; i < edits.length && edits[i].start < end; i++) {
|
|
109
|
+
const edit = edits[i];
|
|
110
|
+
if (edit.end > end) continue;
|
|
111
|
+
out += source.slice(cursor, edit.start) + edit.text;
|
|
112
|
+
cursor = edit.end;
|
|
113
|
+
if (edit.text === "") while (source[cursor] === "\n" && (out === "" || out.endsWith("\n\n"))) cursor++;
|
|
114
|
+
}
|
|
115
|
+
return out + source.slice(cursor, end);
|
|
116
|
+
}
|
|
117
|
+
/** the tag of a plugin-inserted JSX element, reconstructed from its fields */
|
|
118
|
+
function syntheticElement(node, ctx) {
|
|
119
|
+
let attrs = "";
|
|
120
|
+
for (const attr of node.attributes) if (attr.type === "mdxJsxExpressionAttribute") {
|
|
121
|
+
if (attr.value) attrs += ` {${attr.value}}`;
|
|
122
|
+
} else if (attr.value == null) attrs += ` ${attr.name}`;
|
|
123
|
+
else if (typeof attr.value === "string") attrs += ` ${attr.name}="${attr.value}"`;
|
|
124
|
+
else if (attr.value.value) attrs += ` ${attr.name}={${attr.value.value}}`;
|
|
125
|
+
const children = ctx.textContent(node);
|
|
126
|
+
if (!children) return `<${node.name}${attrs} />`;
|
|
127
|
+
return `<${node.name}${attrs}>${children}</${node.name}>`;
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { replaceSource as i, formatTable as n, offsets as r, createStringifier as t };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx, toJs } from "estree-util-to-js";
|
|
2
|
+
import { toEstree } from "hast-util-to-estree";
|
|
3
|
+
//#region src/utils.ts
|
|
4
|
+
/**
|
|
5
|
+
* Flatten a node's text content by walking it in JavaScript.
|
|
6
|
+
*
|
|
7
|
+
* Prefer `ctx.textContent(node, { includeImageAlt: false })` for nodes of the
|
|
8
|
+
* visited document — it walks the tree in Rust without materializing the
|
|
9
|
+
* subtree. This util is for detached trees (e.g. `mdxToMdast()` output), which
|
|
10
|
+
* have no handle behind them and can't use the visitor context.
|
|
11
|
+
*/
|
|
12
|
+
function flattenNode(node) {
|
|
13
|
+
if ("children" in node && Array.isArray(node.children)) return node.children.map((child) => flattenNode(child)).join("");
|
|
14
|
+
if ("value" in node && typeof node.value === "string") return node.value;
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
function handleTag(value, tag) {
|
|
18
|
+
const idx = value.indexOf(tag);
|
|
19
|
+
if (idx !== -1) return value.slice(0, idx).trimEnd() + value.slice(idx + tag.length);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function jsxToSource(hast) {
|
|
23
|
+
const source = toJs(toEstree(hast, { elementAttributeNameCase: "react" }), { handlers: jsx }).value.trim();
|
|
24
|
+
return source.endsWith(";") ? source.slice(0, -1) : source;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { handleTag as n, jsxToSource as r, flattenNode as t };
|