-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpreprocess.ts
More file actions
88 lines (80 loc) · 2.88 KB
/
Copy pathpreprocess.ts
File metadata and controls
88 lines (80 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Transform the small set of MkDocs-Material extensions used in the source
// docs into plain CommonMark / GFM that react-markdown can render.
//
// What we handle, and why each rule exists:
// - `:octicons-...:{ .md-button }` → stripped (button-styled icon links)
// - `!!! type "title"` admonitions → rendered as a styled blockquote with
// a leading **title** line. react-markdown
// then renders the blockquote; the docs
// CSS gives it the colored side-bar treatment.
// - `!!swagger ./openapi.json!!` → replaced with a callout pointing to
// the live `/docs` Swagger UI on a
// running instance, since we don't ship
// the spec from this site.
export type AdmonitionKind = "note" | "warning" | "danger" | "tip" | "info";
function stripOcticonButtons(input: string): string {
// Pattern: [Label :octicons-x:](href){ .md-button } → [Label](href)
return input
.replace(/:octicons-[\w-]+:/g, "")
.replace(/\)\{\s*\.md-button[^}]*\}/g, ")");
}
function rewriteSwagger(input: string): string {
return input.replace(/!!swagger[^!]*!!/g, () =>
[
"> **Live API docs**",
">",
"> Every running Pufferblow instance serves an interactive",
"> Swagger UI at `/docs` and the raw OpenAPI schema at",
"> `/openapi.json`. Point your browser at",
"> `https://your.instance.example/docs` to explore endpoints.",
].join("\n"),
);
}
function transformAdmonitions(input: string): string {
const lines = input.split("\n");
const out: string[] = [];
let i = 0;
while (i < lines.length) {
const line = lines[i];
const m = /^!!!\s+(\w+)(?:\s+"([^"]*)")?\s*$/.exec(line);
if (!m) {
out.push(line);
i++;
continue;
}
const kind = m[1].toLowerCase();
const title = m[2] ?? kind[0].toUpperCase() + kind.slice(1);
i++;
// Consume the indented body. MkDocs requires 4-space indentation.
const body: string[] = [];
while (i < lines.length) {
const next = lines[i];
if (next === "") {
// blank lines are allowed inside the block
body.push("");
i++;
continue;
}
if (/^\s{4}/.test(next)) {
body.push(next.slice(4));
i++;
continue;
}
break;
}
// Trim trailing blank lines we may have absorbed
while (body.length && body[body.length - 1] === "") body.pop();
out.push(`> **${title}**`);
out.push(">");
for (const b of body) out.push(b === "" ? ">" : `> ${b}`);
out.push("");
}
return out.join("\n");
}
export function preprocessMarkdown(input: string): string {
let s = input;
s = stripOcticonButtons(s);
s = rewriteSwagger(s);
s = transformAdmonitions(s);
return s;
}