-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
/
Copy pathindex.js
112 lines (94 loc) · 3.03 KB
/
index.js
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
import { extractFrontmatter } from '@sveltejs/site-kit/markdown';
import { CONTENT_BASE_PATHS } from '../../../constants.js';
import { render_content } from '../renderer.js';
/**
* @param {import('./types').TutorialData} tutorial_data
* @param {string} slug
*/
export async function get_parsed_tutorial(tutorial_data, slug) {
for (const { tutorials } of tutorial_data) {
for (const tutorial of tutorials) {
if (tutorial.slug === slug) {
return {
...tutorial,
content: await render_content(`tutorial/${tutorial.dir}`, tutorial.content)
};
}
}
}
return null;
}
/**
* @returns {Promise<import('./types').TutorialData>}
*/
export async function get_tutorial_data(base = CONTENT_BASE_PATHS.TUTORIAL) {
const { readdir, readFile, stat } = await import('node:fs/promises');
const tutorials = [];
for (const subdir of await readdir(base)) {
/** @type {import('./types').TutorialDatum} */
const section = {
title: '', // Initialise with empty
slug: subdir.split('-').slice(1).join('-'),
tutorials: []
};
if (!((await stat(`${base}/${subdir}`)).isDirectory() || subdir.endsWith('meta.json')))
continue;
if (!subdir.endsWith('meta.json'))
section.title = JSON.parse(await readFile(`${base}/${subdir}/meta.json`, 'utf-8')).title;
for (const section_dir of await readdir(`${base}/${subdir}`)) {
const match = /\d{2}-(.+)/.exec(section_dir);
if (!match) continue;
const slug = match[1];
const tutorial_base_dir = `${base}/${subdir}/${section_dir}`;
// Read the file, get frontmatter
const contents = await readFile(`${tutorial_base_dir}/text.md`, 'utf-8');
const { metadata, body } = extractFrontmatter(contents);
// Get the contents of the apps.
/**
* @type {{
* initial: import('./types').CompletionState[];
* complete: import('./types').CompletionState[];
* }}
*/
const completion_states_data = { initial: [], complete: [] };
for (const app_dir of await readdir(tutorial_base_dir)) {
if (!app_dir.startsWith('app-')) continue;
const app_dir_path = `${tutorial_base_dir}/${app_dir}`;
const app_contents = await readdir(app_dir_path, 'utf-8');
for (const file of app_contents) {
const type = file.split('.').at(-1);
if (!type) {
throw new Error(`Could not determine type from ${file}`);
}
completion_states_data[app_dir === 'app-a' ? 'initial' : 'complete'].push({
name: file,
type,
content: await readFile(`${app_dir_path}/${file}`, 'utf-8')
});
}
}
section.tutorials.push({
title: metadata.title,
slug,
content: body,
dir: `${subdir}/${section_dir}`,
...completion_states_data
});
}
tutorials.push(section);
}
return tutorials;
}
/**
* @param {import('./types').TutorialData} tutorial_data
* @returns {import('./types').TutorialsList}
*/
export function get_tutorial_list(tutorial_data) {
return tutorial_data.map((section) => ({
title: section.title,
tutorials: section.tutorials.map((tutorial) => ({
title: tutorial.title,
slug: tutorial.slug
}))
}));
}