@abreen/tada 1.17.0 → 1.18.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 +41 -7
- package/bin/tada.ts +23 -9
- package/bin/validators.ts +34 -1
- package/build/branding.ts +41 -0
- package/build/build-manifest.ts +10 -5
- package/build/{watch/compiler-types.d.ts → build-types.d.ts} +8 -5
- package/build/build-validation.ts +176 -0
- package/build/bundle.ts +75 -65
- package/build/columns-plugin.ts +27 -1
- package/build/config-loader.ts +3 -3
- package/build/custom-fonts.ts +8 -5
- package/build/deflist-id-plugin.ts +2 -2
- package/build/generate-favicon.ts +7 -6
- package/build/generate-fonts.ts +8 -15
- package/build/generate-katex-assets.ts +19 -17
- package/build/generate-web-app-manifest.ts +3 -11
- package/build/lodash-template.ts +14 -0
- package/build/output-publication.ts +238 -0
- package/build/pagefind.ts +49 -21
- package/build/pdf-text.ts +41 -1
- package/build/pipeline.ts +95 -101
- package/build/site-assets.ts +46 -0
- package/build/site-build.ts +267 -0
- package/build/source-model.ts +223 -229
- package/build/source-records.ts +69 -81
- package/build/template-globals.ts +3 -0
- package/build/templates.ts +12 -8
- package/build/toc-plugin.ts +21 -21
- package/build/types.d.ts +38 -38
- package/build/util.ts +0 -4
- package/build/utils/code.ts +51 -117
- package/build/utils/final-html.ts +171 -47
- package/build/utils/jdi-runner/LiterateRunner.java +9 -1
- package/build/utils/literate-java.ts +11 -7
- package/build/utils/markdown-partials.ts +4 -3
- package/build/utils/markdown.ts +6 -17
- package/build/utils/paths.ts +3 -0
- package/build/utils/plain-text.ts +18 -0
- package/build/utils/render.ts +197 -154
- package/build/utils/shiki-highlighter.ts +11 -0
- package/build/utils/source-template.ts +2 -2
- package/build/utils/trace-core.ts +8 -83
- package/build/utils/trace.ts +38 -95
- package/build/validate-config-links.ts +39 -6
- package/build/watch/build-incremental.ts +46 -103
- package/build/watch/compiler.ts +158 -37
- package/build/watch/engine.ts +207 -162
- package/build/watch/index.ts +9 -2
- package/build/watch/planner.ts +88 -144
- package/build/watch/runtime.ts +21 -34
- package/build/watch/types.d.ts +32 -64
- package/package.json +4 -5
- package/schema/site.schema.json +18 -2
- package/src/_content.scss +447 -0
- package/src/_fonts.scss +90 -0
- package/src/_layout.scss +50 -35
- package/src/appearance-picker/{style.scss → _index.scss} +1 -1
- package/src/code/{style.scss → _index.scss} +61 -0
- package/src/header/{_base.scss → _index.scss} +98 -6
- package/src/index.ts +1 -17
- package/src/navigate/{style.scss → _index.scss} +20 -0
- package/src/navigate/eligible.ts +0 -40
- package/src/navigate/index.ts +50 -5
- package/src/navigate/lifecycle.ts +19 -2
- package/src/navigate/runtime.ts +20 -4
- package/src/page-update/index.ts +33 -20
- package/src/print/{style.scss → _index.scss} +3 -1
- package/src/search/index.ts +30 -2
- package/src/slides/{style.scss → _index.scss} +5 -0
- package/src/style.scss +24 -536
- package/src/timezone/index.ts +29 -3
- package/src/timezone/time-format.ts +4 -0
- package/src/toc/index.ts +6 -5
- package/src/trace/index.ts +11 -1
- package/templates/_author.html +2 -2
- package/templates/_download.html +1 -1
- package/templates/_footer.html +1 -1
- package/templates/_heading.html +3 -3
- package/templates/_nav.html +2 -2
- package/templates/_page-bottom.html +6 -0
- package/templates/_top.html +18 -14
- package/templates/code.html +22 -21
- package/templates/default.html +12 -11
- package/templates/literate.html +6 -5
- package/build/copy.ts +0 -82
- package/build/generate-content-assets.ts +0 -121
- package/build/utils/content-files.ts +0 -170
- package/build/watch/assets.ts +0 -103
- package/build/watch/build-full.ts +0 -97
- package/build/watch/build-helpers.ts +0 -66
- package/build/watch/build-result.ts +0 -19
- package/build/watch/fs-commit.ts +0 -153
- package/build/watch/mutations.ts +0 -73
- package/build/watch/snapshot.ts +0 -201
- package/build/watch/validation.ts +0 -50
- package/src/code.scss +0 -60
- package/src/critical.scss +0 -5
- package/src/header/style.scss +0 -91
- /package/src/{literate.scss → _literate.scss} +0 -0
- /package/src/{material-symbols.scss → _material-symbols.scss} +0 -0
- /package/src/anchor/{style.scss → _index.scss} +0 -0
- /package/src/page-update/{style.scss → _index.scss} +0 -0
- /package/src/question/{style.scss → _index.scss} +0 -0
- /package/src/search/{style.scss → _index.scss} +0 -0
- /package/src/timezone/{style.scss → _index.scss} +0 -0
- /package/src/toc/{style.scss → _index.scss} +0 -0
- /package/src/trace/{style.scss → _index.scss} +0 -0
package/build/utils/render.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import
|
|
3
|
+
import { compileTemplate } from '../lodash-template';
|
|
4
4
|
import type MarkdownIt from 'markdown-it';
|
|
5
|
-
import { stripHtml } from 'string-strip-html';
|
|
6
5
|
import { makeLogger } from '../log';
|
|
7
6
|
import { B } from '../colors';
|
|
8
7
|
import createTemplateGlobals from '../template-globals';
|
|
@@ -28,9 +27,11 @@ import {
|
|
|
28
27
|
import { extensionIsMarkdown } from './file-types';
|
|
29
28
|
import { createTraceHelpers } from './trace';
|
|
30
29
|
import { stripHtmlComments } from './html-comments';
|
|
30
|
+
import { htmlToPlainText } from './plain-text';
|
|
31
31
|
import { finalizeHtmlPage } from './final-html';
|
|
32
32
|
import {
|
|
33
33
|
createApplyBasePath,
|
|
34
|
+
getProjectDir,
|
|
34
35
|
normalizeOutputPath,
|
|
35
36
|
toPosix,
|
|
36
37
|
toUrlPath,
|
|
@@ -41,7 +42,7 @@ import { parseFrontMatterAndContent } from './front-matter';
|
|
|
41
42
|
import { createMarkdown } from './markdown';
|
|
42
43
|
import { generateTocHtml, generateCodeTocHtml } from '../toc-plugin';
|
|
43
44
|
import {
|
|
44
|
-
|
|
45
|
+
extractLiterateJavaCode,
|
|
45
46
|
hasMainMethod,
|
|
46
47
|
deriveClassName,
|
|
47
48
|
compileJavaSource,
|
|
@@ -55,7 +56,6 @@ import type {
|
|
|
55
56
|
RenderLiterateJavaOptions,
|
|
56
57
|
RenderCopiedContentOptions,
|
|
57
58
|
RenderDependencyCollector,
|
|
58
|
-
TraceToolAvailability,
|
|
59
59
|
} from '../types';
|
|
60
60
|
|
|
61
61
|
const log = makeLogger(import.meta.url);
|
|
@@ -66,9 +66,18 @@ export { stripHtmlComments } from './html-comments';
|
|
|
66
66
|
|
|
67
67
|
const REQUIRED_FRONT_MATTER_FIELDS = ['title'];
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
// Page variables that renderers assign themselves. Front matter that sets one
|
|
70
|
+
// would be overwritten or, for `template`, select a nonexistent template.
|
|
71
|
+
const RESERVED_FRONT_MATTER_KEYS: readonly string[] = [
|
|
72
|
+
'template',
|
|
73
|
+
'titleHtml',
|
|
74
|
+
'descriptionHtml',
|
|
75
|
+
'tocHtml',
|
|
76
|
+
'tocItems',
|
|
77
|
+
'codeFilePath',
|
|
78
|
+
'downloadName',
|
|
79
|
+
'filePath',
|
|
80
|
+
];
|
|
72
81
|
|
|
73
82
|
function renderInlineField(
|
|
74
83
|
md: MarkdownIt,
|
|
@@ -81,7 +90,7 @@ function renderInlineField(
|
|
|
81
90
|
}
|
|
82
91
|
const html = md.renderInline(raw);
|
|
83
92
|
vars[`${field}Html`] = html;
|
|
84
|
-
vars[field] =
|
|
93
|
+
vars[field] = htmlToPlainText(html);
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
interface TemplateParametersInput {
|
|
@@ -120,6 +129,19 @@ function resolveAuthor(
|
|
|
120
129
|
pageVariables.author = authorEntry;
|
|
121
130
|
}
|
|
122
131
|
|
|
132
|
+
function rejectReservedFrontMatterKeys(
|
|
133
|
+
pageVariables: Record<string, unknown>,
|
|
134
|
+
filePath: string,
|
|
135
|
+
): void {
|
|
136
|
+
const key = RESERVED_FRONT_MATTER_KEYS.find(k =>
|
|
137
|
+
Object.hasOwn(pageVariables, k),
|
|
138
|
+
);
|
|
139
|
+
if (key) {
|
|
140
|
+
const displayPath = toPosix(path.relative(getProjectDir(), filePath));
|
|
141
|
+
throw new Error(`${displayPath}: front matter key "${key}" is reserved`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
123
145
|
function validateFrontMatter(
|
|
124
146
|
pageVariables: Record<string, unknown>,
|
|
125
147
|
filePath: string,
|
|
@@ -166,10 +188,17 @@ function renderSiteBanner(siteVariables: SiteVariables): string {
|
|
|
166
188
|
return createMarkdown(siteVariables).render(siteVariables.banner);
|
|
167
189
|
}
|
|
168
190
|
|
|
191
|
+
// `<meta charset>` is the first element in `<head>` so browsers find it within
|
|
192
|
+
// the first 1024 bytes. Tags injected into the head go right after it.
|
|
193
|
+
const CHARSET_META_PATTERN = /<meta charset="UTF-8"\s*\/?>/;
|
|
194
|
+
|
|
195
|
+
function insertAfterCharsetMeta(html: string, tags: string): string {
|
|
196
|
+
return html.replace(CHARSET_META_PATTERN, charsetMeta => charsetMeta + tags);
|
|
197
|
+
}
|
|
198
|
+
|
|
169
199
|
export function injectAssetTags(
|
|
170
200
|
html: string,
|
|
171
201
|
assetFiles: string[],
|
|
172
|
-
distDir: string,
|
|
173
202
|
siteVariables: SiteVariables,
|
|
174
203
|
): string {
|
|
175
204
|
const jsAssets = assetFiles.filter(f => f.endsWith('.js'));
|
|
@@ -181,15 +210,8 @@ export function injectAssetTags(
|
|
|
181
210
|
`<script defer src="${normalizeOutputPath('/' + asset)}"></script>`,
|
|
182
211
|
)
|
|
183
212
|
.join('');
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
const criticalTags = criticalAssets
|
|
187
|
-
.map(asset => {
|
|
188
|
-
const css = fs.readFileSync(path.join(distDir, asset), 'utf-8');
|
|
189
|
-
return `<style>${css}</style>`;
|
|
190
|
-
})
|
|
191
|
-
.join('');
|
|
192
|
-
const asyncLinkTags = asyncAssets
|
|
213
|
+
// Render-blocking on purpose: pages never paint without the full stylesheet
|
|
214
|
+
const stylesheetTags = cssAssets
|
|
193
215
|
.map(
|
|
194
216
|
asset =>
|
|
195
217
|
`<link href="${normalizeOutputPath('/' + asset)}" rel="stylesheet">`,
|
|
@@ -197,11 +219,6 @@ export function injectAssetTags(
|
|
|
197
219
|
.join('');
|
|
198
220
|
|
|
199
221
|
const fontPreloadTags = getDefaultFontPreloadFiles(siteVariables)
|
|
200
|
-
.filter(
|
|
201
|
-
preload =>
|
|
202
|
-
preload.source === 'public' ||
|
|
203
|
-
fs.existsSync(path.join(distDir, preload.filePath)),
|
|
204
|
-
)
|
|
205
222
|
.map(preload => {
|
|
206
223
|
const urlPath =
|
|
207
224
|
preload.source === 'public'
|
|
@@ -211,31 +228,27 @@ export function injectAssetTags(
|
|
|
211
228
|
})
|
|
212
229
|
.join('');
|
|
213
230
|
|
|
214
|
-
return
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
.replace('</head>', `${scriptTags}</head>`);
|
|
231
|
+
return insertAfterCharsetMeta(
|
|
232
|
+
html,
|
|
233
|
+
`${fontPreloadTags}${stylesheetTags}`,
|
|
234
|
+
).replace('</head>', `${scriptTags}</head>`);
|
|
220
235
|
}
|
|
221
236
|
|
|
222
237
|
export function injectKatexStylesheet(html: string): string {
|
|
223
238
|
const tag = `<link href="/katex/katex.min.css" rel="stylesheet">`;
|
|
224
|
-
return html
|
|
239
|
+
return insertAfterCharsetMeta(html, tag);
|
|
225
240
|
}
|
|
226
241
|
|
|
227
242
|
export function preparePageTemplateHtml({
|
|
228
243
|
templateHtml,
|
|
229
244
|
assetFiles,
|
|
230
|
-
distDir,
|
|
231
245
|
siteVariables,
|
|
232
246
|
}: {
|
|
233
247
|
templateHtml: string;
|
|
234
248
|
assetFiles: string[];
|
|
235
|
-
distDir: string;
|
|
236
249
|
siteVariables: SiteVariables;
|
|
237
250
|
}): string {
|
|
238
|
-
let html = injectAssetTags(templateHtml, assetFiles,
|
|
251
|
+
let html = injectAssetTags(templateHtml, assetFiles, siteVariables);
|
|
239
252
|
if (templateHtml.includes('class="katex"')) {
|
|
240
253
|
html = injectKatexStylesheet(html);
|
|
241
254
|
}
|
|
@@ -249,13 +262,14 @@ function toContentAssetPath(contentDir: string, filePath: string): string {
|
|
|
249
262
|
export function renderPlainTextPageAsset({
|
|
250
263
|
filePath,
|
|
251
264
|
contentDir,
|
|
252
|
-
distDir,
|
|
253
265
|
siteVariables,
|
|
254
266
|
validInternalTargets,
|
|
255
267
|
assetFiles,
|
|
268
|
+
isWatchMode,
|
|
256
269
|
literateJavaOutputPaths,
|
|
270
|
+
generatedPageTargets,
|
|
271
|
+
codePageSourceTargets,
|
|
257
272
|
dependencyCollector,
|
|
258
|
-
cachedTraceSourceDir,
|
|
259
273
|
traceCache,
|
|
260
274
|
traceToolAvailability,
|
|
261
275
|
}: RenderPlainTextOptions): Asset[] {
|
|
@@ -264,34 +278,21 @@ export function renderPlainTextPageAsset({
|
|
|
264
278
|
const sourceUrlPath = normalizeOutputPath(`/${subPath}.html`);
|
|
265
279
|
|
|
266
280
|
log.info`Rendering page ${B`${subPath + ext}`}`;
|
|
267
|
-
const
|
|
268
|
-
const { content, pageVariables, tocItems, alertIds } = renderPlainTextContent(
|
|
281
|
+
const { content, pageVariables, tocItems } = renderPlainTextContent(
|
|
269
282
|
filePath,
|
|
270
283
|
subPath,
|
|
271
284
|
sourceUrlPath,
|
|
272
285
|
siteVariables,
|
|
273
286
|
validInternalTargets,
|
|
274
|
-
|
|
275
|
-
{
|
|
276
|
-
dependencyCollector,
|
|
277
|
-
traceCache,
|
|
278
|
-
contentDir,
|
|
279
|
-
distDir,
|
|
280
|
-
cachedTraceSourceDir,
|
|
281
|
-
traceToolAvailability,
|
|
282
|
-
},
|
|
287
|
+
isWatchMode,
|
|
288
|
+
{ dependencyCollector, traceCache, contentDir, traceToolAvailability },
|
|
283
289
|
);
|
|
284
290
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (!pageVariables.template) {
|
|
288
|
-
pageVariables.template = 'default';
|
|
289
|
-
}
|
|
291
|
+
pageVariables.template = 'default';
|
|
290
292
|
|
|
291
293
|
if (pageVariables.toc && tocItems) {
|
|
292
294
|
pageVariables.tocHtml = generateTocHtml(
|
|
293
295
|
tocItems as Parameters<typeof generateTocHtml>[0],
|
|
294
|
-
alertIds,
|
|
295
296
|
);
|
|
296
297
|
}
|
|
297
298
|
|
|
@@ -300,7 +301,7 @@ export function renderPlainTextPageAsset({
|
|
|
300
301
|
siteVariables,
|
|
301
302
|
content,
|
|
302
303
|
subPath,
|
|
303
|
-
isWatchMode
|
|
304
|
+
isWatchMode,
|
|
304
305
|
bannerHtml: renderSiteBanner(siteVariables),
|
|
305
306
|
});
|
|
306
307
|
|
|
@@ -310,16 +311,13 @@ export function renderPlainTextPageAsset({
|
|
|
310
311
|
) as string;
|
|
311
312
|
const finalized = finalizeHtmlPage({
|
|
312
313
|
filePath,
|
|
313
|
-
html: preparePageTemplateHtml({
|
|
314
|
-
templateHtml,
|
|
315
|
-
assetFiles,
|
|
316
|
-
distDir,
|
|
317
|
-
siteVariables,
|
|
318
|
-
}),
|
|
314
|
+
html: preparePageTemplateHtml({ templateHtml, assetFiles, siteVariables }),
|
|
319
315
|
siteVariables,
|
|
320
316
|
sourceUrlPath,
|
|
321
317
|
validInternalTargets,
|
|
322
318
|
literateJavaOutputPaths,
|
|
319
|
+
generatedPageTargets,
|
|
320
|
+
codePageSourceTargets,
|
|
323
321
|
dependencyCollector,
|
|
324
322
|
});
|
|
325
323
|
|
|
@@ -335,11 +333,13 @@ export function renderPlainTextPageAsset({
|
|
|
335
333
|
export function renderCodePageAsset({
|
|
336
334
|
filePath,
|
|
337
335
|
contentDir,
|
|
338
|
-
distDir,
|
|
339
336
|
siteVariables,
|
|
340
337
|
assetFiles,
|
|
338
|
+
isWatchMode,
|
|
341
339
|
validInternalTargets,
|
|
342
340
|
literateJavaOutputPaths,
|
|
341
|
+
generatedPageTargets,
|
|
342
|
+
codePageSourceTargets,
|
|
343
343
|
dependencyCollector,
|
|
344
344
|
}: RenderCodePageOptions): Asset[] {
|
|
345
345
|
const { dir, name, ext } = path.parse(filePath);
|
|
@@ -382,23 +382,20 @@ export function renderCodePageAsset({
|
|
|
382
382
|
siteVariables,
|
|
383
383
|
content,
|
|
384
384
|
subPath,
|
|
385
|
-
isWatchMode
|
|
385
|
+
isWatchMode,
|
|
386
386
|
bannerHtml: renderSiteBanner(siteVariables),
|
|
387
387
|
});
|
|
388
388
|
|
|
389
389
|
const templateHtml = render('code.html', templateParameters) as string;
|
|
390
390
|
const finalized = finalizeHtmlPage({
|
|
391
391
|
filePath,
|
|
392
|
-
html: preparePageTemplateHtml({
|
|
393
|
-
templateHtml,
|
|
394
|
-
assetFiles,
|
|
395
|
-
distDir,
|
|
396
|
-
siteVariables,
|
|
397
|
-
}),
|
|
392
|
+
html: preparePageTemplateHtml({ templateHtml, assetFiles, siteVariables }),
|
|
398
393
|
siteVariables,
|
|
399
394
|
sourceUrlPath,
|
|
400
395
|
validInternalTargets,
|
|
401
396
|
literateJavaOutputPaths,
|
|
397
|
+
generatedPageTargets,
|
|
398
|
+
codePageSourceTargets,
|
|
402
399
|
dependencyCollector,
|
|
403
400
|
});
|
|
404
401
|
|
|
@@ -442,58 +439,42 @@ export function renderCopiedContentAsset({
|
|
|
442
439
|
return [{ assetPath: relPath, content: templated }];
|
|
443
440
|
}
|
|
444
441
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
filePath: string
|
|
448
|
-
subPath: string
|
|
449
|
-
sourceUrlPath: string
|
|
450
|
-
siteVariables: SiteVariables
|
|
451
|
-
validInternalTargets:
|
|
452
|
-
isWatchMode: boolean
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
distDir,
|
|
458
|
-
cachedTraceSourceDir,
|
|
459
|
-
traceToolAvailability,
|
|
460
|
-
}: {
|
|
461
|
-
dependencyCollector?: RenderDependencyCollector;
|
|
462
|
-
traceCache?: Map<
|
|
463
|
-
string,
|
|
464
|
-
{
|
|
465
|
-
manifestUrl: string;
|
|
466
|
-
artifactId: string;
|
|
467
|
-
highlightedSources: { file: string; highlightedSource: string }[];
|
|
468
|
-
totalSteps: number;
|
|
469
|
-
sourceMtims: Record<string, number>;
|
|
470
|
-
}
|
|
471
|
-
>;
|
|
472
|
-
contentDir?: string;
|
|
473
|
-
distDir?: string;
|
|
474
|
-
cachedTraceSourceDir?: string;
|
|
475
|
-
traceToolAvailability?: TraceToolAvailability;
|
|
476
|
-
} = {},
|
|
477
|
-
): {
|
|
478
|
-
content: string | null;
|
|
479
|
-
pageVariables: Record<string, unknown>;
|
|
480
|
-
tocItems: unknown[] | null;
|
|
481
|
-
alertIds: string[];
|
|
482
|
-
} {
|
|
483
|
-
const applyBasePath = createApplyBasePath(siteVariables);
|
|
442
|
+
interface PreparePageVariablesInput {
|
|
443
|
+
rawPageVariables: Record<string, unknown>;
|
|
444
|
+
filePath: string;
|
|
445
|
+
subPath: string;
|
|
446
|
+
sourceUrlPath: string;
|
|
447
|
+
siteVariables: SiteVariables;
|
|
448
|
+
validInternalTargets: ReadonlySet<string>;
|
|
449
|
+
isWatchMode: boolean;
|
|
450
|
+
/** Whether this renderer supports `slides: true` (Markdown pages only) */
|
|
451
|
+
allowSlides: boolean;
|
|
452
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
453
|
+
}
|
|
484
454
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
455
|
+
/**
|
|
456
|
+
* Turns parsed front matter into page variables. Shared by every renderer
|
|
457
|
+
* whose source has front matter, so each one applies the same rules:
|
|
458
|
+
* Lodash processing of string values, inline Markdown for the title and
|
|
459
|
+
* description, required fields, author lookup, and parent link validation.
|
|
460
|
+
*/
|
|
461
|
+
function preparePageVariables({
|
|
462
|
+
rawPageVariables,
|
|
463
|
+
filePath,
|
|
464
|
+
subPath,
|
|
465
|
+
sourceUrlPath,
|
|
466
|
+
siteVariables,
|
|
467
|
+
validInternalTargets,
|
|
468
|
+
isWatchMode,
|
|
469
|
+
allowSlides,
|
|
470
|
+
dependencyCollector,
|
|
471
|
+
}: PreparePageVariablesInput): Record<string, unknown> {
|
|
472
|
+
rejectReservedFrontMatterKeys(rawPageVariables, filePath);
|
|
473
|
+
if (rawPageVariables.slides === true && !allowSlides) {
|
|
489
474
|
throw new Error(
|
|
490
475
|
`${filePath}: slides mode is only supported on Markdown pages`,
|
|
491
476
|
);
|
|
492
477
|
}
|
|
493
|
-
const frontMatterMd = createMarkdown(siteVariables, {
|
|
494
|
-
filePath,
|
|
495
|
-
slides: pageVariables.slides === true,
|
|
496
|
-
});
|
|
497
478
|
|
|
498
479
|
// Handle substitutions inside front matter using siteVariables
|
|
499
480
|
const siteOnlyParams = createTemplateParameters({
|
|
@@ -503,21 +484,26 @@ function renderPlainTextContent(
|
|
|
503
484
|
subPath,
|
|
504
485
|
isWatchMode,
|
|
505
486
|
});
|
|
506
|
-
const
|
|
507
|
-
Object.entries(
|
|
487
|
+
const pageVariables: Record<string, unknown> = Object.fromEntries(
|
|
488
|
+
Object.entries(rawPageVariables).map(([k, v]) => [
|
|
508
489
|
k,
|
|
509
|
-
typeof v === 'string' ?
|
|
490
|
+
typeof v === 'string' ? compileTemplate(v)(siteOnlyParams) : v,
|
|
510
491
|
]),
|
|
511
492
|
);
|
|
512
493
|
|
|
513
494
|
// Render title and description as inline Markdown
|
|
514
|
-
|
|
515
|
-
|
|
495
|
+
const frontMatterMd = createMarkdown(siteVariables, {
|
|
496
|
+
filePath,
|
|
497
|
+
slides: pageVariables.slides === true,
|
|
498
|
+
});
|
|
499
|
+
renderInlineField(frontMatterMd, pageVariables, 'title');
|
|
500
|
+
renderInlineField(frontMatterMd, pageVariables, 'description');
|
|
516
501
|
|
|
517
|
-
|
|
502
|
+
validateFrontMatter(pageVariables, filePath);
|
|
503
|
+
resolveAuthor(pageVariables, filePath, dependencyCollector);
|
|
518
504
|
|
|
519
505
|
const parentError = validateParentLink(
|
|
520
|
-
|
|
506
|
+
pageVariables.parent,
|
|
521
507
|
filePath,
|
|
522
508
|
validInternalTargets,
|
|
523
509
|
sourceUrlPath,
|
|
@@ -526,40 +512,84 @@ function renderPlainTextContent(
|
|
|
526
512
|
throw new Error(parentError);
|
|
527
513
|
}
|
|
528
514
|
const resolvedParentTarget = resolveParentLinkTarget(
|
|
529
|
-
|
|
515
|
+
pageVariables.parent,
|
|
530
516
|
sourceUrlPath,
|
|
531
517
|
);
|
|
532
518
|
if (resolvedParentTarget) {
|
|
533
519
|
dependencyCollector?.internalTargets?.add(resolvedParentTarget);
|
|
534
520
|
}
|
|
535
521
|
|
|
522
|
+
return pageVariables;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/** Parses the file, renders using template, returns HTML & params used to generate page */
|
|
526
|
+
function renderPlainTextContent(
|
|
527
|
+
filePath: string,
|
|
528
|
+
subPath: string,
|
|
529
|
+
sourceUrlPath: string,
|
|
530
|
+
siteVariables: SiteVariables,
|
|
531
|
+
validInternalTargets: ReadonlySet<string>,
|
|
532
|
+
isWatchMode: boolean,
|
|
533
|
+
{
|
|
534
|
+
dependencyCollector,
|
|
535
|
+
traceCache,
|
|
536
|
+
contentDir,
|
|
537
|
+
traceToolAvailability,
|
|
538
|
+
}: Pick<
|
|
539
|
+
RenderPlainTextOptions,
|
|
540
|
+
| 'dependencyCollector'
|
|
541
|
+
| 'traceCache'
|
|
542
|
+
| 'contentDir'
|
|
543
|
+
| 'traceToolAvailability'
|
|
544
|
+
>,
|
|
545
|
+
): {
|
|
546
|
+
content: string | null;
|
|
547
|
+
pageVariables: Record<string, unknown>;
|
|
548
|
+
tocItems: unknown[] | null;
|
|
549
|
+
} {
|
|
550
|
+
const applyBasePath = createApplyBasePath(siteVariables);
|
|
551
|
+
|
|
552
|
+
const ext = path.extname(filePath);
|
|
553
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
554
|
+
const { pageVariables: rawPageVariables, content } =
|
|
555
|
+
parseFrontMatterAndContent(raw, ext);
|
|
556
|
+
const pageVariables = preparePageVariables({
|
|
557
|
+
rawPageVariables,
|
|
558
|
+
filePath,
|
|
559
|
+
subPath,
|
|
560
|
+
sourceUrlPath,
|
|
561
|
+
siteVariables,
|
|
562
|
+
validInternalTargets,
|
|
563
|
+
isWatchMode,
|
|
564
|
+
allowSlides: extensionIsMarkdown(ext),
|
|
565
|
+
dependencyCollector,
|
|
566
|
+
});
|
|
567
|
+
|
|
536
568
|
const strippedContent = stripHtmlComments(content);
|
|
537
569
|
|
|
538
570
|
const params = createTemplateParameters({
|
|
539
|
-
pageVariables
|
|
571
|
+
pageVariables,
|
|
540
572
|
siteVariables,
|
|
541
573
|
content: strippedContent,
|
|
542
574
|
subPath,
|
|
543
575
|
isWatchMode,
|
|
544
576
|
});
|
|
545
577
|
|
|
546
|
-
if (traceCache
|
|
578
|
+
if (traceCache) {
|
|
547
579
|
const helpers = createTraceHelpers({
|
|
548
580
|
filePath,
|
|
549
581
|
contentDir,
|
|
550
|
-
distDir,
|
|
551
582
|
applyBasePath,
|
|
552
583
|
cache: traceCache,
|
|
553
584
|
toolAvailability: traceToolAvailability,
|
|
554
585
|
dependencyCollector,
|
|
555
|
-
cachedTraceSourceDir,
|
|
556
586
|
});
|
|
557
587
|
params.renderTrace = helpers.renderTrace;
|
|
558
588
|
}
|
|
559
589
|
|
|
560
590
|
let html: string;
|
|
561
591
|
try {
|
|
562
|
-
html =
|
|
592
|
+
html = compileTemplate(strippedContent)(params);
|
|
563
593
|
} catch (err: unknown) {
|
|
564
594
|
throw new Error(
|
|
565
595
|
`${filePath}: Lodash template error in page or template: ${(err as Error).message}`,
|
|
@@ -568,7 +598,6 @@ function renderPlainTextContent(
|
|
|
568
598
|
}
|
|
569
599
|
|
|
570
600
|
let tocItems: unknown[] | null = null;
|
|
571
|
-
let alertIds: string[] = [];
|
|
572
601
|
if (extensionIsMarkdown(ext)) {
|
|
573
602
|
const md = createMarkdown(siteVariables, {
|
|
574
603
|
filePath,
|
|
@@ -576,29 +605,29 @@ function renderPlainTextContent(
|
|
|
576
605
|
templateParams: params,
|
|
577
606
|
dependencyCollector,
|
|
578
607
|
});
|
|
579
|
-
const env: Record<string, unknown> = {
|
|
608
|
+
const env: Record<string, unknown> = {};
|
|
580
609
|
html = md.render(html!, env);
|
|
581
610
|
tocItems = (env.tocItems as unknown[] | undefined) || null;
|
|
582
|
-
alertIds = env.alertIds as string[];
|
|
583
611
|
}
|
|
584
612
|
|
|
585
613
|
return {
|
|
586
614
|
content: html,
|
|
587
615
|
pageVariables: params.page as Record<string, unknown>,
|
|
588
616
|
tocItems,
|
|
589
|
-
alertIds,
|
|
590
617
|
};
|
|
591
618
|
}
|
|
592
619
|
|
|
593
620
|
export function renderLiterateJavaPageAsset({
|
|
594
621
|
filePath,
|
|
595
622
|
contentDir,
|
|
596
|
-
distDir,
|
|
597
623
|
siteVariables,
|
|
598
624
|
assetFiles,
|
|
625
|
+
isWatchMode,
|
|
599
626
|
skipExecution,
|
|
600
627
|
validInternalTargets,
|
|
601
628
|
literateJavaOutputPaths,
|
|
629
|
+
generatedPageTargets,
|
|
630
|
+
codePageSourceTargets,
|
|
602
631
|
dependencyCollector,
|
|
603
632
|
}: RenderLiterateJavaOptions): Asset[] {
|
|
604
633
|
const { dir, name } = path.parse(filePath);
|
|
@@ -607,16 +636,38 @@ export function renderLiterateJavaPageAsset({
|
|
|
607
636
|
|
|
608
637
|
log.info`Rendering literate Java page ${B`${name}`}`;
|
|
609
638
|
|
|
639
|
+
const sourceUrlPath = `/${subPath}.java.html`;
|
|
610
640
|
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
611
|
-
const {
|
|
641
|
+
const { pageVariables: rawPageVariables, content } =
|
|
642
|
+
parseFrontMatterAndContent(raw, '.md');
|
|
643
|
+
const pageVariables = preparePageVariables({
|
|
644
|
+
rawPageVariables,
|
|
645
|
+
filePath,
|
|
646
|
+
subPath,
|
|
647
|
+
sourceUrlPath,
|
|
648
|
+
siteVariables,
|
|
649
|
+
validInternalTargets,
|
|
650
|
+
isWatchMode,
|
|
651
|
+
allowSlides: false,
|
|
652
|
+
dependencyCollector,
|
|
653
|
+
});
|
|
654
|
+
const params = createTemplateParameters({
|
|
612
655
|
pageVariables,
|
|
656
|
+
siteVariables,
|
|
613
657
|
content,
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
658
|
+
subPath,
|
|
659
|
+
isWatchMode,
|
|
660
|
+
});
|
|
661
|
+
const md = createMarkdown(siteVariables, {
|
|
662
|
+
filePath,
|
|
663
|
+
templateParams: params,
|
|
664
|
+
preserveHtmlComments: true,
|
|
665
|
+
dependencyCollector,
|
|
666
|
+
});
|
|
667
|
+
const env: Record<string, unknown> = {};
|
|
668
|
+
const tokens = md.parse(compileTemplate(content)(params), env);
|
|
669
|
+
const { javaSource, codeBlocks, visibleBlockIndices } =
|
|
670
|
+
extractLiterateJavaCode(tokens);
|
|
620
671
|
|
|
621
672
|
const stdin =
|
|
622
673
|
typeof pageVariables.stdin === 'string' ? pageVariables.stdin : undefined;
|
|
@@ -649,8 +700,6 @@ export function renderLiterateJavaPageAsset({
|
|
|
649
700
|
|
|
650
701
|
// Render full markdown with a custom fence rule that replaces fences
|
|
651
702
|
// with Shiki-highlighted code blocks and optional JDI output columns
|
|
652
|
-
const sourceUrlPath = `/${subPath}.java.html`;
|
|
653
|
-
const md = createMarkdown(siteVariables, { filePath });
|
|
654
703
|
let fenceIndex = 0;
|
|
655
704
|
const defaultFence = md.renderer.rules.fence!;
|
|
656
705
|
|
|
@@ -698,8 +747,9 @@ export function renderLiterateJavaPageAsset({
|
|
|
698
747
|
return codeHtml;
|
|
699
748
|
};
|
|
700
749
|
|
|
701
|
-
const
|
|
702
|
-
|
|
750
|
+
const contentHtml = stripHtmlComments(
|
|
751
|
+
md.renderer.render(tokens, md.options, env),
|
|
752
|
+
);
|
|
703
753
|
|
|
704
754
|
// Build page variables
|
|
705
755
|
const javaFileName = `${className}.java`;
|
|
@@ -707,7 +757,6 @@ export function renderLiterateJavaPageAsset({
|
|
|
707
757
|
`/${toUrlPath(path.relative(contentDir, path.join(dir, javaFileName)))}`,
|
|
708
758
|
);
|
|
709
759
|
|
|
710
|
-
renderInlineField(md, pageVariables, 'title');
|
|
711
760
|
pageVariables.template = 'literate';
|
|
712
761
|
pageVariables.codeFilePath = codeFilePath;
|
|
713
762
|
pageVariables.downloadName = javaFileName;
|
|
@@ -715,34 +764,28 @@ export function renderLiterateJavaPageAsset({
|
|
|
715
764
|
if (pageVariables.toc && env.tocItems) {
|
|
716
765
|
pageVariables.tocHtml = generateTocHtml(
|
|
717
766
|
env.tocItems as Parameters<typeof generateTocHtml>[0],
|
|
718
|
-
env.alertIds as string[],
|
|
719
767
|
);
|
|
720
768
|
}
|
|
721
769
|
|
|
722
|
-
resolveAuthor(pageVariables, filePath, dependencyCollector);
|
|
723
|
-
|
|
724
770
|
const templateParameters = createTemplateParameters({
|
|
725
771
|
pageVariables,
|
|
726
772
|
siteVariables,
|
|
727
773
|
content: contentHtml,
|
|
728
774
|
subPath,
|
|
729
|
-
isWatchMode
|
|
775
|
+
isWatchMode,
|
|
730
776
|
bannerHtml: renderSiteBanner(siteVariables),
|
|
731
777
|
});
|
|
732
778
|
|
|
733
779
|
const templateHtml = render('literate.html', templateParameters) as string;
|
|
734
780
|
const finalized = finalizeHtmlPage({
|
|
735
781
|
filePath,
|
|
736
|
-
html: preparePageTemplateHtml({
|
|
737
|
-
templateHtml,
|
|
738
|
-
assetFiles,
|
|
739
|
-
distDir,
|
|
740
|
-
siteVariables,
|
|
741
|
-
}),
|
|
782
|
+
html: preparePageTemplateHtml({ templateHtml, assetFiles, siteVariables }),
|
|
742
783
|
siteVariables,
|
|
743
784
|
sourceUrlPath,
|
|
744
785
|
validInternalTargets,
|
|
745
786
|
literateJavaOutputPaths,
|
|
787
|
+
generatedPageTargets,
|
|
788
|
+
codePageSourceTargets,
|
|
746
789
|
dependencyCollector,
|
|
747
790
|
});
|
|
748
791
|
|
|
@@ -78,3 +78,14 @@ export function highlightCode(code: string, lang: string): string {
|
|
|
78
78
|
defaultColor: false,
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
export function highlightCodeToHast(
|
|
83
|
+
code: string,
|
|
84
|
+
lang: string,
|
|
85
|
+
): ReturnType<HighlighterGeneric<BundledLanguage, BundledTheme>['codeToHast']> {
|
|
86
|
+
return getHighlighter().codeToHast(code, {
|
|
87
|
+
lang,
|
|
88
|
+
themes: SHIKI_THEMES,
|
|
89
|
+
defaultColor: false,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { compileTemplate } from '../lodash-template';
|
|
2
2
|
import type { SiteVariables } from '../types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -17,7 +17,7 @@ export function applySourceTemplate(
|
|
|
17
17
|
const params = { vars: siteVariables.vars || {}, site: siteVariables };
|
|
18
18
|
|
|
19
19
|
try {
|
|
20
|
-
return
|
|
20
|
+
return compileTemplate(source)(params);
|
|
21
21
|
} catch (err: unknown) {
|
|
22
22
|
throw new Error(
|
|
23
23
|
`${filePath}: Lodash template error in source code: ${(err as Error).message}`,
|