Skip to content

Commit f539e09

Browse files
ruibabyCopilot
andcommitted
Add markdown heading anchors to rendered content
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2dd069e commit f539e09

File tree

8 files changed

+47
-6
lines changed

8 files changed

+47
-6
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"gray-matter": "^4.0.3",
6161
"js-yaml": "^4.1.1",
6262
"markdown-it": "^14.1.1",
63+
"markdown-it-anchor": "^9.2.0",
6364
"mime-types": "^3.0.2",
6465
"ora": "^9.3.0",
6566
"pretty-bytes": "^7.1.0",

pnpm-lock.yaml

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

src/commands/post/__test__/markdown.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { join } from "node:path";
44

55
import { expect, test } from "vitest";
66

7+
import { renderContentByRawType } from "../../../utils/content.js";
78
import {
89
buildPostMarkdownFrontMatter,
910
parsePostMarkdownDocument,
@@ -69,7 +70,10 @@ test("resolvePostMarkdownImportPayload derives title, slug, and rendered markdow
6970
expect(payload.mutationInput.slug).toBe("hello-world");
7071
expect(payload.mutationInput.rawType).toBe("markdown");
7172
expect(payload.mutationInput.content).toBe("# Hello World\n\nParagraph.");
72-
expect(payload.mutationInput.renderedContent).toContain("<h1>Hello World</h1>");
73+
expect(payload.mutationInput.renderedContent).toBe(
74+
renderContentByRawType("# Hello World\n\nParagraph.", "markdown"),
75+
);
76+
expect(payload.mutationInput.renderedContent).toContain('id="hello-world"');
7377
} finally {
7478
await rm(tempDir, { recursive: true, force: true });
7579
}

src/commands/post/__test__/post-markdown-entry.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ halo:
132132
expect(promptState.checkbox).not.toHaveBeenCalled();
133133
expect(
134134
createMyPost.mock.calls[0]?.[0]?.post?.metadata?.annotations?.[CONTENT_JSON_ANNOTATION],
135-
).toContain("<h1>Hello Halo</h1>");
135+
).toContain('id=\\"hello-halo\\"');
136136

137137
const fileContent = await readFile(filePath, "utf8");
138138
expect(fileContent).toContain("title: Hello Halo");

src/commands/post/__test__/post.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,18 @@ test("withSerializedContentAnnotation preserves existing annotations", () => {
5858
},
5959
{
6060
raw: "# Halo",
61-
content: "<h1>Halo</h1>",
61+
content: renderContentByRawType("# Halo", "markdown"),
6262
rawType: "markdown",
6363
},
6464
);
6565

6666
expect(metadata.annotations).toMatchObject({
6767
existing: "value",
68-
[CONTENT_JSON_ANNOTATION]: '{"raw":"# Halo","content":"<h1>Halo</h1>","rawType":"markdown"}',
68+
[CONTENT_JSON_ANNOTATION]: JSON.stringify({
69+
raw: "# Halo",
70+
content: renderContentByRawType("# Halo", "markdown"),
71+
rawType: "markdown",
72+
}),
6973
});
7074
});
7175

src/commands/single-page/__test__/single-page-json-entry.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { afterEach, expect, test, vi } from "vitest";
22

3+
import { renderContentByRawType } from "../../../utils/content.js";
34
import { tryRunSinglePageCommand } from "../index.js";
45

56
afterEach(() => {
@@ -87,7 +88,7 @@ test("tryRunSinglePageCommand imports json as a new single page when it does not
8788
},
8889
content: {
8990
raw: "# About",
90-
content: "<h1>About</h1>\n",
91+
content: renderContentByRawType("# About", "markdown"),
9192
rawType: "markdown",
9293
},
9394
},
@@ -169,7 +170,7 @@ test("tryRunSinglePageCommand imports json by updating an existing single page",
169170
},
170171
content: {
171172
raw: "# About",
172-
content: "<h1>About</h1>\n",
173+
content: renderContentByRawType("# About", "markdown"),
173174
rawType: "markdown",
174175
},
175176
},

src/utils/__test__/content.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { expect, test } from "vitest";
2+
3+
import { renderContentByRawType } from "../content.js";
4+
5+
test("renderContentByRawType adds heading anchors for markdown headings", () => {
6+
const rendered = renderContentByRawType("# Hello Halo", "markdown");
7+
8+
expect(rendered).toContain('id="hello-halo"');
9+
expect(rendered).toContain(">Hello Halo</h1>");
10+
});
11+
12+
test("renderContentByRawType leaves html raw content unchanged", () => {
13+
expect(renderContentByRawType("<h1>Hello Halo</h1>", "html")).toBe("<h1>Hello Halo</h1>");
14+
});

src/utils/content.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import MarkdownIt from "markdown-it";
2+
import MarkdownItAnchor from "markdown-it-anchor";
23

34
export const DEFAULT_CONTENT_RAW_TYPE = "markdown";
45

@@ -10,6 +11,8 @@ const markdownIt = new MarkdownIt({
1011
typographer: true,
1112
});
1213

14+
markdownIt.use(MarkdownItAnchor);
15+
1316
export function normalizeContentRawType(rawType?: string): string {
1417
const normalized = rawType?.trim();
1518
return normalized && normalized.length > 0 ? normalized : DEFAULT_CONTENT_RAW_TYPE;

0 commit comments

Comments
 (0)