@abreen/tada 1.4.0 → 1.5.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.
Files changed (105) hide show
  1. package/README.md +4 -2
  2. package/bin/tada.ts +81 -57
  3. package/build/apply-base-path-plugin.ts +22 -6
  4. package/build/code.test.ts +108 -1
  5. package/build/colors.test.ts +66 -0
  6. package/build/columns-plugin.ts +116 -0
  7. package/build/content-watch.ts +30 -21
  8. package/build/copy.ts +1 -1
  9. package/build/external-links-plugin.ts +1 -1
  10. package/build/generate-content-assets.ts +46 -4
  11. package/build/generate-favicon.ts +1 -1
  12. package/build/generate-fonts.ts +1 -1
  13. package/build/generate-katex-assets.ts +1 -1
  14. package/build/log.test.ts +7 -1
  15. package/build/log.ts +4 -1
  16. package/build/markdown-plugins.test.ts +65 -3
  17. package/build/pagefind.ts +1 -1
  18. package/build/pipeline.ts +4 -20
  19. package/build/serve.test.ts +59 -0
  20. package/build/serve.ts +29 -63
  21. package/build/templates.ts +2 -2
  22. package/build/toc-plugin.test.ts +40 -25
  23. package/build/toc-plugin.ts +9 -2
  24. package/build/{types.ts → types.d.ts} +87 -1
  25. package/build/util.ts +1 -1
  26. package/build/utils/code.ts +76 -3
  27. package/build/utils/content-files.test.ts +56 -0
  28. package/build/utils/content-files.ts +15 -11
  29. package/build/utils/file-types.test.ts +18 -0
  30. package/build/utils/file-types.ts +4 -0
  31. package/build/utils/include.test.ts +117 -0
  32. package/build/utils/include.ts +53 -0
  33. package/build/utils/jdi-runner/TraceRunner.java +416 -0
  34. package/build/utils/literate-java.ts +2 -2
  35. package/build/utils/markdown.ts +32 -14
  36. package/build/utils/paths.ts +1 -1
  37. package/build/utils/render.ts +112 -12
  38. package/build/utils/shiki-highlighter.ts +1 -1
  39. package/build/utils/trace-layout.test.ts +570 -0
  40. package/build/utils/trace-layout.ts +848 -0
  41. package/build/utils/trace-svg.test.ts +425 -0
  42. package/build/utils/trace-svg.ts +905 -0
  43. package/build/utils/trace.test.ts +169 -0
  44. package/build/utils/trace.ts +334 -0
  45. package/build/validate-internal-links-plugin.test.ts +30 -2
  46. package/build/validate-internal-links-plugin.ts +3 -3
  47. package/build/watch-reload-client.ts +4 -20
  48. package/build/watch.ts +436 -448
  49. package/init/content/index.md +10 -5
  50. package/init/content/labs/00/index.md +1 -1
  51. package/init/content/labs/01/SearchTreeDemo.java +31 -0
  52. package/init/content/labs/01/TraceDemo.java +22 -0
  53. package/init/content/labs/01/index.md +27 -0
  54. package/init/content/labs/index.md +2 -0
  55. package/init/content/lectures/01/Rectangle.java +2 -0
  56. package/init/content/lectures/01/index.md +2 -1
  57. package/init/content/lectures/01/rectangle.py +45 -0
  58. package/init/content/lectures/02/_pr1.md +5 -0
  59. package/init/content/lectures/02/index.md +11 -0
  60. package/init/content/lectures/02/subdir/_foobar.html +3 -0
  61. package/init/content/lectures/02/subdir/_pr2.md +6 -0
  62. package/init/content/lectures/index.md +3 -0
  63. package/init/content/markdown.md +30 -0
  64. package/package.json +20 -3
  65. package/src/_base.scss +13 -2
  66. package/src/_layout.scss +6 -5
  67. package/src/anchor/index.test.ts +64 -0
  68. package/src/code/index.test.ts +71 -0
  69. package/src/code/style.scss +23 -0
  70. package/src/code.scss +5 -3
  71. package/src/header/_base.scss +49 -9
  72. package/src/header/index.test.ts +89 -0
  73. package/src/header/index.ts +1 -1
  74. package/src/header/style.scss +1 -5
  75. package/src/index.ts +18 -20
  76. package/src/literate/style.scss +15 -7
  77. package/src/navigate/eligible.test.ts +101 -0
  78. package/src/navigate/eligible.ts +62 -0
  79. package/src/navigate/index.test.ts +82 -0
  80. package/src/navigate/index.ts +365 -0
  81. package/src/navigate/lifecycle.test.ts +26 -0
  82. package/src/navigate/lifecycle.ts +65 -0
  83. package/src/navigate/style.scss +61 -0
  84. package/src/print/index.test.ts +71 -0
  85. package/src/print/style.scss +2 -9
  86. package/src/question/index.test.ts +82 -0
  87. package/src/question/style.scss +12 -0
  88. package/src/search/index.ts +38 -14
  89. package/src/search/style.scss +23 -14
  90. package/src/style.scss +25 -12
  91. package/src/timezone/index.test.ts +301 -1
  92. package/src/timezone/index.ts +68 -56
  93. package/src/timezone/style.scss +19 -0
  94. package/src/toc/index.test.ts +237 -0
  95. package/src/toc/index.ts +29 -69
  96. package/src/toc/style.scss +17 -0
  97. package/src/top/index.test.ts +46 -0
  98. package/src/top/index.ts +2 -2
  99. package/src/trace/index.test.ts +528 -0
  100. package/src/trace/index.ts +250 -0
  101. package/src/trace/style.scss +210 -0
  102. package/src/trace/types.d.ts +47 -0
  103. package/src/util.test.ts +135 -0
  104. package/templates/_top.html +23 -22
  105. package/types/jsdom.d.ts +9 -0
