@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.
Files changed (49) hide show
  1. package/README.md +46 -0
  2. package/build/generate-content-assets.ts +39 -185
  3. package/build/pipeline.ts +1 -1
  4. package/build/source-model.ts +2 -14
  5. package/build/types.d.ts +18 -18
  6. package/build/utils/html-comments.ts +3 -0
  7. package/build/utils/jdi-runner/TraceRunner.java +227 -38
  8. package/build/utils/markdown-partials.ts +235 -0
  9. package/build/utils/markdown.ts +12 -1
  10. package/build/utils/python-runner/trace_runner.py +58 -13
  11. package/build/utils/render.ts +14 -12
  12. package/build/utils/trace-core.ts +136 -14
  13. package/build/utils/trace-heap.ts +34 -0
  14. package/build/utils/trace-java.ts +60 -7
  15. package/build/utils/trace-layout.ts +58 -13
  16. package/build/utils/trace-python.ts +6 -2
  17. package/build/utils/trace-svg.ts +54 -60
  18. package/build/utils/trace.ts +193 -78
  19. package/build/watch/build-full.ts +26 -52
  20. package/build/watch/build-helpers.ts +66 -0
  21. package/build/watch/build-incremental.ts +32 -60
  22. package/build/watch/build-result.ts +19 -0
  23. package/build/watch/compiler-types.d.ts +2 -2
  24. package/build/watch/compiler.ts +30 -62
  25. package/build/watch/config-paths.ts +56 -0
  26. package/build/watch/engine.ts +199 -0
  27. package/{watch → build/watch}/fs-commit.ts +1 -3
  28. package/build/watch/index.ts +1 -1
  29. package/build/watch/mutations.ts +23 -25
  30. package/build/watch/planner.ts +14 -78
  31. package/build/watch/runtime.ts +26 -38
  32. package/build/watch/snapshot.ts +26 -47
  33. package/build/watch/types.d.ts +84 -0
  34. package/build/watch/validation.ts +1 -1
  35. package/init/content/lectures/02/_pr1.md +1 -1
  36. package/init/content/lectures/02/index.md +2 -2
  37. package/init/content/lectures/02/subdir/_foobar.md +3 -0
  38. package/init/content/lectures/02/subdir/_pr2.md +3 -3
  39. package/package.json +1 -2
  40. package/src/slides/index.ts +6 -2
  41. package/src/trace/index.ts +49 -12
  42. package/src/trace/style.scss +10 -0
  43. package/src/trace/types.d.ts +16 -4
  44. package/build/utils/include.ts +0 -57
  45. package/build/watch-reachability-state.ts +0 -305
  46. package/init/content/lectures/02/subdir/_foobar.html +0 -3
  47. package/watch/engine.ts +0 -296
  48. package/watch/events.ts +0 -10
  49. package/watch/types.d.ts +0 -103
