@abreen/tada 1.4.1 → 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 (103) 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 +97 -11
  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 +48 -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/question/index.test.ts +82 -0
  86. package/src/question/style.scss +12 -0
  87. package/src/search/index.ts +38 -14
  88. package/src/search/style.scss +23 -14
  89. package/src/style.scss +25 -12
  90. package/src/timezone/index.test.ts +301 -1
  91. package/src/timezone/index.ts +68 -56
  92. package/src/toc/index.test.ts +237 -0
  93. package/src/toc/index.ts +29 -69
  94. package/src/toc/style.scss +17 -0
  95. package/src/top/index.test.ts +46 -0
  96. package/src/top/index.ts +2 -2
  97. package/src/trace/index.test.ts +528 -0
  98. package/src/trace/index.ts +250 -0
  99. package/src/trace/style.scss +210 -0
  100. package/src/trace/types.d.ts +47 -0
  101. package/src/util.test.ts +135 -0
  102. package/templates/_top.html +23 -22
  103. 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,
@@ -174,19 +177,27 @@ export function renderPlainTextPageAsset({
174
177
  siteVariables,
175
178
  validInternalTargets,
176
179
  assetFiles,
180
+ literateJavaOutputPaths,
181
+ traceCache,
177
182
  }: RenderPlainTextOptions): Asset[] {
178
183
  const { dir, name, ext } = path.parse(filePath);
179
184
  const subPath = path.relative(contentDir, path.join(dir, name));
180
185
  const applyBasePath = createApplyBasePath(siteVariables);
181
186
 
182
187
  log.info`Rendering page ${B`${subPath + ext}`}`;
183
- const { content, pageVariables, tocItems } = renderPlainTextContent(
188
+ const { content, pageVariables, tocItems, alertIds } = renderPlainTextContent(
184
189
  filePath,
185
190
  subPath,
186
191
  siteVariables,
187
192
  applyBasePath,
188
193
  validInternalTargets,
189
- { validateInternalLinks: extensionIsMarkdown(ext.toLowerCase()) },
194
+ {
195
+ validateInternalLinks: extensionIsMarkdown(ext.toLowerCase()),
196
+ traceCache,
197
+ contentDir,
198
+ distDir,
199
+ literateJavaOutputPaths,
200
+ },
190
201
  );
191
202
 
192
203
  validateFrontMatter(pageVariables, filePath);
@@ -198,6 +209,7 @@ export function renderPlainTextPageAsset({
198
209
  if (pageVariables.toc && tocItems) {
199
210
  pageVariables.tocHtml = generateTocHtml(
200
211
  tocItems as Parameters<typeof generateTocHtml>[0],
212
+ alertIds,
201
213
  );
202
214
  }
203
215
 
@@ -238,9 +250,15 @@ export function renderCodePageAsset({
238
250
  const applyBasePath = createApplyBasePath(siteVariables);
239
251
  const lang = siteVariables.codeLanguages![ext.slice(1).toLowerCase()];
240
252
  const sourceCode = fs.readFileSync(filePath, 'utf-8');
253
+ const pageDirPath = path.relative(contentDir, dir);
241
254
 
242
255
  log.info`Rendering code page ${B`${subPath + ext}`}`;
243
- const content = renderCodeWithComments(sourceCode, lang, siteVariables);
256
+ const content = renderCodeWithComments(
257
+ sourceCode,
258
+ lang,
259
+ siteVariables,
260
+ pageDirPath,
261
+ );
244
262
  const codeFilePath = applyBasePath(
245
263
  normalizeOutputPath(`/${toContentAssetPath(contentDir, filePath)}`),
246
264
  );
@@ -275,7 +293,10 @@ export function renderCodePageAsset({
275
293
 
276
294
  return [
277
295
  {
278
- assetPath: toContentAssetPath(contentDir, path.join(dir, `${name}.html`)),
296
+ assetPath: toContentAssetPath(
297
+ contentDir,
298
+ path.join(dir, `${name}${ext}.html`),
299
+ ),
279
300
  content: html,
280
301
  },
281
302
  ];
@@ -284,11 +305,24 @@ export function renderCodePageAsset({
284
305
  export function renderCopiedContentAsset({
285
306
  filePath,
286
307
  contentDir,
308
+ siteVariables,
287
309
  }: RenderCopiedContentOptions): Asset[] {
288
310
  const label = 'Copying source file';
289
311
  const relPath = toContentAssetPath(contentDir, filePath);
290
312
 
291
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
+
292
326
  return [{ assetPath: relPath, content: fs.readFileSync(filePath) }];
293
327
  }
294
328
 
@@ -299,11 +333,32 @@ function renderPlainTextContent(
299
333
  siteVariables: SiteVariables,
300
334
  applyBasePath: (subPath: string) => string,
301
335
  validInternalTargets: Set<string>,
302
- { 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
+ } = {},
303
357
  ): {
304
358
  content: string | null;
305
359
  pageVariables: Record<string, unknown>;
306
360
  tocItems: unknown[] | null;
361
+ alertIds: string[];
307
362
  } {
308
363
  const sourceUrlPath = `/${subPath}.html`;
309
364
  const md = createMarkdown(siteVariables, {
@@ -316,6 +371,8 @@ function renderPlainTextContent(
316
371
  ? Object.keys(siteVariables.codeLanguages!)
317
372
  : [],
318
373
  },
374
+ literateJavaOutputPaths,
375
+ sourceUrlPath,
319
376
  });
320
377
 
321
378
  const ext = path.extname(filePath);
@@ -382,6 +439,19 @@ function renderPlainTextContent(
382
439
  subPath,
383
440
  });
384
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
+
385
455
  let html: string;
386
456
  try {
387
457
  html = _.template(strippedContent)(params);
@@ -393,16 +463,19 @@ function renderPlainTextContent(
393
463
  }
394
464
 
395
465
  let tocItems: unknown[] | null = null;
466
+ let alertIds: string[] = [];
396
467
  if (extensionIsMarkdown(ext)) {
397
- const env: Record<string, unknown> = {};
468
+ const env: Record<string, unknown> = { alertIds: [] as string[] };
398
469
  html = md.render(html!, env);
399
470
  tocItems = (env.tocItems as unknown[] | undefined) || null;
471
+ alertIds = env.alertIds as string[];
400
472
  }
401
473
 
402
474
  return {
403
475
  content: html,
404
476
  pageVariables: params.page as Record<string, unknown>,
405
477
  tocItems,
478
+ alertIds,
406
479
  };
407
480
  }
408
481
 
@@ -417,6 +490,8 @@ export function renderLiterateJavaPageAsset({
417
490
  siteVariables,
418
491
  assetFiles,
419
492
  skipExecution,
493
+ validInternalTargets,
494
+ literateJavaOutputPaths,
420
495
  }: RenderLiterateJavaOptions): Asset[] {
421
496
  const { dir, name } = path.parse(filePath);
422
497
  const className = deriveClassName(filePath);
@@ -467,8 +542,18 @@ export function renderLiterateJavaPageAsset({
467
542
 
468
543
  // Render full markdown with a custom fence rule that replaces fences
469
544
  // with Shiki-highlighted code blocks and optional JDI output columns
545
+ const sourceUrlPath = `/${subPath}.java.html`;
470
546
  const md = createMarkdown(siteVariables, {
471
- 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,
472
557
  });
473
558
  let fenceIndex = 0;
474
559
  const defaultFence = md.renderer.rules.fence!;
@@ -520,7 +605,7 @@ export function renderLiterateJavaPageAsset({
520
605
  return codeHtml;
521
606
  };
522
607
 
523
- const env: Record<string, unknown> = {};
608
+ const env: Record<string, unknown> = { alertIds: [] as string[] };
524
609
  const contentHtml = md.render(stripHtmlComments(content), env);
525
610
 
526
611
  // Build page variables
@@ -541,6 +626,7 @@ export function renderLiterateJavaPageAsset({
541
626
  if (pageVariables.toc && env.tocItems) {
542
627
  pageVariables.tocHtml = generateTocHtml(
543
628
  env.tocItems as Parameters<typeof generateTocHtml>[0],
629
+ env.alertIds as string[],
544
630
  );
545
631
  }
546
632
 
@@ -564,7 +650,7 @@ export function renderLiterateJavaPageAsset({
564
650
  {
565
651
  assetPath: toContentAssetPath(
566
652
  contentDir,
567
- path.join(dir, `${className}.html`),
653
+ path.join(dir, `${className}.java.html`),
568
654
  ),
569
655
  content: html,
570
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;