Skip to content

Commit 85de77e

Browse files
committed
markdownをセクションごとに分割
1 parent 05e15b3 commit 85de77e

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

app/[docs_id]/page.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { notFound } from "next/navigation";
22
import { ChatForm } from "./chatForm";
33
import { StyledMarkdown } from "./markdown";
44
import { getCloudflareContext } from "@opennextjs/cloudflare";
5-
import { readFile } from "node:fs/promises";
5+
import { readFile } from "node:fs/promises";
66
import { join } from "node:path";
7+
import { splitMarkdown } from "./splitMarkdown";
78

89
export default async function Page({
910
params,
@@ -14,13 +15,13 @@ export default async function Page({
1415

1516
let mdContent: string;
1617
try {
17-
if (process.env.NODE_ENV === 'development') {
18+
if (process.env.NODE_ENV === "development") {
1819
mdContent = await readFile(
1920
join(process.cwd(), "public", "docs", `${docs_id}.md`),
2021
"utf-8"
2122
);
2223
} else {
23-
const cfAssets = getCloudflareContext().env.ASSETS;
24+
const cfAssets = getCloudflareContext().env.ASSETS;
2425
mdContent = await cfAssets!
2526
.fetch(`https://assets.local/docs/${docs_id}.md`)
2627
.then((res) => res.text());
@@ -30,9 +31,13 @@ export default async function Page({
3031
notFound();
3132
}
3233

34+
const splitMdContent: string[] = await splitMarkdown(mdContent);
35+
3336
return (
3437
<div className="p-4">
35-
<StyledMarkdown content={mdContent} />
38+
{splitMdContent.map((section, index) => (
39+
<StyledMarkdown key={index} content={section} />
40+
))}
3641
<ChatForm />
3742
</div>
3843
);

app/[docs_id]/splitMarkdown.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"use server";
2+
3+
import { unified } from "unified";
4+
import remarkParse from "remark-parse";
5+
import remarkGfm from "remark-gfm";
6+
7+
export async function splitMarkdown(content: string): Promise<string[]> {
8+
const tree = unified().use(remarkParse).use(remarkGfm).parse(content);
9+
// console.log(tree.children.map(({ type, position }) => ({ type, position: JSON.stringify(position) })));
10+
const headingNodes = tree.children.filter((node) => node.type === "heading");
11+
const splitContent = content.split("\n");
12+
const sections: string[] = [];
13+
for (let i = 0; i < headingNodes.length; i++) {
14+
const startLine = headingNodes.at(i)?.position?.start.line;
15+
if (startLine === undefined) {
16+
continue;
17+
}
18+
let endLine: number | undefined = undefined;
19+
for (let j = i + 1; j < headingNodes.length; j++) {
20+
if (headingNodes.at(j)?.position?.start.line !== undefined) {
21+
endLine = headingNodes.at(j)!.position!.start.line;
22+
break;
23+
}
24+
}
25+
const sectionContent = splitContent
26+
.slice(startLine - 1, endLine !== undefined ? endLine - 1 : undefined)
27+
.join("\n");
28+
sections.push(sectionContent);
29+
}
30+
return sections;
31+
}

0 commit comments

Comments
 (0)