-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathretrieveMdPages.ts
More file actions
128 lines (116 loc) · 3.8 KB
/
retrieveMdPages.ts
File metadata and controls
128 lines (116 loc) · 3.8 KB
1
2
3
4
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import fs from "fs/promises";
import { join } from "path";
import { format } from "date-fns";
import matter from "gray-matter";
import { unified } from "unified";
import parse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import rehypeSlug from "rehype-slug";
import remarkHeadings, { hasHeadingsData } from "@vcarl/remark-headings";
import { toString } from "mdast-util-to-string";
import rehypeWrapFirstList from "./rehypeWrapFirstList";
import rehypeWrapTimecodes from "./rehypeWrapTimecodes";
const loadMd = async (path: string) => {
const fullPath = join(process.cwd(), `${path}.md`);
const fileContents = await fs.readFile(fullPath, "utf8");
return matter(fileContents);
};
const stripSuffix = (filename: string, suffix: string) =>
filename.replace(new RegExp(`\.${suffix}`), "");
const remarkTextProcessor = unified().use(parse).use(remarkHeadings);
export const processMdPlaintext = (mdSource: string) => {
const vfile = remarkTextProcessor.parse(mdSource);
const html = toString(vfile).replaceAll(/<a.*> /g, "");
if (hasHeadingsData(vfile.data)) {
return { html: html, headings: vfile.data.headings };
}
return { html: html, headings: [] };
};
const remarkHtmlProcessor = unified()
.use(parse)
.use(remarkGfm)
.use(remarkHeadings as ReturnType<ReturnType<typeof unified>["use"]>)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeSlug)
.use(rehypeStringify, { allowDangerousHtml: true });
export interface ProcessMdOptions {
wrapFirstList?: boolean;
}
export const processMd = (mdSource: string, options?: ProcessMdOptions) => {
let processor = remarkHtmlProcessor;
// If wrapFirstList is enabled, add the rehype plugin
if (options?.wrapFirstList) {
processor = unified()
.use(parse)
.use(remarkGfm)
.use(remarkHeadings as ReturnType<ReturnType<typeof unified>["use"]>)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeSlug)
.use(rehypeWrapTimecodes)
.use(rehypeWrapFirstList)
.use(rehypeStringify, { allowDangerousHtml: true });
}
const vfile = processor.processSync(mdSource);
if (hasHeadingsData(vfile.data)) {
return { html: vfile.toString(), headings: vfile.data.headings };
}
return { html: vfile.toString(), headings: [] };
};
export const loadAllMd = async <DocType>(
directory: string,
): Promise<DocType[]> => {
const postsDirectory = join(process.cwd(), directory);
const slugs = await fs
.readdir(postsDirectory)
.then((files) =>
files.filter((f) => f.endsWith(".md")).map((x) => stripSuffix(x, "md")),
);
return Promise.all(
slugs.map((slug) => loadMdBySlug<DocType>(directory, slug)),
);
};
export interface Transcript {
content: string;
slug: string;
date: string;
time: string;
title: string;
description: string;
location: string;
people: string;
[k: string]: string | boolean | undefined;
}
export interface MdPage {
content: string;
title: string;
description?: string;
sidebar?: boolean;
[k: string]: string | boolean | undefined;
}
export interface BlogPost {
content: string;
slug: string;
title: string;
author: string;
date: string;
description: string;
}
export const loadMdBySlug = async <DocType>(
directory: string,
slug: string,
) => {
const { data, content } = await loadMd(join(directory, slug));
const mapped = Object.entries(data).map((pair) => {
// Next doesn't like getting Date instances, so strip them to strings
// It's really annoying that the parser doesn't let us do this
if (pair[1] instanceof Date) {
return [pair[0], format(pair[1], "yyyy-MM-dd")];
}
return pair;
});
mapped.push(["slug", slug]);
mapped.push(["content", content]);
return Object.fromEntries(mapped) as DocType;
};