@abreen/tada 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -33
- package/bin/tada.ts +356 -0
- package/bin/validators.test.ts +204 -0
- package/bin/validators.ts +83 -0
- package/{webpack/apply-base-path-plugin.js → build/apply-base-path-plugin.ts} +16 -7
- package/build/bundle.ts +117 -0
- package/{webpack/code.test.js → build/code.test.ts} +6 -7
- package/build/colors.ts +25 -0
- package/build/content-watch.ts +107 -0
- package/build/copy.ts +118 -0
- package/{webpack/deflist-id-plugin.js → build/deflist-id-plugin.ts} +7 -6
- package/{webpack/external-links-plugin.js → build/external-links-plugin.ts} +14 -5
- package/build/features.ts +11 -0
- package/build/generate-content-assets.ts +315 -0
- package/build/generate-favicon.ts +165 -0
- package/build/generate-fonts.ts +31 -0
- package/{webpack/generate-manifest-plugin.js → build/generate-manifest.ts} +29 -36
- package/build/globals.test.ts +101 -0
- package/{webpack/globals.js → build/globals.ts} +28 -13
- package/{webpack/heading-subtitle-plugin.js → build/heading-subtitle-plugin.ts} +4 -2
- package/build/json-schema.test.ts +57 -0
- package/build/json-schema.ts +33 -0
- package/build/log.test.ts +111 -0
- package/build/log.ts +167 -0
- package/{webpack/markdown-plugins.test.js → build/markdown-plugins.test.ts} +94 -9
- package/{webpack/pagefind-plugin.test.js → build/pagefind.test.ts} +74 -13
- package/build/pagefind.ts +339 -0
- package/{webpack/pdf-text.js → build/pdf-text.ts} +47 -27
- package/build/pipeline.ts +93 -0
- package/{webpack/reachability.test.js → build/reachability.test.ts} +3 -3
- package/{webpack/reachability.js → build/reachability.ts} +77 -34
- package/build/serve.ts +112 -0
- package/{webpack/site-variables.js → build/site-variables.ts} +22 -15
- package/{webpack → build}/site.schema.json +3 -10
- package/{webpack/templates.js → build/templates.ts} +35 -33
- package/{webpack/text-to-id.js → build/text-to-id.ts} +2 -2
- package/build/toc-plugin.test.ts +105 -0
- package/{webpack/toc-plugin.js → build/toc-plugin.ts} +32 -13
- package/build/types.ts +172 -0
- package/build/util.ts +26 -0
- package/{webpack/utils/code.js → build/utils/code.ts} +119 -60
- package/{webpack/utils/content-files.js → build/utils/content-files.ts} +40 -35
- package/build/utils/derive-theme.test.ts +111 -0
- package/build/utils/derive-theme.ts +85 -0
- package/build/utils/file-types.test.ts +61 -0
- package/build/utils/file-types.ts +13 -0
- package/build/utils/front-matter.test.ts +80 -0
- package/{webpack/utils/front-matter.js → build/utils/front-matter.ts} +22 -9
- package/{webpack → build}/utils/jdi-runner/LiterateRunner.java +1 -1
- package/{webpack/utils/literate-java.js → build/utils/literate-java.ts} +63 -34
- package/{webpack/utils/markdown.js → build/utils/markdown.ts} +94 -49
- package/build/utils/paths.test.ts +91 -0
- package/{webpack/utils/paths.js → build/utils/paths.ts} +14 -22
- package/{webpack/utils/render.js → build/utils/render.ts} +188 -123
- package/build/utils/shiki-highlighter.ts +29 -0
- package/build/validate-internal-links-plugin.test.ts +106 -0
- package/{webpack/validate-internal-links-plugin.js → build/validate-internal-links-plugin.ts} +47 -20
- package/{webpack/watch-reachability-state.test.js → build/watch-reachability-state.test.ts} +8 -8
- package/{webpack/watch-reachability-state.js → build/watch-reachability-state.ts} +63 -24
- package/{webpack/watch-reload-client.js → build/watch-reload-client.ts} +3 -1
- package/build/watch.ts +573 -0
- package/content/index.md +9 -3
- package/content/markdown.md +2 -1
- package/content/problem_sets/index.html +14 -0
- package/fonts/google-sans-code/woff2/GoogleSansCodeVariable-Italic.woff2 +0 -0
- package/fonts/google-sans-code/woff2/GoogleSansCodeVariable.woff2 +0 -0
- package/fonts/inter/woff2/InterVariable-Italic.woff2 +0 -0
- package/fonts/inter/woff2/InterVariable.woff2 +0 -0
- package/package.json +28 -19
- package/src/_alerts.scss +92 -0
- package/src/_base.scss +106 -0
- package/src/{layout.scss → _layout.scss} +0 -2
- package/src/anchor/style.scss +1 -9
- package/src/code/index.ts +3 -3
- package/src/code.scss +1 -1
- package/src/critical.scss +5 -0
- package/src/header/_base.scss +129 -0
- package/src/header/style.scss +3 -131
- package/src/index.ts +1 -2
- package/src/question/style.scss +1 -1
- package/src/search/index.ts +36 -15
- package/src/search/style.scss +9 -15
- package/src/style.scss +6 -269
- package/src/toc/style.scss +5 -39
- package/src/util.ts +8 -5
- package/templates/_theme.scss +38 -14
- package/tsconfig.json +10 -6
- package/types/file-system-access.d.ts +5 -0
- package/types/markdown-it-plugins.d.ts +11 -0
- package/types/untyped-modules.d.ts +40 -0
- package/bin/tada.js +0 -361
- package/content/problem_sets/index.md +0 -6
- package/webpack/build-state.js +0 -97
- package/webpack/colors.js +0 -15
- package/webpack/config.base.js +0 -151
- package/webpack/config.dev.js +0 -23
- package/webpack/config.prod.js +0 -32
- package/webpack/content-watch-plugin.js +0 -153
- package/webpack/features.js +0 -5
- package/webpack/generate-content-assets-plugin.js +0 -308
- package/webpack/generate-favicon-plugin.js +0 -198
- package/webpack/generate-fonts-plugin.js +0 -69
- package/webpack/json-schema.js +0 -19
- package/webpack/log.js +0 -143
- package/webpack/pagefind-plugin.js +0 -379
- package/webpack/print-flair-plugin.js +0 -22
- package/webpack/serve.js +0 -104
- package/webpack/util.js +0 -49
- package/webpack/utils/define-plugin.js +0 -20
- package/webpack/utils/file-types.js +0 -26
- package/webpack/utils/parse-hsl.js +0 -8
- package/webpack/utils/shiki-highlighter.js +0 -26
- package/webpack/watch.js +0 -166
- /package/{webpack → build}/flair.json +0 -0
- /package/{webpack → build}/utils/jdi-runner/LiterateRunner.class +0 -0
- /package/fonts/google-sans-code/{GoogleSansCodeVariable-Italic.ttf → ttf/GoogleSansCodeVariable-Italic.ttf} +0 -0
- /package/fonts/google-sans-code/{GoogleSansCodeVariable.ttf → ttf/GoogleSansCodeVariable.ttf} +0 -0
- /package/fonts/inter/{InterVariable-Italic.ttf → ttf/InterVariable-Italic.ttf} +0 -0
- /package/fonts/inter/{InterVariable.ttf → ttf/InterVariable.ttf} +0 -0
- /package/types/{dev.ts → dev.d.ts} +0 -0
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { makeLogger } = require('./log');
|
|
4
|
-
const { collectReachableSiteAssets } = require('./reachability');
|
|
5
|
-
const ContentWatchPlugin = require('./content-watch-plugin');
|
|
6
|
-
const {
|
|
7
|
-
getBuildContentFiles,
|
|
8
|
-
getContentDir,
|
|
9
|
-
normalizeOutputPath,
|
|
10
|
-
} = require('./util');
|
|
11
|
-
const { assertMutoolAvailable, extractPdfPages } = require('./pdf-text');
|
|
12
|
-
|
|
13
|
-
const log = makeLogger(__filename);
|
|
14
|
-
const PAGEFIND_VERBOSE = process.env.TADA_LOG_LEVEL === 'debug';
|
|
15
|
-
const PAGEFIND_OUTPUT_SUBDIR = 'pagefind';
|
|
16
|
-
|
|
17
|
-
let pagefindModulePromise = null;
|
|
18
|
-
|
|
19
|
-
function getPagefind() {
|
|
20
|
-
if (!pagefindModulePromise) {
|
|
21
|
-
pagefindModulePromise = import('pagefind');
|
|
22
|
-
}
|
|
23
|
-
return pagefindModulePromise;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function formatPagefindErrors(step, errors) {
|
|
27
|
-
if (!errors?.length) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
return `${step} failed: ${errors.join(' | ')}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function readAssetContent(outputFileSystem, distPath, sourcePath) {
|
|
34
|
-
const filePath = path.join(distPath, sourcePath);
|
|
35
|
-
return String(outputFileSystem.readFileSync(filePath, 'utf-8'));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function addHtmlFile(index, htmlFile) {
|
|
39
|
-
const { errors: addErrors } = await index.addHTMLFile(htmlFile);
|
|
40
|
-
const addError = formatPagefindErrors(
|
|
41
|
-
`index.addHTMLFile(${htmlFile.sourcePath})`,
|
|
42
|
-
addErrors,
|
|
43
|
-
);
|
|
44
|
-
if (addError) {
|
|
45
|
-
throw new Error(addError);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function addPdfRecord(index, record, sourcePath) {
|
|
50
|
-
const { errors: addErrors } = await index.addCustomRecord(record);
|
|
51
|
-
const addError = formatPagefindErrors(
|
|
52
|
-
`index.addCustomRecord(${sourcePath})`,
|
|
53
|
-
addErrors,
|
|
54
|
-
);
|
|
55
|
-
if (addError) {
|
|
56
|
-
throw new Error(addError);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getPdfSourceByOutputPath(siteVariables) {
|
|
61
|
-
const contentDir = getContentDir();
|
|
62
|
-
const contentFiles = getBuildContentFiles(
|
|
63
|
-
contentDir,
|
|
64
|
-
Object.keys(siteVariables?.codeLanguages || {}),
|
|
65
|
-
);
|
|
66
|
-
const pdfFiles = contentFiles.filter(
|
|
67
|
-
filePath => path.extname(filePath).toLowerCase() === '.pdf',
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
return new Map(
|
|
71
|
-
pdfFiles.map(filePath => {
|
|
72
|
-
const relPath = path.relative(contentDir, filePath);
|
|
73
|
-
return [normalizeOutputPath(`/${relPath}`), filePath];
|
|
74
|
-
}),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function collectIndexTargets(
|
|
79
|
-
htmlAssetsByPath,
|
|
80
|
-
siteVariables,
|
|
81
|
-
pdfSourceByOutputPath,
|
|
82
|
-
) {
|
|
83
|
-
if (htmlAssetsByPath.size === 0) {
|
|
84
|
-
return { reachableHtmlPaths: [], reachablePdfPaths: [] };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return collectReachableSiteAssets({
|
|
88
|
-
htmlAssetsByPath,
|
|
89
|
-
knownPdfPaths: new Set(pdfSourceByOutputPath.keys()),
|
|
90
|
-
rootPath: 'index.html',
|
|
91
|
-
basePath: siteVariables?.basePath || '/',
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function buildIndex({
|
|
96
|
-
distPath,
|
|
97
|
-
htmlAssetsByPath,
|
|
98
|
-
reachableHtmlPaths,
|
|
99
|
-
reachablePdfPaths,
|
|
100
|
-
pdfSourceByOutputPath,
|
|
101
|
-
loadPagefind = getPagefind,
|
|
102
|
-
checkMutool = assertMutoolAvailable,
|
|
103
|
-
extractPages = extractPdfPages,
|
|
104
|
-
}) {
|
|
105
|
-
const pagefind = await loadPagefind();
|
|
106
|
-
const { index, errors: createErrors } = await pagefind.createIndex({
|
|
107
|
-
keepIndexUrl: true,
|
|
108
|
-
verbose: PAGEFIND_VERBOSE,
|
|
109
|
-
});
|
|
110
|
-
const createError = formatPagefindErrors(
|
|
111
|
-
'pagefind.createIndex()',
|
|
112
|
-
createErrors,
|
|
113
|
-
);
|
|
114
|
-
if (createError) {
|
|
115
|
-
throw new Error(createError);
|
|
116
|
-
}
|
|
117
|
-
if (!index) {
|
|
118
|
-
throw new Error('pagefind.createIndex() did not return an index');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
for (const sourcePath of reachableHtmlPaths) {
|
|
123
|
-
await addHtmlFile(index, {
|
|
124
|
-
sourcePath,
|
|
125
|
-
content: htmlAssetsByPath.get(sourcePath),
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
let mutoolAvailable = true;
|
|
130
|
-
if (reachablePdfPaths.length > 0) {
|
|
131
|
-
try {
|
|
132
|
-
await checkMutool();
|
|
133
|
-
} catch {
|
|
134
|
-
mutoolAvailable = false;
|
|
135
|
-
log.warn`mutool was not found; search results will not include PDFs`;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
for (const pdfPath of mutoolAvailable ? reachablePdfPaths : []) {
|
|
140
|
-
const sourceFilePath = pdfSourceByOutputPath.get(pdfPath);
|
|
141
|
-
if (!sourceFilePath) {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const { pages, hasExtractedText } = await extractPages(sourceFilePath);
|
|
146
|
-
const title = path.posix.basename(pdfPath);
|
|
147
|
-
|
|
148
|
-
if (!hasExtractedText) {
|
|
149
|
-
await addPdfRecord(
|
|
150
|
-
index,
|
|
151
|
-
{ url: pdfPath, content: title, language: 'en', meta: { title } },
|
|
152
|
-
pdfPath,
|
|
153
|
-
);
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
for (const page of pages) {
|
|
158
|
-
await addPdfRecord(
|
|
159
|
-
index,
|
|
160
|
-
{
|
|
161
|
-
url: `${pdfPath}#page=${page.pageNumber}`,
|
|
162
|
-
content: page.content,
|
|
163
|
-
language: 'en',
|
|
164
|
-
meta: { title, page: String(page.pageNumber) },
|
|
165
|
-
},
|
|
166
|
-
`${pdfPath}#page=${page.pageNumber}`,
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const { errors: writeErrors } = await index.writeFiles({
|
|
172
|
-
outputPath: path.join(distPath, PAGEFIND_OUTPUT_SUBDIR),
|
|
173
|
-
});
|
|
174
|
-
const writeError = formatPagefindErrors('index.writeFiles()', writeErrors);
|
|
175
|
-
if (writeError) {
|
|
176
|
-
throw new Error(writeError);
|
|
177
|
-
}
|
|
178
|
-
} finally {
|
|
179
|
-
await index.deleteIndex().catch(() => null);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
class PagefindPlugin {
|
|
184
|
-
constructor(siteVariables) {
|
|
185
|
-
this.siteVariables = siteVariables || {};
|
|
186
|
-
this.watchRunInProgress = false;
|
|
187
|
-
this.watchRunQueued = false;
|
|
188
|
-
this.lastDistPath = null;
|
|
189
|
-
this.htmlCacheByAssetPath = new Map();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
getHtmlAssetsByPath(compilation, distPath, outputFileSystem) {
|
|
193
|
-
return new Map(
|
|
194
|
-
compilation
|
|
195
|
-
.getAssets()
|
|
196
|
-
.filter(asset => asset.name.endsWith('.html'))
|
|
197
|
-
.map(asset => [
|
|
198
|
-
asset.name.replace(/\\/g, '/'),
|
|
199
|
-
readAssetContent(
|
|
200
|
-
outputFileSystem,
|
|
201
|
-
distPath,
|
|
202
|
-
asset.name.replace(/\\/g, '/'),
|
|
203
|
-
),
|
|
204
|
-
]),
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
getIndexTargets(htmlAssetsByPath) {
|
|
209
|
-
return collectIndexTargets(
|
|
210
|
-
htmlAssetsByPath,
|
|
211
|
-
this.siteVariables,
|
|
212
|
-
getPdfSourceByOutputPath(this.siteVariables),
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
runWatchIndex() {
|
|
217
|
-
if (this.watchRunInProgress) {
|
|
218
|
-
this.watchRunQueued = true;
|
|
219
|
-
log.info`Indexing is still running in the background; queueing a rerun`;
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
this.watchRunInProgress = true;
|
|
224
|
-
this.watchRunQueued = false;
|
|
225
|
-
const distPath = this.lastDistPath;
|
|
226
|
-
const htmlAssetsByPath = new Map(this.htmlCacheByAssetPath);
|
|
227
|
-
const pdfSourceByOutputPath = getPdfSourceByOutputPath(this.siteVariables);
|
|
228
|
-
const start = Date.now();
|
|
229
|
-
|
|
230
|
-
log.debug`Preparing search index background snapshot`;
|
|
231
|
-
|
|
232
|
-
let reachableHtmlPaths;
|
|
233
|
-
let reachablePdfPaths;
|
|
234
|
-
try {
|
|
235
|
-
({ reachableHtmlPaths, reachablePdfPaths } = collectIndexTargets(
|
|
236
|
-
htmlAssetsByPath,
|
|
237
|
-
this.siteVariables,
|
|
238
|
-
pdfSourceByOutputPath,
|
|
239
|
-
));
|
|
240
|
-
} catch (err) {
|
|
241
|
-
this.watchRunInProgress = false;
|
|
242
|
-
log.warn`Pagefind failed: ${err.message}`;
|
|
243
|
-
if (this.watchRunQueued) {
|
|
244
|
-
this.runWatchIndex();
|
|
245
|
-
}
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const snapshotReadyAt = Date.now();
|
|
250
|
-
log.debug`Building search index in background`;
|
|
251
|
-
buildIndex({
|
|
252
|
-
distPath,
|
|
253
|
-
htmlAssetsByPath,
|
|
254
|
-
reachableHtmlPaths,
|
|
255
|
-
reachablePdfPaths,
|
|
256
|
-
pdfSourceByOutputPath,
|
|
257
|
-
})
|
|
258
|
-
.then(() => {
|
|
259
|
-
const finishedAt = Date.now();
|
|
260
|
-
log.info`Background search index ready in ${finishedAt - snapshotReadyAt}ms (${finishedAt - start}ms total)`;
|
|
261
|
-
})
|
|
262
|
-
.catch(err => {
|
|
263
|
-
const failedAt = Date.now();
|
|
264
|
-
log.warn`Search index failed after ${failedAt - snapshotReadyAt}ms of indexing (${failedAt - start}ms total): ${err.message}`;
|
|
265
|
-
})
|
|
266
|
-
.finally(() => {
|
|
267
|
-
this.watchRunInProgress = false;
|
|
268
|
-
if (this.watchRunQueued) {
|
|
269
|
-
log.info`Starting queued Pagefind background rerun`;
|
|
270
|
-
this.runWatchIndex();
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
apply(compiler) {
|
|
276
|
-
compiler.hooks.afterEmit.tapAsync(
|
|
277
|
-
'PagefindPlugin',
|
|
278
|
-
(compilation, callback) => {
|
|
279
|
-
const distPath =
|
|
280
|
-
compiler.options?.output?.path ||
|
|
281
|
-
compiler.outputPath ||
|
|
282
|
-
compilation.compiler.outputPath;
|
|
283
|
-
const outputFileSystem =
|
|
284
|
-
compiler.outputFileSystem ||
|
|
285
|
-
compilation.compiler.outputFileSystem ||
|
|
286
|
-
fs;
|
|
287
|
-
const isWatch = !!compiler.watching;
|
|
288
|
-
|
|
289
|
-
if (compilation.errors.length > 0) {
|
|
290
|
-
callback();
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
let htmlAssetsByPath;
|
|
295
|
-
try {
|
|
296
|
-
htmlAssetsByPath = this.getHtmlAssetsByPath(
|
|
297
|
-
compilation,
|
|
298
|
-
distPath,
|
|
299
|
-
outputFileSystem,
|
|
300
|
-
);
|
|
301
|
-
} catch (err) {
|
|
302
|
-
compilation.errors.push(err);
|
|
303
|
-
callback(err);
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (isWatch) {
|
|
308
|
-
this.lastDistPath = distPath;
|
|
309
|
-
this.htmlCacheByAssetPath = htmlAssetsByPath;
|
|
310
|
-
callback();
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const pdfSourceByOutputPath = getPdfSourceByOutputPath(
|
|
315
|
-
this.siteVariables,
|
|
316
|
-
);
|
|
317
|
-
const start = Date.now();
|
|
318
|
-
let reachableHtmlPaths;
|
|
319
|
-
let reachablePdfPaths;
|
|
320
|
-
|
|
321
|
-
log.info`Finding reachable pages for search index`;
|
|
322
|
-
try {
|
|
323
|
-
({ reachableHtmlPaths, reachablePdfPaths } = collectIndexTargets(
|
|
324
|
-
htmlAssetsByPath,
|
|
325
|
-
this.siteVariables,
|
|
326
|
-
pdfSourceByOutputPath,
|
|
327
|
-
));
|
|
328
|
-
} catch (err) {
|
|
329
|
-
compilation.errors.push(err);
|
|
330
|
-
callback(err);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const snapshotReadyAt = Date.now();
|
|
335
|
-
log.info`Building search index for ${reachableHtmlPaths.length} page(s) and ${reachablePdfPaths.length} PDF(s) after ${snapshotReadyAt - start}ms of snapshot prep`;
|
|
336
|
-
buildIndex({
|
|
337
|
-
distPath,
|
|
338
|
-
htmlAssetsByPath,
|
|
339
|
-
reachableHtmlPaths,
|
|
340
|
-
reachablePdfPaths,
|
|
341
|
-
pdfSourceByOutputPath,
|
|
342
|
-
})
|
|
343
|
-
.then(async () => {
|
|
344
|
-
try {
|
|
345
|
-
const pagefind = await getPagefind();
|
|
346
|
-
await pagefind.close();
|
|
347
|
-
} catch (_err) {
|
|
348
|
-
// Best-effort cleanup for non-watch builds.
|
|
349
|
-
}
|
|
350
|
-
const finishedAt = Date.now();
|
|
351
|
-
log.info`Search index built in ${finishedAt - snapshotReadyAt}ms (${finishedAt - start}ms total)`;
|
|
352
|
-
callback();
|
|
353
|
-
})
|
|
354
|
-
.catch(err => {
|
|
355
|
-
const failedAt = Date.now();
|
|
356
|
-
log.error`Search indexing failed after ${failedAt - snapshotReadyAt}ms of indexing (${failedAt - start}ms total): ${err.message}`;
|
|
357
|
-
compilation.errors.push(err);
|
|
358
|
-
callback(err);
|
|
359
|
-
});
|
|
360
|
-
},
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
compiler.hooks.done.tap('PagefindPluginWatchRun', stats => {
|
|
364
|
-
if (
|
|
365
|
-
!compiler.watching ||
|
|
366
|
-
stats.hasErrors() ||
|
|
367
|
-
ContentWatchPlugin.needsRestart()
|
|
368
|
-
) {
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
setImmediate(() => this.runWatchIndex());
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
module.exports = PagefindPlugin;
|
|
378
|
-
module.exports.buildIndex = buildIndex;
|
|
379
|
-
module.exports.collectIndexTargets = collectIndexTargets;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
const { getFlair } = require('./log');
|
|
2
|
-
const { getDistDir } = require('./util');
|
|
3
|
-
|
|
4
|
-
module.exports = {
|
|
5
|
-
apply: compiler => {
|
|
6
|
-
compiler.hooks.afterEmit.tap('AfterEmitPlugin', compilation => {
|
|
7
|
-
const isWatch =
|
|
8
|
-
!!compiler.watching ||
|
|
9
|
-
!!compiler.watchMode ||
|
|
10
|
-
!!compilation?.compiler?.watchMode;
|
|
11
|
-
if (isWatch) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const distDir = getDistDir();
|
|
16
|
-
|
|
17
|
-
console.log(getFlair());
|
|
18
|
-
console.log(`The build output is available at ${distDir}`);
|
|
19
|
-
console.log('Now use `tada serve` to start a local web server');
|
|
20
|
-
});
|
|
21
|
-
},
|
|
22
|
-
};
|
package/webpack/serve.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { getDistDir } = require('./util');
|
|
4
|
-
const { makeLogger } = require('./log');
|
|
5
|
-
const { B } = require('./colors');
|
|
6
|
-
|
|
7
|
-
const log = makeLogger(__filename);
|
|
8
|
-
|
|
9
|
-
function messageReady(port) {
|
|
10
|
-
if (process.send) {
|
|
11
|
-
process.send({ ready: true, port });
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
let distDir;
|
|
16
|
-
try {
|
|
17
|
-
distDir = getDistDir();
|
|
18
|
-
} catch (err) {
|
|
19
|
-
log.error`Failed to start server: ${err}`;
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function resolvePathname(pathname) {
|
|
24
|
-
let decodedPath;
|
|
25
|
-
try {
|
|
26
|
-
decodedPath = decodeURIComponent(pathname);
|
|
27
|
-
} catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const resolvedPath = path.resolve(distDir, '.' + decodedPath);
|
|
32
|
-
const relativePath = path.relative(distDir, resolvedPath);
|
|
33
|
-
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let stat;
|
|
38
|
-
try {
|
|
39
|
-
stat = fs.statSync(resolvedPath);
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (stat.isDirectory()) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!stat.isFile()) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return resolvedPath;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function createResponse(req) {
|
|
56
|
-
const url = new URL(req.url);
|
|
57
|
-
const filePath = resolvePathname(url.pathname);
|
|
58
|
-
if (!filePath) {
|
|
59
|
-
return new Response('Not Found', { status: 404 });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return new Response(Bun.file(filePath));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function tryListen(port, fallbackPort) {
|
|
66
|
-
return new Promise((resolve, reject) => {
|
|
67
|
-
try {
|
|
68
|
-
const server = Bun.serve({
|
|
69
|
-
port,
|
|
70
|
-
fetch: createResponse,
|
|
71
|
-
error(error) {
|
|
72
|
-
log.error`Request failed: ${error}`;
|
|
73
|
-
return new Response('Internal Server Error', { status: 500 });
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
log.info`Dev server: ${B`http://localhost:${server.port}/index.html`}`;
|
|
78
|
-
messageReady(server.port);
|
|
79
|
-
resolve(server);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
if (err.code === 'EADDRINUSE' && fallbackPort) {
|
|
82
|
-
log.warn`Port ${port} in use, trying fallback ${fallbackPort}...`;
|
|
83
|
-
return tryListen(fallbackPort, null).then(resolve).catch(reject);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
reject(err);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
tryListen(8080, 8081).catch(err => {
|
|
92
|
-
log.error`Failed to start server: ${err}`;
|
|
93
|
-
process.exit(1);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
process.on('uncaughtException', err => {
|
|
97
|
-
log.error`Uncaught exception: ${err}`;
|
|
98
|
-
process.exit(1);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
process.on('unhandledRejection', reason => {
|
|
102
|
-
log.error`Unhandled rejection: ${reason}`;
|
|
103
|
-
process.exit(1);
|
|
104
|
-
});
|
package/webpack/util.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
extensionIsMarkdown,
|
|
3
|
-
getBuildContentFiles,
|
|
4
|
-
getContentFiles,
|
|
5
|
-
getValidInternalTargets,
|
|
6
|
-
shouldSkipContentFile,
|
|
7
|
-
} = require('./utils/content-files');
|
|
8
|
-
const { createDefinePlugin } = require('./utils/define-plugin');
|
|
9
|
-
const { createMarkdown } = require('./utils/markdown');
|
|
10
|
-
const {
|
|
11
|
-
createApplyBasePath,
|
|
12
|
-
getContentDir,
|
|
13
|
-
getDistDir,
|
|
14
|
-
getPackageDir,
|
|
15
|
-
getProjectDir,
|
|
16
|
-
getPublicDir,
|
|
17
|
-
normalizeOutputPath,
|
|
18
|
-
} = require('./utils/paths');
|
|
19
|
-
const {
|
|
20
|
-
injectWebpackAssets,
|
|
21
|
-
renderCodePageAsset,
|
|
22
|
-
renderCopiedContentAsset,
|
|
23
|
-
renderLiterateJavaPageAsset,
|
|
24
|
-
renderPlainTextPageAsset,
|
|
25
|
-
} = require('./utils/render');
|
|
26
|
-
const { parseFrontMatter } = require('./utils/front-matter');
|
|
27
|
-
|
|
28
|
-
module.exports = {
|
|
29
|
-
createMarkdown,
|
|
30
|
-
getContentDir,
|
|
31
|
-
getDistDir,
|
|
32
|
-
getPackageDir,
|
|
33
|
-
getProjectDir,
|
|
34
|
-
getPublicDir,
|
|
35
|
-
getContentFiles,
|
|
36
|
-
getBuildContentFiles,
|
|
37
|
-
getValidInternalTargets,
|
|
38
|
-
shouldSkipContentFile,
|
|
39
|
-
extensionIsMarkdown,
|
|
40
|
-
parseFrontMatter,
|
|
41
|
-
createDefinePlugin,
|
|
42
|
-
createApplyBasePath,
|
|
43
|
-
injectWebpackAssets,
|
|
44
|
-
normalizeOutputPath,
|
|
45
|
-
renderCodePageAsset,
|
|
46
|
-
renderCopiedContentAsset,
|
|
47
|
-
renderLiterateJavaPageAsset,
|
|
48
|
-
renderPlainTextPageAsset,
|
|
49
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const { DefinePlugin } = require('webpack');
|
|
2
|
-
|
|
3
|
-
function createDefinePlugin(siteVariables, isDev = false) {
|
|
4
|
-
return new DefinePlugin({
|
|
5
|
-
'window.siteVariables.base': JSON.stringify(siteVariables.base),
|
|
6
|
-
'window.siteVariables.basePath': JSON.stringify(siteVariables.basePath),
|
|
7
|
-
'window.siteVariables.titlePostfix': JSON.stringify(
|
|
8
|
-
siteVariables.titlePostfix,
|
|
9
|
-
),
|
|
10
|
-
'window.siteVariables.defaultTimeZone': JSON.stringify(
|
|
11
|
-
siteVariables.defaultTimeZone,
|
|
12
|
-
),
|
|
13
|
-
'window.siteVariables.timezones': JSON.stringify(
|
|
14
|
-
require('../../src/timezone/timezones.json'),
|
|
15
|
-
),
|
|
16
|
-
'window.IS_DEV': JSON.stringify(isDev),
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = { createDefinePlugin };
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
|
|
3
|
-
const PUBLIC_ASSET_EXTENSIONS = [
|
|
4
|
-
'png',
|
|
5
|
-
'jpg',
|
|
6
|
-
'jpeg',
|
|
7
|
-
'gif',
|
|
8
|
-
'svg',
|
|
9
|
-
'txt',
|
|
10
|
-
'zip',
|
|
11
|
-
'pdf',
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
function extensionIsMarkdown(ext) {
|
|
15
|
-
return ['.md', '.markdown'].includes(ext);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function isLiterateJava(filePath) {
|
|
19
|
-
return path.basename(filePath).toLowerCase().endsWith('.java.md');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
module.exports = {
|
|
23
|
-
PUBLIC_ASSET_EXTENSIONS,
|
|
24
|
-
extensionIsMarkdown,
|
|
25
|
-
isLiterateJava,
|
|
26
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const { makeLogger } = require('../log');
|
|
2
|
-
|
|
3
|
-
const log = makeLogger(__filename);
|
|
4
|
-
|
|
5
|
-
let highlighter = null;
|
|
6
|
-
|
|
7
|
-
async function initHighlighter(langs) {
|
|
8
|
-
if (highlighter) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
log.info`Initializing syntax highlighter`;
|
|
12
|
-
const { createHighlighter } = await import('shiki');
|
|
13
|
-
highlighter = await createHighlighter({
|
|
14
|
-
themes: ['github-light', 'github-dark'],
|
|
15
|
-
langs,
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function getHighlighter() {
|
|
20
|
-
if (!highlighter) {
|
|
21
|
-
throw new Error('Shiki highlighter not initialized');
|
|
22
|
-
}
|
|
23
|
-
return highlighter;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
module.exports = { initHighlighter, getHighlighter };
|