@xyd-js/content 0.1.0-xyd.10
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/CHANGELOG.md +49 -0
- package/README.md +3 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +22004 -0
- package/dist/index.js.map +1 -0
- package/dist/md.d.ts +14 -0
- package/dist/md.js +20410 -0
- package/dist/md.js.map +1 -0
- package/dist/mdToc-CYxzibVZ.d.ts +11 -0
- package/dist/vite.d.ts +987 -0
- package/dist/vite.js +20420 -0
- package/dist/vite.js.map +1 -0
- package/package.json +45 -0
- package/packages/md/index.ts +13 -0
- package/packages/md/plugins/index.ts +26 -0
- package/packages/md/plugins/mdCode.ts +19 -0
- package/packages/md/plugins/mdCodeGroup.ts +40 -0
- package/packages/md/plugins/mdComponentDirective.ts +141 -0
- package/packages/md/plugins/mdPage.ts +32 -0
- package/packages/md/plugins/mdThemeSettings.ts +30 -0
- package/packages/md/plugins/mdToc.ts +133 -0
- package/packages/vite/index.ts +14 -0
- package/src/fs.ts +43 -0
- package/src/index.ts +8 -0
- package/src/navigation.ts +172 -0
- package/tsconfig.json +26 -0
- package/tsup.config.ts +29 -0
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xyd-js/content",
|
|
3
|
+
"version": "0.1.0-xyd.10",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./package.json": "./package.json",
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./vite": "./dist/vite.js",
|
|
11
|
+
"./md": "./dist/md.js"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@mdx-js/mdx": "^3.1.0",
|
|
15
|
+
"@mdx-js/rollup": "^3.0.1",
|
|
16
|
+
"estree-util-is-identifier-name": "^3.0.0",
|
|
17
|
+
"estree-util-value-to-estree": "^3.1.2",
|
|
18
|
+
"gray-matter": "^4.0.3",
|
|
19
|
+
"mdast": "^3.0.0",
|
|
20
|
+
"mdast-util-mdx": "^3.0.0",
|
|
21
|
+
"mdast-util-mdx-jsx": "^3.1.3",
|
|
22
|
+
"mdast-util-to-string": "^4.0.0",
|
|
23
|
+
"remark-directive": "^3.0.0",
|
|
24
|
+
"remark-frontmatter": "^5.0.0",
|
|
25
|
+
"remark-gfm": "^4.0.0",
|
|
26
|
+
"remark-mdx-frontmatter": "^5.0.0",
|
|
27
|
+
"unified": "^11.0.5",
|
|
28
|
+
"unist-util-visit": "^5.0.0",
|
|
29
|
+
"vfile": "^6.0.3",
|
|
30
|
+
"@xyd-js/core": "0.1.0-xyd.9"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.7.8",
|
|
34
|
+
"rimraf": "^3.0.2",
|
|
35
|
+
"tsup": "^8.3.0",
|
|
36
|
+
"typescript": "^4.5.5",
|
|
37
|
+
"vite": "^6.0.7"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"clean": "rimraf build",
|
|
41
|
+
"prebuild": "pnpm clean",
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"watch": "tsup --watch"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {RemarkMdxTocOptions} from "./plugins/mdToc";
|
|
2
|
+
import {defaultPlugins} from "./plugins"
|
|
3
|
+
|
|
4
|
+
export {RemarkMdxTocOptions} from "./plugins/mdToc";
|
|
5
|
+
|
|
6
|
+
export function mdOptions(toc: RemarkMdxTocOptions) {
|
|
7
|
+
return {
|
|
8
|
+
remarkPlugins: [
|
|
9
|
+
...defaultPlugins(toc)
|
|
10
|
+
],
|
|
11
|
+
rehypePlugins: []
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import remarkFrontmatter from "remark-frontmatter";
|
|
2
|
+
import remarkMdxFrontmatter from "remark-mdx-frontmatter";
|
|
3
|
+
import remarkGfm from "remark-gfm";
|
|
4
|
+
import remarkDirective from 'remark-directive'
|
|
5
|
+
|
|
6
|
+
import {remarkMdxToc, RemarkMdxTocOptions} from "./mdToc";
|
|
7
|
+
import {remarkInjectCodeMeta} from "./mdCode";
|
|
8
|
+
import {extractThemeSettings} from "./mdThemeSettings";
|
|
9
|
+
import {extractPage} from "./mdPage";
|
|
10
|
+
import {mdCodeGroup} from "./mdCodeGroup";
|
|
11
|
+
import {remarkDirectiveWithMarkdown} from "./mdComponentDirective";
|
|
12
|
+
|
|
13
|
+
export function defaultPlugins(toc: RemarkMdxTocOptions) {
|
|
14
|
+
return [
|
|
15
|
+
remarkFrontmatter,
|
|
16
|
+
remarkMdxFrontmatter,
|
|
17
|
+
remarkGfm,
|
|
18
|
+
remarkDirective,
|
|
19
|
+
remarkMdxToc(toc),
|
|
20
|
+
remarkInjectCodeMeta,
|
|
21
|
+
extractThemeSettings,
|
|
22
|
+
extractPage,
|
|
23
|
+
mdCodeGroup,
|
|
24
|
+
remarkDirectiveWithMarkdown
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {visit} from "unist-util-visit";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This plugin injects the code meta into the code node's data
|
|
5
|
+
* so that it can be used in the code block component
|
|
6
|
+
*/
|
|
7
|
+
export function remarkInjectCodeMeta() {
|
|
8
|
+
return (tree: any) => {
|
|
9
|
+
visit(tree, 'code', (node) => {
|
|
10
|
+
if (node.meta) {
|
|
11
|
+
node.data = node.data || {};
|
|
12
|
+
node.data.hProperties = {
|
|
13
|
+
...(node.data.hProperties || {}),
|
|
14
|
+
meta: node.meta,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {visit} from 'unist-util-visit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This plugin transforms a custom container directive into a JSX node
|
|
5
|
+
* https://github.com/remarkjs/remark-directive is needed to parse the container directive
|
|
6
|
+
*/
|
|
7
|
+
export function mdCodeGroup() {
|
|
8
|
+
return (tree: any) => {
|
|
9
|
+
visit(tree, 'containerDirective', (node) => {
|
|
10
|
+
// TODO: is `code-group` ok name? -> rename to CodeSample? or use `mdComponentDirective` instead
|
|
11
|
+
if (node.name !== 'code-group') {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const description = node.attributes?.title || '';
|
|
16
|
+
const codeblocks = [];
|
|
17
|
+
|
|
18
|
+
for (const child of node.children) {
|
|
19
|
+
if (child.type === 'code') {
|
|
20
|
+
const meta = child.meta || '';
|
|
21
|
+
const value = child.value || '';
|
|
22
|
+
const lang = child.lang || '';
|
|
23
|
+
|
|
24
|
+
codeblocks.push({value, lang, meta});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Add metadata to the node
|
|
29
|
+
node.data = {
|
|
30
|
+
hName: 'DirectiveCodeSample',
|
|
31
|
+
hProperties: {
|
|
32
|
+
description,
|
|
33
|
+
codeblocks: JSON.stringify(codeblocks),
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
node.children = [];
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {Plugin, unified} from "unified";
|
|
2
|
+
import remarkParse from "remark-parse";
|
|
3
|
+
import remarkMdx from "remark-mdx";
|
|
4
|
+
import {visit} from "unist-util-visit";
|
|
5
|
+
import {Node as UnistNode} from "unist";
|
|
6
|
+
|
|
7
|
+
function toPascalCase(str: string) {
|
|
8
|
+
return str
|
|
9
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2") // Add space before capital letters
|
|
10
|
+
.replace(/[^a-zA-Z0-9]/g, " ") // Replace special characters with space
|
|
11
|
+
.split(" ") // Split by space
|
|
12
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize first letter
|
|
13
|
+
.join("");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const supportedDirectives: { [key: string]: boolean } = {
|
|
18
|
+
Details: true,
|
|
19
|
+
details: true,
|
|
20
|
+
|
|
21
|
+
Table: true,
|
|
22
|
+
table: true,
|
|
23
|
+
|
|
24
|
+
Subtitle: true,
|
|
25
|
+
subtitle: true,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tableComponents: { [key: string]: boolean } = {
|
|
29
|
+
Table: true,
|
|
30
|
+
table: true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const parseMarkdown = (content: string) => {
|
|
34
|
+
const ast = unified()
|
|
35
|
+
.use(remarkParse)
|
|
36
|
+
.use(remarkMdx)
|
|
37
|
+
.parse(content);
|
|
38
|
+
return ast.children;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const remarkDirectiveWithMarkdown: Plugin = () => {
|
|
42
|
+
return (tree: UnistNode) => {
|
|
43
|
+
visit(tree, 'containerDirective', (node: any) => {
|
|
44
|
+
if (!supportedDirectives[node.name]) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const isTable = tableComponents[node.name];
|
|
49
|
+
const attributes = [];
|
|
50
|
+
|
|
51
|
+
// TODO: MORE GENERIC CUZ IT HAS IMPL DETAILS OF TABLE
|
|
52
|
+
if (isTable) {
|
|
53
|
+
// TODO: support tsx tables like: [<>`Promise<Reference[]>`</>] ?
|
|
54
|
+
const tableData = JSON.parse(node.children[0].value);
|
|
55
|
+
const [header, ...rows] = tableData;
|
|
56
|
+
|
|
57
|
+
const jsxNode = {
|
|
58
|
+
type: 'mdxJsxFlowElement',
|
|
59
|
+
name: 'Table',
|
|
60
|
+
attributes: [],
|
|
61
|
+
children: [
|
|
62
|
+
{
|
|
63
|
+
type: 'mdxJsxFlowElement',
|
|
64
|
+
name: 'Table.Head',
|
|
65
|
+
attributes: [],
|
|
66
|
+
children: [
|
|
67
|
+
{
|
|
68
|
+
type: 'mdxJsxFlowElement',
|
|
69
|
+
name: 'Table.Tr',
|
|
70
|
+
attributes: [],
|
|
71
|
+
children: header.map((cell: string) => ({
|
|
72
|
+
type: 'mdxJsxFlowElement',
|
|
73
|
+
name: 'Table.Th',
|
|
74
|
+
attributes: [],
|
|
75
|
+
children: parseMarkdown(cell)
|
|
76
|
+
}))
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
// TODO: Table.Cell ?
|
|
81
|
+
...rows.map((row: string[]) => ({
|
|
82
|
+
type: 'mdxJsxFlowElement',
|
|
83
|
+
name: 'Table.Tr',
|
|
84
|
+
attributes: [],
|
|
85
|
+
children: row.map((cell: string) => ({
|
|
86
|
+
type: 'mdxJsxFlowElement',
|
|
87
|
+
name: 'Table.Td',
|
|
88
|
+
attributes: [],
|
|
89
|
+
children: parseMarkdown(cell)
|
|
90
|
+
}))
|
|
91
|
+
}))
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
Object.assign(node, jsxNode);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (node.attributes) {
|
|
100
|
+
const jsxProps = []
|
|
101
|
+
|
|
102
|
+
for (let [key, value] of Object.entries(node.attributes)) {
|
|
103
|
+
if (typeof value === "string" && !value.startsWith("<")) {
|
|
104
|
+
attributes.push({
|
|
105
|
+
type: 'mdxJsxAttribute',
|
|
106
|
+
name: key,
|
|
107
|
+
value: value
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
jsxProps.push(`${key}={${value}}`)
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const mdxString = `<Fragment ${jsxProps.join(" ")}></Fragment>`
|
|
116
|
+
|
|
117
|
+
const ast = unified()
|
|
118
|
+
.use(remarkParse)
|
|
119
|
+
.use(remarkMdx)
|
|
120
|
+
.parse(mdxString);
|
|
121
|
+
|
|
122
|
+
if (ast && ast.children[0] && ast.children[0].attributes) {
|
|
123
|
+
for (const attr of ast.children[0].attributes) {
|
|
124
|
+
// TODO: support markdown also e.g Hello `World` - currently it mus be: Hello <code>World</code>
|
|
125
|
+
attributes.push(attr);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const jsxNode = {
|
|
131
|
+
type: 'mdxJsxFlowElement',
|
|
132
|
+
name: toPascalCase(node.name),
|
|
133
|
+
attributes: attributes,
|
|
134
|
+
children: node.children
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
Object.assign(node, jsxNode);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {Plugin} from 'unified';
|
|
2
|
+
import {Node as UnistNode} from 'unist';
|
|
3
|
+
import {visit} from 'unist-util-visit';
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
var page: boolean | null | undefined
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* This plugin extracts the `page` variable from the markdown file.
|
|
11
|
+
* This variable(`page`) is used to determine if theme should be dropped out.
|
|
12
|
+
*
|
|
13
|
+
* It means that if page=true, theme is not used, and we can use the markdown file as a standalone page.
|
|
14
|
+
*/
|
|
15
|
+
export const extractPage: Plugin = () => {
|
|
16
|
+
return (tree: UnistNode) => {
|
|
17
|
+
visit(tree, 'exportNamedDeclaration', (node: any) => {
|
|
18
|
+
const declaration = node.declaration;
|
|
19
|
+
|
|
20
|
+
if (!declaration || !declaration.declarations || !declaration.declarations.length) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// seek declarations like export const page = true in md files
|
|
25
|
+
declaration.declarations.forEach((decl: any) => {
|
|
26
|
+
if (decl.id.name === 'page') {
|
|
27
|
+
global.page = decl.init as boolean;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {Plugin} from 'unified';
|
|
2
|
+
import {Node as UnistNode} from 'unist';
|
|
3
|
+
import {visit} from 'unist-util-visit';
|
|
4
|
+
|
|
5
|
+
interface ThemeSettings {
|
|
6
|
+
bigArticle: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
var themeSettings: ThemeSettings | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This plugin adds the `themeSettings` variable to the global scope.
|
|
15
|
+
* This variable is used to determine the theme settings for the current page.
|
|
16
|
+
*/
|
|
17
|
+
export const extractThemeSettings: Plugin = () => {
|
|
18
|
+
return (tree: UnistNode) => {
|
|
19
|
+
visit(tree, 'exportNamedDeclaration', (node: any) => {
|
|
20
|
+
const declaration = node.declaration;
|
|
21
|
+
if (declaration && declaration.declarations) {
|
|
22
|
+
declaration.declarations.forEach((decl: any) => {
|
|
23
|
+
if (decl.id.name === 'themeSettings') {
|
|
24
|
+
global.themeSettings = decl.init as ThemeSettings;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {Root, Heading} from "mdast";
|
|
2
|
+
import {MdxjsEsm} from "mdast-util-mdx";
|
|
3
|
+
import {Plugin} from "unified"; // TODO: use Plugin type
|
|
4
|
+
import {MdxJsxFlowElement, MdxJsxAttribute} from "mdast-util-mdx-jsx";
|
|
5
|
+
|
|
6
|
+
export type TocEntry = {
|
|
7
|
+
depth: number,
|
|
8
|
+
value: string,
|
|
9
|
+
attributes: { [key: string]: string },
|
|
10
|
+
children: TocEntry[]
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type CustomTag = {
|
|
14
|
+
name: RegExp,
|
|
15
|
+
depth: (name: string) => number
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export interface RemarkMdxTocOptions {
|
|
19
|
+
name?: string,
|
|
20
|
+
customTags?: CustomTag[],
|
|
21
|
+
minDepth?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// TODO: fix any
|
|
25
|
+
export const remarkMdxToc = (options: RemarkMdxTocOptions): Plugin => () => async (ast: any) => {
|
|
26
|
+
const {visit} = await import("unist-util-visit");
|
|
27
|
+
const {toString} = await import("mdast-util-to-string");
|
|
28
|
+
const {valueToEstree} = await import('estree-util-value-to-estree')
|
|
29
|
+
const {name: isIdentifierName} = await import('estree-util-is-identifier-name');
|
|
30
|
+
|
|
31
|
+
const mdast = ast as Root;
|
|
32
|
+
const name = options.name ?? "toc";
|
|
33
|
+
if (!isIdentifierName(name)) {
|
|
34
|
+
throw new Error(`Invalid name for an identifier: ${name}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const toc: TocEntry[] = [];
|
|
38
|
+
const flatToc: TocEntry[] = [];
|
|
39
|
+
const createEntry = (node: Heading | MdxJsxFlowElement, depth: number): TocEntry => {
|
|
40
|
+
let attributes = (node.data || {}) as TocEntry['attributes'];
|
|
41
|
+
if (node.type === "mdxJsxFlowElement") {
|
|
42
|
+
attributes = Object.fromEntries(
|
|
43
|
+
node.attributes
|
|
44
|
+
.filter(attribute => attribute.type === 'mdxJsxAttribute' && typeof attribute.value === 'string')
|
|
45
|
+
.map(attribute => [(attribute as MdxJsxAttribute).name, attribute.value])
|
|
46
|
+
) as TocEntry['attributes'];
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
depth,
|
|
50
|
+
value: toString(node, {includeImageAlt: false}),
|
|
51
|
+
attributes,
|
|
52
|
+
children: []
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
visit(mdast, ["heading", "mdxJsxFlowElement"], node => {
|
|
57
|
+
let depth = 0;
|
|
58
|
+
if (node.type === "mdxJsxFlowElement") {
|
|
59
|
+
let valid = false;
|
|
60
|
+
if (/^h[1-6]$/.test(node.name || "")) {
|
|
61
|
+
valid = true;
|
|
62
|
+
depth = parseInt(node.name!.substring(1));
|
|
63
|
+
} else if (options.customTags) {
|
|
64
|
+
for (const tag of options.customTags) {
|
|
65
|
+
if (tag.name.test(node.name || "")) {
|
|
66
|
+
valid = true;
|
|
67
|
+
depth = tag.depth(node.name || "");
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!valid) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
} else if (node.type === "heading") {
|
|
77
|
+
depth = node.depth;
|
|
78
|
+
} else {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (depth && (options?.minDepth && options.minDepth > depth)) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const entry = createEntry(node, depth);
|
|
87
|
+
flatToc.push(entry);
|
|
88
|
+
|
|
89
|
+
let parent: TocEntry[] = toc;
|
|
90
|
+
for (let i = flatToc.length - 1; i >= 0; --i) {
|
|
91
|
+
const current = flatToc[i];
|
|
92
|
+
if (current.depth < entry.depth) {
|
|
93
|
+
parent = current.children;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
parent.push(entry);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const tocExport: MdxjsEsm = {
|
|
101
|
+
type: "mdxjsEsm",
|
|
102
|
+
value: "",
|
|
103
|
+
data: {
|
|
104
|
+
estree: {
|
|
105
|
+
type: "Program",
|
|
106
|
+
sourceType: "module",
|
|
107
|
+
body: [
|
|
108
|
+
{
|
|
109
|
+
type: "ExportNamedDeclaration",
|
|
110
|
+
specifiers: [],
|
|
111
|
+
attributes: [],
|
|
112
|
+
source: null,
|
|
113
|
+
declaration: {
|
|
114
|
+
type: "VariableDeclaration",
|
|
115
|
+
kind: "const",
|
|
116
|
+
declarations: [
|
|
117
|
+
{
|
|
118
|
+
type: "VariableDeclarator",
|
|
119
|
+
id: {
|
|
120
|
+
type: "Identifier",
|
|
121
|
+
name
|
|
122
|
+
},
|
|
123
|
+
init: valueToEstree(toc)
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
mdast.children.unshift(tocExport);
|
|
133
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type {Plugin} from 'rollup';
|
|
2
|
+
import mdx from '@mdx-js/rollup';
|
|
3
|
+
|
|
4
|
+
import {RemarkMdxTocOptions, mdOptions} from "../md";
|
|
5
|
+
|
|
6
|
+
export interface VitePluginInterface {
|
|
7
|
+
toc: RemarkMdxTocOptions
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function vitePlugins(options: VitePluginInterface): Plugin[] {
|
|
11
|
+
return [
|
|
12
|
+
mdx(mdOptions(options.toc)),
|
|
13
|
+
];
|
|
14
|
+
}
|
package/src/fs.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {promises as fs} from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import {VFile} from "vfile";
|
|
5
|
+
import {compile as mdxCompile} from "@mdx-js/mdx";
|
|
6
|
+
|
|
7
|
+
import {mdOptions} from "../packages/md";
|
|
8
|
+
|
|
9
|
+
export async function compileBySlug(
|
|
10
|
+
slug: string,
|
|
11
|
+
mdx: boolean
|
|
12
|
+
): Promise<string> {
|
|
13
|
+
// TODO: cwd ?
|
|
14
|
+
const filePath = path.join(process.cwd(), `${slug}.${mdx ? "mdx" : "md"}`)
|
|
15
|
+
|
|
16
|
+
await fs.access(filePath)
|
|
17
|
+
|
|
18
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
19
|
+
|
|
20
|
+
return await compile(content, filePath)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function compile(content: string, filePath: string): Promise<string> {
|
|
24
|
+
const vfile = new VFile({
|
|
25
|
+
path: filePath,
|
|
26
|
+
value: content,
|
|
27
|
+
contents: content
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const opt = mdOptions({
|
|
31
|
+
minDepth: 2 // TODO: configurable?
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const compiled = await mdxCompile(vfile, {
|
|
35
|
+
remarkPlugins: opt.remarkPlugins,
|
|
36
|
+
rehypePlugins: opt.rehypePlugins,
|
|
37
|
+
recmaPlugins: [],
|
|
38
|
+
outputFormat: 'function-body',
|
|
39
|
+
development: false,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return String(compiled)
|
|
43
|
+
}
|