@abreen/tada 1.17.1 → 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.
Files changed (101) hide show
  1. package/README.md +37 -6
  2. package/bin/tada.ts +16 -7
  3. package/bin/validators.ts +33 -0
  4. package/build/branding.ts +41 -0
  5. package/build/build-manifest.ts +9 -4
  6. package/build/{watch/compiler-types.d.ts → build-types.d.ts} +8 -5
  7. package/build/build-validation.ts +176 -0
  8. package/build/bundle.ts +75 -65
  9. package/build/config-loader.ts +3 -3
  10. package/build/custom-fonts.ts +8 -5
  11. package/build/generate-favicon.ts +7 -6
  12. package/build/generate-fonts.ts +8 -15
  13. package/build/generate-katex-assets.ts +19 -17
  14. package/build/generate-web-app-manifest.ts +3 -11
  15. package/build/lodash-template.ts +14 -0
  16. package/build/output-publication.ts +238 -0
  17. package/build/pagefind.ts +49 -21
  18. package/build/pdf-text.ts +41 -1
  19. package/build/pipeline.ts +95 -101
  20. package/build/site-assets.ts +46 -0
  21. package/build/site-build.ts +267 -0
  22. package/build/source-model.ts +223 -244
  23. package/build/source-records.ts +69 -81
  24. package/build/template-globals.ts +3 -0
  25. package/build/templates.ts +5 -2
  26. package/build/toc-plugin.ts +21 -21
  27. package/build/types.d.ts +38 -38
  28. package/build/util.ts +0 -4
  29. package/build/utils/code.ts +38 -101
  30. package/build/utils/final-html.ts +171 -47
  31. package/build/utils/literate-java.ts +11 -7
  32. package/build/utils/markdown-partials.ts +4 -3
  33. package/build/utils/markdown.ts +6 -17
  34. package/build/utils/paths.ts +3 -0
  35. package/build/utils/plain-text.ts +18 -0
  36. package/build/utils/render.ts +197 -154
  37. package/build/utils/shiki-highlighter.ts +11 -0
  38. package/build/utils/source-template.ts +2 -2
  39. package/build/utils/trace-core.ts +8 -83
  40. package/build/utils/trace.ts +38 -95
  41. package/build/validate-config-links.ts +5 -5
  42. package/build/watch/build-incremental.ts +46 -103
  43. package/build/watch/compiler.ts +158 -37
  44. package/build/watch/engine.ts +207 -176
  45. package/build/watch/index.ts +9 -2
  46. package/build/watch/planner.ts +88 -144
  47. package/build/watch/runtime.ts +21 -34
  48. package/build/watch/types.d.ts +32 -64
  49. package/package.json +4 -4
  50. package/schema/site.schema.json +18 -2
  51. package/src/_content.scss +447 -0
  52. package/src/_fonts.scss +90 -0
  53. package/src/_layout.scss +50 -35
  54. package/src/appearance-picker/{style.scss → _index.scss} +1 -1
  55. package/src/code/{style.scss → _index.scss} +61 -0
  56. package/src/header/{_base.scss → _index.scss} +98 -6
  57. package/src/index.ts +1 -17
  58. package/src/navigate/{style.scss → _index.scss} +20 -0
  59. package/src/navigate/eligible.ts +0 -40
  60. package/src/navigate/index.ts +38 -4
  61. package/src/navigate/lifecycle.ts +19 -2
  62. package/src/navigate/runtime.ts +20 -4
  63. package/src/page-update/index.ts +33 -20
  64. package/src/print/{style.scss → _index.scss} +3 -1
  65. package/src/search/index.ts +7 -0
  66. package/src/slides/{style.scss → _index.scss} +5 -0
  67. package/src/style.scss +24 -536
  68. package/src/toc/index.ts +2 -2
  69. package/templates/_author.html +2 -2
  70. package/templates/_download.html +1 -1
  71. package/templates/_footer.html +1 -1
  72. package/templates/_heading.html +3 -3
  73. package/templates/_nav.html +2 -2
  74. package/templates/_page-bottom.html +6 -0
  75. package/templates/_top.html +18 -14
  76. package/templates/code.html +22 -21
  77. package/templates/default.html +12 -11
  78. package/templates/literate.html +6 -5
  79. package/build/copy.ts +0 -82
  80. package/build/generate-content-assets.ts +0 -121
  81. package/build/utils/content-files.ts +0 -170
  82. package/build/watch/assets.ts +0 -103
  83. package/build/watch/build-full.ts +0 -97
  84. package/build/watch/build-helpers.ts +0 -66
  85. package/build/watch/build-result.ts +0 -19
  86. package/build/watch/fs-commit.ts +0 -218
  87. package/build/watch/mutations.ts +0 -73
  88. package/build/watch/snapshot.ts +0 -201
  89. package/build/watch/validation.ts +0 -57
  90. package/src/code.scss +0 -60
  91. package/src/critical.scss +0 -5
  92. package/src/header/style.scss +0 -91
  93. /package/src/{literate.scss → _literate.scss} +0 -0
  94. /package/src/{material-symbols.scss → _material-symbols.scss} +0 -0
  95. /package/src/anchor/{style.scss → _index.scss} +0 -0
  96. /package/src/page-update/{style.scss → _index.scss} +0 -0
  97. /package/src/question/{style.scss → _index.scss} +0 -0
  98. /package/src/search/{style.scss → _index.scss} +0 -0
  99. /package/src/timezone/{style.scss → _index.scss} +0 -0
  100. /package/src/toc/{style.scss → _index.scss} +0 -0
  101. /package/src/trace/{style.scss → _index.scss} +0 -0
