@abreen/tada 1.13.7 → 1.14.1
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 +46 -0
- package/build/generate-content-assets.ts +39 -185
- package/build/pipeline.ts +1 -1
- package/build/source-model.ts +2 -14
- package/build/types.d.ts +18 -18
- package/build/utils/html-comments.ts +3 -0
- package/build/utils/jdi-runner/TraceRunner.java +227 -38
- package/build/utils/markdown-partials.ts +235 -0
- package/build/utils/markdown.ts +12 -1
- package/build/utils/python-runner/trace_runner.py +58 -13
- package/build/utils/render.ts +14 -12
- package/build/utils/trace-core.ts +136 -14
- package/build/utils/trace-heap.ts +34 -0
- package/build/utils/trace-java.ts +60 -7
- package/build/utils/trace-layout.ts +58 -13
- package/build/utils/trace-python.ts +6 -2
- package/build/utils/trace-svg.ts +54 -60
- package/build/utils/trace.ts +193 -78
- package/build/watch/build-full.ts +26 -52
- package/build/watch/build-helpers.ts +66 -0
- package/build/watch/build-incremental.ts +32 -60
- package/build/watch/build-result.ts +19 -0
- package/build/watch/compiler-types.d.ts +2 -2
- package/build/watch/compiler.ts +30 -62
- package/build/watch/config-paths.ts +56 -0
- package/build/watch/engine.ts +199 -0
- package/{watch → build/watch}/fs-commit.ts +1 -3
- package/build/watch/index.ts +1 -1
- package/build/watch/mutations.ts +23 -25
- package/build/watch/planner.ts +14 -78
- package/build/watch/runtime.ts +26 -38
- package/build/watch/snapshot.ts +26 -47
- package/build/watch/types.d.ts +84 -0
- package/build/watch/validation.ts +1 -1
- package/init/content/lectures/02/_pr1.md +1 -1
- package/init/content/lectures/02/index.md +2 -2
- package/init/content/lectures/02/subdir/_foobar.md +3 -0
- package/init/content/lectures/02/subdir/_pr2.md +3 -3
- package/package.json +1 -2
- package/src/slides/index.ts +6 -2
- package/src/trace/index.ts +49 -12
- package/src/trace/style.scss +10 -0
- package/src/trace/types.d.ts +16 -4
- package/build/utils/include.ts +0 -57
- package/build/watch-reachability-state.ts +0 -305
- package/init/content/lectures/02/subdir/_foobar.html +0 -3
- package/watch/engine.ts +0 -296
- package/watch/events.ts +0 -10
- package/watch/types.d.ts +0 -103
package/build/utils/trace.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { makeLogger } from '../log';
|
|
4
5
|
import { B } from '../colors';
|
|
@@ -43,9 +44,9 @@ export interface TraceContext {
|
|
|
43
44
|
export interface TraceResult {
|
|
44
45
|
manifestUrl: string;
|
|
45
46
|
artifactId: string;
|
|
46
|
-
highlightedSource: string;
|
|
47
|
+
highlightedSources: { file: string; highlightedSource: string }[];
|
|
47
48
|
totalSteps: number;
|
|
48
|
-
|
|
49
|
+
sourceMtims: Record<string, number>;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export function isTraceSourceFile(filePath: string): boolean {
|
|
@@ -89,31 +90,44 @@ function disabledTraceMessage(fileName: string): string {
|
|
|
89
90
|
return `Python was not found; trace for ${B`${fileName}`} will be disabled`;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
interface TraceSourceFile {
|
|
94
|
+
requestedPath: string;
|
|
95
|
+
absolutePath: string;
|
|
96
|
+
file: string;
|
|
97
|
+
source: string;
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
function runTraceForFile(
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
primaryFilePath: string,
|
|
102
|
+
tracedFilePaths: string[],
|
|
103
|
+
sources: { file: string; source: string }[],
|
|
100
104
|
): { output: string; ignoreFields?: Record<string, string[]> } {
|
|
101
|
-
const ext = path.extname(
|
|
105
|
+
const ext = path.extname(primaryFilePath).toLowerCase();
|
|
102
106
|
if (ext === '.java') {
|
|
103
|
-
validateJavaTraceTarget(
|
|
107
|
+
validateJavaTraceTarget(primaryFilePath, sources[0].source);
|
|
108
|
+
const ignoreFields: Record<string, string[]> = {};
|
|
109
|
+
for (const source of sources) {
|
|
110
|
+
const sourceFields = parseIgnoreFields(source.source);
|
|
111
|
+
for (const [className, fieldNames] of Object.entries(sourceFields)) {
|
|
112
|
+
ignoreFields[className] = [
|
|
113
|
+
...(ignoreFields[className] ?? []),
|
|
114
|
+
...fieldNames,
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
104
118
|
return {
|
|
105
|
-
output: runJavaTrace(
|
|
106
|
-
ignoreFields
|
|
119
|
+
output: runJavaTrace(tracedFilePaths, path.parse(primaryFilePath).name),
|
|
120
|
+
ignoreFields,
|
|
107
121
|
};
|
|
108
122
|
}
|
|
109
123
|
if (ext === '.py') {
|
|
110
|
-
return { output: runPythonTrace(
|
|
124
|
+
return { output: runPythonTrace(primaryFilePath, tracedFilePaths) };
|
|
111
125
|
}
|
|
112
|
-
throw new Error(`Unsupported trace source: ${
|
|
126
|
+
throw new Error(`Unsupported trace source: ${primaryFilePath}`);
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
export function createTraceHelpers(context: TraceContext): {
|
|
116
|
-
renderTrace: (sourceFile: string) => string;
|
|
130
|
+
renderTrace: (sourceFile: string, companionFiles?: string[]) => string;
|
|
117
131
|
} {
|
|
118
132
|
const {
|
|
119
133
|
filePath,
|
|
@@ -127,60 +141,158 @@ export function createTraceHelpers(context: TraceContext): {
|
|
|
127
141
|
} = context;
|
|
128
142
|
const pageDir = path.dirname(filePath);
|
|
129
143
|
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
144
|
+
function resolveTraceSources(
|
|
145
|
+
sourceFile: string,
|
|
146
|
+
companionFiles?: string[],
|
|
147
|
+
): TraceSourceFile[] {
|
|
148
|
+
if (companionFiles !== undefined && !Array.isArray(companionFiles)) {
|
|
149
|
+
throw new Error('renderTrace companionFiles must be an array');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const requestedPaths = [sourceFile, ...(companionFiles ?? [])];
|
|
153
|
+
const sources = requestedPaths.map(requestedPath => {
|
|
154
|
+
const absolutePath = path.resolve(pageDir, requestedPath);
|
|
155
|
+
if (!fs.existsSync(absolutePath)) {
|
|
156
|
+
throw new Error(`Trace target not found: ${absolutePath}`);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
requestedPath,
|
|
160
|
+
absolutePath,
|
|
161
|
+
file: path.basename(requestedPath),
|
|
162
|
+
source: fs.readFileSync(absolutePath, 'utf-8'),
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const primaryExt = path.extname(sources[0].absolutePath).toLowerCase();
|
|
167
|
+
for (const source of sources) {
|
|
168
|
+
const ext = path.extname(source.absolutePath).toLowerCase();
|
|
169
|
+
if (ext !== primaryExt) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Trace companion must use the same extension as ${sourceFile}: ${source.requestedPath}`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
traceLanguageForFile(source.absolutePath);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const seenBasenames = new Set<string>();
|
|
178
|
+
for (const source of sources) {
|
|
179
|
+
if (seenBasenames.has(source.file)) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`Trace files must have unique basenames in a flat workspace: ${source.file}`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
seenBasenames.add(source.file);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return sources;
|
|
188
|
+
}
|
|
135
189
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
190
|
+
function cacheKeyForSources(sources: TraceSourceFile[]): string {
|
|
191
|
+
return JSON.stringify(sources.map(source => source.absolutePath));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getSourceMtims(sources: TraceSourceFile[]): Record<string, number> {
|
|
195
|
+
return Object.fromEntries(
|
|
196
|
+
sources.map(source => [
|
|
197
|
+
source.absolutePath,
|
|
198
|
+
fs.statSync(source.absolutePath).mtimeMs,
|
|
199
|
+
]),
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function cacheIsFresh(
|
|
204
|
+
sources: TraceSourceFile[],
|
|
205
|
+
cached: TraceResult,
|
|
206
|
+
): boolean {
|
|
207
|
+
return sources.every(source => {
|
|
208
|
+
const mtime = fs.statSync(source.absolutePath, {
|
|
139
209
|
throwIfNoEntry: false,
|
|
140
210
|
})?.mtimeMs;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
sourceDistDir: cachedTraceSourceDir || distDir,
|
|
153
|
-
})
|
|
154
|
-
) {
|
|
155
|
-
for (const outputPath of outputPaths) {
|
|
156
|
-
dependencyCollector?.generatedOutputPaths?.add(outputPath);
|
|
157
|
-
}
|
|
158
|
-
return {
|
|
159
|
-
...cached,
|
|
160
|
-
manifestUrl: buildManifestUrl({
|
|
161
|
-
relDir,
|
|
162
|
-
traceName,
|
|
163
|
-
artifactId: cached.artifactId,
|
|
164
|
-
applyBasePath,
|
|
165
|
-
}),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
211
|
+
return (
|
|
212
|
+
mtime !== undefined && cached.sourceMtims[source.absolutePath] === mtime
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function createTraceWorkspace(sources: TraceSourceFile[]): string {
|
|
218
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tada-trace-work-'));
|
|
219
|
+
try {
|
|
220
|
+
for (const source of sources) {
|
|
221
|
+
fs.copyFileSync(source.absolutePath, path.join(tempDir, source.file));
|
|
168
222
|
}
|
|
223
|
+
return tempDir;
|
|
224
|
+
} catch (err) {
|
|
225
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
226
|
+
throw err;
|
|
169
227
|
}
|
|
228
|
+
}
|
|
170
229
|
|
|
171
|
-
|
|
172
|
-
|
|
230
|
+
function getOrRunTrace(
|
|
231
|
+
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);
|
|
173
237
|
}
|
|
238
|
+
const sourceFilePath = sources[0].absolutePath;
|
|
239
|
+
const traceName = path.parse(sourceFile).name;
|
|
240
|
+
const relDir = toPosix(path.relative(contentDir, pageDir));
|
|
241
|
+
const cacheKey = cacheKeyForSources(sources);
|
|
174
242
|
|
|
175
|
-
const
|
|
243
|
+
const cached = cache.get(cacheKey);
|
|
244
|
+
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
|
+
}
|
|
271
|
+
}
|
|
176
272
|
|
|
177
273
|
log.info`Tracing ${B`${sourceFile}`}`;
|
|
178
274
|
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
275
|
+
const workspaceDir = createTraceWorkspace(sources);
|
|
276
|
+
let output: string;
|
|
277
|
+
let ignoreFields: Record<string, string[]> | undefined;
|
|
278
|
+
try {
|
|
279
|
+
const workspacePaths = sources.map(source =>
|
|
280
|
+
path.join(workspaceDir, source.file),
|
|
281
|
+
);
|
|
282
|
+
({ output, ignoreFields } = runTraceForFile(
|
|
283
|
+
workspacePaths[0],
|
|
284
|
+
workspacePaths,
|
|
285
|
+
sources.map(source => ({ file: source.file, source: source.source })),
|
|
286
|
+
));
|
|
287
|
+
} finally {
|
|
288
|
+
fs.rmSync(workspaceDir, { recursive: true, force: true });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const language = traceLanguageForFile(sourceFilePath);
|
|
292
|
+
const highlightedSources = sources.map(source => ({
|
|
293
|
+
file: source.file,
|
|
294
|
+
highlightedSource: highlightTraceSource(source.source, language),
|
|
295
|
+
}));
|
|
184
296
|
const traceOutputDir = path.join(distDir, relDir, '_traces', traceName);
|
|
185
297
|
|
|
186
298
|
const traceOutput = chunkTraceOutput(
|
|
@@ -188,8 +300,8 @@ export function createTraceHelpers(context: TraceContext): {
|
|
|
188
300
|
traceOutputDir,
|
|
189
301
|
relDir,
|
|
190
302
|
traceName,
|
|
191
|
-
|
|
192
|
-
source,
|
|
303
|
+
sources[0].file,
|
|
304
|
+
sources.map(source => ({ file: source.file, source: source.source })),
|
|
193
305
|
{ chunkSize: DEFAULT_CHUNK_SIZE, ignoreFields },
|
|
194
306
|
);
|
|
195
307
|
for (const outputPath of traceOutput.outputPaths) {
|
|
@@ -204,45 +316,48 @@ export function createTraceHelpers(context: TraceContext): {
|
|
|
204
316
|
});
|
|
205
317
|
|
|
206
318
|
const totalSteps = traceOutput.manifest.totalSteps;
|
|
207
|
-
const
|
|
208
|
-
cache.set(
|
|
319
|
+
const sourceMtims = getSourceMtims(sources);
|
|
320
|
+
cache.set(cacheKey, {
|
|
209
321
|
manifestUrl,
|
|
210
322
|
artifactId: traceOutput.artifactId,
|
|
211
|
-
|
|
323
|
+
highlightedSources,
|
|
212
324
|
totalSteps,
|
|
213
|
-
|
|
325
|
+
sourceMtims,
|
|
214
326
|
});
|
|
215
327
|
return {
|
|
216
328
|
manifestUrl,
|
|
217
329
|
artifactId: traceOutput.artifactId,
|
|
218
|
-
|
|
330
|
+
highlightedSources,
|
|
219
331
|
totalSteps,
|
|
220
|
-
|
|
332
|
+
sourceMtims,
|
|
221
333
|
};
|
|
222
334
|
}
|
|
223
335
|
|
|
224
336
|
return {
|
|
225
|
-
renderTrace: (sourceFile: string): string => {
|
|
226
|
-
const
|
|
337
|
+
renderTrace: (sourceFile: string, companionFiles?: string[]): string => {
|
|
338
|
+
const sources = resolveTraceSources(sourceFile, companionFiles);
|
|
339
|
+
for (const source of sources) {
|
|
340
|
+
dependencyCollector?.traceFiles?.add(source.absolutePath);
|
|
341
|
+
}
|
|
342
|
+
const sourceFilePath = sources[0].absolutePath;
|
|
227
343
|
const available = availabilityForFile(sourceFilePath, toolAvailability);
|
|
228
344
|
if (available === false) {
|
|
229
345
|
log.warn`${disabledTraceMessage(sourceFile)}`;
|
|
230
|
-
|
|
231
|
-
throw new Error(`Trace target not found: ${sourceFilePath}`);
|
|
232
|
-
}
|
|
233
|
-
const source = fs.readFileSync(sourceFilePath, 'utf-8');
|
|
346
|
+
const language = traceLanguageForFile(sourceFilePath);
|
|
234
347
|
return renderTraceWidgetHtml({
|
|
235
|
-
|
|
236
|
-
source,
|
|
237
|
-
|
|
238
|
-
),
|
|
348
|
+
highlightedSources: sources.map(source => ({
|
|
349
|
+
file: source.file,
|
|
350
|
+
highlightedSource: highlightTraceSource(source.source, language),
|
|
351
|
+
})),
|
|
239
352
|
});
|
|
240
353
|
}
|
|
241
354
|
|
|
242
|
-
const { manifestUrl,
|
|
243
|
-
|
|
355
|
+
const { manifestUrl, highlightedSources, totalSteps } = getOrRunTrace(
|
|
356
|
+
sourceFile,
|
|
357
|
+
companionFiles,
|
|
358
|
+
);
|
|
244
359
|
return renderTraceWidgetHtml({
|
|
245
|
-
|
|
360
|
+
highlightedSources,
|
|
246
361
|
manifestUrl,
|
|
247
362
|
totalSteps,
|
|
248
363
|
});
|
|
@@ -1,34 +1,24 @@
|
|
|
1
1
|
import { compileTemplates, config } from '../templates';
|
|
2
2
|
import { getDevSiteVariables } from '../site-variables';
|
|
3
|
-
import { createContentRecord, createPublicRecord } from '../source-records';
|
|
4
3
|
import { getDistDir } from '../util';
|
|
5
|
-
import type { CompilerBuildResult } from '
|
|
6
|
-
import {
|
|
7
|
-
collectHtmlAnalysisByPath,
|
|
8
|
-
collectHtmlAssetsByPath,
|
|
9
|
-
createSnapshot,
|
|
10
|
-
type TadaSourceRecord,
|
|
11
|
-
type TadaSnapshot,
|
|
12
|
-
} from './snapshot';
|
|
4
|
+
import type { CompilerBuildResult } from './types';
|
|
5
|
+
import { createSnapshot, type TadaSourceRecord } from './snapshot';
|
|
13
6
|
import { scanProject } from '../source-model';
|
|
14
|
-
import type {
|
|
15
|
-
TadaBuildMeta,
|
|
16
|
-
TraceCache,
|
|
17
|
-
WatchTraceOptions,
|
|
18
|
-
} from './compiler-types';
|
|
7
|
+
import type { TraceCache, WatchTraceOptions } from './compiler-types';
|
|
19
8
|
import {
|
|
20
9
|
bundleWatchAssets,
|
|
21
10
|
ensureHighlighter,
|
|
22
11
|
makeTempBuildDir,
|
|
23
12
|
populateStaticAssets,
|
|
24
13
|
removeDirIfExists,
|
|
25
|
-
writeAssets,
|
|
26
14
|
} from './assets';
|
|
15
|
+
import { validateConfig, validateProjectConfigLinks } from './validation';
|
|
16
|
+
import { buildFailedFromError, buildSucceeded } from './build-result';
|
|
27
17
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} from './
|
|
18
|
+
buildFailedWithDiagnostics,
|
|
19
|
+
renderContentRecord,
|
|
20
|
+
renderPublicRecord,
|
|
21
|
+
} from './build-helpers';
|
|
32
22
|
|
|
33
23
|
export async function buildFull({
|
|
34
24
|
traceCache,
|
|
@@ -36,7 +26,7 @@ export async function buildFull({
|
|
|
36
26
|
}: {
|
|
37
27
|
traceCache: TraceCache;
|
|
38
28
|
traceOptions: WatchTraceOptions;
|
|
39
|
-
}): Promise<CompilerBuildResult
|
|
29
|
+
}): Promise<CompilerBuildResult> {
|
|
40
30
|
const distDir = getDistDir();
|
|
41
31
|
const outputDir = makeTempBuildDir(distDir);
|
|
42
32
|
try {
|
|
@@ -44,8 +34,7 @@ export async function buildFull({
|
|
|
44
34
|
const scan = scanProject(siteVariables);
|
|
45
35
|
const configDiagnostics = validateConfig(scan);
|
|
46
36
|
if (configDiagnostics.length > 0) {
|
|
47
|
-
|
|
48
|
-
return { ok: false, diagnostics: configDiagnostics };
|
|
37
|
+
return buildFailedWithDiagnostics(outputDir, configDiagnostics);
|
|
49
38
|
}
|
|
50
39
|
|
|
51
40
|
compileTemplates(siteVariables);
|
|
@@ -56,33 +45,34 @@ export async function buildFull({
|
|
|
56
45
|
|
|
57
46
|
const contentRecords = new Map<string, TadaSourceRecord>();
|
|
58
47
|
for (const filePath of scan.contentFiles) {
|
|
59
|
-
const record =
|
|
48
|
+
const record = renderContentRecord({
|
|
60
49
|
filePath,
|
|
61
50
|
siteVariables,
|
|
62
51
|
scan,
|
|
63
52
|
assetFiles,
|
|
64
53
|
outputDir,
|
|
65
54
|
traceCache,
|
|
66
|
-
|
|
55
|
+
traceOptions,
|
|
67
56
|
cachedTraceSourceDir: distDir,
|
|
68
57
|
});
|
|
69
|
-
if (record
|
|
70
|
-
writeAssets(outputDir, record.outputs);
|
|
58
|
+
if (record) {
|
|
71
59
|
contentRecords.set(filePath, record);
|
|
72
60
|
}
|
|
73
61
|
}
|
|
74
62
|
|
|
75
63
|
const publicRecords = new Map<string, TadaSourceRecord>();
|
|
76
64
|
for (const filePath of scan.publicFiles) {
|
|
77
|
-
const record =
|
|
78
|
-
|
|
65
|
+
const record = renderPublicRecord({
|
|
66
|
+
filePath,
|
|
67
|
+
publicDir: scan.publicDir,
|
|
68
|
+
outputDir,
|
|
69
|
+
});
|
|
79
70
|
publicRecords.set(filePath, record);
|
|
80
71
|
}
|
|
81
72
|
|
|
82
73
|
const linkDiagnostics = validateProjectConfigLinks(scan.validTargets);
|
|
83
74
|
if (linkDiagnostics.length > 0) {
|
|
84
|
-
|
|
85
|
-
return { ok: false, diagnostics: linkDiagnostics };
|
|
75
|
+
return buildFailedWithDiagnostics(outputDir, linkDiagnostics);
|
|
86
76
|
}
|
|
87
77
|
|
|
88
78
|
const nextSnapshot = createSnapshot({
|
|
@@ -95,29 +85,13 @@ export async function buildFull({
|
|
|
95
85
|
publicRecords,
|
|
96
86
|
});
|
|
97
87
|
|
|
98
|
-
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
stagedPath: outputDir,
|
|
104
|
-
targetPath: distDir,
|
|
105
|
-
},
|
|
106
|
-
meta: {
|
|
107
|
-
htmlAssetsByPath: collectHtmlAssetsByPath(nextSnapshot.contentRecords),
|
|
108
|
-
htmlAnalysisByPath: collectHtmlAnalysisByPath(
|
|
109
|
-
nextSnapshot.contentRecords,
|
|
110
|
-
),
|
|
111
|
-
siteVariables,
|
|
112
|
-
},
|
|
113
|
-
};
|
|
88
|
+
return buildSucceeded(nextSnapshot, {
|
|
89
|
+
kind: 'replace-root',
|
|
90
|
+
stagedPath: outputDir,
|
|
91
|
+
targetPath: distDir,
|
|
92
|
+
});
|
|
114
93
|
} catch (error) {
|
|
115
94
|
removeDirIfExists(outputDir);
|
|
116
|
-
return
|
|
117
|
-
ok: false,
|
|
118
|
-
diagnostics: diagnosticsFromMessages([
|
|
119
|
-
error instanceof Error ? error.message : String(error),
|
|
120
|
-
]),
|
|
121
|
-
};
|
|
95
|
+
return buildFailedFromError(error);
|
|
122
96
|
}
|
|
123
97
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createContentRecord, createPublicRecord } from '../source-records';
|
|
2
|
+
import type { SiteVariables } from '../types';
|
|
3
|
+
import type { TadaProjectScan, TadaSourceRecord } from './snapshot';
|
|
4
|
+
import type { CompilerBuildResult, WatchDiagnostic } from './types';
|
|
5
|
+
import type { TraceCache, WatchTraceOptions } from './compiler-types';
|
|
6
|
+
import { removeDirIfExists, writeAssets } from './assets';
|
|
7
|
+
|
|
8
|
+
export function buildFailedWithDiagnostics(
|
|
9
|
+
outputDir: string,
|
|
10
|
+
diagnostics: WatchDiagnostic[],
|
|
11
|
+
): CompilerBuildResult {
|
|
12
|
+
removeDirIfExists(outputDir);
|
|
13
|
+
return { ok: false, diagnostics };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function renderContentRecord({
|
|
17
|
+
filePath,
|
|
18
|
+
siteVariables,
|
|
19
|
+
scan,
|
|
20
|
+
assetFiles,
|
|
21
|
+
outputDir,
|
|
22
|
+
traceCache,
|
|
23
|
+
traceOptions,
|
|
24
|
+
cachedTraceSourceDir,
|
|
25
|
+
}: {
|
|
26
|
+
filePath: string;
|
|
27
|
+
siteVariables: SiteVariables;
|
|
28
|
+
scan: TadaProjectScan;
|
|
29
|
+
assetFiles: string[];
|
|
30
|
+
outputDir: string;
|
|
31
|
+
traceCache: TraceCache;
|
|
32
|
+
traceOptions: WatchTraceOptions;
|
|
33
|
+
cachedTraceSourceDir: string;
|
|
34
|
+
}): TadaSourceRecord | undefined {
|
|
35
|
+
const record = createContentRecord({
|
|
36
|
+
filePath,
|
|
37
|
+
siteVariables,
|
|
38
|
+
scan,
|
|
39
|
+
assetFiles,
|
|
40
|
+
outputDir,
|
|
41
|
+
traceCache,
|
|
42
|
+
traceToolAvailability: traceOptions.toolAvailability,
|
|
43
|
+
cachedTraceSourceDir,
|
|
44
|
+
});
|
|
45
|
+
if (record.outputs.size === 0) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
writeAssets(outputDir, record.outputs);
|
|
49
|
+
return record;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function renderPublicRecord({
|
|
53
|
+
filePath,
|
|
54
|
+
publicDir,
|
|
55
|
+
outputDir,
|
|
56
|
+
}: {
|
|
57
|
+
filePath: string;
|
|
58
|
+
publicDir: string;
|
|
59
|
+
outputDir?: string;
|
|
60
|
+
}): TadaSourceRecord {
|
|
61
|
+
const record = createPublicRecord(filePath, publicDir);
|
|
62
|
+
if (outputDir) {
|
|
63
|
+
writeAssets(outputDir, record.outputs);
|
|
64
|
+
}
|
|
65
|
+
return record;
|
|
66
|
+
}
|