package/watch/engine.ts DELETED
@@ -1,296 +0,0 @@
1
- import chokidar from 'chokidar';
2
- import { applyCommitPlan } from './fs-commit';
3
- import { emitWatchEvent } from './events';
4
- import type {
5
- ChangeBatch,
6
- CompilerBuildResult,
7
- CompilerPlanResult,
8
- WatchEngineOptions,
9
- WatchEventKind,
10
- } from './types';
11
-
12
- function normalizeBatch(changes: Map<string, WatchEventKind>): ChangeBatch {
13
- return {
14
- changes: [...changes.entries()]
15
- .sort(([a], [b]) => a.localeCompare(b))
16
- .map(([path, kind]) => ({ path, kind })),
17
- };
18
- }
19
-
20
- function mergeChangeKind(
21
- previous: WatchEventKind | undefined,
22
- next: WatchEventKind,
23
- ): WatchEventKind {
24
- if (!previous) {
25
- return next;
26
- }
27
- if (previous === 'add' && next === 'unlink') {
28
- return 'change';
29
- }
30
- if (previous === 'unlink' && next === 'add') {
31
- return 'change';
32
- }
33
- if (previous === 'add' || next === 'add') {
34
- return 'add';
35
- }
36
- if (previous === 'unlink' || next === 'unlink') {
37
- return 'unlink';
38
- }
39
- return 'change';
40
- }
41
-
42
- function toDiagnostics(error: unknown): { message: string }[] {
43
- if (error instanceof Error) {
44
- return [{ message: error.message }];
45
- }
46
- return [{ message: String(error) }];
47
- }
48
-
49
- function isNoopCommit(commit: {
50
- kind: string;
51
- mutations?: unknown[];
52
- }): boolean {
53
- return (
54
- commit.kind === 'apply-mutations' && (commit.mutations?.length ?? 0) === 0
55
- );
56
- }
57
-
58
- type BuildAttemptOutcome<Snapshot, Meta> =
59
- | { kind: 'skipped'; batch: ChangeBatch; initial: boolean }
60
- | {
61
- kind: 'succeeded';
62
- batch?: ChangeBatch;
63
- initial: boolean;
64
- result: Extract<CompilerBuildResult<Snapshot, Meta>, { ok: true }>;
65
- }
66
- | {
67
- kind: 'failed';
68
- batch?: ChangeBatch;
69
- initial: boolean;
70
- diagnostics: { message: string }[];
71
- meta?: Meta;
72
- };
73
-
74
- export async function runWatchEngine<Snapshot, Plan, Meta>(
75
- options: WatchEngineOptions<Snapshot, Plan, Meta>,
76
- ): Promise<void> {
77
- const debounceMs = options.debounceMs ?? 300;
78
- let snapshot: Snapshot | undefined;
79
- let pending = new Map<string, WatchEventKind>();
80
- let blocked = new Map<string, WatchEventKind>();
81
- let timer: ReturnType<typeof setTimeout> | null = null;
82
- let running = false;
83
-
84
- async function waitForQuietPeriod(): Promise<void> {
85
- await new Promise(resolve => setTimeout(resolve, debounceMs));
86
- }
87
-
88
- async function runBuild(
89
- batch?: ChangeBatch,
90
- initial: boolean = false,
91
- ): Promise<BuildAttemptOutcome<Snapshot, Meta>> {
92
- await emitWatchEvent(options, { kind: 'build-started', batch, initial });
93
- try {
94
- let result: CompilerBuildResult<Snapshot, Meta> | null = null;
95
- if (initial) {
96
- result = await options.compiler.buildInitial();
97
- } else if (batch) {
98
- const nextPlan: CompilerPlanResult<Plan> = await options.compiler.plan(
99
- snapshot,
100
- batch,
101
- );
102
- if (nextPlan.kind === 'skip') {
103
- return { kind: 'skipped', batch, initial };
104
- }
105
- result = await options.compiler.run(nextPlan.plan, snapshot);
106
- }
107
- if (!result) {
108
- return { kind: 'skipped', batch: batch!, initial };
109
- }
110
-
111
- if (result.ok) {
112
- return { kind: 'succeeded', batch, initial, result };
113
- }
114
-
115
- return {
116
- kind: 'failed',
117
- batch,
118
- initial,
119
- diagnostics: result.diagnostics,
120
- meta: result.meta,
121
- };
122
- } catch (error) {
123
- return {
124
- kind: 'failed',
125
- batch,
126
- initial,
127
- diagnostics: toDiagnostics(error),
128
- };
129
- }
130
- }
131
-
132
- async function flush(): Promise<void> {
133
- if (running) {
134
- return;
135
- }
136
- running = true;
137
- try {
138
- let finalSuccess:
139
- | {
140
- batch?: ChangeBatch;
141
- initial: boolean;
142
- result: Extract<CompilerBuildResult<Snapshot, Meta>, { ok: true }>;
143
- changed: boolean;
144
- }
145
- | undefined;
146
-
147
- while (pending.size > 0) {
148
- const batch = normalizeBatch(pending);
149
- pending = new Map();
150
- const outcome = await runBuild(batch, false);
151
-
152
- if (outcome.kind === 'skipped') {
153
- if (pending.size === 0 && !finalSuccess) {
154
- await emitWatchEvent(options, {
155
- kind: 'build-skipped',
156
- batch: outcome.batch,
157
- });
158
- }
159
- continue;
160
- }
161
-
162
- if (outcome.kind === 'failed') {
163
- await emitWatchEvent(options, {
164
- kind: 'build-failed',
165
- initial: outcome.initial,
166
- batch: outcome.batch,
167
- diagnostics: outcome.diagnostics,
168
- meta: outcome.meta,
169
- });
170
- if (outcome.batch) {
171
- for (const change of outcome.batch.changes) {
172
- blocked.set(
173
- change.path,
174
- mergeChangeKind(blocked.get(change.path), change.kind),
175
- );
176
- }
177
- }
178
- return;
179
- }
180
-
181
- const changed = !isNoopCommit(outcome.result.commit);
182
- if (changed) {
183
- applyCommitPlan(outcome.result.commit);
184
- }
185
- snapshot = outcome.result.snapshot;
186
- finalSuccess = {
187
- batch: outcome.batch,
188
- initial: outcome.initial,
189
- result: outcome.result,
190
- changed: (finalSuccess?.changed ?? false) || changed,
191
- };
192
-
193
- if (pending.size === 0) {
194
- await waitForQuietPeriod();
195
- }
196
- }
197
-
198
- if (finalSuccess) {
199
- await emitWatchEvent(options, {
200
- kind: 'build-succeeded',
201
- initial: finalSuccess.initial,
202
- batch: finalSuccess.batch,
203
- changed: finalSuccess.changed,
204
- snapshot: finalSuccess.result.snapshot,
205
- meta: finalSuccess.result.meta,
206
- diagnostics: finalSuccess.result.diagnostics || [],
207
- });
208
- }
209
- } finally {
210
- running = false;
211
- if (pending.size > 0) {
212
- schedule();
213
- }
214
- }
215
- }
216
-
217
- function schedule(): void {
218
- if (timer) {
219
- clearTimeout(timer);
220
- }
221
- timer = setTimeout(() => {
222
- timer = null;
223
- void flush();
224
- }, debounceMs);
225
- }
226
-
227
- function onFileChange(filePath: string, kind: WatchEventKind): void {
228
- if (blocked.size > 0) {
229
- for (const [blockedPath, blockedKind] of blocked) {
230
- pending.set(
231
- blockedPath,
232
- mergeChangeKind(pending.get(blockedPath), blockedKind),
233
- );
234
- }
235
- blocked = new Map();
236
- }
237
- pending.set(filePath, mergeChangeKind(pending.get(filePath), kind));
238
- schedule();
239
- }
240
-
241
- const initialOutcome = await runBuild(undefined, true);
242
- if (initialOutcome.kind === 'failed') {
243
- await emitWatchEvent(options, {
244
- kind: 'build-failed',
245
- initial: true,
246
- diagnostics: initialOutcome.diagnostics,
247
- meta: initialOutcome.meta,
248
- });
249
- } else if (initialOutcome.kind === 'succeeded') {
250
- applyCommitPlan(initialOutcome.result.commit);
251
- snapshot = initialOutcome.result.snapshot;
252
- await emitWatchEvent(options, {
253
- kind: 'build-succeeded',
254
- initial: true,
255
- changed: !isNoopCommit(initialOutcome.result.commit),
256
- snapshot: initialOutcome.result.snapshot,
257
- meta: initialOutcome.result.meta,
258
- diagnostics: initialOutcome.result.diagnostics || [],
259
- });
260
- }
261
-
262
- const watcherEntries = options.compiler
263
- .getWatchTargets()
264
- .map(target => ({
265
- target,
266
- watcher: chokidar.watch(target.path, {
267
- ignoreInitial: true,
268
- atomic: true,
269
- awaitWriteFinish: { stabilityThreshold: 100 },
270
- depth: target.chokidar?.depth,
271
- }),
272
- }));
273
-
274
- let readyCount = 0;
275
- const readyGoal = watcherEntries.length;
276
- const onReady = async () => {
277
- readyCount += 1;
278
- if (readyCount === readyGoal) {
279
- await emitWatchEvent(options, { kind: 'watching' });
280
- }
281
- };
282
-
283
- for (const { watcher, target } of watcherEntries) {
284
- const emitIfIncluded = (filePath: string, kind: WatchEventKind) => {
285
- if (!target.filter || target.filter(filePath)) {
286
- onFileChange(filePath, kind);
287
- }
288
- };
289
- watcher.on('add', filePath => emitIfIncluded(filePath, 'add'));
290
- watcher.on('change', filePath => emitIfIncluded(filePath, 'change'));
291
- watcher.on('unlink', filePath => emitIfIncluded(filePath, 'unlink'));
292
- watcher.on('ready', () => void onReady());
293
- }
294
-
295
- return new Promise(() => {});
296
- }
package/watch/events.ts DELETED
@@ -1,10 +0,0 @@
1
- import type { WatchEngineOptions, WatchLifecycleEvent } from './types';
2
-
3
- export async function emitWatchEvent<Snapshot, Plan, Meta>(
4
- options: WatchEngineOptions<Snapshot, Plan, Meta>,
5
- event: WatchLifecycleEvent<Snapshot, Meta>,
6
- ): Promise<void> {
7
- if (options.onEvent) {
8
- await options.onEvent(event);
9
- }
10
- }
package/watch/types.d.ts DELETED
@@ -1,103 +0,0 @@
1
- export type WatchEventKind = 'add' | 'change' | 'unlink';
2
-
3
- export interface FileChange {
4
- path: string;
5
- kind: WatchEventKind;
6
- }
7
-
8
- export interface ChangeBatch {
9
- changes: FileChange[];
10
- }
11
-
12
- export interface WatchTarget {
13
- path: string;
14
- chokidar?: { depth?: number };
15
- filter?: (filePath: string) => boolean;
16
- }
17
-
18
- export interface WatchDiagnostic {
19
- message: string;
20
- }
21
-
22
- export interface WriteFileMutation {
23
- kind: 'write';
24
- path: string;
25
- content: string | Buffer;
26
- }
27
-
28
- export interface DeleteFileMutation {
29
- kind: 'delete';
30
- path: string;
31
- }
32
-
33
- export type FileMutation = WriteFileMutation | DeleteFileMutation;
34
-
35
- export interface ReplaceRootCommitPlan {
36
- kind: 'replace-root';
37
- stagedPath: string;
38
- targetPath: string;
39
- }
40
-
41
- export interface ApplyMutationsCommitPlan {
42
- kind: 'apply-mutations';
43
- rootDir: string;
44
- mutations: FileMutation[];
45
- }
46
-
47
- export type CommitPlan = ReplaceRootCommitPlan | ApplyMutationsCommitPlan;
48
-
49
- export type CompilerPlanResult<Plan> =
50
- | { kind: 'skip' }
51
- | { kind: 'build'; plan: Plan };
52
-
53
- export type CompilerBuildResult<Snapshot, Meta> =
54
- | {
55
- ok: true;
56
- snapshot: Snapshot;
57
- commit: CommitPlan;
58
- diagnostics?: WatchDiagnostic[];
59
- meta?: Meta;
60
- }
61
- | { ok: false; diagnostics: WatchDiagnostic[]; meta?: Meta };
62
-
63
- export interface WatchCompiler<Snapshot, Plan, Meta> {
64
- getWatchTargets(): WatchTarget[];
65
- buildInitial(): Promise<CompilerBuildResult<Snapshot, Meta>>;
66
- plan(
67
- snapshot: Snapshot | undefined,
68
- batch: ChangeBatch,
69
- ): Promise<CompilerPlanResult<Plan>>;
70
- run(
71
- plan: Plan,
72
- snapshot: Snapshot | undefined,
73
- ): Promise<CompilerBuildResult<Snapshot, Meta>>;
74
- }
75
-
76
- export type WatchLifecycleEvent<Snapshot, Meta> =
77
- | { kind: 'watching' }
78
- | { kind: 'build-started'; batch?: ChangeBatch; initial: boolean }
79
- | {
80
- kind: 'build-succeeded';
81
- initial: boolean;
82
- batch?: ChangeBatch;
83
- changed: boolean;
84
- snapshot: Snapshot;
85
- meta?: Meta;
86
- diagnostics: WatchDiagnostic[];
87
- }
88
- | {
89
- kind: 'build-failed';
90
- initial: boolean;
91
- batch?: ChangeBatch;
92
- diagnostics: WatchDiagnostic[];
93
- meta?: Meta;
94
- }
95
- | { kind: 'build-skipped'; batch: ChangeBatch };
96
-
97
- export interface WatchEngineOptions<Snapshot, Plan, Meta> {
98
- compiler: WatchCompiler<Snapshot, Plan, Meta>;
99
- debounceMs?: number;
100
- onEvent?: (
101
- event: WatchLifecycleEvent<Snapshot, Meta>,
102
- ) => void | Promise<void>;
103
- }