Skip to content

Commit 78a25a2

Browse files
committed
handle headings
1 parent 8c648aa commit 78a25a2

File tree

13 files changed

+519
-97
lines changed

13 files changed

+519
-97
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@
3131
"@types/js-yaml": "^4.0.0",
3232
"@types/marked": "^2.0.0",
3333
"@types/prismjs": "^1.16.4",
34+
"hast": "^1.0.0",
3435
"js-yaml": "^4.0.0",
3536
"marked": "^2.0.1",
37+
"mdast-util-to-hast": "^10.2.0",
38+
"mdast-util-to-string": "^2.0.0",
3639
"prettier": "^2.2.1",
3740
"prism-svelte": "^0.4.7",
3841
"prismjs": "^1.23.0",
@@ -47,6 +50,7 @@
4750
"unified": "^9.2.1",
4851
"unist-util-visit": "^2.0.3",
4952
"uvu": "^0.5.1",
53+
"vfile": "^4.2.1",
5054
"vfile-message": "^2.0.4"
5155
}
5256
}

pnpm-lock.yaml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/format/fixtures/api-docs-html.js

Lines changed: 153 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/format/format.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import markdown from "remark-parse";
33
import remark2rehype from "remark-rehype";
44
import html from "rehype-stringify";
55

6-
const processor = unified().use(markdown).use(remark2rehype).use(html);
6+
var processor = unified().use(markdown).use(remark2rehype).use(html);
77

88
// export const format_docs = {
99
// docs: format_api,
File renamed without changes.

src/format/format_api.ts

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -61,49 +61,49 @@ function get_slug_segments(): string[] {
6161
});
6262
}
6363

64-
function heading_renderer(
65-
text: string,
66-
level: number,
67-
rawtext: string
68-
): string {
69-
if (level < 3 || level > 5)
70-
throw new Error(
71-
`Only level 3 and 4 headings are allowed. Got level ${level} heading.`
72-
);
73-
74-
let slug = make_slug(
75-
level === 3
76-
? [section_title, rawtext].join(" ")
77-
: [...get_slug_segments(), rawtext].join(" ")
78-
);
79-
80-
if (level === 3 || level === 4) {
81-
const title = text.replace(/<\/?code>/g, "");
82-
const prev_section = section_stack[section_stack.length - 1];
83-
84-
if (level > prev_level) {
85-
section_stack.push(prev_section[prev_section.length - 1].sections || []);
86-
} else if (level < prev_level) {
87-
section_stack.pop();
88-
}
89-
90-
section_stack[section_stack.length - 1].push({
91-
slug,
92-
title,
93-
sections: [],
94-
});
95-
prev_level = level;
96-
}
97-
98-
return `
99-
<h${level}>
100-
<span id="${slug}" class="offset-anchor" ${
101-
level > 4 ? "data-scrollignore" : ""
102-
}></span>
103-
<a href="${dir}#${slug}" class="anchor" aria-hidden="true"></a>
104-
${text}
105-
</h${level}>`;
106-
}
64+
// function heading_renderer(
65+
// text: string,
66+
// level: number,
67+
// rawtext: string
68+
// ): string {
69+
// if (level < 3 || level > 5)
70+
// throw new Error(
71+
// `Only level 3 and 4 headings are allowed. Got level ${level} heading.`
72+
// );
73+
74+
// let slug = make_slug(
75+
// level === 3
76+
// ? [section_title, rawtext].join(" ")
77+
// : [...get_slug_segments(), rawtext].join(" ")
78+
// );
79+
80+
// if (level === 3 || level === 4) {
81+
// const title = text.replace(/<\/?code>/g, "");
82+
// const prev_section = section_stack[section_stack.length - 1];
83+
84+
// if (level > prev_level) {
85+
// section_stack.push(prev_section[prev_section.length - 1].sections || []);
86+
// } else if (level < prev_level) {
87+
// section_stack.pop();
88+
// }
89+
90+
// section_stack[section_stack.length - 1].push({
91+
// slug,
92+
// title,
93+
// sections: [],
94+
// });
95+
// prev_level = level;
96+
// }
97+
98+
// return `
99+
// <h${level}>
100+
// <span id="${slug}" class="offset-anchor" ${
101+
// level > 4 ? "data-scrollignore" : ""
102+
// }></span>
103+
// <a href="${dir}#${slug}" class="anchor" aria-hidden="true"></a>
104+
// ${text}
105+
// </h${level}>`;
106+
// }
107107

108108
const renderer = new marked.Renderer();
109109

