-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathcore.ts
More file actions
127 lines (93 loc) · 3.29 KB
/
core.ts
File metadata and controls
127 lines (93 loc) · 3.29 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
import 'core-js/full/array/from-async';
import Router, { RouterParamContext } from '@koa/router';
import { Context, Middleware } from 'koa';
import { HTTPError } from 'koajax';
import { DataObject } from 'mobx-restful';
import { KoaOption, withKoa, withKoaRouter } from 'next-ssr-middleware';
import { ProxyAgent, setGlobalDispatcher } from 'undici';
import { parse } from 'yaml';
const { HTTP_PROXY } = process.env;
if (HTTP_PROXY) setGlobalDispatcher(new ProxyAgent(HTTP_PROXY));
export const safeAPI: Middleware<any, any> = async (context: Context, next) => {
try {
return await next();
} catch (error) {
if (!(error instanceof HTTPError)) {
console.error(error);
context.status = 400;
return (context.body = { message: (error as Error).message });
}
const { message, response } = error;
let { body } = response;
context.status = response.status;
context.statusMessage = message;
if (body instanceof ArrayBuffer)
try {
body = new TextDecoder().decode(new Uint8Array(body));
body = JSON.parse(body);
} catch {
//
}
console.error(JSON.stringify(body, null, 2));
context.body = body;
}
};
export const withSafeKoa = <S, C>(...middlewares: Middleware<S, C>[]) =>
withKoa<S, C>({} as KoaOption, safeAPI, ...middlewares);
export const withSafeKoaRouter = <S, C extends RouterParamContext<S>>(
router: Router<S, C>,
...middlewares: Middleware<S, C>[]
) => withKoaRouter<S, C>({} as KoaOption, router, safeAPI, ...middlewares);
export interface ArticleMeta {
name: string;
path?: string;
meta?: DataObject;
subs: ArticleMeta[];
}
export const MD_pattern = /\.(md|markdown)$/i,
MDX_pattern = /\.mdx?$/i;
export function splitFrontMatter(raw: string) {
const [, frontMatter, markdown] =
raw.trim().match(/^---[\r\n]([\s\S]+?[\r\n])---[\r\n]([\s\S]*)/) || [];
if (!frontMatter) return { markdown: raw };
try {
const meta = parse(frontMatter) as DataObject;
return { markdown, meta };
} catch (error) {
console.error(`Error parsing Front Matter:`, error);
return { markdown };
}
}
export async function* pageListOf(path: string, prefix = 'pages'): AsyncGenerator<ArticleMeta> {
const { readdir, readFile } = 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: [] };
const file = await readFile(`${node.path}/${node.name}`, 'utf-8');
const { meta } = splitFrontMatter(file);
if (meta) article.meta = meta;
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, N extends TreeNode<K>>(
tree: N,
key: K,
): Generator<N> {
for (const node of tree[key] || []) {
yield node as N;
yield* traverseTree(node as N, key);
}
}