@@ -1,4 +1,3 @@
1
- import fs from 'fs';
2
1
  import path from 'path';
3
2
  import { createHash } from 'crypto';
4
3
  import { renderCodeSegment } from './code';
@@ -7,6 +6,7 @@ import { normalizeOutputPath } from './paths';
7
6
  import { computeLayout } from './trace-layout';
8
7
  import { filterStep, generateStepSvg } from './trace-svg';
9
8
  import type {
9
+ TraceArtifactFile,
10
10
  TraceChunkEntry,
11
11
  TraceHeapObject,
12
12
  TraceManifest,
@@ -24,14 +24,15 @@ export interface ChunkTraceOutputOptions {
24
24
  export interface ChunkTraceOutputResult {
25
25
  manifest: TraceManifest;
26
26
  artifactId: string;
27
- outputPaths: string[];
27
+ /** `manifest.json` followed by the chunk files */
28
+ files: TraceArtifactFile[];
28
29
  }
29
30
 
30
31
  function stepOutputEvents(step: TraceStep): TraceOutputEvent[] {
31
32
  return step.output ?? [];
32
33
  }
33
34
 
34
- function hashTraceFiles(files: { name: string; content: string }[]): string {
35
+ function hashTraceFiles(files: TraceArtifactFile[]): string {
35
36
  const hasher = createHash('sha256');
36
37
  for (const file of files) {
37
38
  hasher.update(file.name, 'utf8');
@@ -46,7 +47,8 @@ function safeSvgIdPart(value: string): string {
46
47
  return value.replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '');
47
48
  }
48
49
 
49
- function buildTraceOutputPath(
50
+ /** Output path of a trace artifact file, relative to the output directory */
51
+ export function buildTraceOutputPath(
50
52
  relDir: string,
51
53
  traceName: string,
52
54
  artifactId: string,
@@ -147,8 +149,6 @@ export function bridgeConstructorReturnValues(steps: TraceStep[]): TraceStep[] {
147
149
 
148
150
  export function chunkTraceOutput(
149
151
  output: string,
150
- traceOutputDir: string,
151
- relDir: string,
152
152
  traceName: string,
153
153
  primaryFile: string,
154
154
  sources: { file: string; source: string }[],
@@ -189,7 +189,7 @@ export function chunkTraceOutput(
189
189
 
190
190
  let chunkEntries: TraceChunkEntry[] = [];
191
191
  let chunkIndex = 0;
192
- const chunkFiles: { name: string; content: string }[] = [];
192
+ const chunkFiles: TraceArtifactFile[] = [];
193
193
 
194
194
  for (const [stepIndex, step] of allSteps.entries()) {
195
195
  const svg = generateStepSvg(
@@ -237,21 +237,7 @@ export function chunkTraceOutput(
237
237
  content: JSON.stringify(manifest),
238
238
  };
239
239
  const files = [manifestFile, ...chunkFiles];
240
- const artifactId = hashTraceFiles(files);
241
- const artifactDir = path.join(traceOutputDir, artifactId);
242
-
243
- fs.mkdirSync(artifactDir, { recursive: true });
244
- for (const file of files) {
245
- fs.writeFileSync(path.join(artifactDir, file.name), file.content);
246
- }
247
-
248
- return {
249
- manifest,
250
- artifactId,
251
- outputPaths: files.map(file =>
252
- buildTraceOutputPath(relDir, traceName, artifactId, file.name),
253
- ),
254
- };
240
+ return { manifest, artifactId: hashTraceFiles(files), files };
255
241
  }
256
242
 
257
243
  export function highlightTraceSource(
@@ -263,67 +249,6 @@ export function highlightTraceSource(
263
249
  });
264
250
  }
265
251
 
266
- export function getTraceOutputPaths(
267
- relDir: string,
268
- traceName: string,
269
- artifactId: string,
270
- totalSteps: number,
271
- ): string[] {
272
- const outputPaths = [
273
- buildTraceOutputPath(relDir, traceName, artifactId, 'manifest.json'),
274
- ];
275
- for (
276
- let chunkIndex = 0;
277
- chunkIndex * DEFAULT_CHUNK_SIZE < totalSteps;
278
- chunkIndex++
279
- ) {
280
- outputPaths.push(
281
- buildTraceOutputPath(
282
- relDir,
283
- traceName,
284
- artifactId,
285
- `chunk-${chunkIndex}.json`,
286
- ),
287
- );
288
- }
289
- return outputPaths;
290
- }
291
-
292
- function linkOrCopyFile(sourcePath: string, targetPath: string): void {
293
- try {
294
- fs.linkSync(sourcePath, targetPath);
295
- } catch {
296
- fs.copyFileSync(sourcePath, targetPath);
297
- }
298
- }
299
-
300
- export function materializeTraceOutputs({
301
- outputPaths,
302
- targetDistDir,
303
- sourceDistDir,
304
- }: {
305
- outputPaths: string[];
306
- targetDistDir: string;
307
- sourceDistDir: string;
308
- }): boolean {
309
- for (const relPath of outputPaths) {
310
- const targetPath = path.join(targetDistDir, relPath);
311
- if (fs.existsSync(targetPath)) {
312
- continue;
313
- }
314
-
315
- const sourcePath = path.join(sourceDistDir, relPath);
316
- if (!fs.existsSync(sourcePath)) {
317
- return false;
318
- }
319
-
320
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
321
- linkOrCopyFile(sourcePath, targetPath);
322
- }
323
-
324
- return true;
325
- }
326
-
327
252
  export function buildManifestUrl({
328
253
  relDir,
329
254
  traceName,
@@ -7,11 +7,10 @@ import { toPosix } from './paths';
7
7
  import { checkJavac } from './literate-java';
8
8
  import {
9
9
  buildManifestUrl,
10
+ buildTraceOutputPath,
10
11
  chunkTraceOutput,
11
12
  DEFAULT_CHUNK_SIZE,
12
- getTraceOutputPaths,
13
13
  highlightTraceSource,
14
- materializeTraceOutputs,
15
14
  renderTraceWidgetHtml,
16
15
  } from './trace-core';
17
16
  import {
@@ -25,6 +24,7 @@ import type {
25
24
  RenderDependencyCollector,
26
25
  TraceToolAvailability,
27
26
  } from '../types';
27
+ import type { TraceCache, TraceCacheEntry } from '../build-types';
28
28
 
29
29
  const log = makeLogger(import.meta.url);
30
30
 
@@ -33,20 +33,10 @@ export const TRACEABLE_EXTENSIONS = new Set(['.java', '.py']);
33
33
  export interface TraceContext {
34
34
  filePath: string;
35
35
  contentDir: string;
36
- distDir: string;
37
36
  applyBasePath: (subPath: string) => string;
38
- cache: Map<string, TraceResult>;
37
+ cache: TraceCache;
39
38
  toolAvailability?: TraceToolAvailability;
40
39
  dependencyCollector?: RenderDependencyCollector;
41
- cachedTraceSourceDir?: string;
42
- }
43
-
44
- export interface TraceResult {
45
- manifestUrl: string;
46
- artifactId: string;
47
- highlightedSources: { file: string; highlightedSource: string }[];
48
- totalSteps: number;
49
- sourceMtims: Record<string, number>;
50
40
  }
51
41
 
52
42
  export function isTraceSourceFile(filePath: string): boolean {
@@ -132,12 +122,10 @@ export function createTraceHelpers(context: TraceContext): {
132
122
  const {
133
123
  filePath,
134
124
  contentDir,
135
- distDir,
136
125
  applyBasePath,
137
126
  cache,
138
127
  toolAvailability,
139
128
  dependencyCollector,
140
- cachedTraceSourceDir,
141
129
  } = context;
142
130
  const pageDir = path.dirname(filePath);
143
131
 
@@ -202,7 +190,7 @@ export function createTraceHelpers(context: TraceContext): {
202
190
 
203
191
  function cacheIsFresh(
204
192
  sources: TraceSourceFile[],
205
- cached: TraceResult,
193
+ cached: TraceCacheEntry,
206
194
  ): boolean {
207
195
  return sources.every(source => {
208
196
  const mtime = fs.statSync(source.absolutePath, {
@@ -229,45 +217,13 @@ export function createTraceHelpers(context: TraceContext): {
229
217
 
230
218
  function getOrRunTrace(
231
219
  sourceFile: string,
232
- companionFiles?: string[],
233
- ): TraceResult {
234
- const sources = resolveTraceSources(sourceFile, companionFiles);
235
- for (const source of sources) {
236
- dependencyCollector?.traceFiles?.add(source.absolutePath);
237
- }
238
- const sourceFilePath = sources[0].absolutePath;
239
- const traceName = path.parse(sourceFile).name;
240
- const relDir = toPosix(path.relative(contentDir, pageDir));
220
+ sources: TraceSourceFile[],
221
+ traceName: string,
222
+ ): TraceCacheEntry {
241
223
  const cacheKey = cacheKeyForSources(sources);
242
-
243
224
  const cached = cache.get(cacheKey);
244
225
  if (cached && cacheIsFresh(sources, cached)) {
245
- const outputPaths = getTraceOutputPaths(
246
- relDir,
247
- traceName,
248
- cached.artifactId,
249
- cached.totalSteps,
250
- );
251
- if (
252
- materializeTraceOutputs({
253
- outputPaths,
254
- targetDistDir: distDir,
255
- sourceDistDir: cachedTraceSourceDir || distDir,
256
- })
257
- ) {
258
- for (const outputPath of outputPaths) {
259
- dependencyCollector?.generatedOutputPaths?.add(outputPath);
260
- }
261
- return {
262
- ...cached,
263
- manifestUrl: buildManifestUrl({
264
- relDir,
265
- traceName,
266
- artifactId: cached.artifactId,
267
- applyBasePath,
268
- }),
269
- };
270
- }
226
+ return cached;
271
227
  }
272
228
 
273
229
  log.info`Tracing ${B`${sourceFile}`}`;
@@ -288,49 +244,26 @@ export function createTraceHelpers(context: TraceContext): {
288
244
  fs.rmSync(workspaceDir, { recursive: true, force: true });
289
245
  }
290
246
 
291
- const language = traceLanguageForFile(sourceFilePath);
292
- const highlightedSources = sources.map(source => ({
293
- file: source.file,
294
- highlightedSource: highlightTraceSource(source.source, language),
295
- }));
296
- const traceOutputDir = path.join(distDir, relDir, '_traces', traceName);
297
-
298
- const traceOutput = chunkTraceOutput(
247
+ const language = traceLanguageForFile(sources[0].absolutePath);
248
+ const { manifest, artifactId, files } = chunkTraceOutput(
299
249
  output,
300
- traceOutputDir,
301
- relDir,
302
250
  traceName,
303
251
  sources[0].file,
304
252
  sources.map(source => ({ file: source.file, source: source.source })),
305
253
  { chunkSize: DEFAULT_CHUNK_SIZE, ignoreFields },
306
254
  );
307
- for (const outputPath of traceOutput.outputPaths) {
308
- dependencyCollector?.generatedOutputPaths?.add(outputPath);
309
- }
310
-
311
- const manifestUrl = buildManifestUrl({
312
- relDir,
313
- traceName,
314
- artifactId: traceOutput.artifactId,
315
- applyBasePath,
316
- });
317
-
318
- const totalSteps = traceOutput.manifest.totalSteps;
319
- const sourceMtims = getSourceMtims(sources);
320
- cache.set(cacheKey, {
321
- manifestUrl,
322
- artifactId: traceOutput.artifactId,
323
- highlightedSources,
324
- totalSteps,
325
- sourceMtims,
326
- });
327
- return {
328
- manifestUrl,
329
- artifactId: traceOutput.artifactId,
330
- highlightedSources,
331
- totalSteps,
332
- sourceMtims,
255
+ const entry: TraceCacheEntry = {
256
+ artifactId,
257
+ files,
258
+ highlightedSources: sources.map(source => ({
259
+ file: source.file,
260
+ highlightedSource: highlightTraceSource(source.source, language),
261
+ })),
262
+ totalSteps: manifest.totalSteps,
263
+ sourceMtims: getSourceMtims(sources),
333
264
  };
265
+ cache.set(cacheKey, entry);
266
+ return entry;
334
267
  }
335
268
 
336
269
  return {
@@ -352,14 +285,24 @@ export function createTraceHelpers(context: TraceContext): {
352
285
  });
353
286
  }
354
287
 
355
- const { manifestUrl, highlightedSources, totalSteps } = getOrRunTrace(
356
- sourceFile,
357
- companionFiles,
358
- );
288
+ const traceName = path.parse(sourceFile).name;
289
+ const relDir = toPosix(path.relative(contentDir, pageDir));
290
+ const trace = getOrRunTrace(sourceFile, sources, traceName);
291
+ for (const file of trace.files) {
292
+ dependencyCollector?.traceOutputs?.set(
293
+ buildTraceOutputPath(relDir, traceName, trace.artifactId, file.name),
294
+ file.content,
295
+ );
296
+ }
359
297
  return renderTraceWidgetHtml({
360
- highlightedSources,
361
- manifestUrl,
362
- totalSteps,
298
+ highlightedSources: trace.highlightedSources,
299
+ manifestUrl: buildManifestUrl({
300
+ relDir,
301
+ traceName,
302
+ artifactId: trace.artifactId,
303
+ applyBasePath,
304
+ }),
305
+ totalSteps: trace.totalSteps,
363
306
  });
364
307
  },
365
308
  };
@@ -73,7 +73,7 @@ function getInternalHrefTarget(href: string): string {
73
73
  function validateDirectoryLink(
74
74
  href: string,
75
75
  resolvedTarget: string,
76
- validTargets: Set<string>,
76
+ validTargets: ReadonlySet<string>,
77
77
  context: string,
78
78
  ): string | null {
79
79
  const indexPath = normalizeOutputPath(
@@ -87,7 +87,7 @@ function validateDirectoryLink(
87
87
 
88
88
  export function validateNavLinks(
89
89
  navData: unknown,
90
- validTargets: Set<string>,
90
+ validTargets: ReadonlySet<string>,
91
91
  fileName: string = 'nav.yaml',
92
92
  ): string[] {
93
93
  if (!Array.isArray(navData)) {
@@ -139,7 +139,7 @@ interface AuthorEntry {
139
139
 
140
140
  export function validateAuthorLinks(
141
141
  authorsData: unknown,
142
- validTargets: Set<string>,
142
+ validTargets: ReadonlySet<string>,
143
143
  fileName: string = 'authors.yaml',
144
144
  ): string[] {
145
145
  if (!authorsData || typeof authorsData !== 'object') {
@@ -189,7 +189,7 @@ export function validateAuthorLinks(
189
189
  }
190
190
 
191
191
  export function validateConfigLinks(
192
- validTargets: Set<string>,
192
+ validTargets: ReadonlySet<string>,
193
193
  navData: unknown,
194
194
  authorsData: unknown,
195
195
  {
@@ -211,7 +211,7 @@ function splitHref(href: string): { pathname: string; suffix: string } {
211
211
  export function validateParentLink(
212
212
  parent: unknown,
213
213
  filePath: string,
214
- validTargets: Set<string>,
214
+ validTargets: ReadonlySet<string>,
215
215
  sourceUrlPath: string,
216
216
  ): string | null {
217
217
  if (typeof parent === 'string' && splitHref(parent).pathname === '') {
@@ -1,118 +1,61 @@
1
- import { compileTemplates, config } from '../templates';
2
- import { getDistDir } from '../util';
3
- import type { CompilerBuildResult } from './types';
4
- import type { TraceCache, WatchTraceOptions } from './compiler-types';
5
- import type { TadaIncrementalWatchPlan } from './planner';
6
- import { createSnapshot, type TadaSnapshot } from './snapshot';
1
+ import { compileTemplates } from '../templates';
2
+ import { validateConfig } from '../build-validation';
7
3
  import {
8
- copyExistingBuildAssets,
9
4
  ensureHighlighter,
10
- makeTempBuildDir,
11
- removeDirIfExists,
12
- } from './assets';
13
- import { computeMutations } from './mutations';
14
- import { validateConfig, validateProjectConfigLinks } from './validation';
15
- import { buildFailedFromError, buildSucceeded } from './build-result';
16
- import {
17
- buildFailedWithDiagnostics,
18
- renderContentRecord,
19
- renderPublicRecord,
20
- } from './build-helpers';
5
+ finishBuild,
6
+ renderSources,
7
+ type TadaSnapshot,
8
+ } from '../site-build';
9
+ import type { TraceCache } from '../build-types';
10
+ import type { TraceToolAvailability } from '../types';
11
+ import type { TadaIncrementalWatchPlan } from './planner';
12
+ import type { CompileOutcome } from './types';
21
13
 
22
14
  export async function buildIncremental({
23
15
  plan,
24
16
  snapshot,
25
17
  traceCache,
26
- traceOptions,
18
+ traceToolAvailability,
27
19
  }: {
28
20
  plan: TadaIncrementalWatchPlan;
29
21
  snapshot: TadaSnapshot;
30
22
  traceCache: TraceCache;
31
- traceOptions: WatchTraceOptions;
32
- }): Promise<CompilerBuildResult> {
33
- const distDir = getDistDir();
34
- const outputDir = makeTempBuildDir(distDir);
35
- try {
36
- const siteVariables = snapshot.siteVariables;
37
- const configDiagnostics = validateConfig(plan.scan, siteVariables);
38
- if (configDiagnostics.length > 0) {
39
- return buildFailedWithDiagnostics(outputDir, configDiagnostics);
40
- }
41
-
42
- compileTemplates(siteVariables);
43
- await ensureHighlighter(siteVariables);
44
- copyExistingBuildAssets(distDir, outputDir, snapshot.assetFiles);
45
-
46
- const nextContentRecords = new Map(snapshot.contentRecords);
47
- const nextPublicRecords = new Map(snapshot.publicRecords);
48
-
49
- for (const sourcePath of plan.contentToRemove) {
50
- nextContentRecords.delete(sourcePath);
51
- }
52
- for (const sourcePath of plan.publicToRemove) {
53
- nextPublicRecords.delete(sourcePath);
54
- }
55
-
56
- for (const sourcePath of plan.contentToRender) {
57
- nextContentRecords.delete(sourcePath);
58
- const record = renderContentRecord({
59
- filePath: sourcePath,
60
- siteVariables,
61
- scan: plan.scan,
62
- assetFiles: snapshot.assetFiles,
63
- outputDir,
64
- traceCache,
65
- traceOptions,
66
- cachedTraceSourceDir: distDir,
67
- });
68
- if (record) {
69
- nextContentRecords.set(sourcePath, record);
70
- }
71
- }
72
-
73
- for (const sourcePath of plan.publicToRender) {
74
- nextPublicRecords.delete(sourcePath);
75
- const record = renderPublicRecord({
76
- filePath: sourcePath,
77
- publicDir: plan.scan.publicDir,
78
- });
79
- nextPublicRecords.set(sourcePath, record);
80
- }
81
-
82
- const nextSnapshot = createSnapshot({
83
- siteVariables,
84
- assetFiles: snapshot.assetFiles,
85
- navData: config('nav'),
86
- authorsData: config('authors'),
87
- scan: plan.scan,
88
- contentRecords: nextContentRecords,
89
- publicRecords: nextPublicRecords,
90
- });
23
+ traceToolAvailability: TraceToolAvailability;
24
+ }): Promise<CompileOutcome> {
25
+ const { siteVariables } = snapshot;
26
+ const configDiagnostics = validateConfig(plan.scan, siteVariables);
27
+ if (configDiagnostics.length > 0) {
28
+ return { ok: false, diagnostics: configDiagnostics };
29
+ }
91
30
 
92
- const linkDiagnostics = validateProjectConfigLinks(
93
- nextSnapshot.scan.validTargets,
94
- );
95
- if (linkDiagnostics.length > 0) {
96
- return buildFailedWithDiagnostics(outputDir, linkDiagnostics);
97
- }
31
+ compileTemplates(siteVariables);
32
+ await ensureHighlighter(siteVariables);
98
33
 
99
- const forceSourcePaths = new Set([
100
- ...plan.contentToRender,
101
- ...plan.publicToRender,
102
- ]);
103
- const mutations = computeMutations(
104
- snapshot,
105
- nextSnapshot,
106
- forceSourcePaths,
107
- );
108
- removeDirIfExists(outputDir);
109
- return buildSucceeded(nextSnapshot, {
110
- kind: 'apply-mutations',
111
- rootDir: distDir,
112
- mutations,
113
- });
114
- } catch (error) {
115
- removeDirIfExists(outputDir);
116
- return buildFailedFromError(error);
34
+ const records = new Map(snapshot.records);
35
+ for (const source of [...plan.removeSources, ...plan.renderSources]) {
36
+ records.delete(source);
37
+ }
38
+ const rendered = renderSources(plan.renderSources, {
39
+ siteVariables,
40
+ scan: plan.scan,
41
+ assetFiles: snapshot.assetFiles,
42
+ isWatchMode: true,
43
+ traceCache,
44
+ traceToolAvailability,
45
+ });
46
+ for (const [source, record] of rendered.records) {
47
+ records.set(source, record);
117
48
  }
49
+
50
+ const result = finishBuild({
51
+ siteVariables,
52
+ scan: plan.scan,
53
+ assetFiles: snapshot.assetFiles,
54
+ generatedOutputs: snapshot.generatedOutputs,
55
+ records,
56
+ diagnostics: rendered.diagnostics,
57
+ });
58
+ return result.ok
59
+ ? { ...result, full: false, forceSourcePaths: plan.renderSources }
60
+ : result;
118
61
  }