-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathcore.ts
More file actions
120 lines (93 loc) · 2.86 KB
/
core.ts
File metadata and controls
120 lines (93 loc) · 2.86 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
import { HTTPError } from 'koajax';
import { DataObject } from 'mobx-restful';
import { NextApiRequest, NextApiResponse } from 'next';
import { ProxyAgent, setGlobalDispatcher } from 'undici';
import { parse } from 'yaml';
const { HTTP_PROXY } = process.env;
if (HTTP_PROXY) setGlobalDispatcher(new ProxyAgent(HTTP_PROXY));
export type NextAPI = (
req: NextApiRequest,
res: NextApiResponse,
) => Promise<any>;
export function safeAPI(handler: NextAPI): NextAPI {
return async (req, res) => {
try {
return await handler(req, res);
} catch (error) {
if (!(error instanceof HTTPError)) {
console.error(error);
res.status(400);
return res.send({ message: (error as Error).message });
}
const { message, response } = error;
let { body } = response;
res.status(response.status);
res.statusMessage = message;
if (body instanceof ArrayBuffer)
try {
body = new TextDecoder().decode(new Uint8Array(body));
console.error(body);
body = JSON.parse(body);
console.error(body);
} catch {
//
}
res.send(body);
}
};
}
export interface ArticleMeta {
name: string;
path?: string;
meta?: DataObject;
subs: ArticleMeta[];
}
const MDX_pattern = /\.mdx?$/;
export async function frontMatterOf(path: string) {
const { readFile } = await import('fs/promises');
const file = await readFile(path, 'utf-8');
const [, frontMatter] = file.match(/^---[\r\n]([\s\S]+?[\r\n])---/) || [];
return frontMatter && parse(frontMatter);
}
export async function* pageListOf(
path: string,
prefix = 'pages',
): AsyncGenerator<ArticleMeta> {
const { readdir } = await import('fs/promises');
const list = await readdir(prefix + path, { withFileTypes: true });
for (const node of list) {
let { name, path } = node;
if (name.startsWith('.')) continue;
const isMDX = MDX_pattern.test(name);
name = name.replace(MDX_pattern, '');
path = `${path}/${name}`.replace(new RegExp(`^${prefix}`), '');
if (node.isFile() && isMDX) {
const article: ArticleMeta = { name, path, subs: [] };
try {
const meta = await frontMatterOf(`${node.path}/${node.name}`);
if (meta) article.meta = meta;
} catch (error) {
console.error(
`Error reading front matter for ${node.path}/${node.name}:`,
error,
);
}
yield article;
}
if (!node.isDirectory()) continue;
const subs = await Array.fromAsync(pageListOf(path, prefix));
if (subs.length) yield { name, subs };
}
}
export type TreeNode<K extends string> = {
[key in K]: TreeNode<K>[];
};
export function* traverseTree<K extends string>(
tree: TreeNode<K>,
key: K,
): Generator<TreeNode<K>> {
for (const node of tree[key] || []) {
yield node;
yield* traverseTree(node, key);
}
}