@abreen/tada 1.9.0 → 1.10.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 +24 -34
- package/bin/tada.ts +1 -1
- package/build/apply-base-path-plugin.ts +79 -17
- package/build/bundle.ts +9 -1
- package/build/content-watch.ts +3 -3
- package/build/copy.ts +30 -0
- package/build/generate-content-assets.ts +45 -59
- package/build/pagefind.ts +0 -7
- package/build/serve.ts +4 -0
- package/build/types.d.ts +19 -1
- package/build/util.ts +3 -0
- package/build/utils/content-files.ts +98 -0
- package/build/utils/include.ts +4 -0
- package/build/utils/python-runner/trace_runner.py +272 -0
- package/build/utils/render.ts +34 -8
- package/build/utils/trace-core.ts +203 -0
- package/build/utils/trace-java.ts +132 -0
- package/build/utils/trace-layout.ts +31 -3
- package/build/utils/trace-python.ts +26 -0
- package/build/utils/trace.ts +174 -294
- package/build/validate-internal-links-plugin.ts +16 -4
- package/build/watch/assets.ts +111 -0
- package/build/watch/build-full.ts +124 -0
- package/build/watch/build-incremental.ts +139 -0
- package/build/watch/compiler-types.d.ts +19 -0
- package/build/watch/compiler.ts +112 -0
- package/build/watch/index.ts +22 -0
- package/build/watch/mutations.ts +75 -0
- package/build/watch/planner.ts +230 -0
- package/build/watch/records.ts +190 -0
- package/build/watch/runtime.ts +143 -0
- package/build/watch/snapshot.ts +602 -0
- package/build/watch/validation.ts +36 -0
- package/build/watch-reload-client.ts +10 -5
- package/init/content/labs/01/index.md +6 -0
- package/init/content/labs/01/trace_demo.py +16 -0
- package/package.json +42 -23
- package/python/command.ts +95 -0
- package/python/module.ts +18 -0
- package/src/_alerts.scss +11 -8
- package/src/_base.scss +25 -29
- package/src/_layout.scss +17 -14
- package/src/_mixins.scss +10 -9
- package/src/anchor/style.scss +4 -2
- package/src/code/index.ts +9 -2
- package/src/code/style.scss +14 -13
- package/src/code.scss +14 -13
- package/src/header/_base.scss +21 -24
- package/src/header/style.scss +16 -12
- package/src/index.ts +3 -0
- package/src/literate/style.scss +4 -4
- package/src/navigate/index.ts +43 -279
- package/src/navigate/lifecycle.ts +1 -1
- package/src/navigate/runtime.ts +341 -0
- package/src/page-update/README.md +4 -0
- package/src/page-update/index.ts +280 -0
- package/src/page-update/style.scss +53 -0
- package/src/print/style.scss +4 -4
- package/src/question/style.scss +10 -6
- package/src/search/index.ts +9 -12
- package/src/search/style.scss +44 -42
- package/src/style.scss +63 -58
- package/src/timezone/style.scss +5 -5
- package/src/toc/style.scss +17 -16
- package/src/trace/style.scss +27 -27
- package/src/validators.ts +45 -0
- package/templates/_footer.html +1 -1
- package/templates/_theme.scss +8 -19
- package/watch/engine.ts +296 -0
- package/watch/events.ts +10 -0
- package/watch/fs-commit.ts +102 -0
- package/watch/types.d.ts +103 -0
- package/build/watch.ts +0 -493
package/build/types.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export interface ContentRenderResult {
|
|
|
50
50
|
errors: Error[];
|
|
51
51
|
changedHtmlAssetPaths: Set<string>;
|
|
52
52
|
removedHtmlAssetPaths: Set<string>;
|
|
53
|
+
removedOutputRelPaths: Set<string>;
|
|
53
54
|
htmlAssetsByPath: Map<string, string>;
|
|
54
55
|
buildContentFiles: string[];
|
|
55
56
|
}
|
|
@@ -75,6 +76,8 @@ export interface RenderPlainTextOptions {
|
|
|
75
76
|
validInternalTargets: Set<string>;
|
|
76
77
|
assetFiles: string[];
|
|
77
78
|
literateJavaOutputPaths?: Set<string>;
|
|
79
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
80
|
+
cachedTraceSourceDir?: string;
|
|
78
81
|
traceCache?: Map<
|
|
79
82
|
string,
|
|
80
83
|
{
|
|
@@ -84,7 +87,12 @@ export interface RenderPlainTextOptions {
|
|
|
84
87
|
mtime: number;
|
|
85
88
|
}
|
|
86
89
|
>;
|
|
87
|
-
|
|
90
|
+
traceToolAvailability?: TraceToolAvailability;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface TraceToolAvailability {
|
|
94
|
+
java?: boolean;
|
|
95
|
+
python?: boolean;
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
/** Options for code page asset rendering */
|
|
@@ -94,6 +102,7 @@ export interface RenderCodePageOptions {
|
|
|
94
102
|
distDir: string;
|
|
95
103
|
siteVariables: SiteVariables;
|
|
96
104
|
assetFiles: string[];
|
|
105
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
/** Options for literate Java asset rendering */
|
|
@@ -106,6 +115,7 @@ export interface RenderLiterateJavaOptions {
|
|
|
106
115
|
skipExecution?: boolean;
|
|
107
116
|
validInternalTargets: Set<string>;
|
|
108
117
|
literateJavaOutputPaths?: Set<string>;
|
|
118
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
/** Options for copied content asset rendering */
|
|
@@ -115,6 +125,14 @@ export interface RenderCopiedContentOptions {
|
|
|
115
125
|
siteVariables: SiteVariables;
|
|
116
126
|
}
|
|
117
127
|
|
|
128
|
+
export interface RenderDependencyCollector {
|
|
129
|
+
partials?: Set<string>;
|
|
130
|
+
traceFiles?: Set<string>;
|
|
131
|
+
internalTargets?: Set<string>;
|
|
132
|
+
generatedOutputPaths?: Set<string>;
|
|
133
|
+
setAuthorKey?: (authorKey: string) => void;
|
|
134
|
+
}
|
|
135
|
+
|
|
118
136
|
/** Front matter parse result (from parseFrontMatterAndContent) */
|
|
119
137
|
export interface ParsedContent {
|
|
120
138
|
pageVariables: Record<string, unknown>;
|
package/build/util.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export {
|
|
2
2
|
getBuildContentFiles,
|
|
3
3
|
getContentFiles,
|
|
4
|
+
getContentOutputRelPaths,
|
|
5
|
+
getContentSourceOutputRelPaths,
|
|
4
6
|
getFilesByExtensions,
|
|
5
7
|
getValidInternalTargets,
|
|
6
8
|
shouldSkipContentFile,
|
|
@@ -15,6 +17,7 @@ export {
|
|
|
15
17
|
getProjectDir,
|
|
16
18
|
getPublicDir,
|
|
17
19
|
normalizeOutputPath,
|
|
20
|
+
toPosix,
|
|
18
21
|
} from './utils/paths';
|
|
19
22
|
export {
|
|
20
23
|
injectAssetTags,
|
|
@@ -51,6 +51,104 @@ export function getBuildContentFiles(
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export function getContentSourceOutputRelPaths(
|
|
55
|
+
contentDir: string,
|
|
56
|
+
filePath: string,
|
|
57
|
+
codeExtensions: string[],
|
|
58
|
+
codeEnabled: boolean,
|
|
59
|
+
): Set<string> {
|
|
60
|
+
const processedExtSet = new Set(getProcessedExtensions(codeExtensions));
|
|
61
|
+
const relPath = toPosix(path.relative(contentDir, filePath));
|
|
62
|
+
const ext = path.extname(filePath).slice(1).toLowerCase();
|
|
63
|
+
const parsed = path.parse(relPath);
|
|
64
|
+
const outputs = new Set<string>();
|
|
65
|
+
|
|
66
|
+
if (!processedExtSet.has(ext)) {
|
|
67
|
+
outputs.add(relPath);
|
|
68
|
+
return outputs;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const buildContentFiles = new Set(
|
|
72
|
+
getBuildContentFiles(contentDir, codeExtensions),
|
|
73
|
+
);
|
|
74
|
+
if (!buildContentFiles.has(filePath)) {
|
|
75
|
+
return outputs;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (isLiterateJava(filePath)) {
|
|
79
|
+
outputs.add(toPosix(path.join(parsed.dir, `${parsed.name}.html`)));
|
|
80
|
+
outputs.add(toPosix(path.join(parsed.dir, parsed.name)));
|
|
81
|
+
return outputs;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (
|
|
85
|
+
extensionIsMarkdown(parsed.ext.toLowerCase()) ||
|
|
86
|
+
parsed.ext.toLowerCase() === '.html'
|
|
87
|
+
) {
|
|
88
|
+
outputs.add(toPosix(path.join(parsed.dir, `${parsed.name}.html`)));
|
|
89
|
+
return outputs;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const codeExtensionSet = new Set(
|
|
93
|
+
codeExtensions.map(value => value.toLowerCase()),
|
|
94
|
+
);
|
|
95
|
+
if (codeExtensionSet.has(ext)) {
|
|
96
|
+
outputs.add(relPath);
|
|
97
|
+
if (codeEnabled) {
|
|
98
|
+
outputs.add(`${relPath}.html`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return outputs;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function getContentOutputRelPaths(
|
|
106
|
+
contentDir: string,
|
|
107
|
+
codeExtensions: string[],
|
|
108
|
+
codeEnabled: boolean,
|
|
109
|
+
): Set<string> {
|
|
110
|
+
const buildContentFiles = getBuildContentFiles(contentDir, codeExtensions);
|
|
111
|
+
const codeExtensionSet = new Set(
|
|
112
|
+
codeExtensions.map(ext => ext.toLowerCase()),
|
|
113
|
+
);
|
|
114
|
+
const outputs = new Set<string>();
|
|
115
|
+
|
|
116
|
+
for (const filePath of buildContentFiles) {
|
|
117
|
+
const relPath = toPosix(path.relative(contentDir, filePath));
|
|
118
|
+
const parsed = path.parse(relPath);
|
|
119
|
+
const ext = parsed.ext.toLowerCase();
|
|
120
|
+
|
|
121
|
+
if (isLiterateJava(filePath)) {
|
|
122
|
+
outputs.add(toPosix(path.join(parsed.dir, `${parsed.name}.html`)));
|
|
123
|
+
outputs.add(toPosix(path.join(parsed.dir, parsed.name)));
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (extensionIsMarkdown(ext) || ext === '.html') {
|
|
128
|
+
outputs.add(toPosix(path.join(parsed.dir, `${parsed.name}.html`)));
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (codeExtensionSet.has(ext.slice(1))) {
|
|
133
|
+
outputs.add(relPath);
|
|
134
|
+
if (codeEnabled) {
|
|
135
|
+
outputs.add(`${relPath}.html`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const processedExtSet = new Set(getProcessedExtensions(codeExtensions));
|
|
141
|
+
for (const filePath of walkFiles(contentDir)) {
|
|
142
|
+
const ext = path.extname(filePath).slice(1).toLowerCase();
|
|
143
|
+
if (processedExtSet.has(ext)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
outputs.add(toPosix(path.relative(contentDir, filePath)));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return outputs;
|
|
150
|
+
}
|
|
151
|
+
|
|
54
152
|
function addGeneratedRouteAliases(
|
|
55
153
|
pathSet: Set<string>,
|
|
56
154
|
outputPath: string,
|
package/build/utils/include.ts
CHANGED
|
@@ -3,12 +3,14 @@ import path from 'path';
|
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
import { isPartial } from './file-types';
|
|
5
5
|
import { stripHtmlComments } from './render';
|
|
6
|
+
import type { RenderDependencyCollector } from '../types';
|
|
6
7
|
|
|
7
8
|
const MAX_INCLUDE_DEPTH = 10;
|
|
8
9
|
|
|
9
10
|
export function createIncludeFunction(
|
|
10
11
|
callerFilePath: string,
|
|
11
12
|
templateParams: Record<string, unknown>,
|
|
13
|
+
collector?: RenderDependencyCollector,
|
|
12
14
|
depth: number = 0,
|
|
13
15
|
): (relativePath: string) => string {
|
|
14
16
|
return (relativePath: string): string => {
|
|
@@ -25,6 +27,7 @@ export function createIncludeFunction(
|
|
|
25
27
|
`${callerFilePath}: include target must start with "_": ${relativePath}`,
|
|
26
28
|
);
|
|
27
29
|
}
|
|
30
|
+
collector?.partials?.add(resolved);
|
|
28
31
|
if (depth >= MAX_INCLUDE_DEPTH) {
|
|
29
32
|
throw new Error(
|
|
30
33
|
`${callerFilePath}: maximum include depth (${MAX_INCLUDE_DEPTH}) exceeded`,
|
|
@@ -37,6 +40,7 @@ export function createIncludeFunction(
|
|
|
37
40
|
const nestedInclude = createIncludeFunction(
|
|
38
41
|
resolved,
|
|
39
42
|
templateParams,
|
|
43
|
+
collector,
|
|
40
44
|
depth + 1,
|
|
41
45
|
);
|
|
42
46
|
const nestedParams = { ...templateParams, include: nestedInclude };
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import pdb
|
|
7
|
+
import sys
|
|
8
|
+
import types
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CaptureStream(io.TextIOBase):
|
|
12
|
+
def __init__(self, sink):
|
|
13
|
+
self._sink = sink
|
|
14
|
+
|
|
15
|
+
def write(self, s):
|
|
16
|
+
if not isinstance(s, str):
|
|
17
|
+
s = str(s)
|
|
18
|
+
self._sink.append(s)
|
|
19
|
+
return len(s)
|
|
20
|
+
|
|
21
|
+
def flush(self):
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
def isatty(self):
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TracePdb(pdb.Pdb):
|
|
29
|
+
SYNTHETIC_FRAME_NAMES = {"<listcomp>", "<dictcomp>", "<setcomp>"}
|
|
30
|
+
|
|
31
|
+
def __init__(self, target_path, trace_writer, output_chunks):
|
|
32
|
+
super().__init__(nosigint=True, readrc=False)
|
|
33
|
+
self.target_path = os.path.abspath(target_path)
|
|
34
|
+
self.trace_writer = trace_writer
|
|
35
|
+
self.output_chunks = output_chunks
|
|
36
|
+
self.pending_snapshot = None
|
|
37
|
+
self.object_ids = {}
|
|
38
|
+
self.next_object_id = 1
|
|
39
|
+
|
|
40
|
+
def user_line(self, frame):
|
|
41
|
+
if not self._is_traced_frame(frame):
|
|
42
|
+
self.set_step()
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
snapshot = self._capture_snapshot(frame)
|
|
46
|
+
self._emit_pending()
|
|
47
|
+
self.pending_snapshot = snapshot
|
|
48
|
+
self.set_step()
|
|
49
|
+
|
|
50
|
+
def user_call(self, frame, argument_list):
|
|
51
|
+
if self._is_traced_frame(frame):
|
|
52
|
+
self.set_step()
|
|
53
|
+
|
|
54
|
+
def user_return(self, frame, return_value):
|
|
55
|
+
if self._is_traced_frame(frame):
|
|
56
|
+
snapshot = self._capture_snapshot(frame)
|
|
57
|
+
self._emit_pending()
|
|
58
|
+
self.pending_snapshot = snapshot
|
|
59
|
+
self.set_step()
|
|
60
|
+
|
|
61
|
+
def user_exception(self, frame, exc_info):
|
|
62
|
+
if self._is_traced_frame(frame):
|
|
63
|
+
self.set_step()
|
|
64
|
+
|
|
65
|
+
def flush_pending(self):
|
|
66
|
+
self._emit_pending()
|
|
67
|
+
|
|
68
|
+
def _emit_pending(self):
|
|
69
|
+
if self.pending_snapshot is None:
|
|
70
|
+
return
|
|
71
|
+
payload = dict(self.pending_snapshot)
|
|
72
|
+
payload["stdout"] = self._drain_output()
|
|
73
|
+
self.trace_writer.write(json.dumps(payload) + "\n")
|
|
74
|
+
self.trace_writer.flush()
|
|
75
|
+
self.pending_snapshot = None
|
|
76
|
+
|
|
77
|
+
def _drain_output(self):
|
|
78
|
+
if not self.output_chunks:
|
|
79
|
+
return ""
|
|
80
|
+
output = "".join(self.output_chunks)
|
|
81
|
+
self.output_chunks.clear()
|
|
82
|
+
return output
|
|
83
|
+
|
|
84
|
+
def _capture_snapshot(self, frame):
|
|
85
|
+
reachable = {}
|
|
86
|
+
return {
|
|
87
|
+
"line": frame.f_lineno,
|
|
88
|
+
"file": os.path.basename(frame.f_code.co_filename),
|
|
89
|
+
"stack": self._serialize_stack(frame, reachable),
|
|
90
|
+
"heap": self._serialize_heap(reachable),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
def _serialize_stack(self, frame, reachable):
|
|
94
|
+
frames = []
|
|
95
|
+
current = frame
|
|
96
|
+
while current is not None:
|
|
97
|
+
if self._is_traced_frame(current):
|
|
98
|
+
locals_json = {}
|
|
99
|
+
for name, value in current.f_locals.items():
|
|
100
|
+
if self._should_skip_local(name, value):
|
|
101
|
+
continue
|
|
102
|
+
locals_json[name] = self._serialize_value(value, reachable)
|
|
103
|
+
frames.append(
|
|
104
|
+
{
|
|
105
|
+
"method": current.f_code.co_name,
|
|
106
|
+
"class": "Python",
|
|
107
|
+
"line": current.f_lineno,
|
|
108
|
+
"locals": locals_json,
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
current = current.f_back
|
|
112
|
+
return frames
|
|
113
|
+
|
|
114
|
+
def _serialize_heap(self, reachable):
|
|
115
|
+
heap = {}
|
|
116
|
+
queue = list(reachable.items())
|
|
117
|
+
seen = set()
|
|
118
|
+
idx = 0
|
|
119
|
+
while idx < len(queue):
|
|
120
|
+
obj_id, obj = queue[idx]
|
|
121
|
+
idx += 1
|
|
122
|
+
if obj_id in seen:
|
|
123
|
+
continue
|
|
124
|
+
seen.add(obj_id)
|
|
125
|
+
heap[obj_id] = self._serialize_heap_object(obj, reachable)
|
|
126
|
+
for new_id, new_obj in reachable.items():
|
|
127
|
+
if new_id not in seen:
|
|
128
|
+
queue.append((new_id, new_obj))
|
|
129
|
+
return heap
|
|
130
|
+
|
|
131
|
+
def _serialize_heap_object(self, obj, reachable):
|
|
132
|
+
if isinstance(obj, str):
|
|
133
|
+
return {"type": "String", "value": obj}
|
|
134
|
+
|
|
135
|
+
if isinstance(obj, (list, tuple)):
|
|
136
|
+
return {
|
|
137
|
+
"type": type(obj).__name__,
|
|
138
|
+
"elements": [self._serialize_value(value, reachable) for value in obj],
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if isinstance(obj, dict) and all(isinstance(key, str) for key in obj.keys()):
|
|
142
|
+
return {
|
|
143
|
+
"type": "dict",
|
|
144
|
+
"fields": {
|
|
145
|
+
key: self._serialize_value(value, reachable)
|
|
146
|
+
for key, value in obj.items()
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
obj_dict = getattr(obj, "__dict__", None)
|
|
151
|
+
if isinstance(obj_dict, dict):
|
|
152
|
+
return {
|
|
153
|
+
"type": type(obj).__name__,
|
|
154
|
+
"fields": {
|
|
155
|
+
key: self._serialize_value(value, reachable)
|
|
156
|
+
for key, value in obj_dict.items()
|
|
157
|
+
if not key.startswith("__") and not self._should_skip_local(key, value)
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {"type": type(obj).__name__, "value": self._safe_repr(obj)}
|
|
162
|
+
|
|
163
|
+
def _serialize_value(self, value, reachable):
|
|
164
|
+
if value is None:
|
|
165
|
+
return {"type": "null"}
|
|
166
|
+
if isinstance(value, bool):
|
|
167
|
+
return {"type": "boolean", "value": value}
|
|
168
|
+
if isinstance(value, int) and not isinstance(value, bool):
|
|
169
|
+
return {"type": "int", "value": value}
|
|
170
|
+
if isinstance(value, float):
|
|
171
|
+
return {"type": "double", "value": value}
|
|
172
|
+
if isinstance(value, str):
|
|
173
|
+
obj_id = self._get_object_id(value)
|
|
174
|
+
reachable.setdefault(obj_id, value)
|
|
175
|
+
return {"type": "ref", "id": obj_id}
|
|
176
|
+
|
|
177
|
+
if self._is_heap_value(value):
|
|
178
|
+
obj_id = self._get_object_id(value)
|
|
179
|
+
reachable.setdefault(obj_id, value)
|
|
180
|
+
return {"type": "ref", "id": obj_id}
|
|
181
|
+
|
|
182
|
+
return {"type": "unknown"}
|
|
183
|
+
|
|
184
|
+
def _is_heap_value(self, value):
|
|
185
|
+
if isinstance(value, str):
|
|
186
|
+
return True
|
|
187
|
+
if isinstance(value, (list, tuple)):
|
|
188
|
+
return True
|
|
189
|
+
if isinstance(value, dict):
|
|
190
|
+
return all(isinstance(key, str) for key in value.keys())
|
|
191
|
+
obj_dict = getattr(value, "__dict__", None)
|
|
192
|
+
return isinstance(obj_dict, dict)
|
|
193
|
+
|
|
194
|
+
def _get_object_id(self, obj):
|
|
195
|
+
key = id(obj)
|
|
196
|
+
if key not in self.object_ids:
|
|
197
|
+
self.object_ids[key] = f"obj_{self.next_object_id}"
|
|
198
|
+
self.next_object_id += 1
|
|
199
|
+
return self.object_ids[key]
|
|
200
|
+
|
|
201
|
+
def _safe_repr(self, value):
|
|
202
|
+
try:
|
|
203
|
+
return repr(value)
|
|
204
|
+
except Exception:
|
|
205
|
+
return f"<{type(value).__name__}>"
|
|
206
|
+
|
|
207
|
+
def _is_traced_frame(self, frame):
|
|
208
|
+
return (
|
|
209
|
+
os.path.abspath(frame.f_code.co_filename) == self.target_path
|
|
210
|
+
and frame.f_code.co_name not in self.SYNTHETIC_FRAME_NAMES
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def _should_skip_local(self, name, value):
|
|
214
|
+
if name.startswith("."):
|
|
215
|
+
return True
|
|
216
|
+
if name.startswith("__"):
|
|
217
|
+
return True
|
|
218
|
+
if isinstance(value, (types.ModuleType, types.FunctionType, type)):
|
|
219
|
+
return True
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def main():
|
|
224
|
+
if len(sys.argv) != 2:
|
|
225
|
+
print("Usage: trace_runner.py <python_file>", file=sys.stderr)
|
|
226
|
+
sys.exit(1)
|
|
227
|
+
|
|
228
|
+
target_path = os.path.abspath(sys.argv[1])
|
|
229
|
+
target_dir = os.path.dirname(target_path)
|
|
230
|
+
target_name = os.path.basename(target_path)
|
|
231
|
+
|
|
232
|
+
if target_dir and target_dir not in sys.path:
|
|
233
|
+
sys.path.insert(0, target_dir)
|
|
234
|
+
|
|
235
|
+
trace_writer = sys.stdout
|
|
236
|
+
output_chunks = []
|
|
237
|
+
capture = CaptureStream(output_chunks)
|
|
238
|
+
debugger = TracePdb(target_path, trace_writer, output_chunks)
|
|
239
|
+
|
|
240
|
+
code_globals = {
|
|
241
|
+
"__name__": "__main__",
|
|
242
|
+
"__file__": target_path,
|
|
243
|
+
"__package__": None,
|
|
244
|
+
"__cached__": None,
|
|
245
|
+
"__builtins__": __builtins__,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
original_stdout = sys.stdout
|
|
249
|
+
original_stderr = sys.stderr
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
with open(target_path, "r", encoding="utf-8") as f:
|
|
253
|
+
source = f.read()
|
|
254
|
+
compiled = compile(source, target_path, "exec")
|
|
255
|
+
|
|
256
|
+
sys.stdout = capture
|
|
257
|
+
sys.stderr = capture
|
|
258
|
+
|
|
259
|
+
try:
|
|
260
|
+
debugger.set_step()
|
|
261
|
+
debugger.runcall(exec, compiled, code_globals, code_globals)
|
|
262
|
+
except SystemExit:
|
|
263
|
+
pass
|
|
264
|
+
finally:
|
|
265
|
+
debugger.flush_pending()
|
|
266
|
+
finally:
|
|
267
|
+
sys.stdout = original_stdout
|
|
268
|
+
sys.stderr = original_stderr
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
if __name__ == "__main__":
|
|
272
|
+
main()
|
package/build/utils/render.ts
CHANGED
|
@@ -43,6 +43,8 @@ import type {
|
|
|
43
43
|
RenderCodePageOptions,
|
|
44
44
|
RenderLiterateJavaOptions,
|
|
45
45
|
RenderCopiedContentOptions,
|
|
46
|
+
RenderDependencyCollector,
|
|
47
|
+
TraceToolAvailability,
|
|
46
48
|
} from '../types';
|
|
47
49
|
|
|
48
50
|
const log = makeLogger(import.meta.url);
|
|
@@ -81,6 +83,7 @@ interface TemplateParametersInput {
|
|
|
81
83
|
function resolveAuthor(
|
|
82
84
|
pageVariables: Record<string, unknown>,
|
|
83
85
|
filePath: string,
|
|
86
|
+
dependencyCollector?: RenderDependencyCollector,
|
|
84
87
|
): void {
|
|
85
88
|
if (!pageVariables.author) {
|
|
86
89
|
return;
|
|
@@ -94,6 +97,7 @@ function resolveAuthor(
|
|
|
94
97
|
);
|
|
95
98
|
}
|
|
96
99
|
const authorKey = pageVariables.author as string;
|
|
100
|
+
dependencyCollector?.setAuthorKey?.(authorKey);
|
|
97
101
|
const authorEntry = authors[authorKey];
|
|
98
102
|
if (!authorEntry) {
|
|
99
103
|
throw new Error(
|
|
@@ -205,8 +209,10 @@ export function renderPlainTextPageAsset({
|
|
|
205
209
|
validInternalTargets,
|
|
206
210
|
assetFiles,
|
|
207
211
|
literateJavaOutputPaths,
|
|
212
|
+
dependencyCollector,
|
|
213
|
+
cachedTraceSourceDir,
|
|
208
214
|
traceCache,
|
|
209
|
-
|
|
215
|
+
traceToolAvailability,
|
|
210
216
|
}: RenderPlainTextOptions): Asset[] {
|
|
211
217
|
const { dir, name, ext } = path.parse(filePath);
|
|
212
218
|
const subPath = toPosix(path.relative(contentDir, path.join(dir, name)));
|
|
@@ -223,11 +229,13 @@ export function renderPlainTextPageAsset({
|
|
|
223
229
|
watchMode,
|
|
224
230
|
{
|
|
225
231
|
validateInternalLinks: extensionIsMarkdown(ext.toLowerCase()),
|
|
232
|
+
dependencyCollector,
|
|
226
233
|
traceCache,
|
|
227
234
|
contentDir,
|
|
228
235
|
distDir,
|
|
229
236
|
literateJavaOutputPaths,
|
|
230
|
-
|
|
237
|
+
cachedTraceSourceDir,
|
|
238
|
+
traceToolAvailability,
|
|
231
239
|
},
|
|
232
240
|
);
|
|
233
241
|
|
|
@@ -378,13 +386,16 @@ function renderPlainTextContent(
|
|
|
378
386
|
isWatchMode: boolean,
|
|
379
387
|
{
|
|
380
388
|
validateInternalLinks = true,
|
|
389
|
+
dependencyCollector,
|
|
381
390
|
traceCache,
|
|
382
391
|
contentDir,
|
|
383
392
|
distDir,
|
|
384
393
|
literateJavaOutputPaths,
|
|
385
|
-
|
|
394
|
+
cachedTraceSourceDir,
|
|
395
|
+
traceToolAvailability,
|
|
386
396
|
}: {
|
|
387
397
|
validateInternalLinks?: boolean;
|
|
398
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
388
399
|
traceCache?: Map<
|
|
389
400
|
string,
|
|
390
401
|
{
|
|
@@ -397,7 +408,8 @@ function renderPlainTextContent(
|
|
|
397
408
|
contentDir?: string;
|
|
398
409
|
distDir?: string;
|
|
399
410
|
literateJavaOutputPaths?: Set<string>;
|
|
400
|
-
|
|
411
|
+
cachedTraceSourceDir?: string;
|
|
412
|
+
traceToolAvailability?: TraceToolAvailability;
|
|
401
413
|
} = {},
|
|
402
414
|
): {
|
|
403
415
|
content: string | null;
|
|
@@ -415,6 +427,9 @@ function renderPlainTextContent(
|
|
|
415
427
|
codeExtensions: isFeatureEnabled(siteVariables, 'code')
|
|
416
428
|
? Object.keys(siteVariables.codeLanguages!)
|
|
417
429
|
: [],
|
|
430
|
+
onValidLink: (targetPath: string) => {
|
|
431
|
+
dependencyCollector?.internalTargets?.add(targetPath);
|
|
432
|
+
},
|
|
418
433
|
},
|
|
419
434
|
literateJavaOutputPaths,
|
|
420
435
|
sourceUrlPath,
|
|
@@ -446,7 +461,7 @@ function renderPlainTextContent(
|
|
|
446
461
|
renderInlineField(md, pageVariablesProcessed, 'title');
|
|
447
462
|
renderInlineField(md, pageVariablesProcessed, 'description');
|
|
448
463
|
|
|
449
|
-
resolveAuthor(pageVariablesProcessed, filePath);
|
|
464
|
+
resolveAuthor(pageVariablesProcessed, filePath, dependencyCollector);
|
|
450
465
|
|
|
451
466
|
const parentError = validateParentLink(
|
|
452
467
|
pageVariablesProcessed.parent,
|
|
@@ -456,6 +471,11 @@ function renderPlainTextContent(
|
|
|
456
471
|
if (parentError) {
|
|
457
472
|
throw new Error(parentError);
|
|
458
473
|
}
|
|
474
|
+
if (typeof pageVariablesProcessed.parent === 'string') {
|
|
475
|
+
dependencyCollector?.internalTargets?.add(
|
|
476
|
+
normalizeOutputPath(pageVariablesProcessed.parent),
|
|
477
|
+
);
|
|
478
|
+
}
|
|
459
479
|
|
|
460
480
|
const strippedContent = stripHtmlComments(content);
|
|
461
481
|
|
|
@@ -475,12 +495,14 @@ function renderPlainTextContent(
|
|
|
475
495
|
distDir,
|
|
476
496
|
applyBasePath,
|
|
477
497
|
cache: traceCache,
|
|
478
|
-
|
|
498
|
+
toolAvailability: traceToolAvailability,
|
|
499
|
+
dependencyCollector,
|
|
500
|
+
cachedTraceSourceDir,
|
|
479
501
|
});
|
|
480
502
|
params.renderTrace = helpers.renderTrace;
|
|
481
503
|
}
|
|
482
504
|
|
|
483
|
-
params.include = createIncludeFunction(filePath, params);
|
|
505
|
+
params.include = createIncludeFunction(filePath, params, dependencyCollector);
|
|
484
506
|
|
|
485
507
|
let html: string;
|
|
486
508
|
try {
|
|
@@ -522,6 +544,7 @@ export function renderLiterateJavaPageAsset({
|
|
|
522
544
|
skipExecution,
|
|
523
545
|
validInternalTargets,
|
|
524
546
|
literateJavaOutputPaths,
|
|
547
|
+
dependencyCollector,
|
|
525
548
|
}: RenderLiterateJavaOptions): Asset[] {
|
|
526
549
|
const { dir, name } = path.parse(filePath);
|
|
527
550
|
const className = deriveClassName(filePath);
|
|
@@ -581,6 +604,9 @@ export function renderLiterateJavaPageAsset({
|
|
|
581
604
|
codeExtensions: isFeatureEnabled(siteVariables, 'code')
|
|
582
605
|
? Object.keys(siteVariables.codeLanguages!)
|
|
583
606
|
: [],
|
|
607
|
+
onValidLink: (targetPath: string) => {
|
|
608
|
+
dependencyCollector?.internalTargets?.add(targetPath);
|
|
609
|
+
},
|
|
584
610
|
},
|
|
585
611
|
literateJavaOutputPaths,
|
|
586
612
|
sourceUrlPath,
|
|
@@ -656,7 +682,7 @@ export function renderLiterateJavaPageAsset({
|
|
|
656
682
|
);
|
|
657
683
|
}
|
|
658
684
|
|
|
659
|
-
resolveAuthor(pageVariables, filePath);
|
|
685
|
+
resolveAuthor(pageVariables, filePath, dependencyCollector);
|
|
660
686
|
|
|
661
687
|
const templateParameters = createTemplateParameters({
|
|
662
688
|
pageVariables,
|