@@ -135,11 +135,11 @@ export function format_api(
135135
const section_slug = make_slug(title);
136136

137137
// reset the stateful stuff
138-
dir = directory;
139-
prev_level = 3;
140-
sections = [];
141-
section_stack = [sections];
142-
block_open = false;
138+
// dir = directory;
139+
// prev_level = 3;
140+
// sections = [];
141+
// section_stack = [sections];
142+
// block_open = false;
143143

144144
const html = marked(content, { renderer });
145145

src/format/get_sections.test.ts

Whitespace-only changes.

src/format/get_sections.ts

Whitespace-only changes.

src/format/headings.test.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { suite } from "uvu";
2+
import * as assert from "uvu/assert";
3+
4+
import unified from "unified";
5+
import markdown from "remark-parse";
6+
import extract_frontmatter from "remark-frontmatter";
7+
import rehype from "remark-rehype";
8+
import stringify from "rehype-stringify";
9+
import vFile from "vfile";
10+
11+
import { headings, custom_vfile } from "./headings";
12+
13+
const { process } = unified()
14+
.use(markdown)
15+
.use(extract_frontmatter)
16+
.use(headings)
17+
.use(rehype)
18+
// .use(() => (tree) => console.log(JSON.stringify(tree, null, 2)))
19+
.use(stringify);
20+
21+
const _headings = suite("headings");
22+
23+
_headings("transforms and formats headings", async () => {
24+
const sections: unknown[] = [];
25+
const src = vFile({
26+
contents: `### hello`,
27+
data: {
28+
dir: "blog",
29+
sections,
30+
section_stack: [sections],
31+
section_title: "section",
32+
prev_level: 3,
33+
slugs: [],
34+
seen_slugs: new Map(),
35+
},
36+
});
37+
38+
const output = await process(src);
39+
40+
assert.equal(
41+
output.contents,
42+
`<h3><span id="section-hello" class="offset-anchor"></span><a href="blog#section-hello" class="anchor" aria-hidden></a>hello</h3>`
43+
);
44+
});
45+
46+
_headings("transforms and formats multi-level headings", async () => {
47+
const sections: unknown[] = [];
48+
const src = vFile({
49+
contents: `### subsection
50+
51+
#### subsubsection
52+
`,
53+
data: {
54+
dir: "blog",
55+
sections,
56+
section_stack: [sections],
57+
section_title: "section",
58+
prev_level: 3,
59+
slugs: [],
60+
seen_slugs: new Map(),
61+
},
62+
});
63+
64+
const output = await process(src);
65+
66+
assert.equal(
67+
output.contents,
68+
`<h3><span id="section-subsection" class="offset-anchor"></span><a href="blog#section-subsection" class="anchor" aria-hidden></a>subsection</h3>
69+
<h4><span id="section-subsection-subsubsection" class="offset-anchor"></span><a href="blog#section-subsection-subsubsection" class="anchor" aria-hidden></a>subsubsection</h4>`
70+
);
71+
});
72+
73+
_headings("transforms and formats multi-level headings", async () => {
74+
const sections: unknown[] = [];
75+
const src = vFile({
76+
contents: `### subsection
77+
78+
#### subsubsection
79+
80+
##### subsubsubsection
81+
82+
`,
83+
data: {
84+
dir: "blog",
85+
sections,
86+
section_stack: [sections],
87+
section_title: "section",
88+
prev_level: 3,
89+
slugs: [],
90+
seen_slugs: new Map(),
91+
},
92+
});
93+
94+
const output = await process(src);
95+
96+
assert.equal(
97+
output.contents,
98+
`<h3><span id="section-subsection-1" class="offset-anchor"></span><a href="blog#section-subsection-1" class="anchor" aria-hidden></a>subsection</h3>
99+
<h4><span id="section-subsection-1-subsubsection" class="offset-anchor"></span><a href="blog#section-subsection-1-subsubsection" class="anchor" aria-hidden></a>subsubsection</h4>
100+
<h5><span id="section-subsection-1-subsubsection-subsubsubsection" class="offset-anchor" data-scrollignore></span><a href="blog#section-subsection-1-subsubsection-subsubsubsection" class="anchor" aria-hidden></a>subsubsubsection</h5>`
101+
);
102+
});
103+
104+
_headings.only("transforms and formats multi-level headings", async () => {
105+
const sections: unknown[] = [];
106+
const src = vFile({
107+
contents: `### subsection
108+
109+
#### subsubsection
110+
111+
##### subsubsubsection
112+
113+
### one
114+
115+
#### two
116+
117+
##### three
118+
119+
#### four
120+
121+
`,
122+
data: {
123+
dir: "blog",
124+
sections,
125+
section_stack: [sections],
126+
section_title: "section",
127+
prev_level: 3,
128+
slugs: [],
129+
seen_slugs: new Map(),
130+
},
131+
});
132+
133+
const output = await process(src);
134+
135+
assert.equal(
136+
output.contents,
137+
`<h3><span id="section-subsection" class="offset-anchor"></span><a href="blog#section-subsection" class="anchor" aria-hidden></a>subsection</h3>
138+
<h4><span id="section-subsection-subsubsection" class="offset-anchor"></span><a href="blog#section-subsection-subsubsection" class="anchor" aria-hidden></a>subsubsection</h4>
139+
<h5><span id="section-subsection-subsubsection-subsubsubsection" class="offset-anchor" data-scrollignore></span><a href="blog#section-subsection-subsubsection-subsubsubsection" class="anchor" aria-hidden></a>subsubsubsection</h5>
140+
<h3><span id="section-one" class="offset-anchor"></span><a href="blog#section-one" class="anchor" aria-hidden></a>one</h3>
141+
<h4><span id="section-one-two" class="offset-anchor"></span><a href="blog#section-one-two" class="anchor" aria-hidden></a>two</h4>
142+
<h5><span id="section-one-two-three" class="offset-anchor" data-scrollignore></span><a href="blog#section-one-two-three" class="anchor" aria-hidden></a>three</h5>
143+
<h4><span id="section-one-four" class="offset-anchor"></span><a href="blog#section-one-four" class="anchor" aria-hidden></a>four</h4>`
144+
);
145+
});
146+
147+
_headings.run();

0 commit comments

Comments
 (0)