Skip to content

Commit 2829baa

Browse files
authored
feat: generate static paths for doc slug (#387)
* feat: generate static paths for doc slug * fix: generate only current version
1 parent 8417e36 commit 2829baa

File tree

4 files changed

+146
-92
lines changed

4 files changed

+146
-92
lines changed

pwa/api/doc/index.ts

Lines changed: 107 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import YAML from "yaml";
1010
import { marked } from "marked";
1111
import { cache } from "react";
1212
import { current } from "consts";
13-
import { load as parseHtml } from 'cheerio';
13+
import { load as parseHtml } from "cheerio";
14+
import { Chapters } from "types";
1415

1516
export const MyOctokit = Octokit.plugin(throttling);
16-
const sidebarMemoryCache = new Map()
17+
const sidebarMemoryCache = new Map();
1718

1819
type Options = {
1920
method?: string;
@@ -26,10 +27,13 @@ function toAbsoluteUrl(url: string, githubPath: string): string {
2627
return url;
2728
} catch (err) {
2829
if (path.isAbsolute(url)) {
29-
return url.replace('index.md', '').replace('.md', '');
30+
return url.replace("index.md", "").replace(".md", "");
3031
}
3132

32-
return path.normalize(`/docs/${path.dirname(githubPath)}/${url}`).replace('index.md', '').replace('.md', '')
33+
return path
34+
.normalize(`/docs/${path.dirname(githubPath)}/${url}`)
35+
.replace("index.md", "")
36+
.replace(".md", "");
3337
}
3438
}
3539

@@ -83,16 +87,16 @@ export async function loadMarkdownBySlugArray(slug: string[]) {
8387
}
8488

8589
export const getDocTitle = async (version: string, slug: string[]) => {
86-
const key = slug.join('')
90+
const key = slug.join("");
8791
if (sidebarMemoryCache.has(key)) {
88-
return sidebarMemoryCache.get(key)
92+
return sidebarMemoryCache.get(key);
8993
}
90-
const { data, path } = await getDocContentFromSlug(version, slug)
94+
const { data, path } = await getDocContentFromSlug(version, slug);
9195
const md = Buffer.from((data as any).content, "base64").toString();
92-
const title = extractHeadingsFromMarkdown(md, 1)?.[0]
96+
const title = extractHeadingsFromMarkdown(md, 1)?.[0];
9397

94-
sidebarMemoryCache.set(key, title || slug.shift())
95-
return sidebarMemoryCache.get(key)
98+
sidebarMemoryCache.set(key, title || slug.shift());
99+
return sidebarMemoryCache.get(key);
96100
};
97101

98102
export const loadV2DocumentationNav = cache(async (branch: string) => {
@@ -103,19 +107,24 @@ export const loadV2DocumentationNav = cache(async (branch: string) => {
103107
path: "outline.yaml",
104108
ref: branch,
105109
});
106-
const result = Buffer.from((data as any).content, "base64");
107110

108-
const navData = YAML.parse(result.toString());
111+
if (!("content" in data)) return [];
112+
113+
const result = Buffer.from(data.content, "base64");
114+
115+
const navData: Chapters = YAML.parse(result.toString());
116+
109117
const basePath = branch === current ? `/docs` : `/docs/${branch}`;
110-
const nav = await Promise.all(
111-
navData.chapters.map(async (part: any) => ({
118+
return Promise.all(
119+
navData.chapters.map(async (part) => ({
112120
title: part.title,
113121
basePath: `${basePath}/${part.path}`,
114122
links: await Promise.all(
115123
part.items.map(async (item: string) => ({
116-
title: (
117-
await getDocTitle(branch, [part.path, item === 'index' ? '' : item])
118-
),
124+
title: await getDocTitle(branch, [
125+
part.path,
126+
item === "index" ? "" : item,
127+
]),
119128
link:
120129
item === "index"
121130
? `${basePath}/${part.path}/`
@@ -124,19 +133,30 @@ export const loadV2DocumentationNav = cache(async (branch: string) => {
124133
),
125134
}))
126135
);
127-
return nav;
128136
} catch (error) {
129137
console.error(error);
130138
}
131139
return [];
132140
});
133141

134-
const indexes = ['admin', 'core', 'create-client', 'deployment', 'distribution', 'extra', 'schema-generator']
135-
136-
export const getDocContentFromSlug = async (version: string, slug: string[]) => {
137-
slug = slug.filter(v => v)
142+
const indexes = [
143+
"admin",
144+
"core",
145+
"create-client",
146+
"deployment",
147+
"distribution",
148+
"extra",
149+
"schema-generator",
150+
"client-generator",
151+
];
152+
153+
export const getDocContentFromSlug = async (
154+
version: string,
155+
slug: string[]
156+
) => {
157+
slug = slug.filter((v) => v);
138158
const lastPart = slug.slice(-1)[0];
139-
const p = slug.join("/") + (indexes.includes(lastPart) ? '/index.md' : '.md');
159+
const p = slug.join("/") + (indexes.includes(lastPart) ? "/index.md" : ".md");
140160

141161
try {
142162
const { data } = await octokit.rest.repos.getContent({
@@ -146,37 +166,43 @@ export const getDocContentFromSlug = async (version: string, slug: string[]) =>
146166
ref: version,
147167
});
148168

149-
return { data, path: p }
169+
return { data, path: p };
150170
} catch (error) {
151-
console.error('An error occured while fetching %s', p)
171+
console.error("An error occured while fetching %s", p);
152172
console.error(error);
153-
return { data: {content: 'error'}, path: p }
173+
return { data: { content: "error" }, path: p };
154174
}
155175
};
156176

157-
const codeInside = /\[codeSelector\]([\s\S]+?)(?=\[\/codeSelector])/gm
158-
const codeBlock = /```[a-z]([\s\S]+?)(?=```)/gm
159-
const codeLanguage = /```([a-z]+)/
177+
const codeInside = /\[codeSelector\]([\s\S]+?)(?=\[\/codeSelector])/gm;
178+
const codeBlock = /```[a-z]([\s\S]+?)(?=```)/gm;
179+
const codeLanguage = /```([a-z]+)/;
160180

161181
function getLang(block: string): string {
162-
const language = block.match(codeLanguage)
182+
const language = block.match(codeLanguage);
163183

164184
if (!language?.length) {
165-
return 'text';
185+
return "text";
166186
}
167187

168-
return language[1]
188+
return language[1];
169189
}
170190

171-
export const getHtmlFromGithubContent = async ({ data, path: githubPath }: { data: any, path: string }) => {
191+
export const getHtmlFromGithubContent = async ({
192+
data,
193+
path: githubPath,
194+
}: {
195+
data: any;
196+
path: string;
197+
}) => {
172198
const result = Buffer.from(data.content, "base64").toString();
173199

174200
marked.setOptions({ mangle: false, headerIds: false });
175201

176202
const highlighter = await getHighlighter({
177203
themes: ["github-light", "one-dark-pro"],
178204
});
179-
const languages = highlighter.getLoadedLanguages()
205+
const languages = highlighter.getLoadedLanguages();
180206

181207
marked.use(
182208
markedHighlight({
@@ -200,54 +226,53 @@ export const getHtmlFromGithubContent = async ({ data, path: githubPath }: { dat
200226
// this allows the doc to work on github and on our nextjs website
201227
marked.use({
202228
walkTokens: (token: any) => {
203-
if (!['link', 'image', 'html'].includes(token.type)) {
229+
if (!["link", "image", "html"].includes(token.type)) {
204230
return;
205231
}
206232

207-
if (token.type === 'html') {
208-
const $ = parseHtml(token.raw)
209-
$('a').map(function(i, elem) {
210-
const el = $(this)
211-
const href = el.attr('href')
233+
if (token.type === "html") {
234+
const $ = parseHtml(token.raw);
235+
$("a").map(function (i, elem) {
236+
const el = $(this);
237+
const href = el.attr("href");
212238

213239
if (href) {
214-
el.attr('href', toAbsoluteUrl(href, githubPath))
240+
el.attr("href", toAbsoluteUrl(href, githubPath));
215241
}
216242

217-
return el
218-
})
219-
243+
return el;
244+
});
220245

221-
$('img').map(function(i, elem) {
222-
const el = $(this)
223-
const src = el.attr('src')
246+
$("img").map(function (i, elem) {
247+
const el = $(this);
248+
const src = el.attr("src");
224249

225250
if (src) {
226-
el.attr('src', toAbsoluteUrl(src, githubPath))
251+
el.attr("src", toAbsoluteUrl(src, githubPath));
227252
}
228253

229-
return el
230-
})
254+
return el;
255+
});
231256

232-
token.text = $.html()
257+
token.text = $.html();
233258
return;
234259
}
235260

236-
token.href = toAbsoluteUrl(token.href, githubPath)
237-
}
238-
})
261+
token.href = toAbsoluteUrl(token.href, githubPath);
262+
},
263+
});
239264

240265
marked.use({
241266
hooks: {
242267
preprocess: (markdown: any) => {
243-
const matches = markdown.match(codeInside)
268+
const matches = markdown.match(codeInside);
244269

245270
if (!matches?.length) {
246-
return markdown
271+
return markdown;
247272
}
248273

249274
matches.forEach((m: string) => {
250-
const blocks = m.match(codeBlock)
275+
const blocks = m.match(codeBlock);
251276

252277
if (!blocks) {
253278
return;
@@ -256,29 +281,35 @@ export const getHtmlFromGithubContent = async ({ data, path: githubPath }: { dat
256281
let html = `
257282
<div class="mb-4 overflow-hidden rounded-2xl bg-gray-100 dark:bg-blue-darkest not-prose">
258283
<div class="flex flex-wrap -mb-px bg-gray-300/10 dark:bg-blue/20 border-b border-gray-300 dark:border-blue-dark">
259-
`
284+
`;
260285

261286
blocks.forEach((block: string, i: number) => {
262-
const l = getLang(block)
263-
html += `<div><a key="${l}" onclick="switchCode(event)" role="button" class="inline-block py-2 px-6 border-b-2 font-semibold text-sm uppercase hover:bg-blue-black/5 dark:hover:bg-blue-black/30 transition-all ${i === 0 ? 'text-blue dark:text-white border-blue bg-blue-black/5 dark:bg-blue-black/30' : 'text-gray-400 dark:text-blue/60 border-transparent'}">${l}</a></div>`
264-
})
287+
const l = getLang(block);
288+
html += `<div><a key="${l}" onclick="switchCode(event)" role="button" class="inline-block py-2 px-6 border-b-2 font-semibold text-sm uppercase hover:bg-blue-black/5 dark:hover:bg-blue-black/30 transition-all ${
289+
i === 0
290+
? "text-blue dark:text-white border-blue bg-blue-black/5 dark:bg-blue-black/30"
291+
: "text-gray-400 dark:text-blue/60 border-transparent"
292+
}">${l}</a></div>`;
293+
});
265294

266-
html += '</div>'
295+
html += "</div>";
267296

268297
blocks.forEach((block: string, i: number) => {
269-
const l = getLang(block)
270-
const h = marked.parse(block + `\n\`\`\``)
271-
html += `<div key="${l}" class="p-4 ${i > 0 ? 'hidden' : ''}">${h}</div>`
272-
})
273-
274-
html += '</div>'
275-
markdown = markdown.replace(m, html)
276-
})
277-
278-
return markdown.replaceAll('[/codeSelector]', '')
279-
}
280-
}
281-
})
298+
const l = getLang(block);
299+
const h = marked.parse(block + `\n\`\`\``);
300+
html += `<div key="${l}" class="p-4 ${
301+
i > 0 ? "hidden" : ""
302+
}">${h}</div>`;
303+
});
304+
305+
html += "</div>";
306+
markdown = markdown.replace(m, html);
307+
});
308+
309+
return markdown.replaceAll("[/codeSelector]", "");
310+
},
311+
},
312+
});
282313

283314
return marked.parse(result);
284-
}
315+
};

pwa/app/(common)/docs/[...slug]/layout.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import Sidebar from "components/docs/Sidebar";
33
import { loadV2DocumentationNav } from "api/doc";
44
import { versions, current } from "consts";
55

6-
export async function generateStaticParams() {
7-
return [];
8-
}
9-
106
async function DocLayout({
117
params: { slug },
128
children,

pwa/app/(common)/docs/[...slug]/page.tsx

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@ import {
22
getDocContentFromSlug,
33
getDocTitle,
44
getHtmlFromGithubContent,
5+
loadV2DocumentationNav,
56
} from "api/doc";
67
import classNames from "classnames";
7-
import { versions, current } from "consts";
8+
import { current, versions } from "consts";
89
import Script from "next/script";
910
import { Metadata, ResolvingMetadata } from "next";
1011

1112
export async function generateStaticParams() {
12-
return [];
13+
const slugs: { slug: string[] }[] = [];
14+
const navs = await loadV2DocumentationNav(current);
15+
for (const nav of navs) {
16+
for (const link of nav.links) {
17+
slugs.push({ slug: link.link.replace("/docs/", "").split("/") });
18+
}
19+
}
20+
21+
return slugs;
1322
}
1423

1524
export default async function Page({
@@ -19,6 +28,19 @@ export default async function Page({
1928
slug: string[];
2029
};
2130
}) {
31+
const slugs: { slug: string[] }[] = [];
32+
const navs = await loadV2DocumentationNav(current);
33+
for (const nav of navs) {
34+
for (const link of nav.links) {
35+
slugs.push({
36+
slug: link.link
37+
.replace("/docs/", "")
38+
.split("/")
39+
.filter((s) => s !== ""),
40+
});
41+
}
42+
}
43+
2244
const version = versions.includes(slug[0]) ? slug[0] : current;
2345
const contentSlug = versions.includes(slug[0])
2446
? slug.slice(1, slug.length)
@@ -61,16 +83,13 @@ export default async function Page({
6183
);
6284
}
6385

64-
export async function generateMetadata(
65-
{
66-
params: { slug },
67-
}: {
68-
params: {
69-
slug: string[];
70-
};
71-
},
72-
parent: ResolvingMetadata
73-
): Promise<Metadata> {
86+
export async function generateMetadata({
87+
params: { slug },
88+
}: {
89+
params: {
90+
slug: string[];
91+
};
92+
}): Promise<Metadata> {
7493
const version = versions.includes(slug[0]) ? slug[0] : current;
7594
const title = await getDocTitle(version, slug);
7695

0 commit comments

Comments
 (0)