@@ -12,8 +12,11 @@ import {
12
12
  extractJavaMethodToc,
13
13
  renderCodeSegment,
14
14
  renderCodeWithComments,
15
+ rewriteProseLinks,
15
16
  } from './code';
16
17
  import { extensionIsMarkdown } from './file-types';
18
+ import { createTraceHelpers } from './trace';
19
+ import { createIncludeFunction } from './include';
17
20
  import { createApplyBasePath, normalizeOutputPath } from './paths';
18
21
  import { parseFrontMatterAndContent } from './front-matter';
19
22
  import { createMarkdown } from './markdown';
@@ -34,7 +37,7 @@ import type {
34
37
  RenderCopiedContentOptions,
35
38
  } from '../types';
36
39
 
37
- const log = makeLogger(__filename);
40
+ const log = makeLogger(import.meta.url);
38
41
 
39
42
  const REQUIRED_FRONT_MATTER_FIELDS = ['title'];
40
43
 
@@ -95,7 +98,7 @@ function createTemplateParameters({
95
98
  subPath,
96
99
  }: TemplateParametersInput): Record<string, unknown> {
97
100
  return {
98
- ...(siteVariables.vars || {}),
101
+ vars: siteVariables.vars || {},
99
102
  ...createGlobals(pageVariables, siteVariables, subPath),
100
103
  site: siteVariables,
101
104
  base: siteVariables.base,
@@ -132,8 +135,22 @@ export function injectAssetTags(
132
135
  )
133
136
  .join('');
134
137
 
138
+ const fontPreloadTags = [
139
+ 'inter/InterVariable.woff2',
140
+ 'google-sans-code/GoogleSansCodeVariable.woff2',
141
+ ]
142
+ .filter(f => fs.existsSync(path.join(distDir, f)))
143
+ .map(
144
+ f =>
145
+ `<link rel="preload" href="${applyBasePath('/' + f)}" as="font" type="font/woff2" crossorigin>`,
146
+ )
147
+ .join('');
148
+
135
149
  return html
136
- .replace('<head>', `<head>${criticalTags}${asyncLinkTags}`)
150
+ .replace(
151
+ '<head>',
152
+ `<head>${fontPreloadTags}${criticalTags}${asyncLinkTags}`,
153
+ )
137
154
  .replace('</head>', `${scriptTags}</head>`);
138
155
  }
139
156
 
@@ -160,19 +177,27 @@ export function renderPlainTextPageAsset({
160
177
  siteVariables,
161
178
  validInternalTargets,
162
179
  assetFiles,
180
+ literateJavaOutputPaths,
181
+ traceCache,
163
182
  }: RenderPlainTextOptions): Asset[] {
164
183
  const { dir, name, ext } = path.parse(filePath);
165
184
  const subPath = path.relative(contentDir, path.join(dir, name));
166
185
  const applyBasePath = createApplyBasePath(siteVariables);
167
186
 
168
187
  log.info`Rendering page ${B`${subPath + ext}`}`;
169
- const { content, pageVariables, tocItems } = renderPlainTextContent(
188
+ const { content, pageVariables, tocItems, alertIds } = renderPlainTextContent(
170
189
  filePath,
171
190
  subPath,
172
191
  siteVariables,
173
192
  applyBasePath,
174
193
  validInternalTargets,
175
- { validateInternalLinks: extensionIsMarkdown(ext.toLowerCase()) },
194
+ {
195
+ validateInternalLinks: extensionIsMarkdown(ext.toLowerCase()),
196
+ traceCache,
197
+ contentDir,
198
+ distDir,
199
+ literateJavaOutputPaths,
200
+ },
176
201
  );
177
202
 
178
203
  validateFrontMatter(pageVariables, filePath);
@@ -184,6 +209,7 @@ export function renderPlainTextPageAsset({
184
209
  if (pageVariables.toc && tocItems) {
185
210
  pageVariables.tocHtml = generateTocHtml(
186
211
  tocItems as Parameters<typeof generateTocHtml>[0],
212
+ alertIds,
187
213
  );
188
214
  }
189
215
 
@@ -224,9 +250,15 @@ export function renderCodePageAsset({
224
250
  const applyBasePath = createApplyBasePath(siteVariables);
225
251
  const lang = siteVariables.codeLanguages![ext.slice(1).toLowerCase()];
226
252
  const sourceCode = fs.readFileSync(filePath, 'utf-8');
253
+ const pageDirPath = path.relative(contentDir, dir);
227
254
 
228
255
  log.info`Rendering code page ${B`${subPath + ext}`}`;
229
- const content = renderCodeWithComments(sourceCode, lang, siteVariables);
256
+ const content = renderCodeWithComments(
257
+ sourceCode,
258
+ lang,
259
+ siteVariables,
260
+ pageDirPath,
261
+ );
230
262
  const codeFilePath = applyBasePath(
231
263
  normalizeOutputPath(`/${toContentAssetPath(contentDir, filePath)}`),
232
264
  );
@@ -261,7 +293,10 @@ export function renderCodePageAsset({
261
293
 
262
294
  return [
263
295
  {
264
- assetPath: toContentAssetPath(contentDir, path.join(dir, `${name}.html`)),
296
+ assetPath: toContentAssetPath(
297
+ contentDir,
298
+ path.join(dir, `${name}${ext}.html`),
299
+ ),
265
300
  content: html,
266
301
  },
267
302
  ];
@@ -270,11 +305,24 @@ export function renderCodePageAsset({
270
305
  export function renderCopiedContentAsset({
271
306
  filePath,
272
307
  contentDir,
308
+ siteVariables,
273
309
  }: RenderCopiedContentOptions): Asset[] {
274
310
  const label = 'Copying source file';
275
311
  const relPath = toContentAssetPath(contentDir, filePath);
276
312
 
277
313
  log.info`${label} ${B`${relPath}`}`;
314
+
315
+ if (filePath.endsWith('.java') && isFeatureEnabled(siteVariables, 'code')) {
316
+ const sourceCode = fs.readFileSync(filePath, 'utf-8');
317
+ const pageDirPath = path.relative(contentDir, path.dirname(filePath));
318
+ const rewrittenLines = rewriteProseLinks(
319
+ sourceCode.split('\n'),
320
+ siteVariables,
321
+ pageDirPath,
322
+ );
323
+ return [{ assetPath: relPath, content: rewrittenLines.join('\n') }];
324
+ }
325
+
278
326
  return [{ assetPath: relPath, content: fs.readFileSync(filePath) }];
279
327
  }
280
328
 
@@ -285,11 +333,32 @@ function renderPlainTextContent(
285
333
  siteVariables: SiteVariables,
286
334
  applyBasePath: (subPath: string) => string,
287
335
  validInternalTargets: Set<string>,
288
- { validateInternalLinks = true } = {},
336
+ {
337
+ validateInternalLinks = true,
338
+ traceCache,
339
+ contentDir,
340
+ distDir,
341
+ literateJavaOutputPaths,
342
+ }: {
343
+ validateInternalLinks?: boolean;
344
+ traceCache?: Map<
345
+ string,
346
+ {
347
+ manifestUrl: string;
348
+ highlightedSource: string;
349
+ totalSteps: number;
350
+ mtime: number;
351
+ }
352
+ >;
353
+ contentDir?: string;
354
+ distDir?: string;
355
+ literateJavaOutputPaths?: Set<string>;
356
+ } = {},
289
357
  ): {
290
358
  content: string | null;
291
359
  pageVariables: Record<string, unknown>;
292
360
  tocItems: unknown[] | null;
361
+ alertIds: string[];
293
362
  } {
294
363
  const sourceUrlPath = `/${subPath}.html`;
295
364
  const md = createMarkdown(siteVariables, {
@@ -302,6 +371,8 @@ function renderPlainTextContent(
302
371
  ? Object.keys(siteVariables.codeLanguages!)
303
372
  : [],
304
373
  },
374
+ literateJavaOutputPaths,
375
+ sourceUrlPath,
305
376
  });
306
377
 
307
378
  const ext = path.extname(filePath);
@@ -368,6 +439,19 @@ function renderPlainTextContent(
368
439
  subPath,
369
440
  });
370
441
 
442
+ if (traceCache && contentDir && distDir) {
443
+ const helpers = createTraceHelpers({
444
+ filePath,
445
+ contentDir,
446
+ distDir,
447
+ applyBasePath,
448
+ cache: traceCache,
449
+ });
450
+ params.renderTrace = helpers.renderTrace;
451
+ }
452
+
453
+ params.include = createIncludeFunction(filePath, params);
454
+
371
455
  let html: string;
372
456
  try {
373
457
  html = _.template(strippedContent)(params);
@@ -379,16 +463,19 @@ function renderPlainTextContent(
379
463
  }
380
464
 
381
465
  let tocItems: unknown[] | null = null;
466
+ let alertIds: string[] = [];
382
467
  if (extensionIsMarkdown(ext)) {
383
- const env: Record<string, unknown> = {};
468
+ const env: Record<string, unknown> = { alertIds: [] as string[] };
384
469
  html = md.render(html!, env);
385
470
  tocItems = (env.tocItems as unknown[] | undefined) || null;
471
+ alertIds = env.alertIds as string[];
386
472
  }
387
473
 
388
474
  return {
389
475
  content: html,
390
476
  pageVariables: params.page as Record<string, unknown>,
391
477
  tocItems,
478
+ alertIds,
392
479
  };
393
480
  }
394
481
 
@@ -403,6 +490,8 @@ export function renderLiterateJavaPageAsset({
403
490
  siteVariables,
404
491
  assetFiles,
405
492
  skipExecution,
493
+ validInternalTargets,
494
+ literateJavaOutputPaths,
406
495
  }: RenderLiterateJavaOptions): Asset[] {
407
496
  const { dir, name } = path.parse(filePath);
408
497
  const className = deriveClassName(filePath);
@@ -453,8 +542,18 @@ export function renderLiterateJavaPageAsset({
453
542
 
454
543
  // Render full markdown with a custom fence rule that replaces fences
455
544
  // with Shiki-highlighted code blocks and optional JDI output columns
545
+ const sourceUrlPath = `/${subPath}.java.html`;
456
546
  const md = createMarkdown(siteVariables, {
457
- validatorOptions: { enabled: false },
547
+ validatorOptions: {
548
+ filePath,
549
+ sourceUrlPath,
550
+ validTargets: validInternalTargets,
551
+ codeExtensions: isFeatureEnabled(siteVariables, 'code')
552
+ ? Object.keys(siteVariables.codeLanguages!)
553
+ : [],
554
+ },
555
+ literateJavaOutputPaths,
556
+ sourceUrlPath,
458
557
  });
459
558
  let fenceIndex = 0;
460
559
  const defaultFence = md.renderer.rules.fence!;
@@ -506,7 +605,7 @@ export function renderLiterateJavaPageAsset({
506
605
  return codeHtml;
507
606
  };
508
607
 
509
- const env: Record<string, unknown> = {};
608
+ const env: Record<string, unknown> = { alertIds: [] as string[] };
510
609
  const contentHtml = md.render(stripHtmlComments(content), env);
511
610
 
512
611
  // Build page variables
@@ -527,6 +626,7 @@ export function renderLiterateJavaPageAsset({
527
626
  if (pageVariables.toc && env.tocItems) {
528
627
  pageVariables.tocHtml = generateTocHtml(
529
628
  env.tocItems as Parameters<typeof generateTocHtml>[0],
629
+ env.alertIds as string[],
530
630
  );
531
631
  }
532
632
 
@@ -550,7 +650,7 @@ export function renderLiterateJavaPageAsset({
550
650
  {
551
651
  assetPath: toContentAssetPath(
552
652
  contentDir,
553
- path.join(dir, `${className}.html`),
653
+ path.join(dir, `${className}.java.html`),
554
654
  ),
555
655
  content: html,
556
656
  },
@@ -1,7 +1,7 @@
1
1
  import type { HighlighterGeneric, BundledLanguage, BundledTheme } from 'shiki';
2
2
  import { makeLogger } from '../log';
3
3
 
4
- const log = makeLogger(__filename);
4
+ const log = makeLogger(import.meta.url);
5
5
 
6
6
  let highlighter: HighlighterGeneric<BundledLanguage, BundledTheme> | null =
7
7
  null;