-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.ts
201 lines (173 loc) · 5.61 KB
/
index.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import { promisify } from 'util';
import { exec } from 'child_process';
import { access, cp, readFile, readdir, rm, mkdir, writeFile } from 'fs/promises';
import { render } from 'mustache';
import { DEFAULTS, SRC_CODE_PATTERN, TAILWIND_STYLE } from './lib/constants';
import { Config, SatusCode, SnippetVariables, TemplateVariables } from "./lib/interfaces";
async function compile(config: Config) {
try {
let vars: TemplateVariables = {
locale: config.locale,
};
const template = await readFile(`${DEFAULTS.THEMES}/${config.theme}/template.html`).then(String);
const codesVars = new Map<SatusCode, TemplateVariables>();
await readdir(`${DEFAULTS.SRC}/${config.locale}/`)
.then(files => {
return Promise.all(
files.map(async (file) => {
const srcVars: TemplateVariables = await readJson(`${DEFAULTS.SRC}/${config.locale}/${file}`);
const match = file.match(SRC_CODE_PATTERN);
if (match) {
codesVars.set(Number(match[0]), srcVars);
}
else {
vars = {...vars, ...srcVars};
}
})
)
})
if (codesVars.size > 0) {
await Promise.all(
Array.from(codesVars).map(
([code, codeVars]) => renderPage(template, {...vars, ...codeVars, code})
)
).then(() => {
console.log(`INFO: ${codesVars.size} pages were successfully created`);
});
await readdir(`${DEFAULTS.SNIPPETS}/`)
.then(files => {
return Promise.all(
files.map(async (file) => {
const snippet = await readFile(`${DEFAULTS.SNIPPETS}/${file}`).then(String);
return renderSnippet(file, snippet, { locale: config.locale, codes: Array.from(codesVars.keys()) })
})
)
})
}
else {
throw new Error('No source data to render error pages');
}
} catch (err) {
throw err;
}
}
async function execTailwind(config: Config) {
try {
if (config.tailwind) {
const input = `${DEFAULTS.THEMES}/${config.theme}/${DEFAULTS.ASSETS}/css/${DEFAULTS.TAILWIND_ENTRY}`;
const output = `${DEFAULTS.DIST}/${config.locale}/${DEFAULTS.ASSETS}/css/${DEFAULTS.TAILWIND_ENTRY.replace('.tcss', '.css')}`;
const cmd = `INPUT="${input}" OUTPUT="${output}" npm run build:tailwind`;
console.log(`INFO: build Tailwind CSS styles`);
console.log(`INFO: run '${cmd}'`);
await promisify(exec)(cmd).then(() => {
console.log(`INFO: Tailwind CSS styles were built`);
});
}
else {
console.log(`WARN: Tailwind CSS was disabled in config`);
}
} catch (err) {
throw err;
}
}
async function readJson(path: string) {
try {
return await readFile(path).then(String).then(JSON.parse);
} catch (err) {
throw err;
}
}
async function renderPage(template: string, vars: TemplateVariables) {
try {
if (!vars.code) {
throw new Error('No code variable to render page');
} else if (!vars.locale) {
throw new Error('No locale variable to render page');
}
const path = `${DEFAULTS.DIST}/${vars.locale}/${vars.code}.html`;
console.log(`INFO: render '${path}' page`);
await writeFile(path, render(template, vars), { flag: 'w+' });
} catch (err) {
throw err;
}
}
async function renderSnippet(name: string, template: string, vars: SnippetVariables) {
try {
if (!vars.codes) {
throw new Error('No codes list to render config snippet');
} else if (!vars.locale) {
throw new Error('No locale variable to render config snippet');
}
const path = `${DEFAULTS.DIST}/${vars.locale}/${name}`;
console.log(`INFO: render '${path}' config snippet`);
await writeFile(path, render(template, vars), { flag: 'w+' });
console.log(`INFO: config snippet '${name}' was successfully created`);
} catch (err) {
throw err;
}
}
async function readConfig(): Promise<Config> {
try {
const config = await readJson(DEFAULTS.CONFIG);
if (!config.theme) {
throw new Error(`Please set theme in your configuration: ${DEFAULTS.CONFIG}`);
} else if (!config.locale) {
throw new Error(`Please set locale in your configuration: ${DEFAULTS.CONFIG}`);
}
return config;
} catch (err) {
throw err;
}
}
async function prepare(config: Config) {
try {
console.log(`INFO: prepare build directory '${DEFAULTS.DIST}'`);
await rm(DEFAULTS.DIST, { force: true, recursive: true });
await mkdir(`${DEFAULTS.DIST}/${config.locale}/`, { recursive: true });
} catch (err) {
throw err;
}
}
async function copyAssets(config: Config) {
try {
console.log(`INFO: copying assets to build directory '${DEFAULTS.DIST}'`);
const path = `${DEFAULTS.THEMES}/${config.theme}/${DEFAULTS.ASSETS}`;
let exists = false;
try {
await access(path);
exists = true;
} catch (_) {}
if (exists) {
await cp(
path,
`${DEFAULTS.DIST}/${config.locale}/${DEFAULTS.ASSETS}`,
{
recursive: true,
// Skip Tailwind styles to copy
filter: (src) => !TAILWIND_STYLE.test(src)
}
);
}
else {
console.log(`INFO: no assets in '${config.theme}' theme directory`);
}
} catch (err) {
throw err;
}
}
readConfig()
.then(async (config) => {
await prepare(config);
await compile(config);
await execTailwind(config);
await copyAssets(config);
})
.catch(err => {
console.error(`
An error happened during compile process. Please, check 'README.md' to get more details about calling this process.
Error Message:
${err.message}
Error Stack:
${err.stack}
`);
});