forked from type-challenges/type-challenges
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathloader.ts
117 lines (95 loc) · 3.14 KB
/
loader.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
109
110
111
112
113
114
115
116
117
import path from 'path'
import fs from 'fs-extra'
import fg from 'fast-glob'
import YAML from 'js-yaml'
import type { Quiz, QuizMetaInfo } from './types'
import { defaultLocale, supportedLocales } from './locales'
export async function loadFile(filepath: string) {
if (fs.existsSync(filepath))
return await fs.readFile(filepath, 'utf-8')
return undefined
}
export async function loadLocaleVariations<T = string>(
filepath: string,
preprocessor: (s: string) => T = s => s as any as T,
) {
const { ext, dir, name } = path.parse(filepath)
const data: Record<string, T> = {}
for (const locale of supportedLocales) {
const file = preprocessor(await loadFile(path.join(dir, `${name}.${locale}${ext}`)) || '')
if (file)
data[locale] = file
}
if (!data[defaultLocale]) {
// default version
const file = preprocessor(await loadFile(filepath) || '')
if (file)
data[defaultLocale] = file
}
return data
}
export function readmeCleanUp(text: string) {
return text
.replace(/<!--info-header-start-->[\s\S]*<!--info-header-end-->/, '')
.replace(/<!--info-footer-start-->[\s\S]*<!--info-footer-end-->/, '')
.trim()
}
export function loadInfo(s: string): Partial<QuizMetaInfo> | undefined {
const object = YAML.load(s) as any
if (!object)
return undefined
const arrayKeys = ['tags', 'related']
for (const key of arrayKeys) {
if (object[key]) {
object[key] = (object[key] || '')
.toString()
.split(',')
.map((i: string) => i.trim())
.filter(Boolean)
}
else {
object[key] = undefined
}
}
return object
}
export const QUIZ_ROOT = path.resolve(__dirname, '../questions')
export async function loadQuizes(): Promise<Quiz[]> {
const folders = await fg('{0..9}*-*', {
onlyDirectories: true,
cwd: QUIZ_ROOT,
})
const quizes = await Promise.all(
folders.map(async dir => loadQuiz(dir)),
)
return quizes
}
export async function loadQuiz(dir: string): Promise<Quiz> {
return {
no: Number(dir.replace(/^(\d+)-.*/, '$1')),
difficulty: dir.replace(/^\d+-(.+?)-.*$/, '$1') as any,
path: dir,
info: await loadLocaleVariations(path.join(QUIZ_ROOT, dir, 'info.yml'), loadInfo),
readme: await loadLocaleVariations(path.join(QUIZ_ROOT, dir, 'README.md'), readmeCleanUp),
template: await loadFile(path.join(QUIZ_ROOT, dir, 'template.ts')) || '',
tests: await loadFile(path.join(QUIZ_ROOT, dir, 'test-cases.ts')),
}
}
export async function loadQuizByNo(no: number | string) {
const folders = await fg(`${no}-*`, {
onlyDirectories: true,
cwd: QUIZ_ROOT,
})
if (folders.length)
return await loadQuiz(folders[0])
return undefined
}
export function resolveInfo(quiz: Quiz, locale: string = defaultLocale) {
const info = Object.assign({}, quiz.info[defaultLocale], quiz.info[locale])
info.tags = quiz.info[locale]?.tags || quiz.info[defaultLocale]?.tags || []
info.related = quiz.info[locale]?.related || quiz.info[defaultLocale]?.related || []
if (typeof info.tags === 'string')
// @ts-expect-error
info.tags = info.tags.split(',').map(i => i.trim()).filter(Boolean)
return info as QuizMetaInfo
}