Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8116f74

Browse files
Use custom toc and heading-links remark plugins
1 parent 563526d commit 8116f74

11 files changed

+828
-522
lines changed

‎.eslintrc‎ renamed to ‎.eslintrc.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"generator-star-spacing": ["error", { "before": false, "after": true }],
2323
"indent": ["error", 2, { "ignoreComments": true, "SwitchCase": 1 }],
2424
"linebreak-style": "error",
25+
"no-console": ["error", { "allow": ["error"] }],
2526
"no-trailing-spaces": "error",
2627
"no-unused-vars": ["error", { "argsIgnorePattern": "_.*" }],
2728
"prefer-const": ["error", { "destructuring": "all" }],

‎README.md‎

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,38 @@ features they make available to you.
4343
- [remark-gfm](https://github.com/remarkjs/remark-gfm) -- Adds support for
4444
Github Flavored Markdown specific markdown features such as autolink literals,
4545
footnotes, strikethrough, tables, and tasklists.
46-
- [remark-number-headings](/json-schema-org/json-schema-spec/blob/main/remark-number-headings.js)
47-
-- Adds hierarchical section numbers to headings.
48-
- [remark-toc](https://github.com/remarkjs/remark-toc) -- Adds a table of
49-
contents in a section with a header called "Table of Contents".
46+
- [remark-heading-id](https://github.com/imcuttle/remark-heading-id) -- Adds
47+
support for `{#my-anchor}` syntax to add an `id` to an element so it can be
48+
referenced using URI fragment syntax.
49+
- [remark-headings](/json-schema-org/json-schema-spec/blob/main/remark-headings.js)
50+
-- A collection of enhancements for headings.
51+
- Adds hierarchical section numbers to headings.
52+
- Use the `[Appendix]` prefix on headings that should be numbered as an
53+
appendix.
54+
- Adds id anchors to headers that don't have one
55+
- Example: `#section-2-13`
56+
- Example: `#appendix-a`
57+
- Makes the heading a link utilizing its anchor
58+
- [remark-reference-links](/json-schema-org/json-schema-spec/blob/main/remark-reference-link.js)
59+
-- Adds new syntax for referencing a section of the spec using the section
60+
number as the link text.
61+
- Example:
62+
```markdown
63+
## Foo {#foo}
64+
65+
## Bar
66+
This is covered in {{foo}} // --> Renders to "This is covered in [Section
67+
2.3](#foo)"
68+
- Link text will use "Section" or "Appendix" as needed
69+
```
70+
- [remark-table-of-contents](/json-schema-org/json-schema-spec/blob/main/remark-table-of-contents.js)
71+
-- Adds a table of contents in a section with a header called "Table of
72+
Contents".
5073
- [remark-torchlight](https://github.com/torchlight-api/remark-torchlight) --
5174
Syntax highlighting and more using https://torchlight.dev. Features include
5275
line numbers and line highlighting.
53-
- [rehype-slug](https://github.com/rehypejs/rehype-slug) -- Adds `id` anchors to
54-
header so they can be linked to with URI fragment syntax.
55-
- [rehype-autolink-headings](https://github.com/rehypejs/rehype-autolink-headings)
56-
-- Makes headings clickable.
5776
- [remark-flexible-containers](https://github.com/ipikuka/remark-flexible-containers)
58-
-- Add a callout box using the following syntax. Supported container types are
77+
- Add a callout box using the following syntax. Supported container types are
5978
`warning`, `note`, and `experimental`.
6079

6180
```

‎build/build.js‎

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,17 @@ import dotenv from "dotenv";
22
import { readFileSync, writeFileSync } from "node:fs";
33
import { reporter } from "vfile-reporter";
44
import { remark } from "remark";
5-
import rehypeAutolinkHeadings from "rehype-autolink-headings";
6-
import rehypeSlug from "rehype-slug";
7-
import rehypeStringify from "rehype-stringify";
85
import remarkFlexibleContainers from "remark-flexible-containers";
96
import remarkGfm from "remark-gfm";
107
import remarkHeadingId from "remark-heading-id";
11-
import remarkHeadings from "@vcarl/remark-headings";
12-
import remarkNumberHeadings from "./remark-number-headings.js";
8+
import remarkHeadings from "./remark-headings.js";
139
import remarkPresetLintMarkdownStyleGuide from "remark-preset-lint-markdown-style-guide";
1410
import remarkRehype from "remark-rehype";
15-
import remarkSectionLinks from "./remark-section-links.js";
16-
import remarkToc from "remark-toc";
11+
import remarkReferenceLinks from "./remark-reference-links.js";
12+
import remarkTableOfContents from "./remark-table-of-contents.js";
13+
import remarkTorchLight from "remark-torchlight";
1714
import remarkValidateLinks from "remark-validate-links";
18-
import torchLight from "remark-torchlight";
15+
import rehypeStringify from "rehype-stringify";
1916

2017

2118
dotenv.config();
@@ -25,26 +22,20 @@ dotenv.config();
2522
const html = await remark()
2623
.use(remarkPresetLintMarkdownStyleGuide)
2724
.use(remarkGfm)
28-
.use(torchLight)
29-
.use(remarkFlexibleContainers)
3025
.use(remarkHeadingId)
31-
.use(remarkNumberHeadings, {
26+
.use(remarkHeadings, {
3227
startDepth: 2,
33-
skip: ["Abstract", "Note to Readers", "Table of Contents", "Authors' Addresses", "\\[.*\\]", "draft-.*"],
34-
appendixToken: "[Appendix]",
35-
appendixPrefix: "Appendix"
28+
skip: ["Abstract", "Note to Readers", "Table of Contents", "Authors' Addresses", "\\[.*\\]", "draft-.*"]
3629
})
37-
.use(remarkHeadings)
38-
.use(remarkSectionLinks)
39-
.use(remarkToc,{
40-
tight: true,
41-
heading: "Table of Contents",
42-
skip: "\\[.*\\]|draft-.*"
30+
.use(remarkReferenceLinks)
31+
.use(remarkFlexibleContainers)
32+
.use(remarkTorchLight)
33+
.use(remarkTableOfContents,{
34+
startDepth: 2,
35+
skip: ["Abstract","Note to Readers","\\[.*\\]","Authors' Addresses","draft-.*"]
4336
})
4437
.use(remarkValidateLinks)
4538
.use(remarkRehype)
46-
.use(rehypeSlug)
47-
.use(rehypeAutolinkHeadings, { behavior: "wrap" })
4839
.use(rehypeStringify)
4940
.process(md);
5041

@@ -122,7 +113,7 @@ dotenv.config();
122113
</style>
123114
</head>
124115
<body>
125-
${String(html)}
116+
${html.toString()}
126117
</body>
127118
</html>`);
128119

‎build/remark-headings.js‎

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { visit } from "unist-util-visit";
2+
import { link, text } from "mdast-builder";
3+
import { findAndReplace } from "mdast-util-find-and-replace";
4+
import { toString as nodeToString } from "mdast-util-to-string";
5+
6+
7+
const defaultOptions = {
8+
startDepth: 1,
9+
skip: [],
10+
appendixToken: "[Appendix]",
11+
appendixPrefix: "Appendix"
12+
};
13+
14+
const remarkNumberHeadings = (options) => (tree, file) => {
15+
options = { ...defaultOptions, ...options };
16+
options.skip = new RegExp(`^(${options.skip.join("|")})$`, "u");
17+
18+
// Auto-number headings
19+
let sectionNumbers = [];
20+
21+
visit(tree, "heading", (headingNode) => {
22+
if (headingNode.depth < options.startDepth) {
23+
return;
24+
}
25+
26+
const headingText = nodeToString(headingNode);
27+
if (options.skip.test(headingText)) {
28+
return;
29+
}
30+
31+
if (!("data" in headingNode)) {
32+
headingNode.data = {};
33+
}
34+
35+
if (!("hProperties" in headingNode.data)) {
36+
headingNode.data.hProperties = {};
37+
}
38+
39+
if (headingText.startsWith(options.appendixToken)) {
40+
findAndReplace(headingNode, [options.appendixToken]);
41+
42+
const currentIndex = typeof sectionNumbers[headingNode.depth] === "string"
43+
? sectionNumbers[headingNode.depth]
44+
: "@";
45+
sectionNumbers[headingNode.depth] = String.fromCharCode(currentIndex.charCodeAt(0) + 1);
46+
sectionNumbers = sectionNumbers.slice(0, headingNode.depth + 1);
47+
48+
const sectionNumber = sectionNumbers.slice(options.startDepth, headingNode.depth + 1).join(".");
49+
headingNode.data.section = `${options.appendixPrefix} ${sectionNumber}`;
50+
51+
headingNode.children.splice(0, 0, text(`${headingNode.data.section}. `));
52+
} else {
53+
sectionNumbers[headingNode.depth] = (sectionNumbers[headingNode.depth] ?? 0) + 1;
54+
sectionNumbers = sectionNumbers.slice(0, headingNode.depth + 1);
55+
56+
const sectionNumber = sectionNumbers.slice(options.startDepth, headingNode.depth + 1).join(".");
57+
const prefix = typeof sectionNumbers[options.startDepth] === "string"
58+
? options.appendixPrefix
59+
: "Section";
60+
headingNode.data.section = `${prefix} ${sectionNumber}`;
61+
62+
headingNode.children.splice(0, 0, text(`${sectionNumber}. `));
63+
}
64+
65+
if (!("id" in headingNode.data)) {
66+
const sectionSlug = headingNode.data?.id
67+
?? headingNode.data.section.replaceAll(/[.]/g, "-").toLowerCase();
68+
headingNode.data.hProperties.id = sectionSlug;
69+
headingNode.data.id = sectionSlug;
70+
}
71+
});
72+
73+
// Build headings data used by ./remark-reference-links.js
74+
if (!("data" in file)) {
75+
file.data = {};
76+
}
77+
78+
file.data.headings = {};
79+
80+
visit(tree, "heading", (headingNode) => {
81+
if (headingNode.data?.id) {
82+
if (headingNode.data.id in file.data.headings) {
83+
file.message(`Found duplicate heading id "${headingNode.data.id}"`);
84+
}
85+
file.data.headings[headingNode.data.id] = headingNode;
86+
}
87+
});
88+
89+
// Make heading a link
90+
visit(tree, "heading", (headingNode) => {
91+
if (headingNode.data?.id) {
92+
headingNode.children = [link(`#${headingNode.data.id}`, "", headingNode.children)];
93+
}
94+
});
95+
};
96+
97+
export default remarkNumberHeadings;

‎build/remark-number-headings.js‎

Lines changed: 0 additions & 47 deletions
This file was deleted.

‎build/remark-reference-links.js‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { text, link } from "mdast-builder";
2+
import { toString as nodeToString } from "mdast-util-to-string";
3+
import { findAndReplace } from "mdast-util-find-and-replace";
4+
5+
6+
const referenceLink = /\{\{(?<id>.*?)\}\}/ug;
7+
8+
const remarkReferenceLinks = () => (tree, file) => {
9+
findAndReplace(tree, [referenceLink, (value, id) => {
10+
// file.data.headings comes from ./remark-headings.js
11+
if (!(id in file.data.headings)) {
12+
throw Error(`ReferenceLinkError: No header found with id "${id}"`);
13+
}
14+
15+
const headerText = nodeToString(file.data.headings[id]);
16+
const linkText = text(file.data.headings[id].data.section);
17+
return link(`#${id}`, headerText, [linkText]);
18+
}]);
19+
};
20+
21+
export default remarkReferenceLinks;

‎build/remark-section-links.js‎

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /