Skip to content

Commit 604f46f

Browse files
authored
docs: add util to generate clean markdown for a file (medusajs#11303)
1 parent 3c51709 commit 604f46f

23 files changed

+832
-37
lines changed

www/packages/docs-utils/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
"watch": "tsc --watch"
2929
},
3030
"dependencies": {
31+
"@mdx-js/mdx": "^3.1.0",
3132
"remark-frontmatter": "^5.0.0",
33+
"remark-mdx": "^3.1.0",
3234
"remark-parse": "^11.0.0",
3335
"remark-stringify": "^11.0.0",
3436
"to-vfile": "^8.0.0",

www/packages/remark-rehype-plugins/src/utils/estree-to-js.ts renamed to www/packages/docs-utils/src/estree-to-js.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
ExpressionJsVarLiteral,
88
LiteralExpression,
99
ObjectExpression,
10-
} from "../types/index.js"
10+
} from "types"
1111

1212
export function estreeToJs(estree: Estree) {
1313
// TODO improve on this utility. Currently it's implemented to work

www/packages/remark-rehype-plugins/src/utils/expression-is-utils.ts renamed to www/packages/docs-utils/src/expression-is-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ExpressionJsVarLiteral, ExpressionJsVarObj } from "../types/index.js"
1+
import { ExpressionJsVarLiteral, ExpressionJsVarObj } from "types"
22

33
export function isExpressionJsVarLiteral(
44
expression: unknown
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import remarkMdx from "remark-mdx"
2+
import remarkParse from "remark-parse"
3+
import remarkStringify from "remark-stringify"
4+
import { read } from "to-vfile"
5+
import { UnistNode, UnistNodeWithData, UnistTree } from "types"
6+
import { Plugin, Transformer, unified } from "unified"
7+
import { SKIP } from "unist-util-visit"
8+
import type { VFile } from "vfile"
9+
import {
10+
parseCard,
11+
parseCardList,
12+
parseCodeTabs,
13+
parseDetails,
14+
parseNote,
15+
parsePrerequisites,
16+
parseSourceCodeLink,
17+
parseTable,
18+
parseTabs,
19+
parseTypeList,
20+
parseWorkflowDiagram,
21+
} from "./utils/parse-elms.js"
22+
23+
const parseComponentsPlugin = (): Transformer => {
24+
return async (tree) => {
25+
const { visit } = await import("unist-util-visit")
26+
27+
let pageTitle = ""
28+
29+
visit(
30+
tree as UnistTree,
31+
["mdxJsxFlowElement", "element", "mdxjsEsm", "heading"],
32+
(node: UnistNode, index, parent) => {
33+
if (typeof index !== "number" || !parent) {
34+
return
35+
}
36+
if (
37+
node.type === "mdxjsEsm" &&
38+
node.value?.startsWith("export const metadata = ") &&
39+
node.data &&
40+
"estree" in node.data
41+
) {
42+
const regexMatch = /title: (?<title>.+),?/.exec(node.value)
43+
if (regexMatch?.groups?.title) {
44+
pageTitle = regexMatch.groups.title
45+
.replace(/,$/, "")
46+
.replaceAll(/\$\{.+\}/g, "")
47+
.replaceAll(/^['"`]/g, "")
48+
.replaceAll(/['"`]$/g, "")
49+
.trim()
50+
}
51+
}
52+
if (node.type === "heading") {
53+
if (
54+
node.depth === 1 &&
55+
node.children?.length &&
56+
node.children[0].value === "metadata.title"
57+
) {
58+
node.children[0] = {
59+
type: "text",
60+
value: pageTitle,
61+
}
62+
}
63+
return
64+
}
65+
if (
66+
node.type === "mdxjsEsm" ||
67+
node.name === "Feedback" ||
68+
node.name === "ChildDocs" ||
69+
node.name === "DetailsList"
70+
) {
71+
parent?.children.splice(index, 1)
72+
return [SKIP, index]
73+
}
74+
switch (node.name) {
75+
case "Card":
76+
return parseCard(node, index, parent)
77+
case "CardList":
78+
return parseCardList(node as UnistNodeWithData, index, parent)
79+
case "CodeTabs":
80+
return parseCodeTabs(node as UnistNodeWithData, index, parent)
81+
case "Details":
82+
return parseDetails(node as UnistNodeWithData, index, parent)
83+
case "Note":
84+
return parseNote(node, index, parent)
85+
case "Prerequisites":
86+
return parsePrerequisites(node as UnistNodeWithData, index, parent)
87+
case "SourceCodeLink":
88+
return parseSourceCodeLink(node as UnistNodeWithData, index, parent)
89+
case "Table":
90+
return parseTable(node as UnistNodeWithData, index, parent)
91+
case "Tabs":
92+
return parseTabs(node as UnistNodeWithData, index, parent)
93+
case "TypeList":
94+
return parseTypeList(node as UnistNodeWithData, index, parent)
95+
case "WorkflowDiagram":
96+
return parseWorkflowDiagram(
97+
node as UnistNodeWithData,
98+
index,
99+
parent
100+
)
101+
}
102+
}
103+
)
104+
}
105+
}
106+
107+
const getParsedAsString = (file: VFile): string => {
108+
return file.toString().replaceAll(/^([\s]*)\* /gm, "$1- ")
109+
}
110+
111+
export const getCleanMd = async (
112+
filePath: string,
113+
plugins?: {
114+
before?: Plugin[]
115+
after?: Plugin[]
116+
}
117+
): Promise<string> => {
118+
if (!filePath.endsWith(".md") && !filePath.endsWith(".mdx")) {
119+
return ""
120+
}
121+
const unifier = unified().use(remarkParse).use(remarkMdx).use(remarkStringify)
122+
123+
plugins?.before?.forEach((plugin) => {
124+
unifier.use(...(Array.isArray(plugin) ? plugin : [plugin]))
125+
})
126+
127+
unifier.use(parseComponentsPlugin)
128+
129+
plugins?.after?.forEach((plugin) => {
130+
unifier.use(...(Array.isArray(plugin) ? plugin : [plugin]))
131+
})
132+
133+
const parsed = await unifier.process(await read(filePath))
134+
135+
return getParsedAsString(parsed)
136+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
export * from "./estree-to-js.js"
2+
export * from "./expression-is-utils.js"
13
export * from "./find-title.js"
4+
export * from "./get-clean-md.js"
25
export * from "./get-file-slug-sync.js"
36
export * from "./get-file-slug.js"
47
export * from "./get-front-matter.js"

0 commit comments

Comments
 (0)