vde-open 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 +57 -55
- package/dist/cli.js +2 -2
- package/dist/daemon.js +2 -2
- package/dist/{main-DlLPjYZZ.js → main-C3SHFgNa.js} +489 -12
- package/dist/print-CR5-GDjQ.js +1779 -0
- package/dist/render-BJnuEfHt.js +6235 -0
- package/dist/{render-BNZz0CjQ.js → rendering-rules-DiE2jI7I.js} +39 -6243
- package/dist/{search-index-__laOomT.js → search-index-B7DqaWh6.js} +10 -0
- package/dist/web/assets/index-BsWikuUv.js +97 -0
- package/dist/web/index.html +1 -1
- package/dist/workers/parse-worker.js +10 -4
- package/dist/workers/search-worker.js +1 -1
- package/docs/agent-usage.md +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-BoCe8U41.js +0 -97
|
@@ -0,0 +1,1779 @@
|
|
|
1
|
+
import { D as escapeAttr, E as parseMarkdown, O as escapeHtml$2, k as footnoteReferenceId, n as renderedLinkOf, p as parseMarkdownDocument, r as MARKDOWN_PARSE_OPTIONS, t as localImagePath } from "./rendering-rules-DiE2jI7I.js";
|
|
2
|
+
//#region ../../node_modules/.pnpm/@tanstack+markdown@1.0.0_react@19.3.0/node_modules/@tanstack/markdown/dist/html.js
|
|
3
|
+
function renderHtml(input, options = {}) {
|
|
4
|
+
return (typeof input === "string" ? parseMarkdown(input, options) : input).children.map((node) => renderBlock(node, options)).join("\n");
|
|
5
|
+
}
|
|
6
|
+
function renderBlock(node, options = {}) {
|
|
7
|
+
const extension = renderExtension(node, options);
|
|
8
|
+
if (extension !== void 0) return extension;
|
|
9
|
+
switch (node.type) {
|
|
10
|
+
case "heading": {
|
|
11
|
+
const id = node.id ? ` id="${escapeAttr(node.id)}"` : "";
|
|
12
|
+
const framework = node.framework ? ` data-framework="${escapeAttr(node.framework)}"` : "";
|
|
13
|
+
return `<h${node.depth}${id}${framework}>${renderInlines(node.children, options)}${renderHeadingAnchor(node.id, options)}</h${node.depth}>`;
|
|
14
|
+
}
|
|
15
|
+
case "paragraph": return `<p>${renderInlines(node.children, options)}</p>`;
|
|
16
|
+
case "code": return renderCodeBlock(node, options);
|
|
17
|
+
case "list": {
|
|
18
|
+
const tag = node.ordered ? "ol" : "ul";
|
|
19
|
+
return `<${tag}${node.ordered && node.start !== void 0 && node.start !== 1 ? ` start="${node.start}"` : ""}>\n${node.items.map((item) => `<li>${renderListItemChildren(item.children, item.checked, node.loose, options)}</li>`).join("\n")}\n</${tag}>`;
|
|
20
|
+
}
|
|
21
|
+
case "blockquote": return `<blockquote>\n${node.children.map((child) => renderBlock(child, options)).join("\n")}\n</blockquote>`;
|
|
22
|
+
case "table": return `<table>${`<thead><tr>${node.header.map((cell, index) => renderTableCell("th", cell, node.align[index], options)).join("")}</tr></thead>`}${node.rows.length ? `<tbody>${node.rows.map((row) => `<tr>${row.map((cell, index) => renderTableCell("td", cell, node.align[index], options)).join("")}</tr>`).join("")}</tbody>` : ""}</table>`;
|
|
23
|
+
case "footnotes": return renderFootnotes(node.items, options);
|
|
24
|
+
case "thematicBreak": return "<hr>";
|
|
25
|
+
case "html": return options.allowHtml ? node.value : escapeHtml$2(node.value);
|
|
26
|
+
case "callout": return renderCallout(node, options);
|
|
27
|
+
case "component": return renderComponent(node, options);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function renderInline(node, options = {}) {
|
|
31
|
+
const extension = renderExtension(node, options);
|
|
32
|
+
if (extension !== void 0) return extension;
|
|
33
|
+
switch (node.type) {
|
|
34
|
+
case "text": return escapeHtml$2(node.value);
|
|
35
|
+
case "inlineCode": return `<code>${escapeHtml$2(node.value)}</code>`;
|
|
36
|
+
case "strong": return `<strong>${renderInlines(node.children, options)}</strong>`;
|
|
37
|
+
case "emphasis": return `<em>${renderInlines(node.children, options)}</em>`;
|
|
38
|
+
case "strike": return `<del>${renderInlines(node.children, options)}</del>`;
|
|
39
|
+
case "footnoteReference": return `<sup><a id="user-content-fnref-${escapeAttr(footnoteReferenceId(node.id, node.referenceIndex))}" data-footnote-ref="" aria-describedby="footnote-label" href="#user-content-fn-${escapeAttr(node.id)}">${node.number}</a></sup>`;
|
|
40
|
+
case "link": return `<a href="${escapeAttr(node.href)}"${node.title ? ` title="${escapeAttr(node.title)}"` : ""}>${renderInlines(node.children, options)}</a>`;
|
|
41
|
+
case "image": return `<img src="${escapeAttr(node.src)}" alt="${escapeAttr(node.alt)}"${node.title ? ` title="${escapeAttr(node.title)}"` : ""}>`;
|
|
42
|
+
case "break": return "<br>";
|
|
43
|
+
case "inlineHtml": return options.allowHtml ? node.value : escapeHtml$2(node.value);
|
|
44
|
+
case "inlineComponent": return renderComponent(node, options);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function renderDocument(document, options = {}) {
|
|
48
|
+
return renderHtml(document, options);
|
|
49
|
+
}
|
|
50
|
+
function renderInlines(nodes, options) {
|
|
51
|
+
return nodes.map((node) => renderInline(node, options)).join("");
|
|
52
|
+
}
|
|
53
|
+
function renderCodeBlock(node, options) {
|
|
54
|
+
const lang = node.lang ?? "plaintext";
|
|
55
|
+
const preAttrs = `class="tm-code${options.codeLineNumbers ? " tm-code--line-numbers" : ""}" data-lang="${escapeAttr(lang)}"` + (node.meta ? ` data-meta="${escapeAttr(node.meta)}"` : "") + (node.title ? ` data-code-title="${escapeAttr(node.title)}"` : "") + (node.file ? ` data-filename="${escapeAttr(node.file)}"` : "") + (node.framework ? ` data-framework="${escapeAttr(node.framework)}"` : "");
|
|
56
|
+
const html = options.highlighter?.(node.value, lang, {
|
|
57
|
+
...node.meta && { meta: node.meta },
|
|
58
|
+
...node.highlightLines && { highlightLines: node.highlightLines },
|
|
59
|
+
...options.codeLineNumbers !== void 0 && { lineNumbers: options.codeLineNumbers }
|
|
60
|
+
}) ?? escapeHtml$2(node.value);
|
|
61
|
+
const pre = `<pre ${preAttrs}><code class="language-${escapeAttr(lang)}">${html}</code></pre>`;
|
|
62
|
+
if (!node.title) return pre;
|
|
63
|
+
return `<figure class="tm-code-frame" data-lang="${escapeAttr(lang)}"><figcaption>${escapeHtml$2(node.title)}</figcaption>${pre}</figure>`;
|
|
64
|
+
}
|
|
65
|
+
function renderListItemChildren(children, checked, loose, options) {
|
|
66
|
+
let result = checked === void 0 ? "" : `<input type="checkbox" disabled${checked ? " checked" : ""}> `;
|
|
67
|
+
for (let index = 0; index < children.length; index++) {
|
|
68
|
+
const child = children[index];
|
|
69
|
+
if (child.type === "paragraph" && (!loose || index === 0)) {
|
|
70
|
+
result += renderInlines(child.children, options);
|
|
71
|
+
if (loose) result = `<p>${result}</p>`;
|
|
72
|
+
} else result += (index ? "\n" : "") + renderBlock(child, options);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function renderCallout(node, options) {
|
|
77
|
+
const kind = node.kind.toLowerCase();
|
|
78
|
+
const children = node.children.map((child) => renderBlock(child, options)).join("\n");
|
|
79
|
+
return `<div class="markdown-alert markdown-alert-${escapeAttr(kind)}"><p class="markdown-alert-title">${escapeHtml$2(node.title)}</p><div class="markdown-alert-content">${children}</div></div>`;
|
|
80
|
+
}
|
|
81
|
+
function renderFootnotes(items, options) {
|
|
82
|
+
const renderedItems = items.map((item) => `<li id="user-content-fn-${escapeAttr(item.id)}">\n${renderFootnoteItem(item, options)}\n</li>`).join("\n");
|
|
83
|
+
return `<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes${renderHeadingAnchor("footnote-label", options)}</h2>\n<ol>\n${renderedItems}\n</ol>\n</section>`;
|
|
84
|
+
}
|
|
85
|
+
function renderFootnoteItem(item, options) {
|
|
86
|
+
const backref = renderFootnoteBackrefs(item);
|
|
87
|
+
const lastIndex = item.children.length - 1;
|
|
88
|
+
const result = item.children.map((child, index) => {
|
|
89
|
+
if (index === lastIndex && child.type === "paragraph") return `<p>${renderInlines(child.children, options)}${backref}</p>`;
|
|
90
|
+
return renderBlock(child, options);
|
|
91
|
+
});
|
|
92
|
+
if (item.children[lastIndex]?.type !== "paragraph") result.push(`<p>${backref.trimStart()}</p>`);
|
|
93
|
+
return result.join("\n");
|
|
94
|
+
}
|
|
95
|
+
function renderFootnoteBackrefs(item) {
|
|
96
|
+
let result = "";
|
|
97
|
+
for (let index = 1; index <= (item.referenceCount ?? 1); index++) {
|
|
98
|
+
const referenceId = footnoteReferenceId(item.id, index);
|
|
99
|
+
const label = index === 1 ? `${item.number}` : `${item.number}-${index}`;
|
|
100
|
+
result += ` <a data-footnote-backref="" aria-label="Back to reference ${label}" class="data-footnote-backref" href="#user-content-fnref-${escapeAttr(referenceId)}">↩</a>`;
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
function renderComponent(node, options) {
|
|
105
|
+
const tag = node.tagName ?? (node.type === "inlineComponent" ? "span" : "md-comment-component");
|
|
106
|
+
return `<${tag}${renderComponentAttrs(node)}>${node.type === "inlineComponent" ? renderInlines(node.children, options) : node.children.map((child) => renderBlock(child, options)).join("\n")}</${tag}>`;
|
|
107
|
+
}
|
|
108
|
+
function renderTableCell(tag, cell, align, options) {
|
|
109
|
+
return `<${tag}${align ? ` style="text-align:${align}"` : ""}>${renderInlines(cell.children, options)}</${tag}>`;
|
|
110
|
+
}
|
|
111
|
+
function renderExtension(node, options) {
|
|
112
|
+
for (const extension of options.extensions ?? []) {
|
|
113
|
+
const rendered = extension.renderHtml?.(node, {
|
|
114
|
+
options,
|
|
115
|
+
renderBlock: (block) => renderBlock(block, options),
|
|
116
|
+
renderInline: (inline) => renderInline(inline, options)
|
|
117
|
+
});
|
|
118
|
+
if (rendered !== void 0) return rendered;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function renderHeadingAnchor(id, options) {
|
|
122
|
+
const headingAnchors = options.headingAnchors;
|
|
123
|
+
if (!id || !headingAnchors) return "";
|
|
124
|
+
const anchorOptions = typeof headingAnchors === "object" ? headingAnchors : {};
|
|
125
|
+
return `<a href="#${escapeAttr(id)}" aria-hidden="${anchorOptions.ariaHidden ?? true}" class="${escapeAttr(anchorOptions.className ?? "anchor-heading anchor-heading-link")}" tabindex="${anchorOptions.tabIndex ?? -1}">${escapeHtml$2(anchorOptions.content ?? "#")}</a>`;
|
|
126
|
+
}
|
|
127
|
+
function renderComponentAttrs(node) {
|
|
128
|
+
const props = { ...node.properties };
|
|
129
|
+
if (!node.tagName) {
|
|
130
|
+
props["data-component"] = node.name;
|
|
131
|
+
if (!props["data-attributes"]) props["data-attributes"] = JSON.stringify(node.attributes);
|
|
132
|
+
}
|
|
133
|
+
return Object.entries(props).map(([key, value]) => ` ${key}="${escapeAttr(value)}"`).join("");
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js
|
|
137
|
+
function defineLanguage(definition) {
|
|
138
|
+
return definition;
|
|
139
|
+
}
|
|
140
|
+
function createHighlighter({ fallbackLanguage = "plaintext", languages }) {
|
|
141
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
142
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
143
|
+
for (const definition of languages) {
|
|
144
|
+
const name = normalizeName(definition.name);
|
|
145
|
+
definitions.set(name, definition);
|
|
146
|
+
aliases.set(name, name);
|
|
147
|
+
for (const alias of definition.aliases || []) aliases.set(normalizeName(alias), name);
|
|
148
|
+
}
|
|
149
|
+
const fallback = normalizeName(fallbackLanguage);
|
|
150
|
+
function normalizeLanguage(lang) {
|
|
151
|
+
return aliases.get(normalizeName(lang || fallback)) || fallback;
|
|
152
|
+
}
|
|
153
|
+
function tokenizeRanges(code, lang, depth = 0) {
|
|
154
|
+
const definition = definitions.get(normalizeLanguage(lang));
|
|
155
|
+
if (!definition || depth > 24) return [];
|
|
156
|
+
return normalizeTokenRanges(code.length, definition.tokenize(code, {
|
|
157
|
+
hasLanguage(candidate) {
|
|
158
|
+
const resolved = aliases.get(normalizeName(candidate));
|
|
159
|
+
return Boolean(resolved && definitions.has(resolved));
|
|
160
|
+
},
|
|
161
|
+
tokenize(embeddedCode, embeddedLanguage) {
|
|
162
|
+
return tokenizeRanges(embeddedCode, embeddedLanguage, depth + 1);
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
function tokenize(code, options = {}) {
|
|
167
|
+
const lang = normalizeLanguage(options.lang);
|
|
168
|
+
const ranges = tokenizeRanges(code, lang);
|
|
169
|
+
return {
|
|
170
|
+
code,
|
|
171
|
+
lang,
|
|
172
|
+
tokens: ranges.length ? rangesToTokens(code, ranges) : [{ value: code }]
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function highlight(code, options = {}) {
|
|
176
|
+
const result = tokenize(code, options);
|
|
177
|
+
const innerHtml = renderNodesToHtml(renderTokens(result.tokens, options));
|
|
178
|
+
return {
|
|
179
|
+
...result,
|
|
180
|
+
html: `<pre class="th-code th-code--${escapeHtml$1(result.lang)}${options.lineNumbers ? " th-code--line-numbers" : ""}" data-language="${escapeHtml$1(result.lang)}"><code>${innerHtml}</code></pre>`
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function renderCodeBlockData({ code, decorations, lang, lineNumbers, title }) {
|
|
184
|
+
const copyText = code.trimEnd();
|
|
185
|
+
const result = highlight(copyText, {
|
|
186
|
+
decorations,
|
|
187
|
+
lang,
|
|
188
|
+
lineNumbers
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
copyText,
|
|
192
|
+
htmlMarkup: result.html,
|
|
193
|
+
lang: result.lang,
|
|
194
|
+
title,
|
|
195
|
+
tokens: result.tokens
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
highlight,
|
|
200
|
+
highlightToHtml(code, options = {}) {
|
|
201
|
+
return highlight(code, options).html;
|
|
202
|
+
},
|
|
203
|
+
listLanguages() {
|
|
204
|
+
return [...definitions.keys()];
|
|
205
|
+
},
|
|
206
|
+
normalizeLanguage,
|
|
207
|
+
renderCodeBlockData,
|
|
208
|
+
tokenize
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function renderTokens(tokens, options = {}) {
|
|
212
|
+
const rangeDecorations = [];
|
|
213
|
+
const lineDecorations = [];
|
|
214
|
+
for (const decoration of options.decorations || []) if (decoration.range) rangeDecorations.push(decoration);
|
|
215
|
+
else lineDecorations.push(decoration);
|
|
216
|
+
const wrapLines = Boolean(options.lineNumbers || lineDecorations.length);
|
|
217
|
+
const cursor = {
|
|
218
|
+
index: 0,
|
|
219
|
+
offset: 0
|
|
220
|
+
};
|
|
221
|
+
if (!wrapLines) return renderTokenSlice(tokens, 0, Infinity, rangeDecorations, cursor);
|
|
222
|
+
const code = tokens.map((token) => token.value).join("");
|
|
223
|
+
const nodes = [];
|
|
224
|
+
const lineStarts = getLineStarts(code);
|
|
225
|
+
for (let index = 0; index < lineStarts.length; index++) {
|
|
226
|
+
const line = index + 1;
|
|
227
|
+
const start = lineStarts[index];
|
|
228
|
+
const nextStart = lineStarts[index + 1] ?? code.length;
|
|
229
|
+
const hasNewline = nextStart > start && code[nextStart - 1] === "\n";
|
|
230
|
+
const end = hasNewline ? nextStart - 1 : nextStart;
|
|
231
|
+
const active = lineDecorations.filter((decoration) => includesLine(decoration.lines, line));
|
|
232
|
+
nodes.push({
|
|
233
|
+
type: "element",
|
|
234
|
+
classNames: ["th-line", ...active.flatMap((decoration) => splitClassNames(decoration.className))],
|
|
235
|
+
data: {
|
|
236
|
+
...mergeData(active),
|
|
237
|
+
line: String(line)
|
|
238
|
+
},
|
|
239
|
+
children: renderTokenSlice(tokens, start, end, rangeDecorations, cursor)
|
|
240
|
+
});
|
|
241
|
+
if (hasNewline) nodes.push({
|
|
242
|
+
type: "text",
|
|
243
|
+
value: "\n"
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return nodes;
|
|
247
|
+
}
|
|
248
|
+
function renderNodesToHtml(nodes) {
|
|
249
|
+
let html = "";
|
|
250
|
+
for (const node of nodes) {
|
|
251
|
+
if (node.type === "text") {
|
|
252
|
+
html += escapeHtml$1(node.value);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const className = escapeHtml$1(node.classNames.join(" "));
|
|
256
|
+
let data = "";
|
|
257
|
+
if (node.data) for (const [key, value] of Object.entries(node.data)) data += ` data-${normalizeDataKey(key)}="${escapeHtml$1(value)}"`;
|
|
258
|
+
html += `<span${className ? ` class="${className}"` : ""}${data}>${renderNodesToHtml(node.children)}</span>`;
|
|
259
|
+
}
|
|
260
|
+
return html;
|
|
261
|
+
}
|
|
262
|
+
const htmlEscapes = {
|
|
263
|
+
"&": "&",
|
|
264
|
+
"<": "<",
|
|
265
|
+
">": ">",
|
|
266
|
+
"\"": """,
|
|
267
|
+
"'": "'"
|
|
268
|
+
};
|
|
269
|
+
function escapeHtml$1(value) {
|
|
270
|
+
return value.replace(/[&<>"']/g, (character) => htmlEscapes[character]);
|
|
271
|
+
}
|
|
272
|
+
function normalizeName(value) {
|
|
273
|
+
return value.trim().toLowerCase();
|
|
274
|
+
}
|
|
275
|
+
function normalizeTokenRanges(codeLength, input) {
|
|
276
|
+
const ranges = [];
|
|
277
|
+
let sorted = true;
|
|
278
|
+
let previousStart = 0;
|
|
279
|
+
for (const candidate of input) {
|
|
280
|
+
if (!Number.isInteger(candidate.start) || !Number.isInteger(candidate.end)) continue;
|
|
281
|
+
const start = Math.max(0, Math.min(codeLength, candidate.start));
|
|
282
|
+
const end = Math.max(0, Math.min(codeLength, candidate.end));
|
|
283
|
+
if (start >= end) continue;
|
|
284
|
+
if (start < previousStart) sorted = false;
|
|
285
|
+
previousStart = start;
|
|
286
|
+
ranges.push({
|
|
287
|
+
className: candidate.className,
|
|
288
|
+
start,
|
|
289
|
+
end
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
if (!sorted) ranges.sort((a, b) => a.start - b.start);
|
|
293
|
+
let end = 0;
|
|
294
|
+
let count = 0;
|
|
295
|
+
for (const candidate of ranges) {
|
|
296
|
+
if (candidate.start < end) continue;
|
|
297
|
+
ranges[count++] = candidate;
|
|
298
|
+
end = candidate.end;
|
|
299
|
+
}
|
|
300
|
+
ranges.length = count;
|
|
301
|
+
return ranges;
|
|
302
|
+
}
|
|
303
|
+
function rangesToTokens(code, ranges) {
|
|
304
|
+
const tokens = [];
|
|
305
|
+
let index = 0;
|
|
306
|
+
for (const range of ranges) {
|
|
307
|
+
if (range.start > index) tokens.push({ value: code.slice(index, range.start) });
|
|
308
|
+
tokens.push({
|
|
309
|
+
className: range.className,
|
|
310
|
+
value: code.slice(range.start, range.end)
|
|
311
|
+
});
|
|
312
|
+
index = range.end;
|
|
313
|
+
}
|
|
314
|
+
if (index < code.length) tokens.push({ value: code.slice(index) });
|
|
315
|
+
return tokens;
|
|
316
|
+
}
|
|
317
|
+
function renderTokenSlice(tokens, start, end, decorations, cursor) {
|
|
318
|
+
const nodes = [];
|
|
319
|
+
for (; cursor.index < tokens.length; cursor.index++) {
|
|
320
|
+
const token = tokens[cursor.index];
|
|
321
|
+
const tokenStart = cursor.offset;
|
|
322
|
+
const tokenEnd = tokenStart + token.value.length;
|
|
323
|
+
const sliceStart = Math.max(start, tokenStart);
|
|
324
|
+
const sliceEnd = Math.min(end, tokenEnd);
|
|
325
|
+
if (sliceStart < sliceEnd) {
|
|
326
|
+
let sorted = [sliceStart, sliceEnd];
|
|
327
|
+
if (decorations.length) {
|
|
328
|
+
const boundaries = new Set(sorted);
|
|
329
|
+
for (const decoration of decorations) {
|
|
330
|
+
const [decorationStart, decorationEnd] = decoration.range;
|
|
331
|
+
if (decorationEnd <= sliceStart || decorationStart >= sliceEnd) continue;
|
|
332
|
+
boundaries.add(Math.max(sliceStart, decorationStart));
|
|
333
|
+
boundaries.add(Math.min(sliceEnd, decorationEnd));
|
|
334
|
+
}
|
|
335
|
+
sorted = [...boundaries].sort((a, b) => a - b);
|
|
336
|
+
}
|
|
337
|
+
for (let index = 0; index < sorted.length - 1; index++) {
|
|
338
|
+
const segmentStart = sorted[index];
|
|
339
|
+
const segmentEnd = sorted[index + 1];
|
|
340
|
+
let node = {
|
|
341
|
+
type: "text",
|
|
342
|
+
value: token.value.slice(segmentStart - tokenStart, segmentEnd - tokenStart)
|
|
343
|
+
};
|
|
344
|
+
if (token.className) node = {
|
|
345
|
+
type: "element",
|
|
346
|
+
classNames: ["th-token", `th-${token.className}`],
|
|
347
|
+
children: [node]
|
|
348
|
+
};
|
|
349
|
+
for (const decoration of decorations) {
|
|
350
|
+
if (decoration.range[0] > segmentStart || decoration.range[1] < segmentEnd) continue;
|
|
351
|
+
node = {
|
|
352
|
+
type: "element",
|
|
353
|
+
classNames: ["th-decoration", ...splitClassNames(decoration.className)],
|
|
354
|
+
data: stringifyData(decoration.data),
|
|
355
|
+
children: [node]
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
nodes.push(node);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (tokenEnd > end) break;
|
|
362
|
+
cursor.offset = tokenEnd;
|
|
363
|
+
}
|
|
364
|
+
return nodes;
|
|
365
|
+
}
|
|
366
|
+
function getLineStarts(code) {
|
|
367
|
+
const starts = [0];
|
|
368
|
+
for (let index = 0; index < code.length; index++) if (code[index] === "\n" && index + 1 < code.length) starts.push(index + 1);
|
|
369
|
+
return starts;
|
|
370
|
+
}
|
|
371
|
+
function includesLine(lines, line) {
|
|
372
|
+
return typeof lines === "number" ? lines === line : line >= lines[0] && line <= lines[1];
|
|
373
|
+
}
|
|
374
|
+
function mergeData(decorations) {
|
|
375
|
+
const data = {};
|
|
376
|
+
for (const decoration of decorations) Object.assign(data, stringifyData(decoration.data));
|
|
377
|
+
return data;
|
|
378
|
+
}
|
|
379
|
+
function stringifyData(data) {
|
|
380
|
+
if (!data) return void 0;
|
|
381
|
+
return Object.fromEntries(Object.entries(data).map(([key, value]) => [normalizeDataKey(key), String(value)]));
|
|
382
|
+
}
|
|
383
|
+
function normalizeDataKey(value) {
|
|
384
|
+
return toKebabCase(value).replace(/[^a-z0-9_.:-]/gi, "-");
|
|
385
|
+
}
|
|
386
|
+
function splitClassNames(className) {
|
|
387
|
+
return className?.trim().split(/\s+/).filter(Boolean) || [];
|
|
388
|
+
}
|
|
389
|
+
function toKebabCase(value) {
|
|
390
|
+
return value.replace(/[A-Z]/g, (character) => `-${character.toLowerCase()}`);
|
|
391
|
+
}
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/patterns.js
|
|
394
|
+
function patternTokenizer(patterns) {
|
|
395
|
+
return (code) => collectPatternRanges(code, patterns);
|
|
396
|
+
}
|
|
397
|
+
function collectPatternRanges(code, patterns, initial = [], occupied = new Uint8Array(code.length)) {
|
|
398
|
+
const ranges = [...initial];
|
|
399
|
+
for (const range of initial) occupied.fill(1, range.start, range.end);
|
|
400
|
+
for (const pattern of patterns) {
|
|
401
|
+
if ("collect" in pattern) {
|
|
402
|
+
for (const range of pattern.collect(code)) addRange(ranges, occupied, range);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const regex = cloneRegex(pattern.regex);
|
|
406
|
+
let match;
|
|
407
|
+
while (match = regex.exec(code)) {
|
|
408
|
+
const value = pattern.group ? match[pattern.group] : match[0];
|
|
409
|
+
if (!value) {
|
|
410
|
+
if (!match[0].length) regex.lastIndex++;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const offset = pattern.group ? match[0].length - value.length : 0;
|
|
414
|
+
const start = match.index + offset;
|
|
415
|
+
addRange(ranges, occupied, {
|
|
416
|
+
start,
|
|
417
|
+
end: start + value.length,
|
|
418
|
+
className: typeof pattern.className === "function" ? pattern.className(match) : pattern.className
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return ranges;
|
|
423
|
+
}
|
|
424
|
+
function offsetRanges(ranges, offset) {
|
|
425
|
+
return ranges.map((range) => ({
|
|
426
|
+
...range,
|
|
427
|
+
start: range.start + offset,
|
|
428
|
+
end: range.end + offset
|
|
429
|
+
}));
|
|
430
|
+
}
|
|
431
|
+
function addRange(ranges, occupied, range) {
|
|
432
|
+
if (range.start >= range.end || range.start < 0 || range.end > occupied.length || hasOverlap(occupied, range.start, range.end)) return false;
|
|
433
|
+
ranges.push(range);
|
|
434
|
+
occupied.fill(1, range.start, range.end);
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
function cloneRegex(regex) {
|
|
438
|
+
return new RegExp(regex.source, regex.global ? regex.flags : `${regex.flags}g`);
|
|
439
|
+
}
|
|
440
|
+
function hasOverlap(occupied, start, end) {
|
|
441
|
+
for (let index = start; index < end; index++) if (occupied[index]) return true;
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/css.js
|
|
446
|
+
const css = defineLanguage({
|
|
447
|
+
name: "css",
|
|
448
|
+
tokenize: patternTokenizer([
|
|
449
|
+
{
|
|
450
|
+
className: (match) => match[0].startsWith("/*") ? "comment" : "string",
|
|
451
|
+
regex: /\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
className: "variable",
|
|
455
|
+
regex: /--[A-Za-z0-9_-]+/g
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
className: "selector",
|
|
459
|
+
regex: /(^|[}\n])\s*([^@{}\n][^{}\n]*)(?=\s*\{)/g,
|
|
460
|
+
group: 2
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
className: "property",
|
|
464
|
+
regex: /(?:^|[;{]\s*)([A-Za-z-]+)(?=\s*:)/gm,
|
|
465
|
+
group: 1
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
className: "function",
|
|
469
|
+
regex: /\b[A-Za-z-]+(?=\()/g
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
className: "number",
|
|
473
|
+
regex: /\b\d+(?:\.\d+)?(?:px|rem|em|%|s|ms|vh|vw|deg)?\b/g
|
|
474
|
+
}
|
|
475
|
+
])
|
|
476
|
+
});
|
|
477
|
+
//#endregion
|
|
478
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/markup.js
|
|
479
|
+
const rawTextClosing = {
|
|
480
|
+
script: /<\/script(?=[\s/>])/gi,
|
|
481
|
+
style: /<\/style(?=[\s/>])/gi
|
|
482
|
+
};
|
|
483
|
+
function collectMarkupRanges(code, context, mode = "html") {
|
|
484
|
+
const ranges = [];
|
|
485
|
+
const regions = [];
|
|
486
|
+
let index = 0;
|
|
487
|
+
while ((index = code.indexOf("<", index)) >= 0) {
|
|
488
|
+
if (code.startsWith("<!--", index)) {
|
|
489
|
+
const close = code.indexOf("-->", index + 4);
|
|
490
|
+
const end = close < 0 ? code.length : close + 3;
|
|
491
|
+
ranges.push({
|
|
492
|
+
start: index,
|
|
493
|
+
end,
|
|
494
|
+
className: "comment"
|
|
495
|
+
});
|
|
496
|
+
index = end;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (mode === "ejs" && code.startsWith("<%", index)) {
|
|
500
|
+
const close = code.indexOf("%>", index + 2);
|
|
501
|
+
const end = close < 0 ? code.length : close;
|
|
502
|
+
regions.push({
|
|
503
|
+
start: index + 2,
|
|
504
|
+
end,
|
|
505
|
+
lang: "js"
|
|
506
|
+
});
|
|
507
|
+
index = close < 0 ? code.length : close + 2;
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const closing = code[index + 1] === "/";
|
|
511
|
+
const nameStart = index + (closing ? 2 : 1);
|
|
512
|
+
const nameMatch = /^[A-Za-z][\w:.-]*/.exec(code.slice(nameStart));
|
|
513
|
+
if (!nameMatch) {
|
|
514
|
+
index++;
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const tagEnd = findTagEnd(code, nameStart + nameMatch[0].length);
|
|
518
|
+
if (tagEnd < 0) {
|
|
519
|
+
index++;
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const tagName = nameMatch[0].toLowerCase();
|
|
523
|
+
ranges.push({
|
|
524
|
+
start: nameStart,
|
|
525
|
+
end: nameStart + nameMatch[0].length,
|
|
526
|
+
className: "tag"
|
|
527
|
+
});
|
|
528
|
+
if (!closing) collectAttributes(code, nameStart + nameMatch[0].length, tagEnd, ranges);
|
|
529
|
+
if (!closing && (tagName === "script" || tagName === "style")) {
|
|
530
|
+
const rawTextClose = rawTextClosing[tagName];
|
|
531
|
+
rawTextClose.lastIndex = tagEnd + 1;
|
|
532
|
+
const contentEnd = rawTextClose.exec(code)?.index ?? code.length;
|
|
533
|
+
const lang = getEmbeddedLanguage(tagName, code.slice(index, tagEnd + 1));
|
|
534
|
+
regions.push({
|
|
535
|
+
start: tagEnd + 1,
|
|
536
|
+
end: contentEnd,
|
|
537
|
+
lang
|
|
538
|
+
});
|
|
539
|
+
index = contentEnd;
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
index = tagEnd + 1;
|
|
543
|
+
}
|
|
544
|
+
if (mode === "vue") collectDelimitedRegions(code, "{{", "}}", "js", regions);
|
|
545
|
+
if (mode === "svelte") collectBraceRegions(code, regions);
|
|
546
|
+
for (const region of regions) {
|
|
547
|
+
if (region.start >= region.end || !context.hasLanguage(region.lang)) continue;
|
|
548
|
+
ranges.push(...offsetRanges(context.tokenize(code.slice(region.start, region.end), region.lang), region.start));
|
|
549
|
+
}
|
|
550
|
+
return ranges;
|
|
551
|
+
}
|
|
552
|
+
function collectAttributes(code, start, end, ranges) {
|
|
553
|
+
const source = code.slice(start, end);
|
|
554
|
+
const attributes = /\s([:@A-Za-z_][\w:.-]*)(?=\s*(?:=|\/?>))/g;
|
|
555
|
+
let match;
|
|
556
|
+
while (match = attributes.exec(source)) {
|
|
557
|
+
const offset = match[0].indexOf(match[1]);
|
|
558
|
+
const attributeStart = start + match.index + offset;
|
|
559
|
+
ranges.push({
|
|
560
|
+
start: attributeStart,
|
|
561
|
+
end: attributeStart + match[1].length,
|
|
562
|
+
className: "attr"
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
let index = start;
|
|
566
|
+
while (index < end) {
|
|
567
|
+
const quote = code[index];
|
|
568
|
+
if (quote !== "\"" && quote !== "'") {
|
|
569
|
+
index++;
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
const close = findQuoteEnd(code, index, quote, end);
|
|
573
|
+
ranges.push({
|
|
574
|
+
start: index,
|
|
575
|
+
end: close,
|
|
576
|
+
className: "string"
|
|
577
|
+
});
|
|
578
|
+
index = close;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function getEmbeddedLanguage(tag, openingTag) {
|
|
582
|
+
if (tag === "style") return "css";
|
|
583
|
+
const lang = /\blang\s*=\s*["']?([\w-]+)/i.exec(openingTag)?.[1];
|
|
584
|
+
return lang === "ts" || lang === "typescript" ? "ts" : "js";
|
|
585
|
+
}
|
|
586
|
+
function collectDelimitedRegions(code, open, close, lang, regions) {
|
|
587
|
+
let index = 0;
|
|
588
|
+
while ((index = code.indexOf(open, index)) >= 0) {
|
|
589
|
+
const end = code.indexOf(close, index + open.length);
|
|
590
|
+
if (end < 0) return;
|
|
591
|
+
regions.push({
|
|
592
|
+
start: index + open.length,
|
|
593
|
+
end,
|
|
594
|
+
lang
|
|
595
|
+
});
|
|
596
|
+
index = end + close.length;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function collectBraceRegions(code, regions) {
|
|
600
|
+
let index = 0;
|
|
601
|
+
while (index < code.length) {
|
|
602
|
+
if (code[index] !== "{" || code[index + 1] === "#") {
|
|
603
|
+
index++;
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
const end = code.indexOf("}", index + 1);
|
|
607
|
+
if (end < 0) return;
|
|
608
|
+
regions.push({
|
|
609
|
+
start: index + 1,
|
|
610
|
+
end,
|
|
611
|
+
lang: "js"
|
|
612
|
+
});
|
|
613
|
+
index = end + 1;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
function findTagEnd(code, start) {
|
|
617
|
+
let index = start;
|
|
618
|
+
while (index < code.length) if (code[index] === "\"" || code[index] === "'") index = findQuoteEnd(code, index, code[index], code.length);
|
|
619
|
+
else if (code[index] === ">") return index;
|
|
620
|
+
else index++;
|
|
621
|
+
return -1;
|
|
622
|
+
}
|
|
623
|
+
function findQuoteEnd(code, start, quote, limit) {
|
|
624
|
+
let index = start + 1;
|
|
625
|
+
while (index < limit) if (code[index] === "\\") index += 2;
|
|
626
|
+
else if (code[index] === quote) return index + 1;
|
|
627
|
+
else index++;
|
|
628
|
+
return limit;
|
|
629
|
+
}
|
|
630
|
+
//#endregion
|
|
631
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/html.js
|
|
632
|
+
const html = defineLanguage({
|
|
633
|
+
name: "html",
|
|
634
|
+
aliases: [
|
|
635
|
+
"htm",
|
|
636
|
+
"xml",
|
|
637
|
+
"angular-html"
|
|
638
|
+
],
|
|
639
|
+
tokenize: (code, context) => collectMarkupRanges(code, context)
|
|
640
|
+
});
|
|
641
|
+
//#endregion
|
|
642
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js
|
|
643
|
+
const semanticPatterns = [
|
|
644
|
+
{
|
|
645
|
+
className: "property",
|
|
646
|
+
regex: /(?<!\.)\.([A-Za-z_$][\w$]*)/g,
|
|
647
|
+
group: 1
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
className: "function",
|
|
651
|
+
regex: /@[A-Za-z_$][\w$]*/g
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
className: "keyword",
|
|
655
|
+
regex: new RegExp(`\\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|infer|instanceof|interface|is|keyof|let|module|namespace|new|of|override|package|private|protected|public|readonly|return|satisfies|set|static|super|switch|this|throw|try|type|typeof|using|var|while|with|yield)\\b`, "g")
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
className: "literal",
|
|
659
|
+
regex: /\b(?:false|null|true|undefined|NaN|Infinity)\b/g
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
className: "number",
|
|
663
|
+
regex: /\b(?:0x[\da-f](?:_?[\da-f])*n?|0b[01](?:_?[01])*n?|0o[0-7](?:_?[0-7])*n?|\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:e[+-]?\d(?:_?\d)*)?n?)\b/gi
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
className: "function",
|
|
667
|
+
regex: /\bfunction\s*\*?\s*([A-Za-z_$][\w$]*)/g,
|
|
668
|
+
group: 1
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
className: "function",
|
|
672
|
+
regex: /(^|[^.A-Za-z0-9_$])([A-Za-z_$][\w$]*)(?=\s*\()/g,
|
|
673
|
+
group: 2
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
className: "type",
|
|
677
|
+
regex: /\b(?:Array|Record|Promise|Readonly|Set|Map|WeakMap|WeakSet|string|number|boolean|bigint|symbol|object|unknown|never|void|any|[A-Z][A-Za-z0-9_$]*)\b/g
|
|
678
|
+
}
|
|
679
|
+
];
|
|
680
|
+
function collectScriptRanges(code, jsx = false, jsxAtLineStart = false) {
|
|
681
|
+
const jsxText = jsx ? new Uint8Array(code.length) : void 0;
|
|
682
|
+
const initial = [];
|
|
683
|
+
collectScriptInitialRanges(code, jsx, jsxAtLineStart, jsxText, initial);
|
|
684
|
+
return collectPatternRanges(code, semanticPatterns, initial, jsxText);
|
|
685
|
+
}
|
|
686
|
+
function collectScriptInitialRanges(code, jsx, jsxAtLineStart, jsxText, ranges, index = 0, limit = code.length, tagBody = false) {
|
|
687
|
+
const objectBraces = [];
|
|
688
|
+
const expressions = [];
|
|
689
|
+
let jsxDepth = 0;
|
|
690
|
+
while (index < limit) {
|
|
691
|
+
const expression = expressions.at(-1);
|
|
692
|
+
const inJsxText = jsxDepth > (expression || 0);
|
|
693
|
+
const character = code[index];
|
|
694
|
+
const next = code[index + 1];
|
|
695
|
+
if (inJsxText) {
|
|
696
|
+
if (character === "{") {
|
|
697
|
+
expressions.push(jsxDepth);
|
|
698
|
+
index++;
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
if (character !== "<") {
|
|
702
|
+
const start = index;
|
|
703
|
+
while (index < code.length && code[index] !== "<" && code[index] !== "{") index++;
|
|
704
|
+
jsxText.fill(1, start, index);
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (tagBody && !expressions.length && !jsxDepth && character === ">") return index;
|
|
709
|
+
if (character === "/" && next === "/") {
|
|
710
|
+
const end = findLineEnd(code, index + 2);
|
|
711
|
+
ranges.push({
|
|
712
|
+
start: index,
|
|
713
|
+
end,
|
|
714
|
+
className: "comment"
|
|
715
|
+
});
|
|
716
|
+
index = end;
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
if (character === "/" && next === "*") {
|
|
720
|
+
const close = code.indexOf("*/", index + 2);
|
|
721
|
+
const end = close < 0 ? code.length : close + 2;
|
|
722
|
+
ranges.push({
|
|
723
|
+
start: index,
|
|
724
|
+
end,
|
|
725
|
+
className: "comment"
|
|
726
|
+
});
|
|
727
|
+
index = end;
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
if (character === "'" || character === "\"") {
|
|
731
|
+
const end = findQuotedEnd(code, index, character, tagBody && !expressions.length);
|
|
732
|
+
ranges.push({
|
|
733
|
+
start: index,
|
|
734
|
+
end,
|
|
735
|
+
className: "string"
|
|
736
|
+
});
|
|
737
|
+
index = end;
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
if (character === "`") {
|
|
741
|
+
index = collectTemplateRanges(code, index, ranges, jsx, jsxAtLineStart);
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
if (character === "/" && !(jsx && code[index - 1] === "<") && isRegexStart(code, index)) {
|
|
745
|
+
const end = findRegexEnd(code, index);
|
|
746
|
+
if (end > index + 1) {
|
|
747
|
+
ranges.push({
|
|
748
|
+
start: index,
|
|
749
|
+
end,
|
|
750
|
+
className: "literal"
|
|
751
|
+
});
|
|
752
|
+
index = end;
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (character === "{") {
|
|
757
|
+
const before = previousCodeIndex(code, index, ranges);
|
|
758
|
+
let wordStart = before;
|
|
759
|
+
while (wordStart >= 0 && /[\w$]/.test(code[wordStart])) wordStart--;
|
|
760
|
+
const word = code.slice(wordStart + 1, before + 1);
|
|
761
|
+
objectBraces.push("=(:,[".includes(code[before] || "\0") || /^(?:return|yield|const|let|var)$/.test(word));
|
|
762
|
+
} else if (character === "}") objectBraces.pop();
|
|
763
|
+
else if (objectBraces.at(-1) && /[A-Za-z_$]/.test(character)) {
|
|
764
|
+
const before = previousCodeIndex(code, index, ranges);
|
|
765
|
+
if ("{,;".includes(code[before] || "\0")) {
|
|
766
|
+
let end = index + 1;
|
|
767
|
+
while (end < limit && /[\w$]/.test(code[end])) end++;
|
|
768
|
+
if (code[end + (code.slice(end).match(/^(?:\s|\/\*[\s\S]*?\*\/|\/\/[^\n]*(?:\n|$))*/)?.[0].length || 0)] === ":") {
|
|
769
|
+
ranges.push({
|
|
770
|
+
start: index,
|
|
771
|
+
end,
|
|
772
|
+
className: "property"
|
|
773
|
+
});
|
|
774
|
+
index = end;
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (!jsx) {
|
|
780
|
+
index++;
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
if (!inJsxText && character === "{" && (expressions.length || tagBody)) {
|
|
784
|
+
expressions.push(expressions.length ? expression : jsxDepth);
|
|
785
|
+
index++;
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
if (!inJsxText && expressions.length && character === "}") {
|
|
789
|
+
expressions.pop();
|
|
790
|
+
index++;
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
if (character !== "<") {
|
|
794
|
+
index++;
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
if (code.startsWith("</>", index)) {
|
|
798
|
+
jsxDepth--;
|
|
799
|
+
index += 3;
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
if (code.startsWith("<>", index) && (inJsxText || isJsxStart(code, index, jsxAtLineStart))) {
|
|
803
|
+
jsxDepth++;
|
|
804
|
+
index += 2;
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
const closing = code[index + 1] === "/";
|
|
808
|
+
const nameStart = index + (closing ? 2 : 1);
|
|
809
|
+
const nameMatch = /^[A-Za-z][\w:.-]*/.exec(code.slice(nameStart));
|
|
810
|
+
if (!nameMatch || !closing && !inJsxText && !isJsxStart(code, index, jsxAtLineStart)) {
|
|
811
|
+
index++;
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
const end = collectScriptInitialRanges(code, true, jsxAtLineStart, jsxText, ranges, nameStart + nameMatch[0].length, limit, true);
|
|
815
|
+
if (end < 0 || isTypeParameter(code, index, end, closing)) {
|
|
816
|
+
index++;
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
ranges.push({
|
|
820
|
+
start: nameStart,
|
|
821
|
+
end: nameStart + nameMatch[0].length,
|
|
822
|
+
className: "tag"
|
|
823
|
+
});
|
|
824
|
+
if (!closing) collectJsxAttributes(code, nameStart + nameMatch[0].length, end, ranges);
|
|
825
|
+
const selfClosing = /\/\s*$/.test(code.slice(nameStart, end));
|
|
826
|
+
if (closing) jsxDepth--;
|
|
827
|
+
else if (!selfClosing) jsxDepth++;
|
|
828
|
+
index = end + 1;
|
|
829
|
+
}
|
|
830
|
+
return -1;
|
|
831
|
+
}
|
|
832
|
+
function collectTemplateRanges(code, start, ranges, jsx, jsxAtLineStart) {
|
|
833
|
+
let segmentStart = start;
|
|
834
|
+
let index = start + 1;
|
|
835
|
+
while (index < code.length) {
|
|
836
|
+
if (code[index] === "\\") {
|
|
837
|
+
index += 2;
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
if (code[index] === "`") {
|
|
841
|
+
ranges.push({
|
|
842
|
+
start: segmentStart,
|
|
843
|
+
end: index + 1,
|
|
844
|
+
className: "string"
|
|
845
|
+
});
|
|
846
|
+
return index + 1;
|
|
847
|
+
}
|
|
848
|
+
if (code[index] === "$" && code[index + 1] === "{") {
|
|
849
|
+
if (segmentStart < index) ranges.push({
|
|
850
|
+
start: segmentStart,
|
|
851
|
+
end: index,
|
|
852
|
+
className: "string"
|
|
853
|
+
});
|
|
854
|
+
ranges.push({
|
|
855
|
+
start: index,
|
|
856
|
+
end: index + 2,
|
|
857
|
+
className: "operator"
|
|
858
|
+
});
|
|
859
|
+
const end = findInterpolationEnd(code, index + 2);
|
|
860
|
+
const expressionEnd = end < 0 ? code.length : end;
|
|
861
|
+
const expression = code.slice(index + 2, expressionEnd);
|
|
862
|
+
ranges.push(...offsetRanges(collectScriptRanges(expression, jsx, jsxAtLineStart), index + 2));
|
|
863
|
+
if (end < 0) return code.length;
|
|
864
|
+
ranges.push({
|
|
865
|
+
start: end,
|
|
866
|
+
end: end + 1,
|
|
867
|
+
className: "operator"
|
|
868
|
+
});
|
|
869
|
+
index = end + 1;
|
|
870
|
+
segmentStart = index;
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
index++;
|
|
874
|
+
}
|
|
875
|
+
if (segmentStart < code.length) ranges.push({
|
|
876
|
+
start: segmentStart,
|
|
877
|
+
end: code.length,
|
|
878
|
+
className: "string"
|
|
879
|
+
});
|
|
880
|
+
return code.length;
|
|
881
|
+
}
|
|
882
|
+
function findInterpolationEnd(code, start) {
|
|
883
|
+
let depth = 1;
|
|
884
|
+
let index = start;
|
|
885
|
+
while (index < code.length) {
|
|
886
|
+
const character = code[index];
|
|
887
|
+
const next = code[index + 1];
|
|
888
|
+
if (character === "'" || character === "\"") {
|
|
889
|
+
index = findQuotedEnd(code, index, character);
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (character === "`") {
|
|
893
|
+
index = skipTemplate(code, index);
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
if (character === "/" && next === "/") {
|
|
897
|
+
index = findLineEnd(code, index + 2);
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
if (character === "/" && next === "*") {
|
|
901
|
+
const close = code.indexOf("*/", index + 2);
|
|
902
|
+
index = close < 0 ? code.length : close + 2;
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
if (character === "/" && isRegexStart(code, index)) {
|
|
906
|
+
index = findRegexEnd(code, index);
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
if (character === "{") depth++;
|
|
910
|
+
if (character === "}" && --depth === 0) return index;
|
|
911
|
+
index++;
|
|
912
|
+
}
|
|
913
|
+
return -1;
|
|
914
|
+
}
|
|
915
|
+
function skipTemplate(code, start) {
|
|
916
|
+
let index = start + 1;
|
|
917
|
+
while (index < code.length) if (code[index] === "\\") index += 2;
|
|
918
|
+
else if (code[index] === "`") return index + 1;
|
|
919
|
+
else if (code[index] === "$" && code[index + 1] === "{") {
|
|
920
|
+
const end = findInterpolationEnd(code, index + 2);
|
|
921
|
+
index = end < 0 ? code.length : end + 1;
|
|
922
|
+
} else index++;
|
|
923
|
+
return code.length;
|
|
924
|
+
}
|
|
925
|
+
function collectJsxAttributes(code, start, end, ranges) {
|
|
926
|
+
const source = code.slice(start, end);
|
|
927
|
+
const regex = /\s([:@A-Za-z_$][\w$:.-]*)(?=\s*(?:=|\/?>))/g;
|
|
928
|
+
let match;
|
|
929
|
+
while (match = regex.exec(source)) {
|
|
930
|
+
const attributeStart = start + match.index + 1;
|
|
931
|
+
ranges.push({
|
|
932
|
+
start: attributeStart,
|
|
933
|
+
end: attributeStart + match[1].length,
|
|
934
|
+
className: "attr"
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function isJsxStart(code, index, jsxAtLineStart) {
|
|
939
|
+
if (jsxAtLineStart && /^\s*$/.test(code.slice(code.lastIndexOf("\n", index - 1) + 1, index))) return true;
|
|
940
|
+
const before = code.slice(0, index).trimEnd();
|
|
941
|
+
if (!before) return true;
|
|
942
|
+
if (/\b(?:return|case|yield)$/.test(before)) return true;
|
|
943
|
+
return /(?:[=([{,:;!&|?]|>)$/.test(before);
|
|
944
|
+
}
|
|
945
|
+
function isTypeParameter(code, start, end, closing) {
|
|
946
|
+
if (closing) return false;
|
|
947
|
+
const inside = code.slice(start + 1, end);
|
|
948
|
+
const after = code.slice(end + 1).trimStart();
|
|
949
|
+
return /\s+extends\s+/.test(inside) || after[0] === "(" && !inside.trimEnd().endsWith("/");
|
|
950
|
+
}
|
|
951
|
+
function isRegexStart(code, index) {
|
|
952
|
+
const before = code.slice(0, index).trimEnd();
|
|
953
|
+
if (!before) return true;
|
|
954
|
+
if (/\b(?:case|delete|in|instanceof|of|return|throw|typeof|void|yield)$/.test(before)) return true;
|
|
955
|
+
return /[=([{,:;!&|?~+*%^<>-]$/.test(before);
|
|
956
|
+
}
|
|
957
|
+
function findRegexEnd(code, start) {
|
|
958
|
+
let inClass = false;
|
|
959
|
+
let index = start + 1;
|
|
960
|
+
while (index < code.length && code[index] !== "\n") if (code[index] === "\\") index += 2;
|
|
961
|
+
else if (code[index] === "[") {
|
|
962
|
+
inClass = true;
|
|
963
|
+
index++;
|
|
964
|
+
} else if (code[index] === "]") {
|
|
965
|
+
inClass = false;
|
|
966
|
+
index++;
|
|
967
|
+
} else if (code[index] === "/" && !inClass) {
|
|
968
|
+
index++;
|
|
969
|
+
while (/[a-z]/i.test(code[index] || "")) index++;
|
|
970
|
+
return index;
|
|
971
|
+
} else index++;
|
|
972
|
+
return start + 1;
|
|
973
|
+
}
|
|
974
|
+
function findQuotedEnd(code, start, quote, multiline = false) {
|
|
975
|
+
let index = start + 1;
|
|
976
|
+
while (index < code.length) if (code[index] === "\\") index += 2;
|
|
977
|
+
else if (code[index] === quote) return index + 1;
|
|
978
|
+
else if (!multiline && code[index] === "\n") return index;
|
|
979
|
+
else index++;
|
|
980
|
+
return code.length;
|
|
981
|
+
}
|
|
982
|
+
function findLineEnd(code, start) {
|
|
983
|
+
const end = code.indexOf("\n", start);
|
|
984
|
+
return end < 0 ? code.length : end;
|
|
985
|
+
}
|
|
986
|
+
function previousCodeIndex(code, index, ranges) {
|
|
987
|
+
let before = index - 1;
|
|
988
|
+
let rangeIndex = ranges.length - 1;
|
|
989
|
+
while (before >= 0) {
|
|
990
|
+
if (/\s/.test(code[before])) {
|
|
991
|
+
before--;
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
994
|
+
const range = ranges[rangeIndex];
|
|
995
|
+
if (range && range.end > before) {
|
|
996
|
+
rangeIndex--;
|
|
997
|
+
if (range.className === "comment" && range.start <= before) {
|
|
998
|
+
before = range.start - 1;
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
} else break;
|
|
1002
|
+
}
|
|
1003
|
+
return before;
|
|
1004
|
+
}
|
|
1005
|
+
//#endregion
|
|
1006
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/js.js
|
|
1007
|
+
const js = defineLanguage({
|
|
1008
|
+
name: "js",
|
|
1009
|
+
aliases: [
|
|
1010
|
+
"javascript",
|
|
1011
|
+
"mjs",
|
|
1012
|
+
"cjs",
|
|
1013
|
+
"js-vue"
|
|
1014
|
+
],
|
|
1015
|
+
tokenize: (code) => collectScriptRanges(code)
|
|
1016
|
+
});
|
|
1017
|
+
//#endregion
|
|
1018
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/json.js
|
|
1019
|
+
const json = defineLanguage({
|
|
1020
|
+
name: "json",
|
|
1021
|
+
aliases: ["jsonc", "json5"],
|
|
1022
|
+
tokenize: patternTokenizer([
|
|
1023
|
+
{
|
|
1024
|
+
className: (match) => match[0].startsWith("//") || match[0].startsWith("/*") ? "comment" : match[1] ? "property" : "string",
|
|
1025
|
+
regex: /\/\/[^\n]*|\/\*[\s\S]*?\*\/|("(?:\\.|[^"\\])*")(?=\s*:)|"(?:\\.|[^"\\])*"/g
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
className: "literal",
|
|
1029
|
+
regex: /\b(?:false|null|true)\b/g
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
className: "number",
|
|
1033
|
+
regex: /-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/gi
|
|
1034
|
+
}
|
|
1035
|
+
])
|
|
1036
|
+
});
|
|
1037
|
+
//#endregion
|
|
1038
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/jsx.js
|
|
1039
|
+
const jsx = defineLanguage({
|
|
1040
|
+
name: "jsx",
|
|
1041
|
+
tokenize: (code) => collectScriptRanges(code, true)
|
|
1042
|
+
});
|
|
1043
|
+
//#endregion
|
|
1044
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/markdown.js
|
|
1045
|
+
const markdown = defineLanguage({
|
|
1046
|
+
name: "markdown",
|
|
1047
|
+
aliases: ["md"],
|
|
1048
|
+
tokenize(code, context) {
|
|
1049
|
+
return collectPatternRanges(code, [
|
|
1050
|
+
{
|
|
1051
|
+
className: "heading",
|
|
1052
|
+
regex: /^#{1,6}\s.*$/gm
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
className: "heading",
|
|
1056
|
+
regex: /^.+\n(?:=+|-+)\s*$/gm
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
className: "code-inline",
|
|
1060
|
+
regex: /`[^`\n]+`/g
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
className: "link",
|
|
1064
|
+
regex: /!?\[[^\]]+\]\([^)]+\)/g
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
className: "meta",
|
|
1068
|
+
regex: /^\s{0,3}(?:>|[-*+] |\d+\. )/gm
|
|
1069
|
+
}
|
|
1070
|
+
], collectFencedCode(code, context));
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
function collectFencedCode(code, context) {
|
|
1074
|
+
const ranges = [];
|
|
1075
|
+
const opening = /^( {0,3})(`{3,}|~{3,})\s*([^\n]*)$/gm;
|
|
1076
|
+
let match;
|
|
1077
|
+
while (match = opening.exec(code)) {
|
|
1078
|
+
const marker = match[2];
|
|
1079
|
+
const contentStart = code.indexOf("\n", match.index + match[0].length);
|
|
1080
|
+
if (contentStart < 0) break;
|
|
1081
|
+
const closing = new RegExp(`^ {0,3}${marker[0]}{${marker.length},}\\s*$`, "gm");
|
|
1082
|
+
closing.lastIndex = contentStart + 1;
|
|
1083
|
+
const close = closing.exec(code);
|
|
1084
|
+
const contentEnd = close?.index ?? code.length;
|
|
1085
|
+
const info = match[3].trim().split(/\s+/)[0];
|
|
1086
|
+
const embedded = info && context.hasLanguage(info) ? offsetRanges(context.tokenize(code.slice(contentStart + 1, contentEnd), info), contentStart + 1) : [];
|
|
1087
|
+
ranges.push({
|
|
1088
|
+
start: match.index,
|
|
1089
|
+
end: contentStart,
|
|
1090
|
+
className: "meta"
|
|
1091
|
+
});
|
|
1092
|
+
ranges.push(...fillCodeRange(contentStart + 1, contentEnd, embedded));
|
|
1093
|
+
if (close) ranges.push({
|
|
1094
|
+
start: close.index,
|
|
1095
|
+
end: close.index + close[0].length,
|
|
1096
|
+
className: "meta"
|
|
1097
|
+
});
|
|
1098
|
+
opening.lastIndex = close ? close.index + close[0].length : code.length;
|
|
1099
|
+
}
|
|
1100
|
+
return ranges;
|
|
1101
|
+
}
|
|
1102
|
+
function fillCodeRange(start, end, embedded) {
|
|
1103
|
+
const ranges = [];
|
|
1104
|
+
let index = start;
|
|
1105
|
+
for (const range of embedded) {
|
|
1106
|
+
if (range.start > index) ranges.push({
|
|
1107
|
+
start: index,
|
|
1108
|
+
end: range.start,
|
|
1109
|
+
className: "code-inline"
|
|
1110
|
+
});
|
|
1111
|
+
ranges.push(range);
|
|
1112
|
+
index = range.end;
|
|
1113
|
+
}
|
|
1114
|
+
if (index < end) ranges.push({
|
|
1115
|
+
start: index,
|
|
1116
|
+
end,
|
|
1117
|
+
className: "code-inline"
|
|
1118
|
+
});
|
|
1119
|
+
return ranges;
|
|
1120
|
+
}
|
|
1121
|
+
//#endregion
|
|
1122
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/plaintext.js
|
|
1123
|
+
const plaintext = defineLanguage({
|
|
1124
|
+
name: "plaintext",
|
|
1125
|
+
aliases: [
|
|
1126
|
+
"text",
|
|
1127
|
+
"txt",
|
|
1128
|
+
"-->"
|
|
1129
|
+
],
|
|
1130
|
+
tokenize: () => []
|
|
1131
|
+
});
|
|
1132
|
+
//#endregion
|
|
1133
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/shell.js
|
|
1134
|
+
const shell = defineLanguage({
|
|
1135
|
+
name: "shell",
|
|
1136
|
+
aliases: [
|
|
1137
|
+
"bash",
|
|
1138
|
+
"sh",
|
|
1139
|
+
"zsh",
|
|
1140
|
+
"cmd",
|
|
1141
|
+
"console"
|
|
1142
|
+
],
|
|
1143
|
+
tokenize: patternTokenizer([
|
|
1144
|
+
{ collect: collectShellLexicalRanges },
|
|
1145
|
+
{
|
|
1146
|
+
className: "variable",
|
|
1147
|
+
regex: /\$[A-Za-z_][A-Za-z0-9_]*|\b[A-Z_][A-Z0-9_]*(?==)/g
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
className: "keyword",
|
|
1151
|
+
regex: /\b(?:case|do|done|elif|else|esac|export|fi|for|function|if|in|select|then|time|until|while)\b/g
|
|
1152
|
+
},
|
|
1153
|
+
{
|
|
1154
|
+
className: "command",
|
|
1155
|
+
regex: /(^|[\n;|&])\s*([A-Za-z0-9_./-]+)(?=\s|$)/g,
|
|
1156
|
+
group: 2
|
|
1157
|
+
}
|
|
1158
|
+
])
|
|
1159
|
+
});
|
|
1160
|
+
function collectShellLexicalRanges(code) {
|
|
1161
|
+
const heredocs = [];
|
|
1162
|
+
collectHeredocs(code, heredocs);
|
|
1163
|
+
const ranges = [...heredocs];
|
|
1164
|
+
let heredocIndex = 0;
|
|
1165
|
+
let index = 0;
|
|
1166
|
+
while (index < code.length) {
|
|
1167
|
+
while (heredocIndex < heredocs.length && heredocs[heredocIndex].end <= index) heredocIndex++;
|
|
1168
|
+
const heredoc = heredocs[heredocIndex];
|
|
1169
|
+
if (heredoc && heredoc.start <= index) {
|
|
1170
|
+
index = heredoc.end;
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
const character = code[index];
|
|
1174
|
+
if (character === "\"" || character === "'") {
|
|
1175
|
+
const quote = character;
|
|
1176
|
+
let end = index + 1;
|
|
1177
|
+
while (end < code.length) if (code[end] === "\\" && quote === "\"") end += 2;
|
|
1178
|
+
else if (code[end] === quote) {
|
|
1179
|
+
end++;
|
|
1180
|
+
break;
|
|
1181
|
+
} else end++;
|
|
1182
|
+
end = Math.min(end, code.length);
|
|
1183
|
+
ranges.push({
|
|
1184
|
+
start: index,
|
|
1185
|
+
end,
|
|
1186
|
+
className: "string"
|
|
1187
|
+
});
|
|
1188
|
+
index = end;
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
if (character === "$" && code[index + 1] === "{") {
|
|
1192
|
+
const close = code.indexOf("}", index + 2);
|
|
1193
|
+
const end = close < 0 ? code.length : close + 1;
|
|
1194
|
+
ranges.push({
|
|
1195
|
+
start: index,
|
|
1196
|
+
end,
|
|
1197
|
+
className: "variable"
|
|
1198
|
+
});
|
|
1199
|
+
index = end;
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1202
|
+
if (character === "#" && (index === 0 || code[index - 1] === "\n" || /[\s;|&()]/.test(code[index - 1]))) {
|
|
1203
|
+
const newline = code.indexOf("\n", index);
|
|
1204
|
+
const end = newline < 0 ? code.length : newline;
|
|
1205
|
+
ranges.push({
|
|
1206
|
+
start: index,
|
|
1207
|
+
end,
|
|
1208
|
+
className: "comment"
|
|
1209
|
+
});
|
|
1210
|
+
index = end;
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
index++;
|
|
1214
|
+
}
|
|
1215
|
+
return ranges;
|
|
1216
|
+
}
|
|
1217
|
+
function collectHeredocs(code, ranges) {
|
|
1218
|
+
const regex = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/g;
|
|
1219
|
+
let match;
|
|
1220
|
+
while (match = regex.exec(code)) {
|
|
1221
|
+
if (code[match.index - 1] === "<" || isInsideQuote(code, match.index)) continue;
|
|
1222
|
+
const bodyStartLine = code.indexOf("\n", match.index + match[0].length);
|
|
1223
|
+
if (bodyStartLine < 0) continue;
|
|
1224
|
+
const bodyStart = bodyStartLine + 1;
|
|
1225
|
+
const closingMatch = new RegExp(`^\\t*${match[2]}\\s*$`, "m").exec(code.slice(bodyStart));
|
|
1226
|
+
if (!closingMatch) {
|
|
1227
|
+
ranges.push({
|
|
1228
|
+
start: bodyStart,
|
|
1229
|
+
end: code.length,
|
|
1230
|
+
className: "string"
|
|
1231
|
+
});
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
const end = bodyStart + closingMatch.index;
|
|
1235
|
+
if (end > bodyStart) ranges.push({
|
|
1236
|
+
start: bodyStart,
|
|
1237
|
+
end,
|
|
1238
|
+
className: "string"
|
|
1239
|
+
});
|
|
1240
|
+
const closingStart = bodyStart + closingMatch.index;
|
|
1241
|
+
ranges.push({
|
|
1242
|
+
start: closingStart,
|
|
1243
|
+
end: closingStart + closingMatch[0].length,
|
|
1244
|
+
className: "meta"
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
function isInsideQuote(code, index) {
|
|
1249
|
+
const lineStart = code.lastIndexOf("\n", index - 1) + 1;
|
|
1250
|
+
let quote = "";
|
|
1251
|
+
for (let cursor = lineStart; cursor < index; cursor++) if (code[cursor] === "\\" && quote !== "'") cursor++;
|
|
1252
|
+
else if (quote && code[cursor] === quote) quote = "";
|
|
1253
|
+
else if (!quote && (code[cursor] === "\"" || code[cursor] === "'")) quote = code[cursor];
|
|
1254
|
+
return Boolean(quote);
|
|
1255
|
+
}
|
|
1256
|
+
//#endregion
|
|
1257
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/ts.js
|
|
1258
|
+
const ts = defineLanguage({
|
|
1259
|
+
name: "ts",
|
|
1260
|
+
aliases: ["typescript", "angular-ts"],
|
|
1261
|
+
tokenize: (code) => collectScriptRanges(code)
|
|
1262
|
+
});
|
|
1263
|
+
//#endregion
|
|
1264
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/tsx.js
|
|
1265
|
+
const tsx = defineLanguage({
|
|
1266
|
+
name: "tsx",
|
|
1267
|
+
tokenize: (code) => collectScriptRanges(code, true)
|
|
1268
|
+
});
|
|
1269
|
+
//#endregion
|
|
1270
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/languages/yaml.js
|
|
1271
|
+
const yaml = defineLanguage({
|
|
1272
|
+
name: "yaml",
|
|
1273
|
+
aliases: ["yml"],
|
|
1274
|
+
tokenize(code) {
|
|
1275
|
+
const lexical = [...collectYamlBlockScalars(code), ...collectYamlLexicalRanges(code)];
|
|
1276
|
+
return collectPatternRanges(code, [
|
|
1277
|
+
{
|
|
1278
|
+
className: "property",
|
|
1279
|
+
regex: /^[ \t-]*([A-Za-z0-9_.-]+)(?=\s*:)/gm,
|
|
1280
|
+
group: 1
|
|
1281
|
+
},
|
|
1282
|
+
{ collect: collectYamlValues },
|
|
1283
|
+
{
|
|
1284
|
+
className: "literal",
|
|
1285
|
+
regex: /\b(?:false|null|true|yes|no|on|off|~)\b/gi
|
|
1286
|
+
},
|
|
1287
|
+
{
|
|
1288
|
+
className: "number",
|
|
1289
|
+
regex: /\b\d+(?:\.\d+)?\b/g
|
|
1290
|
+
}
|
|
1291
|
+
], lexical);
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
function collectYamlBlockScalars(code) {
|
|
1295
|
+
const ranges = [];
|
|
1296
|
+
const opening = /^(\s*)[\w.-]+:\s*[>|][+-]?\s*(?:#.*)?$/gm;
|
|
1297
|
+
let match;
|
|
1298
|
+
while (match = opening.exec(code)) {
|
|
1299
|
+
const start = code.indexOf("\n", match.index + match[0].length);
|
|
1300
|
+
if (start < 0) continue;
|
|
1301
|
+
const indentation = match[1].length;
|
|
1302
|
+
let end = start + 1;
|
|
1303
|
+
while (end < code.length) {
|
|
1304
|
+
const lineEnd = code.indexOf("\n", end);
|
|
1305
|
+
const next = lineEnd < 0 ? code.length : lineEnd;
|
|
1306
|
+
const line = code.slice(end, next);
|
|
1307
|
+
if (line.trim() && (line.match(/^\s*/)?.[0].length || 0) <= indentation) break;
|
|
1308
|
+
end = lineEnd < 0 ? code.length : lineEnd + 1;
|
|
1309
|
+
}
|
|
1310
|
+
if (end > start + 1) ranges.push({
|
|
1311
|
+
start: start + 1,
|
|
1312
|
+
end,
|
|
1313
|
+
className: "string"
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
return ranges;
|
|
1317
|
+
}
|
|
1318
|
+
function collectYamlLexicalRanges(code) {
|
|
1319
|
+
const ranges = [];
|
|
1320
|
+
let index = 0;
|
|
1321
|
+
while (index < code.length) {
|
|
1322
|
+
const character = code[index];
|
|
1323
|
+
if (character === "\"" || character === "'") {
|
|
1324
|
+
const quote = character;
|
|
1325
|
+
let end = index + 1;
|
|
1326
|
+
while (end < code.length && code[end] !== "\n") if (code[end] === "\\" && quote === "\"") end += 2;
|
|
1327
|
+
else if (code[end] === quote) {
|
|
1328
|
+
end++;
|
|
1329
|
+
break;
|
|
1330
|
+
} else end++;
|
|
1331
|
+
ranges.push({
|
|
1332
|
+
start: index,
|
|
1333
|
+
end,
|
|
1334
|
+
className: "string"
|
|
1335
|
+
});
|
|
1336
|
+
index = end;
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
if (character === "#" && (index === 0 || code[index - 1] === "\n" || /\s/.test(code[index - 1]))) {
|
|
1340
|
+
const newline = code.indexOf("\n", index);
|
|
1341
|
+
const end = newline < 0 ? code.length : newline;
|
|
1342
|
+
ranges.push({
|
|
1343
|
+
start: index,
|
|
1344
|
+
end,
|
|
1345
|
+
className: "comment"
|
|
1346
|
+
});
|
|
1347
|
+
index = end;
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
index++;
|
|
1351
|
+
}
|
|
1352
|
+
return ranges;
|
|
1353
|
+
}
|
|
1354
|
+
function collectYamlValues(code) {
|
|
1355
|
+
const ranges = [];
|
|
1356
|
+
const regex = /:\s*([^\n]*)/g;
|
|
1357
|
+
let match;
|
|
1358
|
+
while (match = regex.exec(code)) {
|
|
1359
|
+
const value = match[1];
|
|
1360
|
+
const trimmed = value.trimEnd();
|
|
1361
|
+
if (!trimmed) continue;
|
|
1362
|
+
const start = match.index + match[0].indexOf(value);
|
|
1363
|
+
let end = start + trimmed.length;
|
|
1364
|
+
const comment = /\s+#/.exec(trimmed);
|
|
1365
|
+
if (comment) end = start + comment.index;
|
|
1366
|
+
while (end > start && /\s/.test(code[end - 1])) end--;
|
|
1367
|
+
if (end > start) ranges.push({
|
|
1368
|
+
start,
|
|
1369
|
+
end,
|
|
1370
|
+
className: "string"
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
return ranges;
|
|
1374
|
+
}
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/code-fence.js
|
|
1377
|
+
const codeDiffNotation = /(?:(?:\/\/|#)[ \t]*\[!code[ \t]+(\+\+|--)\]|\/\*[ \t]*\[!code[ \t]+(\+\+|--)\][ \t]*\*\/|<!--[ \t]*\[!code[ \t]+(\+\+|--)\][ \t]*-->)[ \t]*\r?$/;
|
|
1378
|
+
function parseCodeDiffNotation(code) {
|
|
1379
|
+
const decorations = [];
|
|
1380
|
+
if (!code.includes("[!code")) return {
|
|
1381
|
+
code,
|
|
1382
|
+
decorations
|
|
1383
|
+
};
|
|
1384
|
+
const lines = code.split("\n");
|
|
1385
|
+
for (let index = 0; index < lines.length; index++) {
|
|
1386
|
+
const line = lines[index];
|
|
1387
|
+
const match = codeDiffNotation.exec(line);
|
|
1388
|
+
if (!match) continue;
|
|
1389
|
+
const notation = match[1] || match[2] || match[3];
|
|
1390
|
+
decorations.push({
|
|
1391
|
+
className: notation === "++" ? "th-line--inserted" : "th-line--deleted",
|
|
1392
|
+
lines: index + 1
|
|
1393
|
+
});
|
|
1394
|
+
lines[index] = line.slice(0, match.index).replace(/[ \t]+$/, "") + (line.endsWith("\r") ? "\r" : "");
|
|
1395
|
+
}
|
|
1396
|
+
return {
|
|
1397
|
+
code: lines.join("\n"),
|
|
1398
|
+
decorations
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
//#endregion
|
|
1402
|
+
//#region ../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/markdown.js
|
|
1403
|
+
function createTanStackMarkdownHighlighter(highlighter) {
|
|
1404
|
+
return (code, lang = "plaintext", options = {}) => {
|
|
1405
|
+
const annotated = parseCodeDiffNotation(code);
|
|
1406
|
+
const result = highlighter.tokenize(annotated.code, { lang });
|
|
1407
|
+
for (const lines of options.highlightLines || []) annotated.decorations.push({
|
|
1408
|
+
className: "th-line--highlighted",
|
|
1409
|
+
lines
|
|
1410
|
+
});
|
|
1411
|
+
return renderNodesToHtml(renderTokens(result.tokens, {
|
|
1412
|
+
lineNumbers: options.lineNumbers,
|
|
1413
|
+
decorations: annotated.decorations
|
|
1414
|
+
}));
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
//#endregion
|
|
1418
|
+
//#region ../../packages/document/src/highlight.ts
|
|
1419
|
+
const MAX_HIGHLIGHT_CHARS = 262144;
|
|
1420
|
+
const highlighter = createHighlighter({ languages: [
|
|
1421
|
+
js,
|
|
1422
|
+
jsx,
|
|
1423
|
+
ts,
|
|
1424
|
+
tsx,
|
|
1425
|
+
json,
|
|
1426
|
+
yaml,
|
|
1427
|
+
html,
|
|
1428
|
+
css,
|
|
1429
|
+
shell,
|
|
1430
|
+
markdown,
|
|
1431
|
+
plaintext
|
|
1432
|
+
] });
|
|
1433
|
+
const registered = new Set(highlighter.listLanguages());
|
|
1434
|
+
const highlightAdapter = createTanStackMarkdownHighlighter(highlighter);
|
|
1435
|
+
const safeHighlighter = (code, lang, options) => {
|
|
1436
|
+
const normalized = lang ? highlighter.normalizeLanguage(lang) : "plaintext";
|
|
1437
|
+
const usable = registered.has(normalized) && code.length <= MAX_HIGHLIGHT_CHARS;
|
|
1438
|
+
return highlightAdapter(code, usable ? normalized : "plaintext", options);
|
|
1439
|
+
};
|
|
1440
|
+
//#endregion
|
|
1441
|
+
//#region ../../packages/document/src/print-style.ts
|
|
1442
|
+
const SANS = [
|
|
1443
|
+
"-apple-system",
|
|
1444
|
+
"BlinkMacSystemFont",
|
|
1445
|
+
"'Hiragino Sans'",
|
|
1446
|
+
"'Hiragino Kaku Gothic ProN'",
|
|
1447
|
+
"'Segoe UI'",
|
|
1448
|
+
"'Yu Gothic Medium'",
|
|
1449
|
+
"'Yu Gothic'",
|
|
1450
|
+
"Meiryo",
|
|
1451
|
+
"'Noto Sans CJK JP'",
|
|
1452
|
+
"'Noto Sans JP'",
|
|
1453
|
+
"sans-serif"
|
|
1454
|
+
].join(", ");
|
|
1455
|
+
const MONO = [
|
|
1456
|
+
"ui-monospace",
|
|
1457
|
+
"'SF Mono'",
|
|
1458
|
+
"SFMono-Regular",
|
|
1459
|
+
"Menlo",
|
|
1460
|
+
"Consolas",
|
|
1461
|
+
"'Liberation Mono'",
|
|
1462
|
+
"'Hiragino Sans'",
|
|
1463
|
+
"'Yu Gothic Medium'",
|
|
1464
|
+
"'Noto Sans CJK JP'",
|
|
1465
|
+
"monospace"
|
|
1466
|
+
].join(", ");
|
|
1467
|
+
function printPageStyle(cssTitle) {
|
|
1468
|
+
return `@page {
|
|
1469
|
+
size: A4;
|
|
1470
|
+
margin: 20mm;
|
|
1471
|
+
@top-left {
|
|
1472
|
+
content: ${cssTitle};
|
|
1473
|
+
vertical-align: bottom;
|
|
1474
|
+
padding-bottom: 6mm;
|
|
1475
|
+
font: 8pt/1.4 ${SANS};
|
|
1476
|
+
color: #57606a;
|
|
1477
|
+
}
|
|
1478
|
+
@bottom-center {
|
|
1479
|
+
content: counter(page) " / " counter(pages);
|
|
1480
|
+
vertical-align: top;
|
|
1481
|
+
padding-top: 6mm;
|
|
1482
|
+
font: 8pt/1.4 ${SANS};
|
|
1483
|
+
color: #57606a;
|
|
1484
|
+
}
|
|
1485
|
+
}`;
|
|
1486
|
+
}
|
|
1487
|
+
const PRINT_STYLE = `
|
|
1488
|
+
:root {
|
|
1489
|
+
color-scheme: light;
|
|
1490
|
+
print-color-adjust: exact;
|
|
1491
|
+
-webkit-print-color-adjust: exact;
|
|
1492
|
+
}
|
|
1493
|
+
*, *::before, *::after {
|
|
1494
|
+
box-sizing: border-box;
|
|
1495
|
+
}
|
|
1496
|
+
html, body {
|
|
1497
|
+
margin: 0;
|
|
1498
|
+
padding: 0;
|
|
1499
|
+
background: #ffffff;
|
|
1500
|
+
}
|
|
1501
|
+
body {
|
|
1502
|
+
font-family: ${SANS};
|
|
1503
|
+
font-size: 10.5pt;
|
|
1504
|
+
line-height: 1.75;
|
|
1505
|
+
color: #1f2328;
|
|
1506
|
+
font-kerning: normal;
|
|
1507
|
+
overflow-wrap: anywhere;
|
|
1508
|
+
}
|
|
1509
|
+
.document > :first-child {
|
|
1510
|
+
margin-top: 0;
|
|
1511
|
+
}
|
|
1512
|
+
h1, h2, h3, h4, h5, h6 {
|
|
1513
|
+
margin: 1.7em 0 0.6em;
|
|
1514
|
+
font-weight: 600;
|
|
1515
|
+
line-height: 1.35;
|
|
1516
|
+
color: #111418;
|
|
1517
|
+
break-after: avoid;
|
|
1518
|
+
}
|
|
1519
|
+
h1 {
|
|
1520
|
+
font-size: 20pt;
|
|
1521
|
+
font-weight: 700;
|
|
1522
|
+
padding-bottom: 0.3em;
|
|
1523
|
+
border-bottom: 1.5pt solid #1f2328;
|
|
1524
|
+
}
|
|
1525
|
+
h2 {
|
|
1526
|
+
font-size: 14.5pt;
|
|
1527
|
+
padding-bottom: 0.25em;
|
|
1528
|
+
border-bottom: 0.75pt solid #d0d7de;
|
|
1529
|
+
}
|
|
1530
|
+
h3 {
|
|
1531
|
+
font-size: 12pt;
|
|
1532
|
+
}
|
|
1533
|
+
h4 {
|
|
1534
|
+
font-size: 10.5pt;
|
|
1535
|
+
}
|
|
1536
|
+
h5, h6 {
|
|
1537
|
+
font-size: 10pt;
|
|
1538
|
+
color: #57606a;
|
|
1539
|
+
}
|
|
1540
|
+
p, ul, ol, table, pre, blockquote, figure, .keep-together {
|
|
1541
|
+
margin: 0.8em 0;
|
|
1542
|
+
}
|
|
1543
|
+
p, li, blockquote {
|
|
1544
|
+
orphans: 3;
|
|
1545
|
+
widows: 3;
|
|
1546
|
+
}
|
|
1547
|
+
ul, ol {
|
|
1548
|
+
padding-left: 1.6em;
|
|
1549
|
+
}
|
|
1550
|
+
ul {
|
|
1551
|
+
list-style: disc;
|
|
1552
|
+
}
|
|
1553
|
+
ol {
|
|
1554
|
+
list-style: decimal;
|
|
1555
|
+
}
|
|
1556
|
+
li + li, li > ul, li > ol {
|
|
1557
|
+
margin-top: 0.2em;
|
|
1558
|
+
}
|
|
1559
|
+
li > ul, li > ol, li > p:last-child {
|
|
1560
|
+
margin-bottom: 0;
|
|
1561
|
+
}
|
|
1562
|
+
li > p:first-child {
|
|
1563
|
+
margin-top: 0;
|
|
1564
|
+
}
|
|
1565
|
+
li:has(> input[type='checkbox']), li:has(> p:first-child > input[type='checkbox']) {
|
|
1566
|
+
list-style: none;
|
|
1567
|
+
margin-left: -1.4em;
|
|
1568
|
+
}
|
|
1569
|
+
input[type='checkbox'] {
|
|
1570
|
+
appearance: none;
|
|
1571
|
+
width: 0.95em;
|
|
1572
|
+
height: 0.95em;
|
|
1573
|
+
margin: 0 0.45em 0 0;
|
|
1574
|
+
border: 1pt solid #57606a;
|
|
1575
|
+
border-radius: 2pt;
|
|
1576
|
+
vertical-align: -0.12em;
|
|
1577
|
+
background: #ffffff;
|
|
1578
|
+
}
|
|
1579
|
+
input[type='checkbox']:checked {
|
|
1580
|
+
border-color: #1f2328;
|
|
1581
|
+
background: #1f2328 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23ffffff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 90% no-repeat;
|
|
1582
|
+
}
|
|
1583
|
+
a {
|
|
1584
|
+
color: #0969da;
|
|
1585
|
+
text-decoration: underline;
|
|
1586
|
+
text-decoration-color: #9cc3ec;
|
|
1587
|
+
text-underline-offset: 2px;
|
|
1588
|
+
}
|
|
1589
|
+
strong {
|
|
1590
|
+
font-weight: 600;
|
|
1591
|
+
}
|
|
1592
|
+
hr {
|
|
1593
|
+
margin: 1.8em 0;
|
|
1594
|
+
border: 0;
|
|
1595
|
+
border-top: 0.75pt solid #d0d7de;
|
|
1596
|
+
}
|
|
1597
|
+
img {
|
|
1598
|
+
display: block;
|
|
1599
|
+
max-width: 100%;
|
|
1600
|
+
max-height: 230mm;
|
|
1601
|
+
height: auto;
|
|
1602
|
+
margin: 0 auto;
|
|
1603
|
+
break-inside: avoid;
|
|
1604
|
+
}
|
|
1605
|
+
.blocked-image {
|
|
1606
|
+
color: #57606a;
|
|
1607
|
+
font-size: 0.9em;
|
|
1608
|
+
}
|
|
1609
|
+
blockquote {
|
|
1610
|
+
margin-left: 0;
|
|
1611
|
+
margin-right: 0;
|
|
1612
|
+
padding: 0.1em 1em;
|
|
1613
|
+
border-left: 3pt solid #d0d7de;
|
|
1614
|
+
color: #57606a;
|
|
1615
|
+
}
|
|
1616
|
+
blockquote > :first-child {
|
|
1617
|
+
margin-top: 0;
|
|
1618
|
+
}
|
|
1619
|
+
blockquote > :last-child {
|
|
1620
|
+
margin-bottom: 0;
|
|
1621
|
+
}
|
|
1622
|
+
table {
|
|
1623
|
+
display: table;
|
|
1624
|
+
width: 100%;
|
|
1625
|
+
border-collapse: collapse;
|
|
1626
|
+
font-size: 9.5pt;
|
|
1627
|
+
line-height: 1.55;
|
|
1628
|
+
}
|
|
1629
|
+
thead {
|
|
1630
|
+
display: table-header-group;
|
|
1631
|
+
}
|
|
1632
|
+
tr {
|
|
1633
|
+
break-inside: avoid;
|
|
1634
|
+
}
|
|
1635
|
+
th, td {
|
|
1636
|
+
padding: 0.45em 0.75em;
|
|
1637
|
+
border: 0.75pt solid #d0d7de;
|
|
1638
|
+
text-align: left;
|
|
1639
|
+
vertical-align: top;
|
|
1640
|
+
}
|
|
1641
|
+
th {
|
|
1642
|
+
background: #f3f5f7;
|
|
1643
|
+
font-weight: 600;
|
|
1644
|
+
}
|
|
1645
|
+
code, pre {
|
|
1646
|
+
font-family: ${MONO};
|
|
1647
|
+
}
|
|
1648
|
+
:not(pre) > code {
|
|
1649
|
+
padding: 0.1em 0.35em;
|
|
1650
|
+
border-radius: 3pt;
|
|
1651
|
+
background: #eff2f5;
|
|
1652
|
+
font-size: 0.88em;
|
|
1653
|
+
}
|
|
1654
|
+
pre {
|
|
1655
|
+
padding: 0.8em 1em;
|
|
1656
|
+
border: 0.75pt solid #d8dee4;
|
|
1657
|
+
border-radius: 4pt;
|
|
1658
|
+
background: #f6f8fa;
|
|
1659
|
+
font-size: 8.8pt;
|
|
1660
|
+
line-height: 1.55;
|
|
1661
|
+
white-space: pre-wrap;
|
|
1662
|
+
overflow-wrap: anywhere;
|
|
1663
|
+
box-decoration-break: clone;
|
|
1664
|
+
-webkit-box-decoration-break: clone;
|
|
1665
|
+
}
|
|
1666
|
+
.keep-together {
|
|
1667
|
+
break-inside: avoid;
|
|
1668
|
+
}
|
|
1669
|
+
.keep-together > pre, .keep-together > figure {
|
|
1670
|
+
margin: 0;
|
|
1671
|
+
}
|
|
1672
|
+
figure.tm-code-frame > figcaption {
|
|
1673
|
+
margin-bottom: 0.3em;
|
|
1674
|
+
break-after: avoid;
|
|
1675
|
+
font-family: ${MONO};
|
|
1676
|
+
font-size: 8.5pt;
|
|
1677
|
+
color: #57606a;
|
|
1678
|
+
}
|
|
1679
|
+
figure.tm-code-frame > pre {
|
|
1680
|
+
margin: 0;
|
|
1681
|
+
}
|
|
1682
|
+
.th-keyword { color: #cf222e; font-weight: 600; }
|
|
1683
|
+
.th-string, .th-code-inline, .th-inserted { color: #0a3069; }
|
|
1684
|
+
.th-number, .th-literal { color: #0550ae; }
|
|
1685
|
+
.th-comment, .th-meta { color: #59636e; }
|
|
1686
|
+
.th-function, .th-command, .th-property, .th-link { color: #6639ba; }
|
|
1687
|
+
.th-tag { color: #116329; }
|
|
1688
|
+
.th-type, .th-attr, .th-selector, .th-variable { color: #953800; }
|
|
1689
|
+
.th-heading { color: #0550ae; font-weight: 600; }
|
|
1690
|
+
.th-deleted { color: #82071e; }
|
|
1691
|
+
.footnotes {
|
|
1692
|
+
margin-top: 2em;
|
|
1693
|
+
padding-top: 0.6em;
|
|
1694
|
+
border-top: 0.75pt solid #d0d7de;
|
|
1695
|
+
font-size: 9pt;
|
|
1696
|
+
color: #57606a;
|
|
1697
|
+
}
|
|
1698
|
+
.footnotes ol {
|
|
1699
|
+
margin: 0;
|
|
1700
|
+
}
|
|
1701
|
+
/* The hidden "Footnotes" heading of the renderer would appear in the PDF outline. */
|
|
1702
|
+
.sr-only {
|
|
1703
|
+
display: none;
|
|
1704
|
+
}
|
|
1705
|
+
.data-footnote-backref {
|
|
1706
|
+
text-decoration: none;
|
|
1707
|
+
font-variant-emoji: text;
|
|
1708
|
+
}
|
|
1709
|
+
`;
|
|
1710
|
+
//#endregion
|
|
1711
|
+
//#region ../../packages/document/src/print.ts
|
|
1712
|
+
const PRINT_CSP = "default-src 'none'; img-src data:; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'";
|
|
1713
|
+
const KANA = /[\u3041-\u3096\u30a1-\u30fa]/;
|
|
1714
|
+
const HANGUL = /[\uac00-\ud7af]/;
|
|
1715
|
+
const IMAGE_SLOT = /^[0-9a-f]{32,}$/;
|
|
1716
|
+
const KEEP_TOGETHER_LINES = 25;
|
|
1717
|
+
const HEADER_TITLE_LENGTH = 60;
|
|
1718
|
+
function escapeHtml(value) {
|
|
1719
|
+
return value.replace(/[&<>"'`]/g, (character) => `&#${String(character.charCodeAt(0))};`);
|
|
1720
|
+
}
|
|
1721
|
+
function cssString(value) {
|
|
1722
|
+
let escaped = "";
|
|
1723
|
+
for (const character of value) escaped += /^[A-Za-z0-9 ]$/.test(character) ? character : `\\${(character.codePointAt(0) ?? 65533).toString(16)} `;
|
|
1724
|
+
return `"${escaped}"`;
|
|
1725
|
+
}
|
|
1726
|
+
function headerTitle(title) {
|
|
1727
|
+
const characters = Array.from(title);
|
|
1728
|
+
return characters.length > HEADER_TITLE_LENGTH ? `${characters.slice(0, 59).join("")}…` : title;
|
|
1729
|
+
}
|
|
1730
|
+
function printNodes(input, baseOptions) {
|
|
1731
|
+
const images = new Map(input.images.map((logicalPath, index) => [logicalPath, index]));
|
|
1732
|
+
return {
|
|
1733
|
+
name: "vde-open-print",
|
|
1734
|
+
renderHtml(node, context) {
|
|
1735
|
+
if (node.type === "image") {
|
|
1736
|
+
const logicalPath = localImagePath(node.src, input.documentLogicalPath);
|
|
1737
|
+
const index = logicalPath === null ? void 0 : images.get(logicalPath);
|
|
1738
|
+
if (index === void 0) return `<span class="blocked-image">${escapeHtml(node.alt ? `[image: ${node.alt}]` : "[image]")}</span>`;
|
|
1739
|
+
const title = node.title ? ` title="${escapeHtml(node.title)}"` : "";
|
|
1740
|
+
return `<img src="${input.imageSlot}-${String(index)}" alt="${escapeHtml(node.alt)}"${title}>`;
|
|
1741
|
+
}
|
|
1742
|
+
if (node.type === "link") {
|
|
1743
|
+
const children = node.children.map((child) => context.renderInline(child)).join("");
|
|
1744
|
+
const kind = renderedLinkOf(node.href);
|
|
1745
|
+
if (kind !== "fragment" && kind !== "external") return children;
|
|
1746
|
+
const title = node.title ? ` title="${escapeHtml(node.title)}"` : "";
|
|
1747
|
+
return `<a href="${escapeHtml(node.href)}"${title}>${children}</a>`;
|
|
1748
|
+
}
|
|
1749
|
+
if (node.type === "code" && node.value.split("\n").length <= KEEP_TOGETHER_LINES) return `<div class="keep-together">${renderBlock(node, baseOptions)}</div>`;
|
|
1750
|
+
}
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
function renderPrintDocument(input) {
|
|
1754
|
+
if (!IMAGE_SLOT.test(input.imageSlot)) throw new Error("The image slot must be random hexadecimal.");
|
|
1755
|
+
const baseOptions = {
|
|
1756
|
+
...MARKDOWN_PARSE_OPTIONS,
|
|
1757
|
+
allowHtml: false,
|
|
1758
|
+
highlighter: safeHighlighter
|
|
1759
|
+
};
|
|
1760
|
+
const body = renderDocument(parseMarkdownDocument(input.source), {
|
|
1761
|
+
...baseOptions,
|
|
1762
|
+
extensions: [printNodes(input, baseOptions)]
|
|
1763
|
+
});
|
|
1764
|
+
return [
|
|
1765
|
+
"<!doctype html>",
|
|
1766
|
+
`<html${KANA.test(input.source) ? " lang=\"ja\"" : HANGUL.test(input.source) ? " lang=\"ko\"" : ""}>`,
|
|
1767
|
+
"<head>",
|
|
1768
|
+
"<meta charset=\"utf-8\">",
|
|
1769
|
+
`<meta http-equiv="Content-Security-Policy" content="${PRINT_CSP}">`,
|
|
1770
|
+
`<title>${escapeHtml(input.title)}</title>`,
|
|
1771
|
+
`<style>${printPageStyle(cssString(headerTitle(input.title)))}${PRINT_STYLE}</style>`,
|
|
1772
|
+
"</head>",
|
|
1773
|
+
`<body><main class="document">${body}</main></body>`,
|
|
1774
|
+
"</html>",
|
|
1775
|
+
""
|
|
1776
|
+
].join("\n");
|
|
1777
|
+
}
|
|
1778
|
+
//#endregion
|
|
1779
|
+
export { cssString, headerTitle, renderPrintDocument };
|