@abreen/tada 1.13.9 → 1.14.2
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 +2 -10
- package/build/types.d.ts +18 -6
- 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 +148 -16
- 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 +68 -66
- package/build/utils/trace.ts +193 -78
- package/build/watch/compiler-types.d.ts +2 -2
- package/build/watch/compiler.ts +5 -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 -1
- package/src/question/index.ts +13 -1
- package/src/slides/index.ts +7 -3
- 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/init/content/lectures/02/subdir/_foobar.html +0 -3
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import type MarkdownIt from 'markdown-it';
|
|
5
|
+
import type StateCore from 'markdown-it/lib/rules_core/state_core.mjs';
|
|
6
|
+
import type StateBlock from 'markdown-it/lib/rules_block/state_block.mjs';
|
|
7
|
+
import { extensionIsMarkdown, isPartial } from './file-types';
|
|
8
|
+
import { stripHtmlComments } from './html-comments';
|
|
9
|
+
import type { RenderDependencyCollector } from '../types';
|
|
10
|
+
|
|
11
|
+
const MAX_INCLUDE_DEPTH = 10;
|
|
12
|
+
const PARTIAL_DIRECTIVE_PATTERN = /^\{\{\{([\s\S]*?)\}\}\}$/;
|
|
13
|
+
const ESCAPED_PARTIAL_DIRECTIVE_PATTERN = /^\\\{\{\{[\s\S]*\}\}\}$/;
|
|
14
|
+
const PARTIAL_CONTEXT_STACK_KEY = '__tadaMarkdownPartialContextStack';
|
|
15
|
+
const LOOSE_PARTIAL_LIST_META_KEY = '__tadaLoosePartialList';
|
|
16
|
+
|
|
17
|
+
interface MarkdownPartialContext {
|
|
18
|
+
filePath: string;
|
|
19
|
+
depth: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface MarkdownPartialsEnv {
|
|
23
|
+
[PARTIAL_CONTEXT_STACK_KEY]?: MarkdownPartialContext[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface MarkdownPartialsOptions {
|
|
27
|
+
filePath: string;
|
|
28
|
+
templateParams: Record<string, unknown>;
|
|
29
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getLineText(state: StateBlock, line: number): string {
|
|
33
|
+
const start = state.bMarks[line] + state.tShift[line];
|
|
34
|
+
const end = state.eMarks[line];
|
|
35
|
+
return state.src.slice(start, end);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getCurrentPartialContext(
|
|
39
|
+
env: MarkdownPartialsEnv,
|
|
40
|
+
filePath: string,
|
|
41
|
+
): MarkdownPartialContext {
|
|
42
|
+
const stack = env[PARTIAL_CONTEXT_STACK_KEY];
|
|
43
|
+
return stack?.[stack.length - 1] ?? { filePath, depth: 0 };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function renderPartialContent(
|
|
47
|
+
relativePath: string,
|
|
48
|
+
caller: MarkdownPartialContext,
|
|
49
|
+
options: MarkdownPartialsOptions,
|
|
50
|
+
): { resolvedPath: string; content: string } {
|
|
51
|
+
const resolvedPath = path.resolve(
|
|
52
|
+
path.dirname(caller.filePath),
|
|
53
|
+
relativePath,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`${caller.filePath}: partial not found: ${relativePath} (resolved to ${resolvedPath})`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (!isPartial(resolvedPath)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`${caller.filePath}: partial target must start with "_": ${relativePath}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (!extensionIsMarkdown(path.extname(resolvedPath).toLowerCase())) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`${caller.filePath}: partial target must be a Markdown file: ${relativePath}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
options.dependencyCollector?.partials?.add(resolvedPath);
|
|
73
|
+
if (caller.depth >= MAX_INCLUDE_DEPTH) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`${caller.filePath}: maximum include depth (${MAX_INCLUDE_DEPTH}) exceeded`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const raw = fs.readFileSync(resolvedPath, 'utf-8');
|
|
80
|
+
const content = stripHtmlComments(raw);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
return {
|
|
84
|
+
resolvedPath,
|
|
85
|
+
content: _.template(content)(options.templateParams),
|
|
86
|
+
};
|
|
87
|
+
} catch (err) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`${resolvedPath}: Lodash template error in partial: ${(err as Error).message}`,
|
|
90
|
+
{ cause: err },
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function tokenizePartialContent(
|
|
96
|
+
state: StateBlock,
|
|
97
|
+
content: string,
|
|
98
|
+
context: MarkdownPartialContext,
|
|
99
|
+
): void {
|
|
100
|
+
const env = state.env as MarkdownPartialsEnv;
|
|
101
|
+
const stack = (env[PARTIAL_CONTEXT_STACK_KEY] ??= []);
|
|
102
|
+
stack.push(context);
|
|
103
|
+
const tokenStart = state.tokens.length;
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const childState = new state.md.block.State(
|
|
107
|
+
content,
|
|
108
|
+
state.md,
|
|
109
|
+
state.env,
|
|
110
|
+
state.tokens,
|
|
111
|
+
);
|
|
112
|
+
childState.level = state.level;
|
|
113
|
+
childState.parentType = state.parentType;
|
|
114
|
+
childState.tight = state.tight;
|
|
115
|
+
childState.ddIndent = state.ddIndent;
|
|
116
|
+
childState.listIndent = state.listIndent;
|
|
117
|
+
|
|
118
|
+
state.md.block.tokenize(childState, childState.line, childState.lineMax);
|
|
119
|
+
if (!childState.tight) {
|
|
120
|
+
markCurrentListLoose(state, tokenStart);
|
|
121
|
+
}
|
|
122
|
+
} finally {
|
|
123
|
+
stack.pop();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function markCurrentListLoose(state: StateBlock, tokenStart: number): void {
|
|
128
|
+
let closedLists = 0;
|
|
129
|
+
for (let i = tokenStart - 1; i >= 0; i--) {
|
|
130
|
+
const token = state.tokens[i];
|
|
131
|
+
if (
|
|
132
|
+
token.type === 'bullet_list_close' ||
|
|
133
|
+
token.type === 'ordered_list_close'
|
|
134
|
+
) {
|
|
135
|
+
closedLists++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (
|
|
140
|
+
token.type === 'bullet_list_open' ||
|
|
141
|
+
token.type === 'ordered_list_open'
|
|
142
|
+
) {
|
|
143
|
+
if (closedLists === 0) {
|
|
144
|
+
token.meta = {
|
|
145
|
+
...(token.meta ?? {}),
|
|
146
|
+
[LOOSE_PARTIAL_LIST_META_KEY]: true,
|
|
147
|
+
};
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
closedLists--;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function restoreLoosePartialLists(state: StateCore): void {
|
|
156
|
+
const looseListLevels: number[] = [];
|
|
157
|
+
|
|
158
|
+
for (const token of state.tokens) {
|
|
159
|
+
if (
|
|
160
|
+
token.type === 'bullet_list_open' ||
|
|
161
|
+
token.type === 'ordered_list_open'
|
|
162
|
+
) {
|
|
163
|
+
if (token.meta?.[LOOSE_PARTIAL_LIST_META_KEY]) {
|
|
164
|
+
looseListLevels.push(token.level);
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
token.type === 'bullet_list_close' ||
|
|
171
|
+
token.type === 'ordered_list_close'
|
|
172
|
+
) {
|
|
173
|
+
const listIndex = looseListLevels.lastIndexOf(token.level);
|
|
174
|
+
if (listIndex !== -1) {
|
|
175
|
+
looseListLevels.splice(listIndex, 1);
|
|
176
|
+
}
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (token.type !== 'paragraph_open' && token.type !== 'paragraph_close') {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (looseListLevels.some(level => token.level === level + 2)) {
|
|
185
|
+
token.hidden = false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export default function markdownPartialsPlugin(
|
|
191
|
+
md: MarkdownIt,
|
|
192
|
+
options: MarkdownPartialsOptions,
|
|
193
|
+
): void {
|
|
194
|
+
md.core.ruler.after(
|
|
195
|
+
'block',
|
|
196
|
+
'tada_markdown_partial_loose_lists',
|
|
197
|
+
restoreLoosePartialLists,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
md.block.ruler.before(
|
|
201
|
+
'paragraph',
|
|
202
|
+
'tada_markdown_partial',
|
|
203
|
+
(state, startLine, _endLine, silent) => {
|
|
204
|
+
const trimmedLine = getLineText(state, startLine).trim();
|
|
205
|
+
if (ESCAPED_PARTIAL_DIRECTIVE_PATTERN.test(trimmedLine)) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const match = trimmedLine.match(PARTIAL_DIRECTIVE_PATTERN);
|
|
210
|
+
if (!match) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (silent) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const relativePath = match[1].trim();
|
|
219
|
+
if (!relativePath) {
|
|
220
|
+
throw new Error(`${options.filePath}: partial path is empty`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const env = state.env as MarkdownPartialsEnv;
|
|
224
|
+
const caller = getCurrentPartialContext(env, options.filePath);
|
|
225
|
+
const partial = renderPartialContent(relativePath, caller, options);
|
|
226
|
+
tokenizePartialContent(state, partial.content, {
|
|
227
|
+
filePath: partial.resolvedPath,
|
|
228
|
+
depth: caller.depth + 1,
|
|
229
|
+
});
|
|
230
|
+
state.line = startLine + 1;
|
|
231
|
+
return true;
|
|
232
|
+
},
|
|
233
|
+
{ alt: ['paragraph', 'reference', 'blockquote', 'list'] },
|
|
234
|
+
);
|
|
235
|
+
}
|
package/build/utils/markdown.ts
CHANGED
|
@@ -18,7 +18,8 @@ import columnsPlugin from '../columns-plugin';
|
|
|
18
18
|
import markdownItKatex from '@vscode/markdown-it-katex';
|
|
19
19
|
import katex from 'katex';
|
|
20
20
|
import renderA11yString from 'katex/contrib/render-a11y-string';
|
|
21
|
-
import
|
|
21
|
+
import markdownPartialsPlugin from './markdown-partials';
|
|
22
|
+
import type { RenderDependencyCollector, SiteVariables } from '../types';
|
|
22
23
|
|
|
23
24
|
const DETAILS_PATTERN = /^details\s+(.*)$/;
|
|
24
25
|
const ALERT_PATTERN = /^(note|warning)(?:\s+"(.+)"|\s+(.+))?$/;
|
|
@@ -31,6 +32,8 @@ interface CreateMarkdownOptions {
|
|
|
31
32
|
literateJavaOutputPaths?: Set<string>;
|
|
32
33
|
sourceUrlPath?: string;
|
|
33
34
|
validTargets?: Set<string>;
|
|
35
|
+
templateParams?: Record<string, unknown>;
|
|
36
|
+
dependencyCollector?: RenderDependencyCollector;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
function capitalize(str: string): string {
|
|
@@ -102,6 +105,14 @@ export function createMarkdown(
|
|
|
102
105
|
},
|
|
103
106
|
});
|
|
104
107
|
|
|
108
|
+
if (filePath && options.templateParams) {
|
|
109
|
+
markdown.use(markdownPartialsPlugin, {
|
|
110
|
+
filePath,
|
|
111
|
+
templateParams: options.templateParams,
|
|
112
|
+
dependencyCollector: options.dependencyCollector,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
105
116
|
function createWrapperToken(
|
|
106
117
|
type: string,
|
|
107
118
|
nesting: -1 | 0 | 1,
|
|
@@ -5,17 +5,22 @@ import json
|
|
|
5
5
|
import os
|
|
6
6
|
import pdb
|
|
7
7
|
import sys
|
|
8
|
+
import traceback
|
|
8
9
|
import types
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class CaptureStream(io.TextIOBase):
|
|
12
|
-
def __init__(self, sink):
|
|
13
|
+
def __init__(self, sink, stream):
|
|
13
14
|
self._sink = sink
|
|
15
|
+
self._stream = stream
|
|
14
16
|
|
|
15
17
|
def write(self, s):
|
|
16
18
|
if not isinstance(s, str):
|
|
17
19
|
s = str(s)
|
|
18
|
-
self._sink.
|
|
20
|
+
if self._sink and self._sink[-1]["stream"] == self._stream:
|
|
21
|
+
self._sink[-1]["text"] += s
|
|
22
|
+
else:
|
|
23
|
+
self._sink.append({"stream": self._stream, "text": s})
|
|
19
24
|
return len(s)
|
|
20
25
|
|
|
21
26
|
def flush(self):
|
|
@@ -28,9 +33,10 @@ class CaptureStream(io.TextIOBase):
|
|
|
28
33
|
class TracePdb(pdb.Pdb):
|
|
29
34
|
SYNTHETIC_FRAME_NAMES = {"<listcomp>", "<dictcomp>", "<setcomp>"}
|
|
30
35
|
|
|
31
|
-
def __init__(self, target_path, trace_writer, output_chunks):
|
|
36
|
+
def __init__(self, target_path, traced_paths, trace_writer, output_chunks):
|
|
32
37
|
super().__init__(nosigint=True, readrc=False)
|
|
33
38
|
self.target_path = os.path.abspath(target_path)
|
|
39
|
+
self.traced_paths = set(os.path.abspath(path) for path in traced_paths)
|
|
34
40
|
self.trace_writer = trace_writer
|
|
35
41
|
self.output_chunks = output_chunks
|
|
36
42
|
self.pending_snapshot = None
|
|
@@ -69,18 +75,24 @@ class TracePdb(pdb.Pdb):
|
|
|
69
75
|
if self.pending_snapshot is None:
|
|
70
76
|
return
|
|
71
77
|
payload = dict(self.pending_snapshot)
|
|
72
|
-
payload["
|
|
78
|
+
payload["output"] = self._drain_output()
|
|
73
79
|
self.trace_writer.write(json.dumps(payload) + "\n")
|
|
74
80
|
self.trace_writer.flush()
|
|
75
81
|
self.pending_snapshot = None
|
|
76
82
|
|
|
77
83
|
def _drain_output(self):
|
|
78
84
|
if not self.output_chunks:
|
|
79
|
-
return
|
|
80
|
-
output =
|
|
85
|
+
return []
|
|
86
|
+
output = list(self.output_chunks)
|
|
81
87
|
self.output_chunks.clear()
|
|
82
88
|
return output
|
|
83
89
|
|
|
90
|
+
def emit_crash(self, frame):
|
|
91
|
+
payload = self._capture_snapshot(frame)
|
|
92
|
+
payload["output"] = self._drain_output()
|
|
93
|
+
self.trace_writer.write(json.dumps(payload) + "\n")
|
|
94
|
+
self.trace_writer.flush()
|
|
95
|
+
|
|
84
96
|
def _capture_snapshot(self, frame):
|
|
85
97
|
reachable = {}
|
|
86
98
|
return {
|
|
@@ -206,7 +218,7 @@ class TracePdb(pdb.Pdb):
|
|
|
206
218
|
|
|
207
219
|
def _is_traced_frame(self, frame):
|
|
208
220
|
return (
|
|
209
|
-
os.path.abspath(frame.f_code.co_filename)
|
|
221
|
+
os.path.abspath(frame.f_code.co_filename) in self.traced_paths
|
|
210
222
|
and frame.f_code.co_name not in self.SYNTHETIC_FRAME_NAMES
|
|
211
223
|
)
|
|
212
224
|
|
|
@@ -221,11 +233,14 @@ class TracePdb(pdb.Pdb):
|
|
|
221
233
|
|
|
222
234
|
|
|
223
235
|
def main():
|
|
224
|
-
if len(sys.argv)
|
|
225
|
-
print("Usage: trace_runner.py <python_file>", file=sys.stderr)
|
|
236
|
+
if len(sys.argv) < 2:
|
|
237
|
+
print("Usage: trace_runner.py <python_file> [traced_file ...]", file=sys.stderr)
|
|
226
238
|
sys.exit(1)
|
|
227
239
|
|
|
228
240
|
target_path = os.path.abspath(sys.argv[1])
|
|
241
|
+
traced_paths = [os.path.abspath(path) for path in sys.argv[2:]]
|
|
242
|
+
if target_path not in traced_paths:
|
|
243
|
+
traced_paths.insert(0, target_path)
|
|
229
244
|
target_dir = os.path.dirname(target_path)
|
|
230
245
|
target_name = os.path.basename(target_path)
|
|
231
246
|
|
|
@@ -234,8 +249,9 @@ def main():
|
|
|
234
249
|
|
|
235
250
|
trace_writer = sys.stdout
|
|
236
251
|
output_chunks = []
|
|
237
|
-
|
|
238
|
-
|
|
252
|
+
stdout_capture = CaptureStream(output_chunks, "stdout")
|
|
253
|
+
stderr_capture = CaptureStream(output_chunks, "stderr")
|
|
254
|
+
debugger = TracePdb(target_path, traced_paths, trace_writer, output_chunks)
|
|
239
255
|
|
|
240
256
|
code_globals = {
|
|
241
257
|
"__name__": "__main__",
|
|
@@ -253,14 +269,21 @@ def main():
|
|
|
253
269
|
source = f.read()
|
|
254
270
|
compiled = compile(source, target_path, "exec")
|
|
255
271
|
|
|
256
|
-
sys.stdout =
|
|
257
|
-
sys.stderr =
|
|
272
|
+
sys.stdout = stdout_capture
|
|
273
|
+
sys.stderr = stderr_capture
|
|
258
274
|
|
|
259
275
|
try:
|
|
260
276
|
debugger.set_step()
|
|
261
277
|
debugger.runcall(exec, compiled, code_globals, code_globals)
|
|
262
278
|
except SystemExit:
|
|
263
279
|
pass
|
|
280
|
+
except BaseException as exc:
|
|
281
|
+
debugger.flush_pending()
|
|
282
|
+
sys.stderr.write(format_target_traceback(exc, set(traced_paths)))
|
|
283
|
+
frame = find_traced_exception_frame(debugger, exc.__traceback__)
|
|
284
|
+
if frame is None:
|
|
285
|
+
raise
|
|
286
|
+
debugger.emit_crash(frame)
|
|
264
287
|
finally:
|
|
265
288
|
debugger.flush_pending()
|
|
266
289
|
finally:
|
|
@@ -268,5 +291,27 @@ def main():
|
|
|
268
291
|
sys.stderr = original_stderr
|
|
269
292
|
|
|
270
293
|
|
|
294
|
+
def find_traced_exception_frame(debugger, tb):
|
|
295
|
+
traced = None
|
|
296
|
+
while tb is not None:
|
|
297
|
+
if debugger._is_traced_frame(tb.tb_frame):
|
|
298
|
+
traced = tb.tb_frame
|
|
299
|
+
tb = tb.tb_next
|
|
300
|
+
return traced
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def format_target_traceback(exc, traced_paths):
|
|
304
|
+
frames = [
|
|
305
|
+
frame
|
|
306
|
+
for frame in traceback.extract_tb(exc.__traceback__)
|
|
307
|
+
if os.path.abspath(frame.filename) in traced_paths
|
|
308
|
+
]
|
|
309
|
+
return (
|
|
310
|
+
"Traceback (most recent call last):\n"
|
|
311
|
+
+ "".join(traceback.format_list(frames))
|
|
312
|
+
+ "".join(traceback.format_exception_only(type(exc), exc))
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
271
316
|
if __name__ == "__main__":
|
|
272
317
|
main()
|
package/build/utils/render.ts
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
} from './code';
|
|
26
26
|
import { extensionIsMarkdown } from './file-types';
|
|
27
27
|
import { createTraceHelpers } from './trace';
|
|
28
|
-
import {
|
|
28
|
+
import { stripHtmlComments } from './html-comments';
|
|
29
29
|
import { finalizeHtmlPage } from './final-html';
|
|
30
30
|
import {
|
|
31
31
|
createApplyBasePath,
|
|
@@ -60,6 +60,8 @@ const log = makeLogger(import.meta.url);
|
|
|
60
60
|
|
|
61
61
|
const tadaVersion: string = pkg.version;
|
|
62
62
|
|
|
63
|
+
export { stripHtmlComments } from './html-comments';
|
|
64
|
+
|
|
63
65
|
const REQUIRED_FRONT_MATTER_FIELDS = ['title'];
|
|
64
66
|
|
|
65
67
|
function isWatchMode(assetFiles: string[]): boolean {
|
|
@@ -433,9 +435,9 @@ function renderPlainTextContent(
|
|
|
433
435
|
{
|
|
434
436
|
manifestUrl: string;
|
|
435
437
|
artifactId: string;
|
|
436
|
-
highlightedSource: string;
|
|
438
|
+
highlightedSources: { file: string; highlightedSource: string }[];
|
|
437
439
|
totalSteps: number;
|
|
438
|
-
|
|
440
|
+
sourceMtims: Record<string, number>;
|
|
439
441
|
}
|
|
440
442
|
>;
|
|
441
443
|
contentDir?: string;
|
|
@@ -459,7 +461,7 @@ function renderPlainTextContent(
|
|
|
459
461
|
`${filePath}: slides mode is only supported on Markdown pages`,
|
|
460
462
|
);
|
|
461
463
|
}
|
|
462
|
-
const
|
|
464
|
+
const frontMatterMd = createMarkdown(siteVariables, {
|
|
463
465
|
filePath,
|
|
464
466
|
slides: pageVariables.slides === true,
|
|
465
467
|
});
|
|
@@ -480,8 +482,8 @@ function renderPlainTextContent(
|
|
|
480
482
|
);
|
|
481
483
|
|
|
482
484
|
// Render title and description as inline Markdown
|
|
483
|
-
renderInlineField(
|
|
484
|
-
renderInlineField(
|
|
485
|
+
renderInlineField(frontMatterMd, pageVariablesProcessed, 'title');
|
|
486
|
+
renderInlineField(frontMatterMd, pageVariablesProcessed, 'description');
|
|
485
487
|
|
|
486
488
|
resolveAuthor(pageVariablesProcessed, filePath, dependencyCollector);
|
|
487
489
|
|
|
@@ -526,8 +528,6 @@ function renderPlainTextContent(
|
|
|
526
528
|
params.renderTrace = helpers.renderTrace;
|
|
527
529
|
}
|
|
528
530
|
|
|
529
|
-
params.include = createIncludeFunction(filePath, params, dependencyCollector);
|
|
530
|
-
|
|
531
531
|
let html: string;
|
|
532
532
|
try {
|
|
533
533
|
html = _.template(strippedContent)(params);
|
|
@@ -541,6 +541,12 @@ function renderPlainTextContent(
|
|
|
541
541
|
let tocItems: unknown[] | null = null;
|
|
542
542
|
let alertIds: string[] = [];
|
|
543
543
|
if (extensionIsMarkdown(ext)) {
|
|
544
|
+
const md = createMarkdown(siteVariables, {
|
|
545
|
+
filePath,
|
|
546
|
+
slides: pageVariables.slides === true,
|
|
547
|
+
templateParams: params,
|
|
548
|
+
dependencyCollector,
|
|
549
|
+
});
|
|
544
550
|
const env: Record<string, unknown> = { alertIds: [] as string[] };
|
|
545
551
|
html = md.render(html!, env);
|
|
546
552
|
tocItems = (env.tocItems as unknown[] | undefined) || null;
|
|
@@ -555,10 +561,6 @@ function renderPlainTextContent(
|
|
|
555
561
|
};
|
|
556
562
|
}
|
|
557
563
|
|
|
558
|
-
export function stripHtmlComments(str: string): string {
|
|
559
|
-
return str.replace(/<!---[\s\S]*?-->/g, '');
|
|
560
|
-
}
|
|
561
|
-
|
|
562
564
|
export function renderLiterateJavaPageAsset({
|
|
563
565
|
filePath,
|
|
564
566
|
contentDir,
|