@owomark/view 0.1.4 → 0.1.6
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 +16 -281
- package/dist/{chunk-Y72HQJQI.js → chunk-KHKPOH74.js} +2 -3
- package/dist/{chunk-F3LG7AML.js → chunk-WA6XHBZS.js} +34 -13
- package/dist/index.d.ts +21 -77
- package/dist/index.js +268 -46
- package/dist/internal/virtual/height-estimator.d.ts +2 -9
- package/dist/internal/virtual/height-estimator.js +1 -1
- package/dist/internal/virtual/viewport-manager.js +1 -1
- package/dist/types-DsL_4tUb.d.ts +93 -0
- package/package.json +2 -38
- package/src/style.css +0 -3
- package/src/theme/dark.css +6 -0
- package/src/theme/light.css +6 -0
- package/src/theme/owomark.css +22 -2
- package/dist/chunk-DHRAXGIK.js +0 -1710
- package/dist/static.d.ts +0 -220
- package/dist/static.js +0 -40
- package/src/mdx-components/mdx-components.css +0 -336
package/dist/chunk-DHRAXGIK.js
DELETED
|
@@ -1,1710 +0,0 @@
|
|
|
1
|
-
// src/processor/rehype-math-display-fix.ts
|
|
2
|
-
function rehypeMathDisplayFix() {
|
|
3
|
-
return (tree) => {
|
|
4
|
-
walk(tree);
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
function walk(node) {
|
|
8
|
-
if (!node?.type || !Array.isArray(node.children)) return;
|
|
9
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
10
|
-
const child = node.children[i];
|
|
11
|
-
if (child?.type === "element" && child.tagName === "pre" && Array.isArray(child.children) && child.children.length === 1) {
|
|
12
|
-
const codeEl = child.children[0];
|
|
13
|
-
if (codeEl?.type === "element" && codeEl.tagName === "code") {
|
|
14
|
-
const classes = codeEl.properties?.className ?? [];
|
|
15
|
-
if (classes.includes("math-display")) {
|
|
16
|
-
node.children[i] = {
|
|
17
|
-
type: "element",
|
|
18
|
-
tagName: "div",
|
|
19
|
-
properties: { className: ["math-display-block"] },
|
|
20
|
-
children: codeEl.children
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
walk(child);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// src/processor/remark-soft-breaks.ts
|
|
30
|
-
function remarkConvertSoftBreaksToHardBreaks() {
|
|
31
|
-
return (tree) => {
|
|
32
|
-
walkNode(tree);
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
function walkNode(node) {
|
|
36
|
-
if (!node || typeof node !== "object") return;
|
|
37
|
-
if (node.type === "paragraph" && Array.isArray(node.children)) {
|
|
38
|
-
node.children = rewriteInlineChildren(node.children);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (Array.isArray(node.children)) {
|
|
42
|
-
for (const child of node.children) {
|
|
43
|
-
walkNode(child);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function rewriteInlineChildren(children) {
|
|
48
|
-
let changed = false;
|
|
49
|
-
const result = [];
|
|
50
|
-
for (const child of children) {
|
|
51
|
-
if (!child || typeof child !== "object") continue;
|
|
52
|
-
if (child.type === "text" && typeof child.value === "string" && /[\r\n]/.test(child.value)) {
|
|
53
|
-
pushSplitTextNodes(result, child);
|
|
54
|
-
changed = true;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (Array.isArray(child.children)) {
|
|
58
|
-
const rewritten = rewriteInlineChildren(child.children);
|
|
59
|
-
if (rewritten !== child.children) {
|
|
60
|
-
result.push({ ...child, children: rewritten });
|
|
61
|
-
changed = true;
|
|
62
|
-
} else {
|
|
63
|
-
result.push(child);
|
|
64
|
-
}
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
result.push(child);
|
|
68
|
-
}
|
|
69
|
-
return changed ? result : children;
|
|
70
|
-
}
|
|
71
|
-
function pushSplitTextNodes(target, textNode) {
|
|
72
|
-
const normalized = textNode.value.replace(/\r\n?/g, "\n");
|
|
73
|
-
const parts = normalized.split("\n");
|
|
74
|
-
for (let i = 0; i < parts.length; i++) {
|
|
75
|
-
if (parts[i]) {
|
|
76
|
-
target.push({ ...textNode, value: parts[i] });
|
|
77
|
-
}
|
|
78
|
-
if (i < parts.length - 1) {
|
|
79
|
-
target.push({ type: "break" });
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// src/processor/remark-side-annotation.ts
|
|
85
|
-
var STRUCTURAL_TYPES = {
|
|
86
|
-
":": "plain",
|
|
87
|
-
"}": "brace",
|
|
88
|
-
"{": "left-brace",
|
|
89
|
-
"]": "bracket",
|
|
90
|
-
"[": "left-bracket",
|
|
91
|
-
"|": "line",
|
|
92
|
-
"-": "dash",
|
|
93
|
-
"->": "arrow",
|
|
94
|
-
"=>": "fat-arrow",
|
|
95
|
-
"~>": "wave-arrow"
|
|
96
|
-
};
|
|
97
|
-
var SEMANTIC_TYPES = {
|
|
98
|
-
"!": "warning",
|
|
99
|
-
"?": "question"
|
|
100
|
-
};
|
|
101
|
-
var COMPOUND_TYPES = {
|
|
102
|
-
"}->": "brace-arrow",
|
|
103
|
-
"}=>": "brace-fat-arrow",
|
|
104
|
-
"]->": "bracket-arrow",
|
|
105
|
-
"]=>": "bracket-fat-arrow",
|
|
106
|
-
"|->": "line-arrow",
|
|
107
|
-
"|=>": "line-fat-arrow",
|
|
108
|
-
"}!": "brace-warning",
|
|
109
|
-
"}?": "brace-question"
|
|
110
|
-
};
|
|
111
|
-
var TYPE_TABLE = {
|
|
112
|
-
...STRUCTURAL_TYPES,
|
|
113
|
-
...SEMANTIC_TYPES,
|
|
114
|
-
...COMPOUND_TYPES
|
|
115
|
-
};
|
|
116
|
-
var TYPE_SYMBOLS_SORTED = Object.keys(TYPE_TABLE).sort(
|
|
117
|
-
(a, b) => b.length - a.length
|
|
118
|
-
);
|
|
119
|
-
var TYPE_BY_KEYWORD = Object.fromEntries(
|
|
120
|
-
Object.entries(TYPE_TABLE).map(([symbol, keyword]) => [keyword, symbol])
|
|
121
|
-
);
|
|
122
|
-
function makeSideAnnotationNode(opts) {
|
|
123
|
-
const classNames = ["side-annotation", `side-type-${opts.sideType}`];
|
|
124
|
-
if (opts.orphan) classNames.push("side-orphan");
|
|
125
|
-
const hProperties = {
|
|
126
|
-
className: classNames,
|
|
127
|
-
"data-side-type": opts.sideType
|
|
128
|
-
};
|
|
129
|
-
if (opts.inlineText) {
|
|
130
|
-
hProperties["data-side-text"] = opts.inlineText;
|
|
131
|
-
}
|
|
132
|
-
if (opts.orphan) {
|
|
133
|
-
hProperties["data-side-orphan"] = "true";
|
|
134
|
-
}
|
|
135
|
-
return {
|
|
136
|
-
type: "sideAnnotation",
|
|
137
|
-
data: { hName: "div", hProperties },
|
|
138
|
-
sideType: opts.sideType,
|
|
139
|
-
sideTypeSymbol: opts.sideTypeSymbol,
|
|
140
|
-
noteRef: opts.noteRef ?? null,
|
|
141
|
-
inlineText: opts.inlineText ?? null,
|
|
142
|
-
orphan: opts.orphan,
|
|
143
|
-
children: opts.children
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
var INLINE_ANNOTATION_RE = /(?:^|(?<=\s))\(>((?:[^ ()\\]|\\.)+?) ((?:[^)\\]|\\.)*)\)\s*$/m;
|
|
147
|
-
var CONTINUATION_RE = /(?:^|(?<=\s))\(>\+\)\s*$/m;
|
|
148
|
-
var CONTINUATION_RE_GLOBAL = /(?:^|(?<=\s))\(>\+\)\s*$/gm;
|
|
149
|
-
var ESCAPE_RE = /\(\\>/;
|
|
150
|
-
var NOTE_DEF_RE = /^\[>([\w-]+)\]:\s*(?:\{type=([^}"]+|"[^"]*")\}\s*)?/;
|
|
151
|
-
var NOTE_REF_RE = /^\[>([\w-]+)\]$/;
|
|
152
|
-
function remarkSideAnnotation() {
|
|
153
|
-
return (tree) => {
|
|
154
|
-
const noteDefinitions = collectNoteDefinitions(tree);
|
|
155
|
-
processDirectiveContainers(tree, noteDefinitions);
|
|
156
|
-
processInlineAnnotations(tree);
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function collectNoteDefinitions(tree) {
|
|
160
|
-
const defs = /* @__PURE__ */ new Map();
|
|
161
|
-
const toRemove = [];
|
|
162
|
-
for (let i = 0; i < tree.children.length; i++) {
|
|
163
|
-
const node = tree.children[i];
|
|
164
|
-
if (node.type !== "paragraph") continue;
|
|
165
|
-
const text = extractParagraphText(node);
|
|
166
|
-
const match = NOTE_DEF_RE.exec(text);
|
|
167
|
-
if (!match) continue;
|
|
168
|
-
const id = match[1];
|
|
169
|
-
if (defs.has(id)) continue;
|
|
170
|
-
let typeSymbol = ":";
|
|
171
|
-
if (match[2]) {
|
|
172
|
-
const raw = match[2].replace(/^"|"$/g, "");
|
|
173
|
-
if (TYPE_TABLE[raw]) {
|
|
174
|
-
typeSymbol = raw;
|
|
175
|
-
} else if (TYPE_BY_KEYWORD[raw]) {
|
|
176
|
-
typeSymbol = TYPE_BY_KEYWORD[raw];
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
const contentText = text.slice(match[0].length).trim();
|
|
180
|
-
const contentChildren = [];
|
|
181
|
-
if (contentText) {
|
|
182
|
-
contentChildren.push({
|
|
183
|
-
type: "paragraph",
|
|
184
|
-
children: [{ type: "text", value: contentText }]
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
let j = i + 1;
|
|
188
|
-
while (j < tree.children.length) {
|
|
189
|
-
const next = tree.children[j];
|
|
190
|
-
if (next.type === "paragraph") {
|
|
191
|
-
const nextText = extractParagraphText(next);
|
|
192
|
-
if (nextText.startsWith(" ")) {
|
|
193
|
-
contentChildren.push({
|
|
194
|
-
type: "paragraph",
|
|
195
|
-
children: [{ type: "text", value: nextText.replace(/^ /gm, "") }]
|
|
196
|
-
});
|
|
197
|
-
toRemove.push(j);
|
|
198
|
-
j++;
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
break;
|
|
203
|
-
}
|
|
204
|
-
defs.set(id, {
|
|
205
|
-
type: "sideNoteDefinition",
|
|
206
|
-
identifier: id,
|
|
207
|
-
sideTypeSymbol: typeSymbol,
|
|
208
|
-
sideType: TYPE_TABLE[typeSymbol] || "plain",
|
|
209
|
-
children: contentChildren
|
|
210
|
-
});
|
|
211
|
-
toRemove.push(i);
|
|
212
|
-
}
|
|
213
|
-
for (const idx of toRemove.sort((a, b) => b - a)) {
|
|
214
|
-
tree.children.splice(idx, 1);
|
|
215
|
-
}
|
|
216
|
-
return defs;
|
|
217
|
-
}
|
|
218
|
-
function processDirectiveContainers(tree, noteDefinitions) {
|
|
219
|
-
for (let i = 0; i < tree.children.length; i++) {
|
|
220
|
-
const node = tree.children[i];
|
|
221
|
-
if (node.type !== "containerDirective" || node.name !== "side") continue;
|
|
222
|
-
if (!node.children || node.children.length === 0) continue;
|
|
223
|
-
const label = extractDirectiveLabel(node);
|
|
224
|
-
let sideType = "plain";
|
|
225
|
-
let sideTypeSymbol = ":";
|
|
226
|
-
let noteRef = null;
|
|
227
|
-
let inlineText = null;
|
|
228
|
-
if (label) {
|
|
229
|
-
const refMatch = NOTE_REF_RE.exec(label.trim());
|
|
230
|
-
if (refMatch) {
|
|
231
|
-
noteRef = refMatch[1];
|
|
232
|
-
const def = noteDefinitions.get(noteRef);
|
|
233
|
-
if (def) {
|
|
234
|
-
sideType = def.sideType;
|
|
235
|
-
sideTypeSymbol = def.sideTypeSymbol;
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
const stripped = label.trim().replace(/^\(>(.*)\)$/, "$1");
|
|
239
|
-
const parsed = parseInlineAnnotationText(stripped);
|
|
240
|
-
if (parsed) {
|
|
241
|
-
sideType = parsed.sideType;
|
|
242
|
-
sideTypeSymbol = parsed.sideTypeSymbol;
|
|
243
|
-
inlineText = parsed.content;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
const resolvedText = noteRef ? noteDefinitions.get(noteRef)?.children.map(
|
|
248
|
-
(c) => c.type === "paragraph" ? extractParagraphText(c) : ""
|
|
249
|
-
).join("\n") || null : inlineText;
|
|
250
|
-
const sideNode = makeSideAnnotationNode({
|
|
251
|
-
sideType,
|
|
252
|
-
sideTypeSymbol,
|
|
253
|
-
noteRef,
|
|
254
|
-
inlineText: resolvedText,
|
|
255
|
-
children: node.children
|
|
256
|
-
});
|
|
257
|
-
tree.children[i] = sideNode;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
function processInlineAnnotations(tree) {
|
|
261
|
-
processAnnotationsInChildren(tree.children);
|
|
262
|
-
}
|
|
263
|
-
function processAnnotationsInChildren(children) {
|
|
264
|
-
let i = children.length - 1;
|
|
265
|
-
while (i >= 0) {
|
|
266
|
-
const node = children[i];
|
|
267
|
-
if (node.type === "paragraph") {
|
|
268
|
-
const result = tryExtractInlineAnnotation(node);
|
|
269
|
-
if (result?.type === "continuation") {
|
|
270
|
-
const chainResult = buildContinuationChain(children, i);
|
|
271
|
-
if (chainResult) {
|
|
272
|
-
const { startIdx, sideNode } = chainResult;
|
|
273
|
-
const count = i - startIdx + 1;
|
|
274
|
-
children.splice(startIdx, count, sideNode);
|
|
275
|
-
i = startIdx - 1;
|
|
276
|
-
continue;
|
|
277
|
-
} else {
|
|
278
|
-
const strippedNode = stripAnnotationMatches(node, CONTINUATION_RE);
|
|
279
|
-
children[i] = makeSideAnnotationNode({
|
|
280
|
-
sideType: "plain",
|
|
281
|
-
sideTypeSymbol: ":",
|
|
282
|
-
orphan: true,
|
|
283
|
-
children: [strippedNode]
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
} else if (result?.type === "annotation") {
|
|
287
|
-
let strippedNode = node;
|
|
288
|
-
if (result.softBreakAnnotation) {
|
|
289
|
-
strippedNode = stripAnnotationMatches(strippedNode, CONTINUATION_RE_GLOBAL, { removeAllOccurrences: true });
|
|
290
|
-
}
|
|
291
|
-
strippedNode = stripAnnotationMatches(strippedNode, INLINE_ANNOTATION_RE);
|
|
292
|
-
children[i] = makeSideAnnotationNode({
|
|
293
|
-
sideType: result.sideType,
|
|
294
|
-
sideTypeSymbol: result.sideTypeSymbol,
|
|
295
|
-
inlineText: result.content,
|
|
296
|
-
children: [strippedNode]
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
if (node.type === "list" && Array.isArray(node.children)) {
|
|
301
|
-
processListAnnotations(node, children, i);
|
|
302
|
-
}
|
|
303
|
-
if (node.type === "blockquote" && Array.isArray(node.children)) {
|
|
304
|
-
processAnnotationsInChildren(node.children);
|
|
305
|
-
}
|
|
306
|
-
i--;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
function processListAnnotations(listNode, parentChildren, listIdx) {
|
|
310
|
-
const listItems = listNode.children;
|
|
311
|
-
if (!listItems?.length) return;
|
|
312
|
-
for (const li of listItems) {
|
|
313
|
-
if (li.type === "listItem" && Array.isArray(li.children)) {
|
|
314
|
-
const subChildren = li.children.slice(1);
|
|
315
|
-
if (subChildren.length) processAnnotationsInChildren(subChildren);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
const infos = listItems.map((li) => {
|
|
319
|
-
if (li.type !== "listItem" || !Array.isArray(li.children)) {
|
|
320
|
-
return { annotation: null, paragraph: null };
|
|
321
|
-
}
|
|
322
|
-
const firstChild = li.children[0];
|
|
323
|
-
if (!firstChild || firstChild.type !== "paragraph") {
|
|
324
|
-
return { annotation: null, paragraph: null };
|
|
325
|
-
}
|
|
326
|
-
return {
|
|
327
|
-
annotation: tryExtractInlineAnnotation(firstChild),
|
|
328
|
-
paragraph: firstChild
|
|
329
|
-
};
|
|
330
|
-
});
|
|
331
|
-
const chains = [];
|
|
332
|
-
const consumed = /* @__PURE__ */ new Set();
|
|
333
|
-
let i = infos.length - 1;
|
|
334
|
-
while (i >= 0) {
|
|
335
|
-
const info = infos[i];
|
|
336
|
-
if (info.annotation?.type === "continuation") {
|
|
337
|
-
const chainEnd = i;
|
|
338
|
-
let j = i - 1;
|
|
339
|
-
let headIdx = -1;
|
|
340
|
-
let headResult = null;
|
|
341
|
-
while (j >= 0) {
|
|
342
|
-
const prev = infos[j];
|
|
343
|
-
if (!prev.annotation) break;
|
|
344
|
-
if (prev.annotation.type === "continuation") {
|
|
345
|
-
j--;
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
if (prev.annotation.type === "annotation") {
|
|
349
|
-
headIdx = j;
|
|
350
|
-
headResult = prev.annotation;
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
if (headIdx >= 0 && headResult && headResult.type === "annotation") {
|
|
356
|
-
chains.push({
|
|
357
|
-
headIdx,
|
|
358
|
-
endIdx: chainEnd,
|
|
359
|
-
sideType: headResult.sideType,
|
|
360
|
-
sideTypeSymbol: headResult.sideTypeSymbol,
|
|
361
|
-
content: headResult.content
|
|
362
|
-
});
|
|
363
|
-
for (let k = headIdx; k <= chainEnd; k++) consumed.add(k);
|
|
364
|
-
i = headIdx - 1;
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
i--;
|
|
369
|
-
}
|
|
370
|
-
for (let idx = 0; idx < infos.length; idx++) {
|
|
371
|
-
if (consumed.has(idx)) continue;
|
|
372
|
-
const info = infos[idx];
|
|
373
|
-
if (info.annotation?.type === "continuation" && info.paragraph) {
|
|
374
|
-
const strippedNode = stripAnnotationMatches(info.paragraph, CONTINUATION_RE);
|
|
375
|
-
listItems[idx].children[0] = makeSideAnnotationNode({
|
|
376
|
-
sideType: "plain",
|
|
377
|
-
sideTypeSymbol: ":",
|
|
378
|
-
orphan: true,
|
|
379
|
-
children: [strippedNode]
|
|
380
|
-
});
|
|
381
|
-
} else if (info.annotation?.type === "annotation" && info.paragraph) {
|
|
382
|
-
const strippedNode = stripAnnotationMatches(info.paragraph, INLINE_ANNOTATION_RE);
|
|
383
|
-
listItems[idx].children[0] = makeSideAnnotationNode({
|
|
384
|
-
sideType: info.annotation.sideType,
|
|
385
|
-
sideTypeSymbol: info.annotation.sideTypeSymbol,
|
|
386
|
-
inlineText: info.annotation.content,
|
|
387
|
-
children: [strippedNode]
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
if (chains.length === 0) return;
|
|
392
|
-
chains.sort((a, b) => a.headIdx - b.headIdx);
|
|
393
|
-
const replacements = [];
|
|
394
|
-
let cursor = 0;
|
|
395
|
-
const baseStart = listNode.start ?? 1;
|
|
396
|
-
for (const chain of chains) {
|
|
397
|
-
if (cursor < chain.headIdx) {
|
|
398
|
-
const beforeItems = listItems.slice(cursor, chain.headIdx);
|
|
399
|
-
const beforeList = { ...listNode, children: beforeItems };
|
|
400
|
-
if (listNode.ordered && cursor > 0) {
|
|
401
|
-
beforeList.start = baseStart + cursor;
|
|
402
|
-
}
|
|
403
|
-
replacements.push(beforeList);
|
|
404
|
-
}
|
|
405
|
-
const chainItems = listItems.slice(chain.headIdx, chain.endIdx + 1);
|
|
406
|
-
for (let k = 0; k < chainItems.length; k++) {
|
|
407
|
-
const li = chainItems[k];
|
|
408
|
-
if (li.children?.[0]?.type === "paragraph") {
|
|
409
|
-
li.children[0] = stripAnnotationMatches(
|
|
410
|
-
li.children[0],
|
|
411
|
-
k === 0 ? INLINE_ANNOTATION_RE : CONTINUATION_RE
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
const subList = {
|
|
416
|
-
...listNode,
|
|
417
|
-
children: chainItems,
|
|
418
|
-
...listNode.ordered && chain.headIdx > 0 ? { start: baseStart + chain.headIdx } : {}
|
|
419
|
-
};
|
|
420
|
-
replacements.push(makeSideAnnotationNode({
|
|
421
|
-
sideType: chain.sideType,
|
|
422
|
-
sideTypeSymbol: chain.sideTypeSymbol,
|
|
423
|
-
inlineText: chain.content,
|
|
424
|
-
children: [subList]
|
|
425
|
-
}));
|
|
426
|
-
cursor = chain.endIdx + 1;
|
|
427
|
-
}
|
|
428
|
-
if (cursor < listItems.length) {
|
|
429
|
-
const afterItems = listItems.slice(cursor);
|
|
430
|
-
const afterList = { ...listNode, children: afterItems };
|
|
431
|
-
if (listNode.ordered) {
|
|
432
|
-
afterList.start = baseStart + cursor;
|
|
433
|
-
}
|
|
434
|
-
replacements.push(afterList);
|
|
435
|
-
}
|
|
436
|
-
parentChildren.splice(listIdx, 1, ...replacements);
|
|
437
|
-
}
|
|
438
|
-
function buildContinuationChain(children, continuationIdx) {
|
|
439
|
-
const chainMembers = [continuationIdx];
|
|
440
|
-
let j = continuationIdx - 1;
|
|
441
|
-
while (j >= 0) {
|
|
442
|
-
const prev = children[j];
|
|
443
|
-
if (prev.type !== "paragraph") break;
|
|
444
|
-
const prevResult = tryExtractInlineAnnotation(prev);
|
|
445
|
-
if (prevResult?.type === "continuation") {
|
|
446
|
-
chainMembers.unshift(j);
|
|
447
|
-
j--;
|
|
448
|
-
continue;
|
|
449
|
-
}
|
|
450
|
-
if (prevResult?.type === "annotation") {
|
|
451
|
-
chainMembers.unshift(j);
|
|
452
|
-
const headBlock = stripAnnotationMatches(
|
|
453
|
-
children[j],
|
|
454
|
-
INLINE_ANNOTATION_RE
|
|
455
|
-
);
|
|
456
|
-
const memberBlocks = [headBlock];
|
|
457
|
-
for (let k = 1; k < chainMembers.length; k++) {
|
|
458
|
-
memberBlocks.push(
|
|
459
|
-
stripAnnotationMatches(
|
|
460
|
-
children[chainMembers[k]],
|
|
461
|
-
CONTINUATION_RE
|
|
462
|
-
)
|
|
463
|
-
);
|
|
464
|
-
}
|
|
465
|
-
const sideNode = makeSideAnnotationNode({
|
|
466
|
-
sideType: prevResult.sideType,
|
|
467
|
-
sideTypeSymbol: prevResult.sideTypeSymbol,
|
|
468
|
-
inlineText: prevResult.content,
|
|
469
|
-
children: memberBlocks
|
|
470
|
-
});
|
|
471
|
-
return { startIdx: j, sideNode };
|
|
472
|
-
}
|
|
473
|
-
break;
|
|
474
|
-
}
|
|
475
|
-
return null;
|
|
476
|
-
}
|
|
477
|
-
function tryExtractInlineAnnotation(paragraph) {
|
|
478
|
-
const text = extractParagraphText(paragraph);
|
|
479
|
-
if (!text) return null;
|
|
480
|
-
if (ESCAPE_RE.test(text)) return null;
|
|
481
|
-
if (CONTINUATION_RE.test(text)) {
|
|
482
|
-
if (text.includes("\n")) {
|
|
483
|
-
const lines = text.split("\n");
|
|
484
|
-
for (let i = 0; i < lines.length - 1; i++) {
|
|
485
|
-
const parsed2 = parseInlineAnnotationFromText(lines[i]);
|
|
486
|
-
if (parsed2) return { type: "annotation", ...parsed2, softBreakAnnotation: true };
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
return { type: "continuation" };
|
|
490
|
-
}
|
|
491
|
-
const parsed = parseInlineAnnotationFromText(text);
|
|
492
|
-
if (parsed) return { type: "annotation", ...parsed };
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
|
-
function parseInlineAnnotationFromText(text) {
|
|
496
|
-
const openIdx = text.lastIndexOf("(>");
|
|
497
|
-
if (openIdx < 0) return null;
|
|
498
|
-
const afterOpen = text.slice(openIdx + 2);
|
|
499
|
-
const closeIdx = findUnescapedClose(afterOpen);
|
|
500
|
-
if (closeIdx < 0) return null;
|
|
501
|
-
const afterClose = afterOpen.slice(closeIdx + 1).trim();
|
|
502
|
-
if (afterClose) return null;
|
|
503
|
-
const inner = afterOpen.slice(0, closeIdx);
|
|
504
|
-
if (inner === "+") return null;
|
|
505
|
-
return parseInlineAnnotationText(inner);
|
|
506
|
-
}
|
|
507
|
-
function parseInlineAnnotationText(inner) {
|
|
508
|
-
const spaceIdx = inner.indexOf(" ");
|
|
509
|
-
if (spaceIdx < 0) return null;
|
|
510
|
-
const typeCandidate = inner.slice(0, spaceIdx);
|
|
511
|
-
if (!typeCandidate) return null;
|
|
512
|
-
const sideType = TYPE_TABLE[typeCandidate];
|
|
513
|
-
if (sideType) {
|
|
514
|
-
const content2 = inner.slice(spaceIdx + 1).replace(/\\([)])/g, "$1").trim();
|
|
515
|
-
if (!content2) return null;
|
|
516
|
-
return { sideType, sideTypeSymbol: typeCandidate, content: content2 };
|
|
517
|
-
}
|
|
518
|
-
const symbolFromKeyword = TYPE_BY_KEYWORD[typeCandidate];
|
|
519
|
-
if (!symbolFromKeyword) return null;
|
|
520
|
-
const content = inner.slice(spaceIdx + 1).replace(/\\([)])/g, "$1").trim();
|
|
521
|
-
if (!content) return null;
|
|
522
|
-
return { sideType: typeCandidate, sideTypeSymbol: symbolFromKeyword, content };
|
|
523
|
-
}
|
|
524
|
-
function findUnescapedClose(s) {
|
|
525
|
-
for (let i = 0; i < s.length; i++) {
|
|
526
|
-
if (s[i] === "\\" && i + 1 < s.length) {
|
|
527
|
-
i++;
|
|
528
|
-
continue;
|
|
529
|
-
}
|
|
530
|
-
if (s[i] === ")") return i;
|
|
531
|
-
}
|
|
532
|
-
return -1;
|
|
533
|
-
}
|
|
534
|
-
function extractParagraphText(paragraph) {
|
|
535
|
-
return extractPhrasingText(paragraph.children);
|
|
536
|
-
}
|
|
537
|
-
function stripAnnotationMatches(paragraph, pattern, options) {
|
|
538
|
-
const { children } = stripAnnotationMatchesFromChildren(
|
|
539
|
-
paragraph.children,
|
|
540
|
-
pattern,
|
|
541
|
-
options?.removeAllOccurrences ?? false
|
|
542
|
-
);
|
|
543
|
-
return { ...paragraph, children };
|
|
544
|
-
}
|
|
545
|
-
function extractPhrasingText(children) {
|
|
546
|
-
return children.map((child) => {
|
|
547
|
-
if (child.type === "text") return child.value;
|
|
548
|
-
if (child.type === "break") return "\n";
|
|
549
|
-
if ("children" in child && Array.isArray(child.children)) {
|
|
550
|
-
return extractPhrasingText(child.children);
|
|
551
|
-
}
|
|
552
|
-
return "";
|
|
553
|
-
}).join("");
|
|
554
|
-
}
|
|
555
|
-
function stripAnnotationMatchesFromChildren(children, pattern, removeAllOccurrences) {
|
|
556
|
-
const nextChildren = [...children];
|
|
557
|
-
let stripped = false;
|
|
558
|
-
const regex = new RegExp(pattern.source, pattern.flags);
|
|
559
|
-
for (let i = nextChildren.length - 1; i >= 0; i--) {
|
|
560
|
-
const child = nextChildren[i];
|
|
561
|
-
if (child.type === "text") {
|
|
562
|
-
regex.lastIndex = 0;
|
|
563
|
-
const newValue = child.value.replace(regex, "").trimEnd();
|
|
564
|
-
if (newValue === child.value) continue;
|
|
565
|
-
if (newValue) {
|
|
566
|
-
nextChildren[i] = { ...child, value: newValue };
|
|
567
|
-
} else {
|
|
568
|
-
nextChildren.splice(i, 1);
|
|
569
|
-
}
|
|
570
|
-
stripped = true;
|
|
571
|
-
if (!removeAllOccurrences) {
|
|
572
|
-
return { children: nextChildren, stripped: true };
|
|
573
|
-
}
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
if ("children" in child && Array.isArray(child.children)) {
|
|
577
|
-
const nested = stripAnnotationMatchesFromChildren(
|
|
578
|
-
child.children,
|
|
579
|
-
pattern,
|
|
580
|
-
removeAllOccurrences
|
|
581
|
-
);
|
|
582
|
-
if (!nested.stripped) continue;
|
|
583
|
-
if (nested.children.length > 0) {
|
|
584
|
-
nextChildren[i] = { ...child, children: nested.children };
|
|
585
|
-
} else {
|
|
586
|
-
nextChildren.splice(i, 1);
|
|
587
|
-
}
|
|
588
|
-
stripped = true;
|
|
589
|
-
if (!removeAllOccurrences) {
|
|
590
|
-
return { children: nextChildren, stripped: true };
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
return { children: nextChildren, stripped };
|
|
595
|
-
}
|
|
596
|
-
function extractDirectiveLabel(node) {
|
|
597
|
-
if (node.attributes?.label) return node.attributes.label;
|
|
598
|
-
if (node.children?.[0]?.type === "paragraph") {
|
|
599
|
-
const split = splitDirectiveLabelParagraph(node.children[0]);
|
|
600
|
-
const firstText = split.labelText;
|
|
601
|
-
if (firstText.startsWith("(>") || firstText.startsWith("[>")) {
|
|
602
|
-
if (split.remainder) {
|
|
603
|
-
node.children = [split.remainder, ...node.children.slice(1)];
|
|
604
|
-
} else {
|
|
605
|
-
node.children = node.children.slice(1);
|
|
606
|
-
}
|
|
607
|
-
return firstText;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
612
|
-
function splitDirectiveLabelParagraph(paragraph) {
|
|
613
|
-
const children = paragraph.children;
|
|
614
|
-
const before = [];
|
|
615
|
-
const after = [];
|
|
616
|
-
let foundBreak = false;
|
|
617
|
-
for (const child of children) {
|
|
618
|
-
if (foundBreak) {
|
|
619
|
-
after.push(child);
|
|
620
|
-
continue;
|
|
621
|
-
}
|
|
622
|
-
if (child.type === "break") {
|
|
623
|
-
foundBreak = true;
|
|
624
|
-
continue;
|
|
625
|
-
}
|
|
626
|
-
if (child.type === "text" && child.value.includes("\n")) {
|
|
627
|
-
const newlineIndex = child.value.indexOf("\n");
|
|
628
|
-
const beforeText = child.value.slice(0, newlineIndex);
|
|
629
|
-
const afterText = child.value.slice(newlineIndex + 1);
|
|
630
|
-
if (beforeText) before.push({ ...child, value: beforeText });
|
|
631
|
-
if (afterText) after.push({ ...child, value: afterText });
|
|
632
|
-
foundBreak = true;
|
|
633
|
-
continue;
|
|
634
|
-
}
|
|
635
|
-
before.push(child);
|
|
636
|
-
}
|
|
637
|
-
return {
|
|
638
|
-
labelText: extractPhrasingText(before).trim(),
|
|
639
|
-
remainder: after.length > 0 ? { ...paragraph, children: after } : null
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// src/processor/rehype-side-annotation.ts
|
|
644
|
-
var STROKE_WIDTH = "1.5";
|
|
645
|
-
function el(tagName, properties, children = []) {
|
|
646
|
-
return { type: "element", tagName, properties, children };
|
|
647
|
-
}
|
|
648
|
-
function svgPath(d, extra = {}) {
|
|
649
|
-
return el("path", {
|
|
650
|
-
d,
|
|
651
|
-
fill: "none",
|
|
652
|
-
stroke: "currentColor",
|
|
653
|
-
"stroke-width": STROKE_WIDTH,
|
|
654
|
-
"stroke-linecap": "round",
|
|
655
|
-
...extra
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
function svgPolyline(points, extra = {}) {
|
|
659
|
-
return el("polyline", {
|
|
660
|
-
points,
|
|
661
|
-
fill: "none",
|
|
662
|
-
stroke: "currentColor",
|
|
663
|
-
"stroke-width": STROKE_WIDTH,
|
|
664
|
-
"stroke-linecap": "square",
|
|
665
|
-
"stroke-linejoin": "miter",
|
|
666
|
-
"shape-rendering": "geometricPrecision",
|
|
667
|
-
...extra
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
function svgLine(x1, y1, x2, y2, extra = {}) {
|
|
671
|
-
return el("line", {
|
|
672
|
-
x1: String(x1),
|
|
673
|
-
y1,
|
|
674
|
-
x2: String(x2),
|
|
675
|
-
y2,
|
|
676
|
-
stroke: "currentColor",
|
|
677
|
-
"stroke-width": STROKE_WIDTH,
|
|
678
|
-
"stroke-linecap": "round",
|
|
679
|
-
...extra
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
function svgEl(props, children) {
|
|
683
|
-
return el("svg", {
|
|
684
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
685
|
-
...props
|
|
686
|
-
}, children);
|
|
687
|
-
}
|
|
688
|
-
function svgSegment(cls, w, h, children, extra = {}) {
|
|
689
|
-
return svgEl(
|
|
690
|
-
{ width: String(w), height: String(h), viewBox: `0 0 ${w} ${h}`, class: cls, ...extra },
|
|
691
|
-
children
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
function stretchLineDiv() {
|
|
695
|
-
return el("div", { class: "side-svg-line" });
|
|
696
|
-
}
|
|
697
|
-
function segmented(width, axisPx, segments, extraClass = "") {
|
|
698
|
-
return el("div", {
|
|
699
|
-
class: ["side-annotation-svg", "side-svg-segmented", extraClass].filter(Boolean).join(" "),
|
|
700
|
-
style: `width:${width};--side-svg-axis:${axisPx}px`
|
|
701
|
-
}, segments);
|
|
702
|
-
}
|
|
703
|
-
function braceTopCap() {
|
|
704
|
-
return svgSegment("side-svg-cap", 12, 6, [
|
|
705
|
-
svgPath("M 1 0.75 C 3.5 0.75, 6 2.5, 6 5.25")
|
|
706
|
-
]);
|
|
707
|
-
}
|
|
708
|
-
function braceMidBeak() {
|
|
709
|
-
return svgSegment("side-svg-beak", 12, 8, [
|
|
710
|
-
svgPath("M 6 0 C 6 2.5, 11 4, 11 4 C 11 4, 6 5.5, 6 8")
|
|
711
|
-
]);
|
|
712
|
-
}
|
|
713
|
-
function braceBotCap() {
|
|
714
|
-
return svgSegment("side-svg-cap", 12, 6, [
|
|
715
|
-
svgPath("M 6 0.75 C 6 3.5, 3.5 5.25, 1 5.25")
|
|
716
|
-
]);
|
|
717
|
-
}
|
|
718
|
-
function leftBraceTopCap() {
|
|
719
|
-
return svgSegment("side-svg-cap", 12, 6, [
|
|
720
|
-
svgPath("M 11 0.75 C 8.5 0.75, 6 2.5, 6 5.25")
|
|
721
|
-
]);
|
|
722
|
-
}
|
|
723
|
-
function leftBraceMidBeak() {
|
|
724
|
-
return svgSegment("side-svg-beak", 12, 8, [
|
|
725
|
-
svgPath("M 6 0 C 6 2.5, 1 4, 1 4 C 1 4, 6 5.5, 6 8")
|
|
726
|
-
]);
|
|
727
|
-
}
|
|
728
|
-
function leftBraceBotCap() {
|
|
729
|
-
return svgSegment("side-svg-cap", 12, 6, [
|
|
730
|
-
svgPath("M 6 0.75 C 6 3.5, 8.5 5.25, 11 5.25")
|
|
731
|
-
]);
|
|
732
|
-
}
|
|
733
|
-
function bracketTopCap() {
|
|
734
|
-
return svgSegment("side-svg-cap", 8, 6, [
|
|
735
|
-
svgPolyline("1,0.75 4,0.75 4,5.25")
|
|
736
|
-
]);
|
|
737
|
-
}
|
|
738
|
-
function bracketBotCap() {
|
|
739
|
-
return svgSegment("side-svg-cap", 8, 6, [
|
|
740
|
-
svgPolyline("4,0.75 4,5.25 1,5.25")
|
|
741
|
-
]);
|
|
742
|
-
}
|
|
743
|
-
function leftBracketTopCap() {
|
|
744
|
-
return svgSegment("side-svg-cap", 8, 6, [
|
|
745
|
-
svgPolyline("7,0.75 4,0.75 4,5.25")
|
|
746
|
-
]);
|
|
747
|
-
}
|
|
748
|
-
function leftBracketBotCap() {
|
|
749
|
-
return svgSegment("side-svg-cap", 8, 6, [
|
|
750
|
-
svgPolyline("4,0.75 4,5.25 7,5.25")
|
|
751
|
-
]);
|
|
752
|
-
}
|
|
753
|
-
var SVG_GENERATORS = {
|
|
754
|
-
// --- Segmented stretch types ---
|
|
755
|
-
brace: () => segmented("12px", 6, [
|
|
756
|
-
braceTopCap(),
|
|
757
|
-
stretchLineDiv(),
|
|
758
|
-
braceMidBeak(),
|
|
759
|
-
stretchLineDiv(),
|
|
760
|
-
braceBotCap()
|
|
761
|
-
]),
|
|
762
|
-
"left-brace": () => segmented("12px", 6, [
|
|
763
|
-
leftBraceTopCap(),
|
|
764
|
-
stretchLineDiv(),
|
|
765
|
-
leftBraceMidBeak(),
|
|
766
|
-
stretchLineDiv(),
|
|
767
|
-
leftBraceBotCap()
|
|
768
|
-
]),
|
|
769
|
-
bracket: () => segmented("8px", 4, [
|
|
770
|
-
bracketTopCap(),
|
|
771
|
-
stretchLineDiv(),
|
|
772
|
-
bracketBotCap()
|
|
773
|
-
], "side-svg-bracket"),
|
|
774
|
-
"left-bracket": () => segmented("8px", 4, [
|
|
775
|
-
leftBracketTopCap(),
|
|
776
|
-
stretchLineDiv(),
|
|
777
|
-
leftBracketBotCap()
|
|
778
|
-
], "side-svg-left-bracket"),
|
|
779
|
-
// --- Non-segmented vertical line (non-scaling-stroke prevents thickening) ---
|
|
780
|
-
line: () => svgEl(
|
|
781
|
-
{ width: "4", viewBox: "0 0 4 100", preserveAspectRatio: "none", class: "side-annotation-svg side-svg-vline" },
|
|
782
|
-
[svgLine(2, "2", 2, "98", { "vector-effect": "non-scaling-stroke" })]
|
|
783
|
-
),
|
|
784
|
-
// --- Fixed-size (non-stretch) SVGs ---
|
|
785
|
-
dash: () => svgEl(
|
|
786
|
-
{ width: "20", height: "4", viewBox: "0 0 20 4", class: "side-annotation-svg side-svg-dash" },
|
|
787
|
-
[svgLine(1, "2", 19, "2")]
|
|
788
|
-
),
|
|
789
|
-
arrow: () => svgEl(
|
|
790
|
-
{ width: "24", height: "16", viewBox: "0 0 24 16", class: "side-annotation-svg side-svg-arrow" },
|
|
791
|
-
[svgPath("M 1 8 L 20 8 M 16 3 L 21 8 L 16 13")]
|
|
792
|
-
),
|
|
793
|
-
"fat-arrow": () => svgEl(
|
|
794
|
-
{ width: "24", height: "16", viewBox: "0 0 24 16", class: "side-annotation-svg side-svg-fat-arrow" },
|
|
795
|
-
[svgPath("M 1 5 L 16 5 M 1 11 L 16 11 M 15 2 L 22 8 L 15 14")]
|
|
796
|
-
),
|
|
797
|
-
"wave-arrow": () => svgEl(
|
|
798
|
-
{ width: "28", height: "16", viewBox: "0 0 28 16", class: "side-annotation-svg side-svg-wave-arrow" },
|
|
799
|
-
[svgPath("M 1 8 C 4 3, 8 13, 12 8 C 16 3, 20 8, 20 8 M 18 3 L 23 8 L 18 13")]
|
|
800
|
-
),
|
|
801
|
-
// --- Compound segmented types — cohesive integrated designs ---
|
|
802
|
-
// Arrow/fat-arrow emerges directly from the structural element:
|
|
803
|
-
// - Brace: shaft runs straight through beak (no tip), arrow T-branches at midpoint
|
|
804
|
-
// - Bracket/Line: shaft continues through beak, arrow T-branches at midpoint
|
|
805
|
-
"brace-arrow": () => segmented("12px", 6, [
|
|
806
|
-
braceTopCap(),
|
|
807
|
-
stretchLineDiv(),
|
|
808
|
-
svgSegment("side-svg-beak", 12, 8, [
|
|
809
|
-
// Shaft straight through — no brace tip, let the arrow be the focus
|
|
810
|
-
svgLine(6, "0", 6, "8", { "stroke-linecap": "square", "shape-rendering": "geometricPrecision" }),
|
|
811
|
-
// Arrow T-branches from shaft midpoint
|
|
812
|
-
svgPath("M 6 4 L 19 4 M 16 1.5 L 20 4 L 16 6.5")
|
|
813
|
-
], { overflow: "visible" }),
|
|
814
|
-
stretchLineDiv(),
|
|
815
|
-
braceBotCap()
|
|
816
|
-
], "side-svg-compound-arrow"),
|
|
817
|
-
"brace-fat-arrow": () => segmented("12px", 6, [
|
|
818
|
-
braceTopCap(),
|
|
819
|
-
stretchLineDiv(),
|
|
820
|
-
svgSegment("side-svg-beak", 12, 8, [
|
|
821
|
-
// Shaft straight through — no brace tip
|
|
822
|
-
svgLine(6, "0", 6, "8", { "stroke-linecap": "square", "shape-rendering": "geometricPrecision" }),
|
|
823
|
-
// Double-line + chevron (=>) from shaft
|
|
824
|
-
svgPath("M 6 2.5 L 14 2.5 M 6 5.5 L 14 5.5 M 13 0.5 L 18 4 L 13 7.5")
|
|
825
|
-
], { overflow: "visible" }),
|
|
826
|
-
stretchLineDiv(),
|
|
827
|
-
braceBotCap()
|
|
828
|
-
], "side-svg-compound-arrow"),
|
|
829
|
-
"bracket-arrow": () => segmented("8px", 4, [
|
|
830
|
-
bracketTopCap(),
|
|
831
|
-
stretchLineDiv(),
|
|
832
|
-
svgSegment("side-svg-beak", 8, 8, [
|
|
833
|
-
// Shaft continues through beak
|
|
834
|
-
svgLine(4, "0", 4, "8", { "stroke-linecap": "square", "shape-rendering": "geometricPrecision" }),
|
|
835
|
-
// Arrow T-branches from shaft midpoint
|
|
836
|
-
svgPath("M 4 4 L 17 4 M 14 1.5 L 18 4 L 14 6.5")
|
|
837
|
-
], { overflow: "visible" }),
|
|
838
|
-
stretchLineDiv(),
|
|
839
|
-
bracketBotCap()
|
|
840
|
-
], "side-svg-bracket side-svg-compound-arrow"),
|
|
841
|
-
"bracket-fat-arrow": () => segmented("8px", 4, [
|
|
842
|
-
bracketTopCap(),
|
|
843
|
-
stretchLineDiv(),
|
|
844
|
-
svgSegment("side-svg-beak", 8, 8, [
|
|
845
|
-
// Shaft continues through beak
|
|
846
|
-
svgLine(4, "0", 4, "8", { "stroke-linecap": "square", "shape-rendering": "geometricPrecision" }),
|
|
847
|
-
// Double-line + chevron (=>) from shaft
|
|
848
|
-
svgPath("M 4 2.5 L 13 2.5 M 4 5.5 L 13 5.5 M 12 0.5 L 17 4 L 12 7.5")
|
|
849
|
-
], { overflow: "visible" }),
|
|
850
|
-
stretchLineDiv(),
|
|
851
|
-
bracketBotCap()
|
|
852
|
-
], "side-svg-bracket side-svg-compound-arrow"),
|
|
853
|
-
"line-arrow": () => segmented("4px", 2, [
|
|
854
|
-
stretchLineDiv(),
|
|
855
|
-
svgSegment("side-svg-beak", 4, 8, [
|
|
856
|
-
// Shaft continues through beak
|
|
857
|
-
svgLine(2, "0", 2, "8", { "stroke-linecap": "square", "shape-rendering": "geometricPrecision" }),
|
|
858
|
-
// Arrow T-branches from shaft midpoint
|
|
859
|
-
svgPath("M 2 4 L 15 4 M 12 1.5 L 16 4 L 12 6.5")
|
|
860
|
-
], { overflow: "visible" }),
|
|
861
|
-
stretchLineDiv()
|
|
862
|
-
], "side-svg-compound-arrow"),
|
|
863
|
-
"line-fat-arrow": () => segmented("4px", 2, [
|
|
864
|
-
stretchLineDiv(),
|
|
865
|
-
svgSegment("side-svg-beak", 4, 8, [
|
|
866
|
-
// Shaft continues through beak
|
|
867
|
-
svgLine(2, "0", 2, "8", { "stroke-linecap": "square", "shape-rendering": "geometricPrecision" }),
|
|
868
|
-
// Double-line + chevron (=>) from shaft
|
|
869
|
-
svgPath("M 2 2.5 L 11 2.5 M 2 5.5 L 11 5.5 M 10 0.5 L 15 4 L 10 7.5")
|
|
870
|
-
], { overflow: "visible" }),
|
|
871
|
-
stretchLineDiv()
|
|
872
|
-
], "side-svg-compound-arrow")
|
|
873
|
-
};
|
|
874
|
-
SVG_GENERATORS["warning"] = SVG_GENERATORS["line"];
|
|
875
|
-
SVG_GENERATORS["question"] = SVG_GENERATORS["line"];
|
|
876
|
-
SVG_GENERATORS["brace-warning"] = SVG_GENERATORS["brace"];
|
|
877
|
-
SVG_GENERATORS["brace-question"] = SVG_GENERATORS["brace"];
|
|
878
|
-
function rehypeSideAnnotation() {
|
|
879
|
-
return (tree) => {
|
|
880
|
-
visit(tree);
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
function visit(node) {
|
|
884
|
-
if (!node.children) return;
|
|
885
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
886
|
-
const child = node.children[i];
|
|
887
|
-
if (child.type === "element" && child.properties?.["data-side-type"]) {
|
|
888
|
-
node.children[i] = transform(child);
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
visit(child);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
function transform(node) {
|
|
895
|
-
const properties = node.properties ?? {};
|
|
896
|
-
const sideType = String(properties["data-side-type"] || "plain");
|
|
897
|
-
const sideText = properties["data-side-text"] ? String(properties["data-side-text"]) : null;
|
|
898
|
-
const isOrphan = properties["data-side-orphan"] != null;
|
|
899
|
-
const mainContent = el("div", { class: "side-annotation-main" }, node.children);
|
|
900
|
-
const asideChildren = [];
|
|
901
|
-
if (isOrphan) {
|
|
902
|
-
asideChildren.push(SVG_GENERATORS["line"]());
|
|
903
|
-
} else {
|
|
904
|
-
const svgGen = SVG_GENERATORS[sideType];
|
|
905
|
-
if (svgGen) {
|
|
906
|
-
asideChildren.push(svgGen());
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
if (sideText) {
|
|
910
|
-
asideChildren.push(
|
|
911
|
-
el("span", { class: "side-annotation-text" }, [
|
|
912
|
-
{ type: "text", value: sideText }
|
|
913
|
-
])
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
const asideClass = ["side-annotation-aside"];
|
|
917
|
-
if (isOrphan) asideClass.push("side-annotation-orphan");
|
|
918
|
-
const sideColumn = el("div", { class: asideClass.join(" ") }, asideChildren);
|
|
919
|
-
return {
|
|
920
|
-
...node,
|
|
921
|
-
children: [mainContent, sideColumn]
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
// src/mdx-components/callout.ts
|
|
926
|
-
import { createElement } from "react";
|
|
927
|
-
var ICONS = { info: "i", warn: "!", error: "\xD7" };
|
|
928
|
-
function Callout({ type = "info", children }) {
|
|
929
|
-
return createElement(
|
|
930
|
-
"div",
|
|
931
|
-
{ className: `mdx-callout mdx-callout-${type}`, "data-callout-type": type },
|
|
932
|
-
createElement("span", { className: "mdx-callout-icon" }, ICONS[type] || ICONS.info),
|
|
933
|
-
createElement("div", { className: "mdx-callout-content" }, children)
|
|
934
|
-
);
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
// src/mdx-components/code-demo.ts
|
|
938
|
-
import { createElement as createElement2 } from "react";
|
|
939
|
-
function CodeDemo({ title, language = "text", code }) {
|
|
940
|
-
return createElement2(
|
|
941
|
-
"figure",
|
|
942
|
-
{ className: "mdx-code-demo", "data-code-demo": "" },
|
|
943
|
-
title && createElement2("figcaption", null, title),
|
|
944
|
-
createElement2(
|
|
945
|
-
"pre",
|
|
946
|
-
{ "data-language": language },
|
|
947
|
-
createElement2("code", null, code)
|
|
948
|
-
)
|
|
949
|
-
);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// src/mdx-components/steps.ts
|
|
953
|
-
import { createElement as createElement3, Children } from "react";
|
|
954
|
-
function Steps({ children }) {
|
|
955
|
-
const items = [];
|
|
956
|
-
Children.forEach(children, (child) => {
|
|
957
|
-
if (child && typeof child === "object" && "props" in child) {
|
|
958
|
-
items.push(child);
|
|
959
|
-
}
|
|
960
|
-
});
|
|
961
|
-
return createElement3(
|
|
962
|
-
"div",
|
|
963
|
-
{ className: "mdx-steps" },
|
|
964
|
-
items.map(
|
|
965
|
-
(item, i) => createElement3(
|
|
966
|
-
"div",
|
|
967
|
-
{ className: "mdx-steps-item", key: i },
|
|
968
|
-
createElement3(
|
|
969
|
-
"div",
|
|
970
|
-
{ className: "mdx-steps-indicator" },
|
|
971
|
-
createElement3("span", { className: "mdx-steps-number" }, String(i + 1)),
|
|
972
|
-
i < items.length - 1 && createElement3("div", { className: "mdx-steps-line" })
|
|
973
|
-
),
|
|
974
|
-
createElement3("div", { className: "mdx-steps-content" }, item)
|
|
975
|
-
)
|
|
976
|
-
)
|
|
977
|
-
);
|
|
978
|
-
}
|
|
979
|
-
function Step({ title, children }) {
|
|
980
|
-
return createElement3(
|
|
981
|
-
"div",
|
|
982
|
-
{ className: "mdx-step" },
|
|
983
|
-
title && createElement3("h4", { className: "mdx-step-title" }, title),
|
|
984
|
-
children && createElement3("div", { className: "mdx-step-body" }, children)
|
|
985
|
-
);
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
// src/mdx-components/tabs.ts
|
|
989
|
-
import { createElement as createElement4, Children as Children2 } from "react";
|
|
990
|
-
function Tabs({ children }) {
|
|
991
|
-
const tabs = [];
|
|
992
|
-
Children2.forEach(children, (child) => {
|
|
993
|
-
if (child && typeof child === "object" && "props" in child) {
|
|
994
|
-
tabs.push({ label: child.props.label || `Tab ${tabs.length + 1}`, content: child });
|
|
995
|
-
}
|
|
996
|
-
});
|
|
997
|
-
const groupId = `mdx-tabs-${Math.random().toString(36).slice(2, 8)}`;
|
|
998
|
-
return createElement4(
|
|
999
|
-
"div",
|
|
1000
|
-
{ className: "mdx-tabs" },
|
|
1001
|
-
createElement4(
|
|
1002
|
-
"div",
|
|
1003
|
-
{ className: "mdx-tabs-list", role: "tablist" },
|
|
1004
|
-
tabs.map(
|
|
1005
|
-
(tab, i) => createElement4(
|
|
1006
|
-
"label",
|
|
1007
|
-
{ className: "mdx-tabs-trigger", key: i },
|
|
1008
|
-
createElement4("input", {
|
|
1009
|
-
type: "radio",
|
|
1010
|
-
name: groupId,
|
|
1011
|
-
className: "mdx-tabs-radio",
|
|
1012
|
-
defaultChecked: i === 0
|
|
1013
|
-
}),
|
|
1014
|
-
createElement4("span", null, tab.label)
|
|
1015
|
-
)
|
|
1016
|
-
)
|
|
1017
|
-
),
|
|
1018
|
-
tabs.map(
|
|
1019
|
-
(tab, i) => createElement4("div", { className: "mdx-tabs-panel", key: i }, tab.content)
|
|
1020
|
-
)
|
|
1021
|
-
);
|
|
1022
|
-
}
|
|
1023
|
-
function Tab({ label: _label, children }) {
|
|
1024
|
-
return createElement4("div", null, children);
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// src/mdx-components/file-tree.ts
|
|
1028
|
-
import { createElement as createElement5 } from "react";
|
|
1029
|
-
function parseFileTree(text) {
|
|
1030
|
-
const entries = [];
|
|
1031
|
-
for (const line of text.split("\n")) {
|
|
1032
|
-
const trimmed = line.replace(/^[\s\-\*]*/, "");
|
|
1033
|
-
if (!trimmed) continue;
|
|
1034
|
-
const leadingSpaces = line.match(/^(\s*)/)?.[1].length ?? 0;
|
|
1035
|
-
const depth = Math.floor(leadingSpaces / 2);
|
|
1036
|
-
const isDir = trimmed.endsWith("/");
|
|
1037
|
-
const name = isDir ? trimmed.slice(0, -1) : trimmed;
|
|
1038
|
-
entries.push({ name, isDir, depth });
|
|
1039
|
-
}
|
|
1040
|
-
return entries;
|
|
1041
|
-
}
|
|
1042
|
-
function FileTree({ children }) {
|
|
1043
|
-
const text = extractText(children);
|
|
1044
|
-
const entries = parseFileTree(text);
|
|
1045
|
-
return createElement5(
|
|
1046
|
-
"div",
|
|
1047
|
-
{ className: "mdx-file-tree" },
|
|
1048
|
-
entries.map(
|
|
1049
|
-
(entry, i) => createElement5(
|
|
1050
|
-
"div",
|
|
1051
|
-
{
|
|
1052
|
-
className: `mdx-file-tree-entry ${entry.isDir ? "mdx-file-tree-dir" : "mdx-file-tree-file"}`,
|
|
1053
|
-
style: { paddingLeft: `${entry.depth * 1.25 + 0.5}rem` },
|
|
1054
|
-
key: i
|
|
1055
|
-
},
|
|
1056
|
-
createElement5("span", { className: "mdx-file-tree-icon" }, entry.isDir ? "\u{1F4C1}" : "\u{1F4C4}"),
|
|
1057
|
-
createElement5("span", { className: "mdx-file-tree-name" }, entry.name)
|
|
1058
|
-
)
|
|
1059
|
-
)
|
|
1060
|
-
);
|
|
1061
|
-
}
|
|
1062
|
-
function extractText(node) {
|
|
1063
|
-
if (typeof node === "string") return node;
|
|
1064
|
-
if (typeof node === "number") return String(node);
|
|
1065
|
-
if (Array.isArray(node)) return node.map(extractText).join("");
|
|
1066
|
-
if (node && typeof node === "object" && "props" in node) {
|
|
1067
|
-
return extractText(node.props.children);
|
|
1068
|
-
}
|
|
1069
|
-
return "";
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
// src/mdx-components/kbd.ts
|
|
1073
|
-
import { createElement as createElement6 } from "react";
|
|
1074
|
-
function Kbd({ children }) {
|
|
1075
|
-
return createElement6("kbd", { className: "mdx-kbd" }, children);
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
// src/mdx-components/index.ts
|
|
1079
|
-
var DEFAULT_MDX_COMPONENTS = {
|
|
1080
|
-
Callout,
|
|
1081
|
-
CodeDemo,
|
|
1082
|
-
Steps,
|
|
1083
|
-
Step,
|
|
1084
|
-
Tabs,
|
|
1085
|
-
Tab,
|
|
1086
|
-
FileTree,
|
|
1087
|
-
Kbd
|
|
1088
|
-
};
|
|
1089
|
-
|
|
1090
|
-
// src/processor/index.ts
|
|
1091
|
-
import { unified } from "unified";
|
|
1092
|
-
import remarkParse from "remark-parse";
|
|
1093
|
-
import remarkGfm from "remark-gfm";
|
|
1094
|
-
import remarkMath from "remark-math";
|
|
1095
|
-
import remarkMdx from "remark-mdx";
|
|
1096
|
-
import remarkRehype from "remark-rehype";
|
|
1097
|
-
import rehypeKatex from "rehype-katex";
|
|
1098
|
-
import rehypeSlug from "rehype-slug";
|
|
1099
|
-
import rehypePrettyCode from "rehype-pretty-code";
|
|
1100
|
-
import rehypeStringify from "rehype-stringify";
|
|
1101
|
-
import remarkDirective from "remark-directive";
|
|
1102
|
-
|
|
1103
|
-
// src/processor/remark-normalize-standalone-math.ts
|
|
1104
|
-
function getOffset(node, edge) {
|
|
1105
|
-
const value = node?.position?.[edge]?.offset;
|
|
1106
|
-
return typeof value === "number" ? value : null;
|
|
1107
|
-
}
|
|
1108
|
-
function isStandaloneDisplayMathParagraph(node, source) {
|
|
1109
|
-
if (node.type !== "paragraph" || !Array.isArray(node.children) || node.children.length !== 1) {
|
|
1110
|
-
return false;
|
|
1111
|
-
}
|
|
1112
|
-
const onlyChild = node.children[0];
|
|
1113
|
-
if (onlyChild?.type !== "inlineMath") return false;
|
|
1114
|
-
const start = getOffset(node, "start");
|
|
1115
|
-
const end = getOffset(node, "end");
|
|
1116
|
-
if (start == null || end == null) return false;
|
|
1117
|
-
const raw = source.slice(start, end).trim();
|
|
1118
|
-
return /^\$\$(?!\s*$)[\s\S]*?(?<!\\)\$\$$/.test(raw);
|
|
1119
|
-
}
|
|
1120
|
-
function remarkNormalizeStandaloneMath() {
|
|
1121
|
-
return (tree, file) => {
|
|
1122
|
-
const source = typeof file.value === "string" ? file.value : "";
|
|
1123
|
-
if (!source) return;
|
|
1124
|
-
walk2(tree, source);
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
function walk2(node, source) {
|
|
1128
|
-
if (!Array.isArray(node.children)) return;
|
|
1129
|
-
node.children = node.children.map((child) => {
|
|
1130
|
-
if (isStandaloneDisplayMathParagraph(child, source)) {
|
|
1131
|
-
const mathChild = child.children[0];
|
|
1132
|
-
return {
|
|
1133
|
-
type: "math",
|
|
1134
|
-
value: mathChild.value ?? "",
|
|
1135
|
-
data: {
|
|
1136
|
-
hName: "code",
|
|
1137
|
-
hProperties: { className: ["language-math", "math-display"] },
|
|
1138
|
-
hChildren: [{ type: "text", value: mathChild.value ?? "" }]
|
|
1139
|
-
},
|
|
1140
|
-
position: child.position
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
walk2(child, source);
|
|
1144
|
-
return child;
|
|
1145
|
-
});
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
// src/processor/micromark-side-annotation.ts
|
|
1149
|
-
var CODE_OPEN_PAREN = 40;
|
|
1150
|
-
var CODE_CLOSE_PAREN = 41;
|
|
1151
|
-
var CODE_GT = 62;
|
|
1152
|
-
var CODE_BACKSLASH = 92;
|
|
1153
|
-
var CODE_LF = 10;
|
|
1154
|
-
var CODE_CR = 13;
|
|
1155
|
-
function sideAnnotationSyntax() {
|
|
1156
|
-
return {
|
|
1157
|
-
text: {
|
|
1158
|
-
[CODE_OPEN_PAREN]: {
|
|
1159
|
-
name: "sideAnnotationMarker",
|
|
1160
|
-
tokenize: tokenizeSideAnnotation
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
function tokenizeSideAnnotation(effects, ok, nok) {
|
|
1166
|
-
return start;
|
|
1167
|
-
function start(code) {
|
|
1168
|
-
if (code !== CODE_OPEN_PAREN) return nok(code);
|
|
1169
|
-
effects.enter("sideAnnotationMarker");
|
|
1170
|
-
effects.consume(code);
|
|
1171
|
-
return afterOpen;
|
|
1172
|
-
}
|
|
1173
|
-
function afterOpen(code) {
|
|
1174
|
-
if (code !== CODE_GT) return nok(code);
|
|
1175
|
-
effects.consume(code);
|
|
1176
|
-
return content;
|
|
1177
|
-
}
|
|
1178
|
-
function content(code) {
|
|
1179
|
-
if (code === null || code === CODE_LF || code === CODE_CR) {
|
|
1180
|
-
return nok(code);
|
|
1181
|
-
}
|
|
1182
|
-
if (code === CODE_BACKSLASH) {
|
|
1183
|
-
effects.consume(code);
|
|
1184
|
-
return contentEscape;
|
|
1185
|
-
}
|
|
1186
|
-
if (code === CODE_CLOSE_PAREN) {
|
|
1187
|
-
effects.consume(code);
|
|
1188
|
-
effects.exit("sideAnnotationMarker");
|
|
1189
|
-
return ok;
|
|
1190
|
-
}
|
|
1191
|
-
effects.consume(code);
|
|
1192
|
-
return content;
|
|
1193
|
-
}
|
|
1194
|
-
function contentEscape(code) {
|
|
1195
|
-
if (code === null || code === CODE_LF || code === CODE_CR) {
|
|
1196
|
-
return nok(code);
|
|
1197
|
-
}
|
|
1198
|
-
effects.consume(code);
|
|
1199
|
-
return content;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
function sideAnnotationFromMarkdown() {
|
|
1203
|
-
return {
|
|
1204
|
-
enter: {
|
|
1205
|
-
sideAnnotationMarker: enterSideAnnotationMarker
|
|
1206
|
-
},
|
|
1207
|
-
exit: {
|
|
1208
|
-
sideAnnotationMarker: exitSideAnnotationMarker
|
|
1209
|
-
}
|
|
1210
|
-
};
|
|
1211
|
-
function enterSideAnnotationMarker(token) {
|
|
1212
|
-
this.enter({ type: "text", value: "" }, token);
|
|
1213
|
-
}
|
|
1214
|
-
function exitSideAnnotationMarker(token) {
|
|
1215
|
-
const node = this.stack[this.stack.length - 1];
|
|
1216
|
-
node.value = this.sliceSerialize(token);
|
|
1217
|
-
this.exit(token);
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
function remarkMicromarkSideAnnotation() {
|
|
1221
|
-
const data = this.data();
|
|
1222
|
-
const micromarkExtensions = data.micromarkExtensions || (data.micromarkExtensions = []);
|
|
1223
|
-
const fromMarkdownExtensions = data.fromMarkdownExtensions || (data.fromMarkdownExtensions = []);
|
|
1224
|
-
micromarkExtensions.push(sideAnnotationSyntax());
|
|
1225
|
-
fromMarkdownExtensions.push(sideAnnotationFromMarkdown());
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
// src/processor/remark-markdown-sandbox.ts
|
|
1229
|
-
var DEFAULT_OUTER_FENCE_TICKS = 4;
|
|
1230
|
-
var SANDBOX_ROOT_CLASS = "owo-markdown-sandbox";
|
|
1231
|
-
var SANDBOX_BODY_CLASS = "owo-markdown-sandbox__body";
|
|
1232
|
-
function escapeHtml(text) {
|
|
1233
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1234
|
-
}
|
|
1235
|
-
function createSandboxId(startLine, index) {
|
|
1236
|
-
const line = typeof startLine === "number" && Number.isFinite(startLine) ? startLine : index + 1;
|
|
1237
|
-
return `l${line}-${index + 1}`;
|
|
1238
|
-
}
|
|
1239
|
-
function parseBoolean(value) {
|
|
1240
|
-
if (value === void 0) return void 0;
|
|
1241
|
-
if (value === "true") return true;
|
|
1242
|
-
if (value === "false") return false;
|
|
1243
|
-
return void 0;
|
|
1244
|
-
}
|
|
1245
|
-
function tokenizeMeta(meta) {
|
|
1246
|
-
const tokens = [];
|
|
1247
|
-
let current = "";
|
|
1248
|
-
let quote = null;
|
|
1249
|
-
for (let index = 0; index < meta.length; index += 1) {
|
|
1250
|
-
const char = meta[index];
|
|
1251
|
-
if (quote) {
|
|
1252
|
-
if (char === "\\" && index + 1 < meta.length) {
|
|
1253
|
-
current += meta[index + 1];
|
|
1254
|
-
index += 1;
|
|
1255
|
-
continue;
|
|
1256
|
-
}
|
|
1257
|
-
if (char === quote) {
|
|
1258
|
-
quote = null;
|
|
1259
|
-
current += char;
|
|
1260
|
-
continue;
|
|
1261
|
-
}
|
|
1262
|
-
current += char;
|
|
1263
|
-
continue;
|
|
1264
|
-
}
|
|
1265
|
-
if (char === '"' || char === "'") {
|
|
1266
|
-
quote = char;
|
|
1267
|
-
current += char;
|
|
1268
|
-
continue;
|
|
1269
|
-
}
|
|
1270
|
-
if (/\s/.test(char)) {
|
|
1271
|
-
if (current) {
|
|
1272
|
-
tokens.push(current);
|
|
1273
|
-
current = "";
|
|
1274
|
-
}
|
|
1275
|
-
continue;
|
|
1276
|
-
}
|
|
1277
|
-
current += char;
|
|
1278
|
-
}
|
|
1279
|
-
if (current) {
|
|
1280
|
-
tokens.push(current);
|
|
1281
|
-
}
|
|
1282
|
-
return tokens;
|
|
1283
|
-
}
|
|
1284
|
-
function parseMetaValue(raw) {
|
|
1285
|
-
if (raw.length >= 2) {
|
|
1286
|
-
const first = raw[0];
|
|
1287
|
-
const last = raw[raw.length - 1];
|
|
1288
|
-
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
1289
|
-
let value = "";
|
|
1290
|
-
for (let index = 1; index < raw.length - 1; index += 1) {
|
|
1291
|
-
const char = raw[index];
|
|
1292
|
-
if (char === "\\" && index + 1 < raw.length - 1) {
|
|
1293
|
-
value += raw[index + 1];
|
|
1294
|
-
index += 1;
|
|
1295
|
-
continue;
|
|
1296
|
-
}
|
|
1297
|
-
value += char;
|
|
1298
|
-
}
|
|
1299
|
-
return value;
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
return raw;
|
|
1303
|
-
}
|
|
1304
|
-
function parseSandboxMeta(meta) {
|
|
1305
|
-
if (!meta) {
|
|
1306
|
-
return { enabled: false, options: {} };
|
|
1307
|
-
}
|
|
1308
|
-
const tokens = tokenizeMeta(meta);
|
|
1309
|
-
let enabled = false;
|
|
1310
|
-
const options = {};
|
|
1311
|
-
for (const token of tokens) {
|
|
1312
|
-
const equalsIndex = token.indexOf("=");
|
|
1313
|
-
if (equalsIndex === -1) {
|
|
1314
|
-
if (token === "sandbox") {
|
|
1315
|
-
enabled = true;
|
|
1316
|
-
}
|
|
1317
|
-
continue;
|
|
1318
|
-
}
|
|
1319
|
-
const key = token.slice(0, equalsIndex);
|
|
1320
|
-
const value = parseMetaValue(token.slice(equalsIndex + 1));
|
|
1321
|
-
if (key === "title") {
|
|
1322
|
-
options.title = value;
|
|
1323
|
-
continue;
|
|
1324
|
-
}
|
|
1325
|
-
if (key === "sideAnnotation") {
|
|
1326
|
-
const parsed = parseBoolean(value);
|
|
1327
|
-
if (parsed !== void 0) {
|
|
1328
|
-
options.sideAnnotation = parsed;
|
|
1329
|
-
}
|
|
1330
|
-
continue;
|
|
1331
|
-
}
|
|
1332
|
-
if (key === "math") {
|
|
1333
|
-
const parsed = parseBoolean(value);
|
|
1334
|
-
if (parsed !== void 0) {
|
|
1335
|
-
options.math = parsed;
|
|
1336
|
-
}
|
|
1337
|
-
continue;
|
|
1338
|
-
}
|
|
1339
|
-
if (key === "collapsed") {
|
|
1340
|
-
const parsed = parseBoolean(value);
|
|
1341
|
-
if (parsed !== void 0) {
|
|
1342
|
-
options.collapsed = parsed;
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
return { enabled, options };
|
|
1347
|
-
}
|
|
1348
|
-
function getOpeningFenceTicks(sourceLines, startLine) {
|
|
1349
|
-
if (!startLine || startLine < 1 || startLine > sourceLines.length) {
|
|
1350
|
-
return 0;
|
|
1351
|
-
}
|
|
1352
|
-
const line = sourceLines[startLine - 1] ?? "";
|
|
1353
|
-
const match = line.match(/^\s*(`{3,})/);
|
|
1354
|
-
return match ? match[1].length : 0;
|
|
1355
|
-
}
|
|
1356
|
-
function buildFallbackHtml(source, sandboxId, title, errorMessage) {
|
|
1357
|
-
const safeTitle = title ? `<div class="${SANDBOX_ROOT_CLASS}__title">${escapeHtml(title)}</div>` : "";
|
|
1358
|
-
return [
|
|
1359
|
-
`<section class="${SANDBOX_ROOT_CLASS} ${SANDBOX_ROOT_CLASS}--error" data-owo-sandbox-id="${sandboxId}" data-owo-sandbox-state="error">`,
|
|
1360
|
-
`<header class="${SANDBOX_ROOT_CLASS}__header">${safeTitle}<div class="${SANDBOX_ROOT_CLASS}__status">Sandbox render failed</div></header>`,
|
|
1361
|
-
`<div class="${SANDBOX_BODY_CLASS}">`,
|
|
1362
|
-
`<p class="${SANDBOX_ROOT_CLASS}__error-message">${escapeHtml(errorMessage)}</p>`,
|
|
1363
|
-
`<pre class="${SANDBOX_ROOT_CLASS}__source"><code>${escapeHtml(source)}</code></pre>`,
|
|
1364
|
-
"</div>",
|
|
1365
|
-
"</section>"
|
|
1366
|
-
].join("");
|
|
1367
|
-
}
|
|
1368
|
-
function buildSuccessHtml(source, renderedHtml, sandboxId, meta) {
|
|
1369
|
-
const title = meta.title ? `<div class="${SANDBOX_ROOT_CLASS}__title">${escapeHtml(meta.title)}</div>` : "";
|
|
1370
|
-
const sourcePanel = [
|
|
1371
|
-
`<details class="${SANDBOX_ROOT_CLASS}__source-panel">`,
|
|
1372
|
-
"<summary>Source</summary>",
|
|
1373
|
-
`<pre class="${SANDBOX_ROOT_CLASS}__source"><code>${escapeHtml(source)}</code></pre>`,
|
|
1374
|
-
"</details>"
|
|
1375
|
-
].join("");
|
|
1376
|
-
const body = `<div class="${SANDBOX_BODY_CLASS}">${renderedHtml}</div>`;
|
|
1377
|
-
if (meta.collapsed) {
|
|
1378
|
-
return [
|
|
1379
|
-
`<section class="${SANDBOX_ROOT_CLASS}" data-owo-sandbox-id="${sandboxId}" data-owo-sandbox-state="ready">`,
|
|
1380
|
-
`<details class="${SANDBOX_ROOT_CLASS}__details">`,
|
|
1381
|
-
`<summary class="${SANDBOX_ROOT_CLASS}__header">${title}<div class="${SANDBOX_ROOT_CLASS}__status">Sandbox</div></summary>`,
|
|
1382
|
-
body,
|
|
1383
|
-
sourcePanel,
|
|
1384
|
-
"</details>",
|
|
1385
|
-
"</section>"
|
|
1386
|
-
].join("");
|
|
1387
|
-
}
|
|
1388
|
-
return [
|
|
1389
|
-
`<section class="${SANDBOX_ROOT_CLASS}" data-owo-sandbox-id="${sandboxId}" data-owo-sandbox-state="ready">`,
|
|
1390
|
-
`<header class="${SANDBOX_ROOT_CLASS}__header">${title}<div class="${SANDBOX_ROOT_CLASS}__status">Sandbox</div></header>`,
|
|
1391
|
-
body,
|
|
1392
|
-
sourcePanel,
|
|
1393
|
-
"</section>"
|
|
1394
|
-
].join("");
|
|
1395
|
-
}
|
|
1396
|
-
function visitRehype(node, visitor) {
|
|
1397
|
-
if (!node) {
|
|
1398
|
-
return;
|
|
1399
|
-
}
|
|
1400
|
-
visitor(node);
|
|
1401
|
-
if (!Array.isArray(node.children)) {
|
|
1402
|
-
return;
|
|
1403
|
-
}
|
|
1404
|
-
for (const child of node.children) {
|
|
1405
|
-
visitRehype(child, visitor);
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
function namespaceIds(prefix) {
|
|
1409
|
-
return function rehypeNamespaceIds() {
|
|
1410
|
-
return function transform2(tree) {
|
|
1411
|
-
visitRehype(tree, (node) => {
|
|
1412
|
-
const properties = node.properties;
|
|
1413
|
-
if (!properties) {
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
const id = properties.id;
|
|
1417
|
-
if (typeof id === "string" && id.length > 0) {
|
|
1418
|
-
properties.id = `${prefix}${id}`;
|
|
1419
|
-
}
|
|
1420
|
-
const href = properties.href;
|
|
1421
|
-
if (typeof href === "string" && href.startsWith("#") && href.length > 1) {
|
|
1422
|
-
properties.href = `#${prefix}${href.slice(1)}`;
|
|
1423
|
-
}
|
|
1424
|
-
});
|
|
1425
|
-
};
|
|
1426
|
-
};
|
|
1427
|
-
}
|
|
1428
|
-
function stripSourceLineAnchors() {
|
|
1429
|
-
return function rehypeStripSourceLineAnchors() {
|
|
1430
|
-
return function transform2(tree) {
|
|
1431
|
-
visitRehype(tree, (node) => {
|
|
1432
|
-
const properties = node.properties;
|
|
1433
|
-
if (!properties) {
|
|
1434
|
-
return;
|
|
1435
|
-
}
|
|
1436
|
-
delete properties["data-source-line-start"];
|
|
1437
|
-
delete properties["data-source-line-end"];
|
|
1438
|
-
delete properties["data-block-id"];
|
|
1439
|
-
});
|
|
1440
|
-
};
|
|
1441
|
-
};
|
|
1442
|
-
}
|
|
1443
|
-
async function transformChildren(node, sourceLines, options, sandboxCount) {
|
|
1444
|
-
if (!Array.isArray(node.children)) {
|
|
1445
|
-
return;
|
|
1446
|
-
}
|
|
1447
|
-
for (let index = 0; index < node.children.length; index += 1) {
|
|
1448
|
-
const child = node.children[index];
|
|
1449
|
-
if (child.type === "code") {
|
|
1450
|
-
const codeNode = child;
|
|
1451
|
-
const meta = parseSandboxMeta(codeNode.meta);
|
|
1452
|
-
const minOuterFenceTicks = Math.max(
|
|
1453
|
-
4,
|
|
1454
|
-
options.processorOptions.markdownSandbox?.outerFenceTicks ?? DEFAULT_OUTER_FENCE_TICKS
|
|
1455
|
-
);
|
|
1456
|
-
const actualTicks = getOpeningFenceTicks(sourceLines, codeNode.position?.start?.line);
|
|
1457
|
-
const isTopLevelSandbox = (options.processorOptions.markdownSandbox?.nestingDepth ?? 0) === 0;
|
|
1458
|
-
if (options.processorOptions.enableMarkdownSandbox !== false && isTopLevelSandbox && codeNode.lang === "markdown" && meta.enabled && actualTicks >= minOuterFenceTicks) {
|
|
1459
|
-
sandboxCount.value += 1;
|
|
1460
|
-
const sandboxId = createSandboxId(codeNode.position?.start?.line, sandboxCount.value - 1);
|
|
1461
|
-
const nestedProcessor = options.createProcessor({
|
|
1462
|
-
...options.processorOptions,
|
|
1463
|
-
enableMarkdownSandbox: false,
|
|
1464
|
-
enableSideAnnotation: meta.options.sideAnnotation ?? options.processorOptions.enableSideAnnotation,
|
|
1465
|
-
enableMath: meta.options.math ?? options.processorOptions.enableMath,
|
|
1466
|
-
markdownSandbox: {
|
|
1467
|
-
...options.processorOptions.markdownSandbox,
|
|
1468
|
-
nestingDepth: (options.processorOptions.markdownSandbox?.nestingDepth ?? 0) + 1
|
|
1469
|
-
},
|
|
1470
|
-
extraRehypePlugins: [
|
|
1471
|
-
...options.processorOptions.extraRehypePlugins ?? [],
|
|
1472
|
-
namespaceIds(`owo-sb-${sandboxId}-`),
|
|
1473
|
-
stripSourceLineAnchors()
|
|
1474
|
-
]
|
|
1475
|
-
});
|
|
1476
|
-
let html;
|
|
1477
|
-
try {
|
|
1478
|
-
const result = await nestedProcessor.process(codeNode.value);
|
|
1479
|
-
html = buildSuccessHtml(codeNode.value, result.toString(), sandboxId, meta.options);
|
|
1480
|
-
} catch (error) {
|
|
1481
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1482
|
-
html = buildFallbackHtml(codeNode.value, sandboxId, meta.options.title, message);
|
|
1483
|
-
}
|
|
1484
|
-
node.children[index] = {
|
|
1485
|
-
type: "markdownSandbox",
|
|
1486
|
-
value: codeNode.value,
|
|
1487
|
-
data: { html }
|
|
1488
|
-
};
|
|
1489
|
-
continue;
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
if (child && typeof child === "object") {
|
|
1493
|
-
await transformChildren(child, sourceLines, options, sandboxCount);
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
function remarkMarkdownSandbox(options) {
|
|
1498
|
-
return async function transform2(tree, file) {
|
|
1499
|
-
const source = String(file);
|
|
1500
|
-
const sourceLines = source.split(/\r?\n/);
|
|
1501
|
-
await transformChildren(tree, sourceLines, options, { value: 0 });
|
|
1502
|
-
};
|
|
1503
|
-
}
|
|
1504
|
-
function markdownSandboxHandler(_state, node) {
|
|
1505
|
-
return {
|
|
1506
|
-
type: "raw",
|
|
1507
|
-
value: node.data?.html ?? ""
|
|
1508
|
-
};
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
// src/processor/index.ts
|
|
1512
|
-
var DEFAULT_CODE_THEME = "vitesse-light";
|
|
1513
|
-
function buildRemarkPlugins(options) {
|
|
1514
|
-
const enableMath = options.enableMath !== false;
|
|
1515
|
-
const enableSideAnnotation = options.enableSideAnnotation !== false;
|
|
1516
|
-
const enableMarkdownSandbox = options.enableMarkdownSandbox !== false;
|
|
1517
|
-
const plugins = [
|
|
1518
|
-
remarkParse,
|
|
1519
|
-
remarkGfm
|
|
1520
|
-
];
|
|
1521
|
-
if (enableMath) {
|
|
1522
|
-
plugins.push(remarkMath);
|
|
1523
|
-
plugins.push(remarkNormalizeStandaloneMath);
|
|
1524
|
-
}
|
|
1525
|
-
plugins.push(remarkDirective);
|
|
1526
|
-
if (options.mode !== "preview") {
|
|
1527
|
-
if (enableSideAnnotation) {
|
|
1528
|
-
plugins.push(remarkMicromarkSideAnnotation);
|
|
1529
|
-
}
|
|
1530
|
-
plugins.push(remarkMdx);
|
|
1531
|
-
}
|
|
1532
|
-
if (!options.preserveSoftLineBreaks) {
|
|
1533
|
-
plugins.push(remarkConvertSoftBreaksToHardBreaks);
|
|
1534
|
-
}
|
|
1535
|
-
if (enableSideAnnotation) {
|
|
1536
|
-
plugins.push(remarkSideAnnotation);
|
|
1537
|
-
}
|
|
1538
|
-
if (enableMarkdownSandbox) {
|
|
1539
|
-
plugins.push([remarkMarkdownSandbox, {
|
|
1540
|
-
processorOptions: options,
|
|
1541
|
-
createProcessor: createOwoMarkProcessor
|
|
1542
|
-
}]);
|
|
1543
|
-
}
|
|
1544
|
-
if (options.extraRemarkPlugins) {
|
|
1545
|
-
plugins.push(...options.extraRemarkPlugins);
|
|
1546
|
-
}
|
|
1547
|
-
return plugins;
|
|
1548
|
-
}
|
|
1549
|
-
function buildRehypePlugins(options) {
|
|
1550
|
-
const enableMath = options.enableMath !== false;
|
|
1551
|
-
const enableSideAnnotation = options.enableSideAnnotation !== false;
|
|
1552
|
-
const theme = options.codeTheme ?? DEFAULT_CODE_THEME;
|
|
1553
|
-
const plugins = [];
|
|
1554
|
-
if (enableMath) {
|
|
1555
|
-
plugins.push(rehypeKatex, rehypeMathDisplayFix);
|
|
1556
|
-
}
|
|
1557
|
-
plugins.push(rehypeSlug, [rehypePrettyCode, { theme }]);
|
|
1558
|
-
if (enableSideAnnotation) {
|
|
1559
|
-
plugins.push(rehypeSideAnnotation);
|
|
1560
|
-
}
|
|
1561
|
-
if (options.extraRehypePlugins) {
|
|
1562
|
-
plugins.push(...options.extraRehypePlugins);
|
|
1563
|
-
}
|
|
1564
|
-
return plugins;
|
|
1565
|
-
}
|
|
1566
|
-
function createOwoMarkProcessor(options) {
|
|
1567
|
-
const opts = {
|
|
1568
|
-
mode: "preview",
|
|
1569
|
-
preserveSoftLineBreaks: false,
|
|
1570
|
-
...options
|
|
1571
|
-
};
|
|
1572
|
-
if (opts.enableMdx) {
|
|
1573
|
-
return createMdxProcessor(opts);
|
|
1574
|
-
}
|
|
1575
|
-
return createUnifiedProcessor(opts);
|
|
1576
|
-
}
|
|
1577
|
-
function createUnifiedProcessor(opts) {
|
|
1578
|
-
const remarkPlugins = buildRemarkPlugins(opts);
|
|
1579
|
-
const rehypePlugins = buildRehypePlugins(opts);
|
|
1580
|
-
let proc = unified();
|
|
1581
|
-
for (const plugin of remarkPlugins) {
|
|
1582
|
-
proc = applyPlugin(proc, plugin);
|
|
1583
|
-
}
|
|
1584
|
-
proc = proc.use(remarkRehype, {
|
|
1585
|
-
handlers: {
|
|
1586
|
-
markdownSandbox: markdownSandboxHandler
|
|
1587
|
-
}
|
|
1588
|
-
});
|
|
1589
|
-
for (const plugin of rehypePlugins) {
|
|
1590
|
-
proc = applyPlugin(proc, plugin);
|
|
1591
|
-
}
|
|
1592
|
-
proc = proc.use(rehypeStringify, { allowDangerousHtml: true });
|
|
1593
|
-
return {
|
|
1594
|
-
async process(source) {
|
|
1595
|
-
const result = await proc.process(source);
|
|
1596
|
-
return { value: String(result), toString: () => String(result) };
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
}
|
|
1600
|
-
var FENCED_CODE_RE = /^```[\s\S]*?^```/gm;
|
|
1601
|
-
var INLINE_CODE_RE = /`[^`]+`/g;
|
|
1602
|
-
var JSX_TAG_RE = /<([A-Z][A-Za-z0-9]*)/g;
|
|
1603
|
-
function extractComponentNames(source) {
|
|
1604
|
-
const stripped = source.replace(FENCED_CODE_RE, "").replace(INLINE_CODE_RE, "");
|
|
1605
|
-
const names = /* @__PURE__ */ new Set();
|
|
1606
|
-
let match;
|
|
1607
|
-
while ((match = JSX_TAG_RE.exec(stripped)) !== null) {
|
|
1608
|
-
names.add(match[1]);
|
|
1609
|
-
}
|
|
1610
|
-
return names;
|
|
1611
|
-
}
|
|
1612
|
-
function createMdxProcessor(opts) {
|
|
1613
|
-
const { remarkPlugins, rehypePlugins } = getOwoMarkPlugins({ ...opts, mode: "production" });
|
|
1614
|
-
const registeredComponents = { ...DEFAULT_MDX_COMPONENTS, ...opts.mdxComponents };
|
|
1615
|
-
let _evaluate;
|
|
1616
|
-
let _renderToStaticMarkup;
|
|
1617
|
-
let _jsxRuntime;
|
|
1618
|
-
let _react;
|
|
1619
|
-
async function ensureImports() {
|
|
1620
|
-
if (!_evaluate) {
|
|
1621
|
-
const [mdx, runtime, reactDom, react] = await Promise.all([
|
|
1622
|
-
import("@mdx-js/mdx"),
|
|
1623
|
-
import("react/jsx-runtime"),
|
|
1624
|
-
import("react-dom/server"),
|
|
1625
|
-
import("react")
|
|
1626
|
-
]);
|
|
1627
|
-
_evaluate = mdx.evaluate;
|
|
1628
|
-
_jsxRuntime = runtime;
|
|
1629
|
-
_renderToStaticMarkup = reactDom.renderToStaticMarkup;
|
|
1630
|
-
_react = react;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
return {
|
|
1634
|
-
async process(source) {
|
|
1635
|
-
await ensureImports();
|
|
1636
|
-
const usedNames = extractComponentNames(source);
|
|
1637
|
-
const componentMap = { ...registeredComponents };
|
|
1638
|
-
for (const name of usedNames) {
|
|
1639
|
-
if (!(name in componentMap)) {
|
|
1640
|
-
console.warn(`[owomark-mdx] Unregistered MDX component: <${name}>`);
|
|
1641
|
-
componentMap[name] = (props) => _react.createElement("div", { "data-mdx-missing": name }, props.children);
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
const { default: Content } = await _evaluate(source, {
|
|
1645
|
-
..._jsxRuntime,
|
|
1646
|
-
remarkPlugins,
|
|
1647
|
-
rehypePlugins
|
|
1648
|
-
});
|
|
1649
|
-
const html = _renderToStaticMarkup(
|
|
1650
|
-
_react.createElement(Content, { components: componentMap })
|
|
1651
|
-
);
|
|
1652
|
-
return { value: html, toString: () => html };
|
|
1653
|
-
}
|
|
1654
|
-
};
|
|
1655
|
-
}
|
|
1656
|
-
function applyPlugin(proc, entry) {
|
|
1657
|
-
if (Array.isArray(entry)) {
|
|
1658
|
-
const [plugin, ...args] = entry;
|
|
1659
|
-
return proc.use(plugin, ...args);
|
|
1660
|
-
}
|
|
1661
|
-
return proc.use(entry);
|
|
1662
|
-
}
|
|
1663
|
-
var MDX_MANAGED_REMARK_PLUGINS = /* @__PURE__ */ new Set([remarkParse, remarkMdx]);
|
|
1664
|
-
function getOwoMarkPlugins(options) {
|
|
1665
|
-
const opts = {
|
|
1666
|
-
mode: "production",
|
|
1667
|
-
preserveSoftLineBreaks: false,
|
|
1668
|
-
...options
|
|
1669
|
-
};
|
|
1670
|
-
const remarkPlugins = buildRemarkPlugins(opts).filter(
|
|
1671
|
-
(entry) => !MDX_MANAGED_REMARK_PLUGINS.has(entry)
|
|
1672
|
-
);
|
|
1673
|
-
const rehypePlugins = buildRehypePlugins(opts);
|
|
1674
|
-
return { remarkPlugins, rehypePlugins };
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
// src/theme.ts
|
|
1678
|
-
var THEME_LIGHT_CLASS = "owo-theme-light";
|
|
1679
|
-
var THEME_DARK_CLASS = "owo-theme-dark";
|
|
1680
|
-
function getThemeClassName(theme) {
|
|
1681
|
-
switch (theme) {
|
|
1682
|
-
case "light":
|
|
1683
|
-
return THEME_LIGHT_CLASS;
|
|
1684
|
-
case "dark":
|
|
1685
|
-
return THEME_DARK_CLASS;
|
|
1686
|
-
default:
|
|
1687
|
-
return theme;
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
export {
|
|
1692
|
-
rehypeMathDisplayFix,
|
|
1693
|
-
remarkConvertSoftBreaksToHardBreaks,
|
|
1694
|
-
remarkSideAnnotation,
|
|
1695
|
-
rehypeSideAnnotation,
|
|
1696
|
-
Callout,
|
|
1697
|
-
CodeDemo,
|
|
1698
|
-
Steps,
|
|
1699
|
-
Step,
|
|
1700
|
-
Tabs,
|
|
1701
|
-
Tab,
|
|
1702
|
-
FileTree,
|
|
1703
|
-
Kbd,
|
|
1704
|
-
DEFAULT_MDX_COMPONENTS,
|
|
1705
|
-
createOwoMarkProcessor,
|
|
1706
|
-
getOwoMarkPlugins,
|
|
1707
|
-
THEME_LIGHT_CLASS,
|
|
1708
|
-
THEME_DARK_CLASS,
|
|
1709
|
-
getThemeClassName
|
|
1710
|
-
};
|