-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
/
universe.ts
108 lines (103 loc) 路 3.73 KB
/
universe.ts
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
import { Route } from '@/types';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
import { load } from 'cheerio';
import markdownit from 'markdown-it';
import vm from 'node:vm';
interface Package {
name: string;
version: string;
entrypoint: string;
authors: Array<string>;
license: string;
description: string;
repository: string;
keywords: Array<string>;
compiler: string;
exclude: Array<string>;
size: number;
readme: string;
updatedAt: number;
releasedAt: number;
}
interface Context {
an: { exports: Array<Package> };
}
const GITHUBRAW_BASE = 'https://raw.githubusercontent.com';
const PKG_GITHUB_BASE = `${GITHUBRAW_BASE}/typst/packages/main/packages/preview`;
function fixImageSrc(src: string, env: Package) {
if (src.includes('://')) {
if (src.startsWith('https://typst.app/universe/package')) {
src = src.replaceAll('https://typst.app/universe/package', `${PKG_GITHUB_BASE}/${env.name}/${env.version}`);
} else if (src.startsWith('https://github.com/') && src.match(/\.(jpeg|jpg|gif|png|bmp|webp)$/gi)?.length) {
src = src.replace('https://github.com/', `${GITHUBRAW_BASE}/`);
}
} else {
const suffix = src.startsWith('/') ? '' : '/';
const package_base = `${PKG_GITHUB_BASE}/${env.name}/${env.version}${suffix}`;
const url = new URL(src, package_base);
src = url.toString();
}
return src;
}
export const route: Route = {
path: '/universe',
categories: ['program-update'],
example: '/typst/universe',
radar: [
{
source: ['typst.app/universe'],
target: '/universe',
},
],
name: 'Universe',
maintainers: ['HPDell'],
handler: async () => {
const targetUrl = 'https://typst.app/universe/search?kind=packages%2Ctemplates&packages=last-updated';
const page = await ofetch(targetUrl);
const $ = load(page);
const script = $('script')
.toArray()
.map((item) => item.attribs.src)
.find((item) => item && item.startsWith('/scripts/universe-search'));
const data: string = await ofetch(`https://typst.app${script}`, {
parseResponse: (txt) => txt,
});
let packages = data.match(/(an.exports=[\S\s]+);var ([$A-Z_a-z][\w$]*)=new Intl.Collator/)?.[1];
if (packages) {
packages = packages.slice(0, -2);
const context: Context = { an: { exports: [] } };
vm.createContext(context);
vm.runInContext(packages, context, {
displayErrors: true,
});
const md = markdownit('commonmark');
const items = context.an.exports.sort((a, b) => a.updatedAt - b.updatedAt);
const groups = new Map(items.map((it) => [it.name, it]));
const pkgs = [...groups.values()].map((item) => {
const $ = load(md.render(item.readme));
$('img').each((i, el) => {
const src = el.attribs.src;
el.attribs.src = fixImageSrc(src, item);
});
return {
title: `${item.name} (${item.version}) | ${item.description}`,
link: `https://typst.app/universe/package/${item.name}`,
description: $.html(),
pubDate: parseDate(item.updatedAt, 'X'),
};
});
return {
title: 'Typst universe',
link: targetUrl,
item: pkgs,
};
} else {
return {
title: 'Typst universe',
link: targetUrl,
item: [],
};
}
},
};