astro-custom-toc 1.0.4 → 1.1.1
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/dist/index.d.ts
ADDED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { remarkCustomToc, RemarkCustomTocOptions } from "./remark-custom-toc";
|
|
1
|
+
import { remarkCustomToc } from "./remark-custom-toc.js";
|
|
3
2
|
import remarkComment from "remark-comment";
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const integration: AstroIntegration = {
|
|
3
|
+
const astroCustomToc = (options) => {
|
|
4
|
+
const integration = {
|
|
7
5
|
name: "astro-custom-toc",
|
|
8
6
|
hooks: {
|
|
9
7
|
"astro:config:setup": ({ config, updateConfig }) => {
|
|
@@ -24,21 +22,16 @@ const astroCustomToc = (options?: RemarkCustomTocOptions) => {
|
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
};
|
|
27
|
-
|
|
28
25
|
return integration;
|
|
29
26
|
};
|
|
30
|
-
|
|
31
|
-
const checkOrder = (config: AstroConfig) => {
|
|
27
|
+
const checkOrder = (config) => {
|
|
32
28
|
const customTocIndex = config.integrations.findIndex((i) => i.name === "astro-custom-toc");
|
|
33
29
|
const mdxIndex = config.integrations.findIndex((i) => i.name === "@astrojs/mdx");
|
|
34
30
|
if (mdxIndex > -1 && customTocIndex > mdxIndex) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`.trim()
|
|
40
|
-
);
|
|
31
|
+
throw new Error(`
|
|
32
|
+
MDX integration configured before astro-custom-toc.
|
|
33
|
+
\`astroCustomToc()\` must be loaded before \`mdx()\`.
|
|
34
|
+
`.trim());
|
|
41
35
|
}
|
|
42
36
|
};
|
|
43
|
-
|
|
44
37
|
export default astroCustomToc;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AstroUserConfig } from "astro";
|
|
2
|
+
export type RemarkCustomTocTemplate = (html: string) => string;
|
|
3
|
+
export interface RemarkCustomTocOptions {
|
|
4
|
+
template?: RemarkCustomTocTemplate;
|
|
5
|
+
maxDepth?: number;
|
|
6
|
+
ordered?: boolean;
|
|
7
|
+
}
|
|
8
|
+
type RemarkPlugin = NonNullable<NonNullable<AstroUserConfig["markdown"]>["remarkPlugins"]>[number];
|
|
9
|
+
export declare const remarkCustomToc: RemarkPlugin;
|
|
10
|
+
export {};
|
|
@@ -1,39 +1,7 @@
|
|
|
1
|
-
import type { AstroUserConfig } from "astro";
|
|
2
1
|
import { visit } from "unist-util-visit";
|
|
3
2
|
import Slugger from "github-slugger";
|
|
4
3
|
import { JSDOM } from "jsdom";
|
|
5
|
-
|
|
6
|
-
interface Heading {
|
|
7
|
-
slug: string;
|
|
8
|
-
text: string;
|
|
9
|
-
depth: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type RemarkCustomTocTemplate = (html: string) => string;
|
|
13
|
-
|
|
14
|
-
export interface RemarkCustomTocOptions {
|
|
15
|
-
template?: RemarkCustomTocTemplate;
|
|
16
|
-
maxDepth?: number;
|
|
17
|
-
ordered?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type RemarkPlugin = NonNullable<NonNullable<AstroUserConfig["markdown"]>["remarkPlugins"]>[number];
|
|
21
|
-
|
|
22
|
-
interface VFile {
|
|
23
|
-
data: {
|
|
24
|
-
astro?: {
|
|
25
|
-
frontmatter: Record<string, any>;
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface CommentNode {
|
|
31
|
-
type: "comment";
|
|
32
|
-
value: "";
|
|
33
|
-
commentValue: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const defaultTemplate = (html: string) => {
|
|
4
|
+
const defaultTemplate = (html) => {
|
|
37
5
|
return `
|
|
38
6
|
<aside class="toc">
|
|
39
7
|
<h2>Contents</h2>
|
|
@@ -42,63 +10,51 @@ const defaultTemplate = (html: string) => {
|
|
|
42
10
|
</nav>
|
|
43
11
|
</aside>`.trim();
|
|
44
12
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
ordered = false
|
|
50
|
-
}: RemarkCustomTocOptions = {}) => {
|
|
51
|
-
return (tree, { data }: VFile) => {
|
|
52
|
-
if (data.astro && data.astro.frontmatter.showToc !== true) return;
|
|
53
|
-
|
|
13
|
+
export const remarkCustomToc = ({ template = defaultTemplate, maxDepth = 3, ordered = false } = {}) => {
|
|
14
|
+
return (tree, { data }) => {
|
|
15
|
+
if (data.astro && data.astro.frontmatter.showToc !== true)
|
|
16
|
+
return;
|
|
54
17
|
const slugs = new Slugger();
|
|
55
18
|
slugs.reset();
|
|
56
|
-
|
|
57
|
-
const headings: Heading[] = [];
|
|
19
|
+
const headings = [];
|
|
58
20
|
visit(tree, "heading", (node) => {
|
|
59
21
|
const { depth } = node;
|
|
60
|
-
const
|
|
61
|
-
// @ts-ignore
|
|
62
|
-
const text = textNode ? textNode.value : "";
|
|
22
|
+
const text = node.children.map((n) => ("value" in n ? n.value : "")).join("");
|
|
63
23
|
const slug = slugs.slug(text);
|
|
64
24
|
// @ts-ignore
|
|
65
25
|
node.data = { id: slug };
|
|
66
26
|
headings.push({ slug, text, depth });
|
|
67
27
|
});
|
|
68
|
-
|
|
69
28
|
let tocIndex = 0;
|
|
70
|
-
visit(tree, "comment", (node
|
|
29
|
+
visit(tree, "comment", (node, index) => {
|
|
71
30
|
if (node.commentValue.trim().toLowerCase() === "toc" && index !== undefined) {
|
|
72
31
|
tocIndex = index;
|
|
73
32
|
}
|
|
74
33
|
});
|
|
75
|
-
|
|
76
34
|
visit(tree, "html", (node, index) => {
|
|
77
35
|
if (node.value.trim().toLowerCase() === "<!-- toc -->" && index !== undefined) {
|
|
78
36
|
tocIndex = index;
|
|
79
37
|
}
|
|
80
38
|
});
|
|
81
|
-
|
|
82
39
|
const toc = generateToc(template, maxDepth, ordered, headings);
|
|
83
40
|
if (tocIndex === 0) {
|
|
84
41
|
// @ts-ignore
|
|
85
42
|
tree.children.unshift(toc);
|
|
86
|
-
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
87
45
|
// @ts-ignore
|
|
88
46
|
tree.children.splice(tocIndex, 1, toc);
|
|
89
47
|
}
|
|
90
48
|
};
|
|
91
49
|
};
|
|
92
|
-
|
|
93
|
-
const generateToc = (template: RemarkCustomTocTemplate, maxDepth: number, ordered: boolean, headings: Heading[]) => {
|
|
50
|
+
const generateToc = (template, maxDepth, ordered, headings) => {
|
|
94
51
|
const { document } = new JSDOM().window;
|
|
95
|
-
|
|
96
|
-
const toc: HTMLElement = document.createElement(ordered ? "ol" : "ul");
|
|
52
|
+
const toc = document.createElement(ordered ? "ol" : "ul");
|
|
97
53
|
let currentDepth = headings[0].depth;
|
|
98
54
|
let currentParent = toc;
|
|
99
55
|
for (const heading of headings) {
|
|
100
|
-
if (heading.depth > maxDepth)
|
|
101
|
-
|
|
56
|
+
if (heading.depth > maxDepth)
|
|
57
|
+
continue;
|
|
102
58
|
if (heading.depth === currentDepth) {
|
|
103
59
|
const li = document.createElement("li");
|
|
104
60
|
const a = document.createElement("a");
|
|
@@ -107,7 +63,8 @@ const generateToc = (template: RemarkCustomTocTemplate, maxDepth: number, ordere
|
|
|
107
63
|
li.appendChild(a);
|
|
108
64
|
currentParent.appendChild(li);
|
|
109
65
|
currentDepth = heading.depth;
|
|
110
|
-
}
|
|
66
|
+
}
|
|
67
|
+
else if (heading.depth > currentDepth) {
|
|
111
68
|
const ul = document.createElement(ordered ? "ol" : "ul");
|
|
112
69
|
const li = document.createElement("li");
|
|
113
70
|
const a = document.createElement("a");
|
|
@@ -118,9 +75,10 @@ const generateToc = (template: RemarkCustomTocTemplate, maxDepth: number, ordere
|
|
|
118
75
|
currentParent.appendChild(ul);
|
|
119
76
|
currentParent = ul;
|
|
120
77
|
currentDepth = heading.depth;
|
|
121
|
-
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
122
80
|
for (let i = 0; i < currentDepth - heading.depth; i++) {
|
|
123
|
-
currentParent = currentParent.parentElement
|
|
81
|
+
currentParent = currentParent.parentElement;
|
|
124
82
|
}
|
|
125
83
|
const li = document.createElement("li");
|
|
126
84
|
const a = document.createElement("a");
|
|
@@ -131,7 +89,6 @@ const generateToc = (template: RemarkCustomTocTemplate, maxDepth: number, ordere
|
|
|
131
89
|
currentDepth = heading.depth;
|
|
132
90
|
}
|
|
133
91
|
}
|
|
134
|
-
|
|
135
92
|
return {
|
|
136
93
|
type: "html",
|
|
137
94
|
value: template(toc.outerHTML)
|
package/package.json
CHANGED
|
@@ -1,44 +1,49 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "astro-custom-toc",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Astro Integration to generate a customizable table of contents",
|
|
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
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "astro-custom-toc",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Astro Integration to generate a customizable table of contents",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc",
|
|
7
|
+
"format": "prettier ./src/ --write",
|
|
8
|
+
"format:check": "prettier ./src/ --check",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"./dist/"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Robot-Inventor/astro-custom-toc.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"astro",
|
|
23
|
+
"withastro",
|
|
24
|
+
"ui",
|
|
25
|
+
"remark",
|
|
26
|
+
"markdown",
|
|
27
|
+
"astro-integration"
|
|
28
|
+
],
|
|
29
|
+
"author": "Robot-Inventor",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/Robot-Inventor/astro-custom-toc/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/Robot-Inventor/astro-custom-toc#readme",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"github-slugger": "^2.0.0",
|
|
37
|
+
"jsdom": "^24.0.0",
|
|
38
|
+
"remark-comment": "^1.0.0",
|
|
39
|
+
"typescript": "^5.3.3",
|
|
40
|
+
"unist-util-visit": "^5.0.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"astro": "^4.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/jsdom": "^21.1.6",
|
|
47
|
+
"prettier": "^3.2.5"
|
|
48
|
+
}
|
|
49
|
+
}
|