@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
|
@@ -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
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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,
|
package/build/utils/trace.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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(
|
|
292
|
-
const
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
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
|
};
|
|
@@ -70,9 +70,24 @@ function getInternalHrefTarget(href: string): string {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function validateDirectoryLink(
|
|
74
|
+
href: string,
|
|
75
|
+
resolvedTarget: string,
|
|
76
|
+
validTargets: ReadonlySet<string>,
|
|
77
|
+
context: string,
|
|
78
|
+
): string | null {
|
|
79
|
+
const indexPath = normalizeOutputPath(
|
|
80
|
+
path.posix.join(resolvedTarget, 'index.html'),
|
|
81
|
+
);
|
|
82
|
+
if (validTargets.has(indexPath)) {
|
|
83
|
+
return `${context}: directory link must reference index.html explicitly: "${href}" (resolved to "${resolvedTarget}", expected "${indexPath}")`;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
73
88
|
export function validateNavLinks(
|
|
74
89
|
navData: unknown,
|
|
75
|
-
validTargets:
|
|
90
|
+
validTargets: ReadonlySet<string>,
|
|
76
91
|
fileName: string = 'nav.yaml',
|
|
77
92
|
): string[] {
|
|
78
93
|
if (!Array.isArray(navData)) {
|
|
@@ -96,8 +111,16 @@ export function validateNavLinks(
|
|
|
96
111
|
continue;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
const normalized =
|
|
100
|
-
|
|
114
|
+
const normalized = getInternalHrefTarget(link.internal);
|
|
115
|
+
const directoryError = validateDirectoryLink(
|
|
116
|
+
link.internal,
|
|
117
|
+
normalized,
|
|
118
|
+
validTargets,
|
|
119
|
+
`${fileName}: internal link in section "${section.title}"`,
|
|
120
|
+
);
|
|
121
|
+
if (directoryError) {
|
|
122
|
+
errors.push(directoryError);
|
|
123
|
+
} else if (!validTargets.has(normalized)) {
|
|
101
124
|
errors.push(
|
|
102
125
|
`${fileName}: broken internal link in section "${section.title}": "${link.internal}"`,
|
|
103
126
|
);
|
|
@@ -116,7 +139,7 @@ interface AuthorEntry {
|
|
|
116
139
|
|
|
117
140
|
export function validateAuthorLinks(
|
|
118
141
|
authorsData: unknown,
|
|
119
|
-
validTargets:
|
|
142
|
+
validTargets: ReadonlySet<string>,
|
|
120
143
|
fileName: string = 'authors.yaml',
|
|
121
144
|
): string[] {
|
|
122
145
|
if (!authorsData || typeof authorsData !== 'object') {
|
|
@@ -166,7 +189,7 @@ export function validateAuthorLinks(
|
|
|
166
189
|
}
|
|
167
190
|
|
|
168
191
|
export function validateConfigLinks(
|
|
169
|
-
validTargets:
|
|
192
|
+
validTargets: ReadonlySet<string>,
|
|
170
193
|
navData: unknown,
|
|
171
194
|
authorsData: unknown,
|
|
172
195
|
{
|
|
@@ -188,7 +211,7 @@ function splitHref(href: string): { pathname: string; suffix: string } {
|
|
|
188
211
|
export function validateParentLink(
|
|
189
212
|
parent: unknown,
|
|
190
213
|
filePath: string,
|
|
191
|
-
validTargets:
|
|
214
|
+
validTargets: ReadonlySet<string>,
|
|
192
215
|
sourceUrlPath: string,
|
|
193
216
|
): string | null {
|
|
194
217
|
if (typeof parent === 'string' && splitHref(parent).pathname === '') {
|
|
@@ -200,6 +223,16 @@ export function validateParentLink(
|
|
|
200
223
|
return null;
|
|
201
224
|
}
|
|
202
225
|
|
|
226
|
+
const directoryError = validateDirectoryLink(
|
|
227
|
+
parent as string,
|
|
228
|
+
resolvedTarget,
|
|
229
|
+
validTargets,
|
|
230
|
+
`${filePath}: parent link`,
|
|
231
|
+
);
|
|
232
|
+
if (directoryError) {
|
|
233
|
+
return directoryError;
|
|
234
|
+
}
|
|
235
|
+
|
|
203
236
|
if (!validTargets.has(resolvedTarget)) {
|
|
204
237
|
return `${filePath}: broken parent link: "${parent}"`;
|
|
205
238
|
}
|
|
@@ -1,118 +1,61 @@
|
|
|
1
|
-
import { compileTemplates
|
|
2
|
-
import {
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
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
|
-
|
|
18
|
+
traceToolAvailability,
|
|
27
19
|
}: {
|
|
28
20
|
plan: TadaIncrementalWatchPlan;
|
|
29
21
|
snapshot: TadaSnapshot;
|
|
30
22
|
traceCache: TraceCache;
|
|
31
|
-
|
|
32
|
-
}): Promise<
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
);
|
|
95
|
-
if (linkDiagnostics.length > 0) {
|
|
96
|
-
return buildFailedWithDiagnostics(outputDir, linkDiagnostics);
|
|
97
|
-
}
|
|
31
|
+
compileTemplates(siteVariables);
|
|
32
|
+
await ensureHighlighter(siteVariables);
|
|
98
33
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
}
|