quoin-editor 0.4.2 → 1.0.0
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/CHANGELOG.md +205 -0
- package/MIGRATION.md +233 -0
- package/README.md +78 -716
- package/dist/ai.cjs +1107 -0
- package/dist/ai.cjs.map +1 -0
- package/dist/ai.d.cts +68 -0
- package/dist/ai.d.ts +68 -0
- package/dist/ai.js +1107 -0
- package/dist/ai.js.map +1 -0
- package/dist/catalogue.cjs +59 -0
- package/dist/catalogue.cjs.map +1 -0
- package/dist/catalogue.d.cts +39 -0
- package/dist/catalogue.d.ts +39 -0
- package/dist/catalogue.js +59 -0
- package/dist/catalogue.js.map +1 -0
- package/dist/chunk-2QCRZ7OL.cjs +319 -0
- package/dist/chunk-2QCRZ7OL.cjs.map +1 -0
- package/dist/chunk-2VDK27IF.cjs +6666 -0
- package/dist/chunk-2VDK27IF.cjs.map +1 -0
- package/dist/chunk-47MLKSI2.js +326 -0
- package/dist/chunk-47MLKSI2.js.map +1 -0
- package/dist/chunk-5DNCCN6X.cjs +326 -0
- package/dist/chunk-5DNCCN6X.cjs.map +1 -0
- package/dist/chunk-AEJXZBVR.cjs +1378 -0
- package/dist/chunk-AEJXZBVR.cjs.map +1 -0
- package/dist/chunk-CDELOHDY.cjs +239 -0
- package/dist/chunk-CDELOHDY.cjs.map +1 -0
- package/dist/chunk-E75EHRPA.cjs +175 -0
- package/dist/chunk-E75EHRPA.cjs.map +1 -0
- package/dist/chunk-EL2OEJQC.cjs +562 -0
- package/dist/chunk-EL2OEJQC.cjs.map +1 -0
- package/dist/chunk-GLLXHMH2.cjs +25 -0
- package/dist/chunk-GLLXHMH2.cjs.map +1 -0
- package/dist/chunk-GTTPVJSD.cjs +3286 -0
- package/dist/chunk-GTTPVJSD.cjs.map +1 -0
- package/dist/chunk-HELJTLNC.cjs +100 -0
- package/dist/chunk-HELJTLNC.cjs.map +1 -0
- package/dist/chunk-HJIQT3S5.js +4047 -0
- package/dist/chunk-HJIQT3S5.js.map +1 -0
- package/dist/chunk-HZSSEYJS.cjs +504 -0
- package/dist/chunk-HZSSEYJS.cjs.map +1 -0
- package/dist/chunk-JDPTZUBW.js +184 -0
- package/dist/chunk-JDPTZUBW.js.map +1 -0
- package/dist/chunk-JEIFJHEI.js +14 -0
- package/dist/chunk-JEIFJHEI.js.map +1 -0
- package/dist/chunk-K574XHMM.js +25 -0
- package/dist/chunk-K574XHMM.js.map +1 -0
- package/dist/chunk-KAVU6T6J.js +249 -0
- package/dist/chunk-KAVU6T6J.js.map +1 -0
- package/dist/chunk-KXOBZGQO.js +1378 -0
- package/dist/chunk-KXOBZGQO.js.map +1 -0
- package/dist/chunk-LCQSG4M6.js +3335 -0
- package/dist/chunk-LCQSG4M6.js.map +1 -0
- package/dist/chunk-MQ2XQ4MX.js +100 -0
- package/dist/chunk-MQ2XQ4MX.js.map +1 -0
- package/dist/chunk-ND5XJVK2.cjs +3335 -0
- package/dist/chunk-ND5XJVK2.cjs.map +1 -0
- package/dist/chunk-NNDYYEW5.js +504 -0
- package/dist/chunk-NNDYYEW5.js.map +1 -0
- package/dist/chunk-NOKWNK2O.js +319 -0
- package/dist/chunk-NOKWNK2O.js.map +1 -0
- package/dist/chunk-OMOBMXD5.cjs +57 -0
- package/dist/chunk-OMOBMXD5.cjs.map +1 -0
- package/dist/chunk-PMWCQSQX.js +239 -0
- package/dist/chunk-PMWCQSQX.js.map +1 -0
- package/dist/chunk-POBM7MGR.js +30 -0
- package/dist/chunk-POBM7MGR.js.map +1 -0
- package/dist/chunk-PWUEPDA3.cjs +598 -0
- package/dist/chunk-PWUEPDA3.cjs.map +1 -0
- package/dist/chunk-PZ4GT5JO.cjs +4047 -0
- package/dist/chunk-PZ4GT5JO.cjs.map +1 -0
- package/dist/chunk-QAW5NH6S.cjs +14 -0
- package/dist/chunk-QAW5NH6S.cjs.map +1 -0
- package/dist/chunk-RDG4VI6E.cjs +706 -0
- package/dist/chunk-RDG4VI6E.cjs.map +1 -0
- package/dist/chunk-RUDWMKYX.js +562 -0
- package/dist/chunk-RUDWMKYX.js.map +1 -0
- package/dist/chunk-SG37UBDO.js +706 -0
- package/dist/chunk-SG37UBDO.js.map +1 -0
- package/dist/chunk-SLVDAHHK.cjs +30 -0
- package/dist/chunk-SLVDAHHK.cjs.map +1 -0
- package/dist/chunk-T7SW6OWV.js +598 -0
- package/dist/chunk-T7SW6OWV.js.map +1 -0
- package/dist/chunk-TC4DARU2.js +175 -0
- package/dist/chunk-TC4DARU2.js.map +1 -0
- package/dist/chunk-WQHV3MRE.cjs +184 -0
- package/dist/chunk-WQHV3MRE.cjs.map +1 -0
- package/dist/chunk-WXMYDXPN.cjs +33 -0
- package/dist/chunk-WXMYDXPN.cjs.map +1 -0
- package/dist/chunk-XEBWC7ZL.js +57 -0
- package/dist/chunk-XEBWC7ZL.js.map +1 -0
- package/dist/chunk-ZC24WB7Y.cjs +249 -0
- package/dist/chunk-ZC24WB7Y.cjs.map +1 -0
- package/dist/chunk-ZGZEJCRV.js +6666 -0
- package/dist/chunk-ZGZEJCRV.js.map +1 -0
- package/dist/chunk-ZHOSSWUM.js +33 -0
- package/dist/chunk-ZHOSSWUM.js.map +1 -0
- package/dist/chunk-ZS2WA357.js +3286 -0
- package/dist/chunk-ZS2WA357.js.map +1 -0
- package/dist/comments.cjs +993 -0
- package/dist/comments.cjs.map +1 -0
- package/dist/comments.d.cts +88 -0
- package/dist/comments.d.ts +88 -0
- package/dist/comments.js +993 -0
- package/dist/comments.js.map +1 -0
- package/dist/diff.cjs +343 -0
- package/dist/diff.cjs.map +1 -0
- package/dist/diff.d.cts +67 -0
- package/dist/diff.d.ts +67 -0
- package/dist/diff.js +343 -0
- package/dist/diff.js.map +1 -0
- package/dist/docx.cjs +854 -0
- package/dist/docx.cjs.map +1 -0
- package/dist/docx.d.cts +27 -0
- package/dist/docx.d.ts +27 -0
- package/dist/docx.js +854 -0
- package/dist/docx.js.map +1 -0
- package/dist/embed-provider-jXwlRmnp.d.cts +19 -0
- package/dist/embed-provider-jXwlRmnp.d.ts +19 -0
- package/dist/embed.cjs +17 -0
- package/dist/embed.cjs.map +1 -0
- package/dist/embed.d.cts +56 -0
- package/dist/embed.d.ts +56 -0
- package/dist/embed.js +17 -0
- package/dist/embed.js.map +1 -0
- package/dist/emoji-data.cjs +1968 -0
- package/dist/emoji-data.cjs.map +1 -0
- package/dist/emoji-data.js +1968 -0
- package/dist/emoji-data.js.map +1 -0
- package/dist/emoji-extension-C12gDPm6.d.cts +46 -0
- package/dist/emoji-extension-DpQ43HjE.d.ts +46 -0
- package/dist/emoji.cjs +18 -0
- package/dist/emoji.cjs.map +1 -0
- package/dist/emoji.d.cts +31 -0
- package/dist/emoji.d.ts +31 -0
- package/dist/emoji.js +18 -0
- package/dist/emoji.js.map +1 -0
- package/dist/engine.cjs +119 -0
- package/dist/engine.cjs.map +1 -0
- package/dist/engine.d.cts +144 -0
- package/dist/engine.d.ts +144 -0
- package/dist/engine.js +119 -0
- package/dist/engine.js.map +1 -0
- package/dist/find-extension-DKqLLSuP.d.ts +41 -0
- package/dist/find-extension-_sbZEt3R.d.cts +41 -0
- package/dist/find.cjs +20 -0
- package/dist/find.cjs.map +1 -0
- package/dist/find.d.cts +44 -0
- package/dist/find.d.ts +44 -0
- package/dist/find.js +20 -0
- package/dist/find.js.map +1 -0
- package/dist/headless.cjs +151 -518
- package/dist/headless.cjs.map +1 -1
- package/dist/headless.d.cts +102 -69
- package/dist/headless.d.ts +102 -69
- package/dist/headless.js +149 -467
- package/dist/headless.js.map +1 -1
- package/dist/index-CgD72kHB.d.cts +65 -0
- package/dist/index-DNYbTK3w.d.ts +65 -0
- package/dist/index.cjs +183 -2753
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +345 -253
- package/dist/index.d.ts +345 -253
- package/dist/index.js +168 -2696
- package/dist/index.js.map +1 -1
- package/dist/math.cjs +18 -0
- package/dist/math.cjs.map +1 -0
- package/dist/math.d.cts +49 -0
- package/dist/math.d.ts +49 -0
- package/dist/math.js +18 -0
- package/dist/math.js.map +1 -0
- package/dist/mention.cjs +18 -0
- package/dist/mention.cjs.map +1 -0
- package/dist/mention.d.cts +50 -0
- package/dist/mention.d.ts +50 -0
- package/dist/mention.js +18 -0
- package/dist/mention.js.map +1 -0
- package/dist/presence.cjs +565 -0
- package/dist/presence.cjs.map +1 -0
- package/dist/presence.d.cts +30 -0
- package/dist/presence.d.ts +30 -0
- package/dist/presence.js +565 -0
- package/dist/presence.js.map +1 -0
- package/dist/registry-CWBOSAHm.d.cts +121 -0
- package/dist/registry-CWBOSAHm.d.ts +121 -0
- package/dist/stats-extension-Bly88uio.d.ts +40 -0
- package/dist/stats-extension-CJPijvUb.d.cts +40 -0
- package/dist/stats.cjs +19 -0
- package/dist/stats.cjs.map +1 -0
- package/dist/stats.d.cts +19 -0
- package/dist/stats.d.ts +19 -0
- package/dist/stats.js +19 -0
- package/dist/stats.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/table-extension-BTLxFy2S.d.cts +57 -0
- package/dist/table-extension-Dzf4k6hI.d.ts +57 -0
- package/dist/table.cjs +50 -0
- package/dist/table.cjs.map +1 -0
- package/dist/table.d.cts +57 -0
- package/dist/table.d.ts +57 -0
- package/dist/table.js +50 -0
- package/dist/table.js.map +1 -0
- package/dist/to-html-C5t7xyaM.d.ts +21 -0
- package/dist/to-html-CNCITCln.d.cts +21 -0
- package/dist/toc-extension-B3-s6h2x.d.cts +25 -0
- package/dist/toc-extension-DWm5alVj.d.ts +25 -0
- package/dist/toc.cjs +18 -0
- package/dist/toc.cjs.map +1 -0
- package/dist/toc.d.cts +24 -0
- package/dist/toc.d.ts +24 -0
- package/dist/toc.js +18 -0
- package/dist/toc.js.map +1 -0
- package/dist/types-Cz7XJLaK.d.cts +366 -0
- package/dist/types-DULc8wwg.d.cts +120 -0
- package/dist/types-DULc8wwg.d.ts +120 -0
- package/dist/types-a1CRBlEh.d.ts +366 -0
- package/dist/view-controller-DSHw0ltQ.d.cts +118 -0
- package/dist/view-controller-UbpzblGl.d.ts +118 -0
- package/dist/view.cjs +23 -0
- package/dist/view.cjs.map +1 -0
- package/dist/view.d.cts +40 -0
- package/dist/view.d.ts +40 -0
- package/dist/view.js +23 -0
- package/dist/view.js.map +1 -0
- package/dist/yjs.cjs +1026 -0
- package/dist/yjs.cjs.map +1 -0
- package/dist/yjs.d.cts +22 -0
- package/dist/yjs.d.ts +22 -0
- package/dist/yjs.js +1026 -0
- package/dist/yjs.js.map +1 -0
- package/package.json +217 -18
|
@@ -0,0 +1,3335 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/engine/model/attrs.ts
|
|
2
|
+
function sameAttrs(a, b) {
|
|
3
|
+
const left = _nullishCoalesce(a, () => ( {}));
|
|
4
|
+
const right = _nullishCoalesce(b, () => ( {}));
|
|
5
|
+
const keys = Object.keys(left);
|
|
6
|
+
return keys.length === Object.keys(right).length && keys.every((k) => left[k] === right[k]);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/engine/model/compare.ts
|
|
10
|
+
var DIGITS = /^\d+$/;
|
|
11
|
+
function compareCodeUnits(a, b) {
|
|
12
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
13
|
+
}
|
|
14
|
+
function compareDigitRuns(a, b) {
|
|
15
|
+
const x = a.replace(/^0+/, "");
|
|
16
|
+
const y = b.replace(/^0+/, "");
|
|
17
|
+
if (x.length !== y.length) return x.length < y.length ? -1 : 1;
|
|
18
|
+
return compareCodeUnits(x, y) || compareCodeUnits(a, b);
|
|
19
|
+
}
|
|
20
|
+
function compareSegments(a, b) {
|
|
21
|
+
const aNumber = DIGITS.test(a);
|
|
22
|
+
const bNumber = DIGITS.test(b);
|
|
23
|
+
if (aNumber && bNumber) return compareDigitRuns(a, b);
|
|
24
|
+
if (aNumber !== bNumber) return aNumber ? -1 : 1;
|
|
25
|
+
return compareCodeUnits(a, b);
|
|
26
|
+
}
|
|
27
|
+
function compareRegionNames(a, b) {
|
|
28
|
+
const left = a.split(":");
|
|
29
|
+
const right = b.split(":");
|
|
30
|
+
const shared = Math.min(left.length, right.length);
|
|
31
|
+
for (let i = 0; i < shared; i++) {
|
|
32
|
+
const order = compareSegments(left[i], right[i]);
|
|
33
|
+
if (order !== 0) return order;
|
|
34
|
+
}
|
|
35
|
+
return left.length < right.length ? -1 : left.length > right.length ? 1 : 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/engine/model/same-items.ts
|
|
39
|
+
var sameItems = (a, b, same = (x, y) => x === y) => a.length === b.length && a.every((item, i) => same(item, b[i]));
|
|
40
|
+
|
|
41
|
+
// src/engine/model/marks.ts
|
|
42
|
+
var RANK = {
|
|
43
|
+
link: 0,
|
|
44
|
+
comment: 1,
|
|
45
|
+
bold: 2,
|
|
46
|
+
italic: 3,
|
|
47
|
+
underline: 4,
|
|
48
|
+
strike: 5,
|
|
49
|
+
sub: 6,
|
|
50
|
+
sup: 7,
|
|
51
|
+
highlight: 8,
|
|
52
|
+
color: 9,
|
|
53
|
+
background: 10,
|
|
54
|
+
code: 11
|
|
55
|
+
};
|
|
56
|
+
var CUSTOM_RANK = 7.5;
|
|
57
|
+
var STACKABLE = /* @__PURE__ */ new Set(["comment"]);
|
|
58
|
+
function isCoreMark(type) {
|
|
59
|
+
return Object.hasOwn(RANK, type);
|
|
60
|
+
}
|
|
61
|
+
function markRank(type) {
|
|
62
|
+
return isCoreMark(type) ? RANK[type] : CUSTOM_RANK;
|
|
63
|
+
}
|
|
64
|
+
function markKey(mark) {
|
|
65
|
+
return STACKABLE.has(mark.type) ? `${mark.type}:${_nullishCoalesce(_optionalChain([mark, 'access', _3 => _3.attrs, 'optionalAccess', _4 => _4.id]), () => ( ""))}` : mark.type;
|
|
66
|
+
}
|
|
67
|
+
function sameMark(a, b) {
|
|
68
|
+
return a.type === b.type && sameAttrs(a.attrs, b.attrs);
|
|
69
|
+
}
|
|
70
|
+
function compareMarks(a, b) {
|
|
71
|
+
return markRank(a.type) - markRank(b.type) || compareCodeUnits(markKey(a), markKey(b));
|
|
72
|
+
}
|
|
73
|
+
function sortMarks(marks) {
|
|
74
|
+
return [...marks].sort(compareMarks);
|
|
75
|
+
}
|
|
76
|
+
function sameMarkSet(a, b) {
|
|
77
|
+
return sameItems(a, b, sameMark);
|
|
78
|
+
}
|
|
79
|
+
function addMark(set, mark) {
|
|
80
|
+
const key = markKey(mark);
|
|
81
|
+
return sortMarks([...set.filter((m) => markKey(m) !== key), mark]);
|
|
82
|
+
}
|
|
83
|
+
function removeMark(set, mark) {
|
|
84
|
+
if (typeof mark === "string") return sortMarks(set.filter((m) => m.type !== mark));
|
|
85
|
+
const key = markKey(mark);
|
|
86
|
+
return sortMarks(set.filter((m) => markKey(m) !== key));
|
|
87
|
+
}
|
|
88
|
+
function hasMark(set, mark) {
|
|
89
|
+
return typeof mark === "string" ? set.some((m) => m.type === mark) : set.some((m) => sameMark(m, mark));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/engine/model/inline.ts
|
|
93
|
+
var OBJECT_REPLACEMENT = "\uFFFC";
|
|
94
|
+
function text(value, marks = []) {
|
|
95
|
+
return { kind: "text", text: value, marks: sortMarks(marks) };
|
|
96
|
+
}
|
|
97
|
+
function atom(type, attrs, marks = []) {
|
|
98
|
+
return { kind: "atom", type, attrs, marks: sortMarks(marks) };
|
|
99
|
+
}
|
|
100
|
+
function nodeLength(node) {
|
|
101
|
+
return node.kind === "text" ? node.text.length : 1;
|
|
102
|
+
}
|
|
103
|
+
function withMarks(node, marks) {
|
|
104
|
+
return node.kind === "text" ? text(node.text, marks) : atom(node.type, node.attrs, marks);
|
|
105
|
+
}
|
|
106
|
+
function splitCodeBreaks(node) {
|
|
107
|
+
if (node.kind === "atom" || !node.text.includes("\n") || !hasMark(node.marks, "code")) return [node];
|
|
108
|
+
const withoutCode = removeMark(node.marks, "code");
|
|
109
|
+
return node.text.split(/(\n)/).map((part) => text(part, part === "\n" ? withoutCode : node.marks));
|
|
110
|
+
}
|
|
111
|
+
function normalizeInline(nodes) {
|
|
112
|
+
const result = [];
|
|
113
|
+
for (const node of nodes.flatMap(splitCodeBreaks)) {
|
|
114
|
+
if (node.kind === "text" && node.text === "") continue;
|
|
115
|
+
const sorted = withMarks(node, node.marks);
|
|
116
|
+
const last = result[result.length - 1];
|
|
117
|
+
if (_optionalChain([last, 'optionalAccess', _5 => _5.kind]) === "text" && sorted.kind === "text" && sameMarkSet(last.marks, sorted.marks)) {
|
|
118
|
+
result[result.length - 1] = text(last.text + sorted.text, last.marks);
|
|
119
|
+
} else {
|
|
120
|
+
result.push(sorted);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
function inlineLength(inline) {
|
|
126
|
+
return inline.reduce((sum, node) => sum + nodeLength(node), 0);
|
|
127
|
+
}
|
|
128
|
+
function inlineText(inline, atomText = () => OBJECT_REPLACEMENT) {
|
|
129
|
+
return inline.map((node) => node.kind === "text" ? node.text : atomText(node)).join("");
|
|
130
|
+
}
|
|
131
|
+
function sliceInline(inline, from, to) {
|
|
132
|
+
const result = [];
|
|
133
|
+
let start = 0;
|
|
134
|
+
for (const node of inline) {
|
|
135
|
+
const end = start + nodeLength(node);
|
|
136
|
+
if (end > from && start < to) {
|
|
137
|
+
const cutFrom = Math.max(0, from - start);
|
|
138
|
+
result.push(node.kind === "atom" ? node : text(node.text.slice(cutFrom, to - start), node.marks));
|
|
139
|
+
}
|
|
140
|
+
start = end;
|
|
141
|
+
}
|
|
142
|
+
return normalizeInline(result);
|
|
143
|
+
}
|
|
144
|
+
function assertRange(inline, from, to) {
|
|
145
|
+
const length = inlineLength(inline);
|
|
146
|
+
if (from < 0 || from > to || to > length) {
|
|
147
|
+
throw new RangeError(`range ${from} to ${to} is outside 0 to ${length}`);
|
|
148
|
+
}
|
|
149
|
+
return length;
|
|
150
|
+
}
|
|
151
|
+
function replaceInline(inline, from, to, slice) {
|
|
152
|
+
const length = assertRange(inline, from, to);
|
|
153
|
+
return normalizeInline([...sliceInline(inline, 0, from), ...slice, ...sliceInline(inline, to, length)]);
|
|
154
|
+
}
|
|
155
|
+
function mapMarksInRange(inline, from, to, update) {
|
|
156
|
+
assertRange(inline, from, to);
|
|
157
|
+
const result = [];
|
|
158
|
+
let start = 0;
|
|
159
|
+
for (const node of inline) {
|
|
160
|
+
const end = start + nodeLength(node);
|
|
161
|
+
if (end <= from || start >= to) {
|
|
162
|
+
result.push(node);
|
|
163
|
+
} else if (node.kind === "atom") {
|
|
164
|
+
result.push(withMarks(node, update(node.marks)));
|
|
165
|
+
} else {
|
|
166
|
+
const cutFrom = Math.max(from, start) - start;
|
|
167
|
+
const cutTo = Math.min(to, end) - start;
|
|
168
|
+
result.push(
|
|
169
|
+
text(node.text.slice(0, cutFrom), node.marks),
|
|
170
|
+
text(node.text.slice(cutFrom, cutTo), update(node.marks)),
|
|
171
|
+
text(node.text.slice(cutTo), node.marks)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
start = end;
|
|
175
|
+
}
|
|
176
|
+
return normalizeInline(result);
|
|
177
|
+
}
|
|
178
|
+
function addMarkRange(inline, from, to, mark) {
|
|
179
|
+
return mapMarksInRange(inline, from, to, (marks) => addMark(marks, mark));
|
|
180
|
+
}
|
|
181
|
+
function removeMarkRange(inline, from, to, mark) {
|
|
182
|
+
return mapMarksInRange(inline, from, to, (marks) => removeMark(marks, mark));
|
|
183
|
+
}
|
|
184
|
+
function nodeAt(inline, offset) {
|
|
185
|
+
let start = 0;
|
|
186
|
+
for (const node of inline) {
|
|
187
|
+
const end = start + nodeLength(node);
|
|
188
|
+
if (offset >= start && offset < end) return node;
|
|
189
|
+
start = end;
|
|
190
|
+
}
|
|
191
|
+
return void 0;
|
|
192
|
+
}
|
|
193
|
+
function isInclusiveMark(mark) {
|
|
194
|
+
return mark.type !== "link" && mark.type !== "comment";
|
|
195
|
+
}
|
|
196
|
+
function marksAt(inline, offset, isInclusive = isInclusiveMark) {
|
|
197
|
+
const before = _nullishCoalesce(_optionalChain([nodeAt, 'call', _6 => _6(inline, Math.max(0, offset - 1)), 'optionalAccess', _7 => _7.marks]), () => ( []));
|
|
198
|
+
const after = _nullishCoalesce(_optionalChain([nodeAt, 'call', _8 => _8(inline, offset), 'optionalAccess', _9 => _9.marks]), () => ( []));
|
|
199
|
+
return before.filter((mark) => isInclusive(mark) || hasMark(after, mark));
|
|
200
|
+
}
|
|
201
|
+
function equalNode(a, b) {
|
|
202
|
+
if (!sameMarkSet(a.marks, b.marks)) return false;
|
|
203
|
+
if (a.kind === "text") return b.kind === "text" && a.text === b.text;
|
|
204
|
+
return b.kind === "atom" && a.type === b.type && sameAttrs(a.attrs, b.attrs);
|
|
205
|
+
}
|
|
206
|
+
function equalInline(a, b) {
|
|
207
|
+
return sameItems(a, b, equalNode);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/engine/markdown/palette.ts
|
|
211
|
+
var PALETTE = [
|
|
212
|
+
"default",
|
|
213
|
+
"gray",
|
|
214
|
+
"brown",
|
|
215
|
+
"orange",
|
|
216
|
+
"yellow",
|
|
217
|
+
"green",
|
|
218
|
+
"blue",
|
|
219
|
+
"purple",
|
|
220
|
+
"pink",
|
|
221
|
+
"red"
|
|
222
|
+
];
|
|
223
|
+
function isPaletteColor(name) {
|
|
224
|
+
return PALETTE.includes(name);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/engine/model/is-record.ts
|
|
228
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
229
|
+
|
|
230
|
+
// src/engine/blocks/data-fields.ts
|
|
231
|
+
var ALIGNMENTS = ["left", "center", "right", "justify"];
|
|
232
|
+
function str(value) {
|
|
233
|
+
return typeof value === "string" ? value : "";
|
|
234
|
+
}
|
|
235
|
+
function optionalString(value) {
|
|
236
|
+
return typeof value === "string" ? value : void 0;
|
|
237
|
+
}
|
|
238
|
+
function optionalNumber(value) {
|
|
239
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
240
|
+
}
|
|
241
|
+
function paletteOrUndefined(value) {
|
|
242
|
+
return typeof value === "string" && isPaletteColor(value) ? value : void 0;
|
|
243
|
+
}
|
|
244
|
+
function alignOrUndefined(value) {
|
|
245
|
+
return typeof value === "string" && ALIGNMENTS.includes(value) ? value : void 0;
|
|
246
|
+
}
|
|
247
|
+
function extraFields(data, known) {
|
|
248
|
+
const entries = Object.entries(data).filter(([key]) => !known.includes(key));
|
|
249
|
+
return entries.length ? Object.fromEntries(entries) : void 0;
|
|
250
|
+
}
|
|
251
|
+
function withDefined(record) {
|
|
252
|
+
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== void 0));
|
|
253
|
+
}
|
|
254
|
+
function withExtra(fields, attrs) {
|
|
255
|
+
const { extra } = attrs;
|
|
256
|
+
return { ...withDefined(fields), ...isRecord(extra) ? extra : void 0 };
|
|
257
|
+
}
|
|
258
|
+
function regionOf(block, name) {
|
|
259
|
+
return _nullishCoalesce(block.regions[name], () => ( []));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/engine/blocks/bookmark-spec.ts
|
|
263
|
+
var KNOWN = ["url", "title", "description", "image"];
|
|
264
|
+
var bookmarkSpec = {
|
|
265
|
+
type: "BOOKMARK",
|
|
266
|
+
flow: "void",
|
|
267
|
+
fromData: (data) => ({
|
|
268
|
+
attrs: withDefined({
|
|
269
|
+
url: str(data.url),
|
|
270
|
+
title: optionalString(data.title),
|
|
271
|
+
description: optionalString(data.description),
|
|
272
|
+
image: optionalString(data.image),
|
|
273
|
+
extra: extraFields(data, KNOWN)
|
|
274
|
+
}),
|
|
275
|
+
regions: {}
|
|
276
|
+
}),
|
|
277
|
+
toData: ({ attrs }) => withExtra(
|
|
278
|
+
{
|
|
279
|
+
url: str(attrs.url),
|
|
280
|
+
title: optionalString(attrs.title),
|
|
281
|
+
description: optionalString(attrs.description),
|
|
282
|
+
image: optionalString(attrs.image)
|
|
283
|
+
},
|
|
284
|
+
attrs
|
|
285
|
+
),
|
|
286
|
+
initial: () => ({ attrs: { url: "" }, regions: {} })
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/engine/blocks/callout-spec.ts
|
|
290
|
+
var KNOWN2 = ["tone", "body", "icon"];
|
|
291
|
+
var calloutSpec = {
|
|
292
|
+
type: "CALLOUT",
|
|
293
|
+
flow: "text",
|
|
294
|
+
primaryRegion: "body",
|
|
295
|
+
enter: "hardBreak",
|
|
296
|
+
fromData: (data, ctx) => ({
|
|
297
|
+
attrs: withDefined({ tone: str(data.tone), icon: optionalString(data.icon), extra: extraFields(data, KNOWN2) }),
|
|
298
|
+
regions: { body: ctx.inline.parse(str(data.body)) }
|
|
299
|
+
}),
|
|
300
|
+
toData: (block, ctx) => withExtra(
|
|
301
|
+
{
|
|
302
|
+
tone: str(block.attrs.tone),
|
|
303
|
+
body: ctx.inline.serialize(regionOf(block, "body"), { escapeLineStart: true }),
|
|
304
|
+
icon: optionalString(block.attrs.icon)
|
|
305
|
+
},
|
|
306
|
+
block.attrs
|
|
307
|
+
),
|
|
308
|
+
initial: () => ({ attrs: { tone: "info" }, regions: { body: [] } })
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/engine/blocks/code-spec.ts
|
|
312
|
+
var KNOWN3 = ["language", "code"];
|
|
313
|
+
var codeSpec = {
|
|
314
|
+
type: "CODE",
|
|
315
|
+
flow: "void",
|
|
316
|
+
fromData: (data) => ({
|
|
317
|
+
attrs: withDefined({ language: str(data.language), code: str(data.code), extra: extraFields(data, KNOWN3) }),
|
|
318
|
+
regions: {}
|
|
319
|
+
}),
|
|
320
|
+
toData: ({ attrs }) => withExtra({ language: str(attrs.language), code: str(attrs.code) }, attrs),
|
|
321
|
+
initial: () => ({ attrs: { language: "", code: "" }, regions: {} })
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/engine/blocks/marker-spec.ts
|
|
325
|
+
function markerSpec(type) {
|
|
326
|
+
return {
|
|
327
|
+
type,
|
|
328
|
+
flow: "void",
|
|
329
|
+
fromData: (data) => ({ attrs: withDefined({ extra: extraFields(data, []) }), regions: {} }),
|
|
330
|
+
toData: ({ attrs }) => withExtra({}, attrs),
|
|
331
|
+
initial: () => ({ attrs: {}, regions: {} })
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/engine/blocks/divider-spec.ts
|
|
336
|
+
var dividerSpec = markerSpec("DIVIDER");
|
|
337
|
+
|
|
338
|
+
// src/engine/blocks/embed-spec.ts
|
|
339
|
+
var KNOWN4 = ["url", "provider"];
|
|
340
|
+
var embedSpec = {
|
|
341
|
+
type: "EMBED",
|
|
342
|
+
flow: "void",
|
|
343
|
+
fromData: (data) => ({
|
|
344
|
+
attrs: withDefined({ url: str(data.url), provider: str(data.provider), extra: extraFields(data, KNOWN4) }),
|
|
345
|
+
regions: {}
|
|
346
|
+
}),
|
|
347
|
+
toData: ({ attrs }) => withExtra({ url: str(attrs.url), provider: str(attrs.provider) }, attrs),
|
|
348
|
+
initial: () => ({ attrs: { url: "", provider: "" }, regions: {} })
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/engine/blocks/file-spec.ts
|
|
352
|
+
var KNOWN5 = ["storageKey", "filename", "size", "mime"];
|
|
353
|
+
var fileSpec = {
|
|
354
|
+
type: "FILE",
|
|
355
|
+
flow: "void",
|
|
356
|
+
fromData: (data) => ({
|
|
357
|
+
attrs: withDefined({
|
|
358
|
+
storageKey: str(data.storageKey),
|
|
359
|
+
filename: str(data.filename),
|
|
360
|
+
size: optionalNumber(data.size),
|
|
361
|
+
mime: optionalString(data.mime),
|
|
362
|
+
extra: extraFields(data, KNOWN5)
|
|
363
|
+
}),
|
|
364
|
+
regions: {}
|
|
365
|
+
}),
|
|
366
|
+
toData: ({ attrs }) => withExtra(
|
|
367
|
+
{
|
|
368
|
+
storageKey: str(attrs.storageKey),
|
|
369
|
+
filename: str(attrs.filename),
|
|
370
|
+
size: optionalNumber(attrs.size),
|
|
371
|
+
mime: optionalString(attrs.mime)
|
|
372
|
+
},
|
|
373
|
+
attrs
|
|
374
|
+
),
|
|
375
|
+
initial: () => ({ attrs: { storageKey: "", filename: "" }, regions: {} })
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// src/engine/blocks/image-spec.ts
|
|
379
|
+
var KNOWN6 = ["storageKey", "alt", "caption", "width", "height", "url", "align", "widthPercent"];
|
|
380
|
+
var imageSpec = {
|
|
381
|
+
type: "IMAGE",
|
|
382
|
+
flow: "structured",
|
|
383
|
+
fromData: (data, ctx) => ({
|
|
384
|
+
attrs: withDefined({
|
|
385
|
+
storageKey: str(data.storageKey),
|
|
386
|
+
alt: str(data.alt),
|
|
387
|
+
width: optionalNumber(data.width),
|
|
388
|
+
height: optionalNumber(data.height),
|
|
389
|
+
url: optionalString(data.url),
|
|
390
|
+
align: alignOrUndefined(data.align),
|
|
391
|
+
widthPercent: optionalNumber(data.widthPercent),
|
|
392
|
+
extra: extraFields(data, KNOWN6)
|
|
393
|
+
}),
|
|
394
|
+
regions: { caption: ctx.inline.parse(str(data.caption)) }
|
|
395
|
+
}),
|
|
396
|
+
toData: (block, ctx) => withExtra(
|
|
397
|
+
{
|
|
398
|
+
storageKey: str(block.attrs.storageKey),
|
|
399
|
+
alt: str(block.attrs.alt),
|
|
400
|
+
caption: ctx.inline.serialize(regionOf(block, "caption")) || void 0,
|
|
401
|
+
width: optionalNumber(block.attrs.width),
|
|
402
|
+
height: optionalNumber(block.attrs.height),
|
|
403
|
+
url: optionalString(block.attrs.url),
|
|
404
|
+
align: alignOrUndefined(block.attrs.align),
|
|
405
|
+
widthPercent: optionalNumber(block.attrs.widthPercent)
|
|
406
|
+
},
|
|
407
|
+
block.attrs
|
|
408
|
+
),
|
|
409
|
+
initial: () => ({ attrs: { storageKey: "", alt: "" }, regions: { caption: [] } })
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// src/engine/markdown/ordered-start.ts
|
|
413
|
+
var MAX_MARKER_NUMBER = 999999999;
|
|
414
|
+
function orderedStart(start) {
|
|
415
|
+
return typeof start === "number" && Number.isInteger(start) && start >= 0 ? Math.min(start, MAX_MARKER_NUMBER) : 1;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/engine/markdown/line-kind.ts
|
|
419
|
+
var INDENT = /^ {0,3}/;
|
|
420
|
+
var TASK = /^[-*+] \[([ xX])\](?: |$)/;
|
|
421
|
+
var HEADING = /^(#{1,6})(?: +|$)/;
|
|
422
|
+
var CLOSING_SEQUENCE = / +#+ *$/;
|
|
423
|
+
var BULLET = /^[-*+](?: |$)/;
|
|
424
|
+
var ORDERED = /^(\d{1,9})[.)](?: |$)/;
|
|
425
|
+
var QUOTE = /^> ?/;
|
|
426
|
+
function parseLine(markdown) {
|
|
427
|
+
const line = markdown.replace(INDENT, "");
|
|
428
|
+
const after = (match) => line.slice(match[0].length);
|
|
429
|
+
const task = TASK.exec(line);
|
|
430
|
+
if (task) return { kind: "task", checked: task[1] !== " ", rest: after(task) };
|
|
431
|
+
const heading = HEADING.exec(line);
|
|
432
|
+
if (heading) {
|
|
433
|
+
return { kind: "heading", level: heading[1].length, rest: after(heading).replace(CLOSING_SEQUENCE, "") };
|
|
434
|
+
}
|
|
435
|
+
const bullet = BULLET.exec(line);
|
|
436
|
+
if (bullet) return { kind: "bullet", rest: after(bullet) };
|
|
437
|
+
const ordered = ORDERED.exec(line);
|
|
438
|
+
if (ordered) return { kind: "ordered", start: Number(ordered[1]), rest: after(ordered) };
|
|
439
|
+
const quote = QUOTE.exec(line);
|
|
440
|
+
if (quote) return { kind: "quote", rest: after(quote) };
|
|
441
|
+
return { kind: "paragraph", rest: markdown };
|
|
442
|
+
}
|
|
443
|
+
function linePrefix({ kind, level, checked, start }) {
|
|
444
|
+
switch (kind) {
|
|
445
|
+
case "heading":
|
|
446
|
+
return `${"#".repeat(Math.min(6, Math.max(1, _nullishCoalesce(level, () => ( 1)))))} `;
|
|
447
|
+
case "bullet":
|
|
448
|
+
return "- ";
|
|
449
|
+
case "ordered":
|
|
450
|
+
return `${orderedStart(start)}. `;
|
|
451
|
+
case "task":
|
|
452
|
+
return checked ? "- [x] " : "- [ ] ";
|
|
453
|
+
case "quote":
|
|
454
|
+
return "> ";
|
|
455
|
+
default:
|
|
456
|
+
return "";
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/engine/markdown/line-markdown.ts
|
|
461
|
+
var TRAILING_HASHES = /([ \t])(#+)$/;
|
|
462
|
+
var protectClosingSequence = (markdown) => markdown.replace(TRAILING_HASHES, "$1\\$2");
|
|
463
|
+
function lineMarkdown(line, body) {
|
|
464
|
+
return linePrefix(line) + (line.kind === "heading" ? protectClosingSequence(body) : body);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// src/engine/blocks/markdown-spec.ts
|
|
468
|
+
var KNOWN7 = ["markdown", "align", "color", "background"];
|
|
469
|
+
var markdownSpec = {
|
|
470
|
+
type: "MARKDOWN",
|
|
471
|
+
flow: "text",
|
|
472
|
+
primaryRegion: "text",
|
|
473
|
+
fromData(data, ctx) {
|
|
474
|
+
const { rest, ...line } = parseLine(str(data.markdown));
|
|
475
|
+
return {
|
|
476
|
+
attrs: withDefined({
|
|
477
|
+
...line,
|
|
478
|
+
align: alignOrUndefined(data.align),
|
|
479
|
+
color: paletteOrUndefined(data.color),
|
|
480
|
+
background: paletteOrUndefined(data.background),
|
|
481
|
+
extra: extraFields(data, KNOWN7)
|
|
482
|
+
}),
|
|
483
|
+
regions: { text: ctx.inline.parse(rest) }
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
toData(block, ctx) {
|
|
487
|
+
const line = block.attrs;
|
|
488
|
+
const hardBreak = line.kind === "heading" ? "br" : "backslash";
|
|
489
|
+
const body = ctx.inline.serialize(regionOf(block, "text"), { escapeLineStart: true, hardBreak });
|
|
490
|
+
return withExtra(
|
|
491
|
+
{
|
|
492
|
+
markdown: lineMarkdown(line, body),
|
|
493
|
+
align: alignOrUndefined(block.attrs.align),
|
|
494
|
+
color: paletteOrUndefined(block.attrs.color),
|
|
495
|
+
background: paletteOrUndefined(block.attrs.background)
|
|
496
|
+
},
|
|
497
|
+
block.attrs
|
|
498
|
+
);
|
|
499
|
+
},
|
|
500
|
+
initial: () => ({ attrs: { kind: "paragraph" }, regions: { text: [] } }),
|
|
501
|
+
splitAttrs(attrs) {
|
|
502
|
+
const kind = attrs.kind === "heading" ? "paragraph" : attrs.kind;
|
|
503
|
+
return {
|
|
504
|
+
type: "MARKDOWN",
|
|
505
|
+
attrs: withDefined({
|
|
506
|
+
kind,
|
|
507
|
+
checked: kind === "task" ? false : void 0,
|
|
508
|
+
align: alignOrUndefined(attrs.align)
|
|
509
|
+
})
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// src/engine/blocks/math-spec.ts
|
|
515
|
+
var mathSpec = {
|
|
516
|
+
type: "MATH",
|
|
517
|
+
flow: "void",
|
|
518
|
+
fromData: (data) => ({
|
|
519
|
+
attrs: withDefined({ latex: str(data.latex), extra: extraFields(data, ["latex"]) }),
|
|
520
|
+
regions: {}
|
|
521
|
+
}),
|
|
522
|
+
toData: ({ attrs }) => withExtra({ latex: str(attrs.latex) }, attrs),
|
|
523
|
+
initial: () => ({ attrs: { latex: "" }, regions: {} })
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
// src/engine/model/count.ts
|
|
527
|
+
var countOf = (value) => Number.isInteger(value) && value > 0 ? value : 0;
|
|
528
|
+
|
|
529
|
+
// src/engine/blocks/table-spec.ts
|
|
530
|
+
var KNOWN8 = ["rows", "header", "align", "widths"];
|
|
531
|
+
var COLUMN_ALIGNS = ["left", "center", "right"];
|
|
532
|
+
var CELL_WRITE = { escapePipes: true, hardBreak: "br" };
|
|
533
|
+
var cellKey = (row, col) => `cell:${row}:${col}`;
|
|
534
|
+
function columnAligns(value, cols) {
|
|
535
|
+
return Array.from({ length: cols }, (_, col) => {
|
|
536
|
+
const align = Array.isArray(value) ? value[col] : void 0;
|
|
537
|
+
return typeof align === "string" && COLUMN_ALIGNS.includes(align) ? align : null;
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function widthList(value) {
|
|
541
|
+
return Array.isArray(value) && value.every((width) => optionalNumber(width) !== void 0) ? value : void 0;
|
|
542
|
+
}
|
|
543
|
+
var tableSpec = {
|
|
544
|
+
type: "TABLE",
|
|
545
|
+
flow: "structured",
|
|
546
|
+
fromData(data, ctx) {
|
|
547
|
+
const rows = Array.isArray(data.rows) ? data.rows.map((row) => Array.isArray(row) ? row : []) : [];
|
|
548
|
+
const cols = rows.reduce((widest, row) => Math.max(widest, row.length), 0);
|
|
549
|
+
const regions = {};
|
|
550
|
+
rows.forEach((row, r) => {
|
|
551
|
+
for (let c = 0; c < cols; c++) regions[cellKey(r, c)] = ctx.inline.parse(str(row[c]), { softBreak: "space" });
|
|
552
|
+
});
|
|
553
|
+
return {
|
|
554
|
+
attrs: withDefined({
|
|
555
|
+
header: data.header !== false,
|
|
556
|
+
align: columnAligns(data.align, cols),
|
|
557
|
+
widths: widthList(data.widths),
|
|
558
|
+
rows: rows.length,
|
|
559
|
+
cols,
|
|
560
|
+
extra: extraFields(data, KNOWN8)
|
|
561
|
+
}),
|
|
562
|
+
regions
|
|
563
|
+
};
|
|
564
|
+
},
|
|
565
|
+
toData(block, ctx) {
|
|
566
|
+
const { attrs } = block;
|
|
567
|
+
const cols = countOf(attrs.cols);
|
|
568
|
+
const rows = Array.from(
|
|
569
|
+
{ length: countOf(attrs.rows) },
|
|
570
|
+
(_, r) => Array.from({ length: cols }, (_2, c) => ctx.inline.serialize(regionOf(block, cellKey(r, c)), CELL_WRITE))
|
|
571
|
+
);
|
|
572
|
+
return withExtra(
|
|
573
|
+
{ rows, header: attrs.header !== false, align: columnAligns(attrs.align, cols), widths: widthList(attrs.widths) },
|
|
574
|
+
attrs
|
|
575
|
+
);
|
|
576
|
+
},
|
|
577
|
+
initial() {
|
|
578
|
+
const regions = {};
|
|
579
|
+
for (let r = 0; r < 3; r++) for (let c = 0; c < 2; c++) regions[cellKey(r, c)] = [];
|
|
580
|
+
return { attrs: { header: true, align: [null, null], rows: 3, cols: 2 }, regions };
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// src/engine/blocks/toc-spec.ts
|
|
585
|
+
var tocSpec = markerSpec("TOC");
|
|
586
|
+
|
|
587
|
+
// src/engine/blocks/toggle-spec.ts
|
|
588
|
+
var KNOWN9 = ["markdown", "open"];
|
|
589
|
+
var toggleSpec = {
|
|
590
|
+
type: "TOGGLE",
|
|
591
|
+
flow: "text",
|
|
592
|
+
primaryRegion: "text",
|
|
593
|
+
fromData: (data, ctx) => ({
|
|
594
|
+
attrs: withDefined({ open: data.open === true, extra: extraFields(data, KNOWN9) }),
|
|
595
|
+
regions: { text: ctx.inline.parse(str(data.markdown)) }
|
|
596
|
+
}),
|
|
597
|
+
toData: (block, ctx) => withExtra(
|
|
598
|
+
{
|
|
599
|
+
markdown: ctx.inline.serialize(regionOf(block, "text"), { escapeLineStart: true }),
|
|
600
|
+
open: block.attrs.open === true
|
|
601
|
+
},
|
|
602
|
+
block.attrs
|
|
603
|
+
),
|
|
604
|
+
initial: () => ({ attrs: { open: true }, regions: { text: [] } }),
|
|
605
|
+
splitAttrs: () => ({ type: "MARKDOWN", attrs: { kind: "paragraph" } })
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
// src/engine/blocks/core-specs.ts
|
|
609
|
+
var coreBlockSpecs = [
|
|
610
|
+
markdownSpec,
|
|
611
|
+
calloutSpec,
|
|
612
|
+
codeSpec,
|
|
613
|
+
imageSpec,
|
|
614
|
+
fileSpec,
|
|
615
|
+
dividerSpec,
|
|
616
|
+
toggleSpec,
|
|
617
|
+
tableSpec,
|
|
618
|
+
embedSpec,
|
|
619
|
+
bookmarkSpec,
|
|
620
|
+
mathSpec,
|
|
621
|
+
tocSpec
|
|
622
|
+
];
|
|
623
|
+
|
|
624
|
+
// src/engine/schema/core-atoms.ts
|
|
625
|
+
var mention = { type: "mention", plainText: ({ label }) => `@${label}` };
|
|
626
|
+
var math = { type: "math", plainText: ({ latex }) => latex };
|
|
627
|
+
var coreAtomSpecs = [mention, math];
|
|
628
|
+
|
|
629
|
+
// src/engine/schema/core-marks.ts
|
|
630
|
+
var CORE_MARKS = [
|
|
631
|
+
"link",
|
|
632
|
+
"comment",
|
|
633
|
+
"bold",
|
|
634
|
+
"italic",
|
|
635
|
+
"underline",
|
|
636
|
+
"strike",
|
|
637
|
+
"sub",
|
|
638
|
+
"sup",
|
|
639
|
+
"highlight",
|
|
640
|
+
"color",
|
|
641
|
+
"background",
|
|
642
|
+
"code"
|
|
643
|
+
];
|
|
644
|
+
var ANCHORED = /* @__PURE__ */ new Set(["link", "comment"]);
|
|
645
|
+
var coreMarkSpecs = CORE_MARKS.map((type) => ({ type, inclusive: !ANCHORED.has(type) }));
|
|
646
|
+
|
|
647
|
+
// src/engine/schema/create-schema.ts
|
|
648
|
+
var byType = (specs) => new Map(specs.map((spec) => [spec.type, spec]));
|
|
649
|
+
function createSchema(input = {}) {
|
|
650
|
+
return {
|
|
651
|
+
blocks: byType([...coreBlockSpecs, ..._nullishCoalesce(input.blocks, () => ( []))]),
|
|
652
|
+
marks: byType([...coreMarkSpecs, ..._nullishCoalesce(input.marks, () => ( []))]),
|
|
653
|
+
atoms: byType([...coreAtomSpecs, ..._nullishCoalesce(input.atoms, () => ( []))]),
|
|
654
|
+
defaultTextBlock: _nullishCoalesce(input.defaultTextBlock, () => ( "MARKDOWN"))
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// src/engine/markdown/urls.ts
|
|
659
|
+
var SAFE_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "mailto:", "tel:", "mention:"]);
|
|
660
|
+
var ASSET_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "blob:", "data:"]);
|
|
661
|
+
var SCHEME = /^([a-z][a-z0-9+.-]*):/i;
|
|
662
|
+
var CONTROL = /\p{Cc}/u;
|
|
663
|
+
function allowed(href, schemes) {
|
|
664
|
+
const trimmed = href.trim();
|
|
665
|
+
if (CONTROL.test(trimmed)) return null;
|
|
666
|
+
const scheme = SCHEME.exec(trimmed);
|
|
667
|
+
if (!scheme) return trimmed;
|
|
668
|
+
return schemes.has(scheme[1].toLowerCase() + ":") ? trimmed : null;
|
|
669
|
+
}
|
|
670
|
+
function sanitizeHref(href) {
|
|
671
|
+
return allowed(href, SAFE_SCHEMES);
|
|
672
|
+
}
|
|
673
|
+
function sanitizeAssetUrl(href) {
|
|
674
|
+
return allowed(href, ASSET_SCHEMES);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// src/engine/markdown/inline/delimiters.ts
|
|
678
|
+
var WHITESPACE = /^[\p{Zs}\t\n\f\r]$/u;
|
|
679
|
+
var PUNCTUATION = /^[\p{P}\p{S}]$/u;
|
|
680
|
+
function isWhitespace(char) {
|
|
681
|
+
return char === "" || WHITESPACE.test(char);
|
|
682
|
+
}
|
|
683
|
+
function classifyDelimiterRun(before, after, char) {
|
|
684
|
+
const punctuationBefore = PUNCTUATION.test(before);
|
|
685
|
+
const punctuationAfter = PUNCTUATION.test(after);
|
|
686
|
+
const leftFlanking = !isWhitespace(after) && (!punctuationAfter || isWhitespace(before) || punctuationBefore);
|
|
687
|
+
const rightFlanking = !isWhitespace(before) && (!punctuationBefore || isWhitespace(after) || punctuationAfter);
|
|
688
|
+
if (char !== "_") return { canOpen: leftFlanking, canClose: rightFlanking };
|
|
689
|
+
return {
|
|
690
|
+
canOpen: leftFlanking && (!rightFlanking || punctuationBefore),
|
|
691
|
+
canClose: rightFlanking && (!leftFlanking || punctuationAfter)
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function canPair(opener, closer) {
|
|
695
|
+
if (opener.char !== closer.char || !opener.canOpen) return false;
|
|
696
|
+
if (closer.char === "~") return opener.length === closer.length;
|
|
697
|
+
if (!opener.canClose && !closer.canOpen) return true;
|
|
698
|
+
const bothMultiplesOfThree = opener.length % 3 === 0 && closer.length % 3 === 0;
|
|
699
|
+
return (opener.length + closer.length) % 3 !== 0 || bothMultiplesOfThree;
|
|
700
|
+
}
|
|
701
|
+
function emphasisMark(char, used) {
|
|
702
|
+
if (char === "~") return { type: "strike" };
|
|
703
|
+
return { type: used === 2 ? "bold" : "italic" };
|
|
704
|
+
}
|
|
705
|
+
function pair(opener, closer) {
|
|
706
|
+
const used = closer.char === "~" ? closer.count : Math.min(2, opener.count, closer.count);
|
|
707
|
+
const range = { mark: emphasisMark(closer.char, used) };
|
|
708
|
+
opener.count -= used;
|
|
709
|
+
closer.count -= used;
|
|
710
|
+
opener.opens.push(range);
|
|
711
|
+
closer.closes.push(range);
|
|
712
|
+
}
|
|
713
|
+
function clampFloors(floors, length) {
|
|
714
|
+
for (const [key, floor] of floors) if (floor >= length) floors.set(key, length - 1);
|
|
715
|
+
}
|
|
716
|
+
function processEmphasis(stack, bottom) {
|
|
717
|
+
const openers = [];
|
|
718
|
+
const floors = /* @__PURE__ */ new Map();
|
|
719
|
+
let index = bottom;
|
|
720
|
+
while (index < stack.length) {
|
|
721
|
+
const closer = stack[index];
|
|
722
|
+
if (!closer.canClose) {
|
|
723
|
+
openers.push(closer);
|
|
724
|
+
index++;
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
const key = `${closer.char}${closer.canOpen}${closer.length % 3}`;
|
|
728
|
+
const floor = _nullishCoalesce(floors.get(key), () => ( -1));
|
|
729
|
+
let at = openers.length - 1;
|
|
730
|
+
while (at > floor && !canPair(openers[at], closer)) at--;
|
|
731
|
+
if (at > floor) {
|
|
732
|
+
const opener = openers[at];
|
|
733
|
+
pair(opener, closer);
|
|
734
|
+
openers.length = opener.count > 0 ? at + 1 : at;
|
|
735
|
+
clampFloors(floors, openers.length);
|
|
736
|
+
if (closer.count === 0) index++;
|
|
737
|
+
} else {
|
|
738
|
+
floors.set(key, openers.length - 1);
|
|
739
|
+
if (closer.canOpen) openers.push(closer);
|
|
740
|
+
index++;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
stack.length = bottom;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// src/engine/markdown/inline/match-at.ts
|
|
747
|
+
function matchAt(pattern, src, pos) {
|
|
748
|
+
pattern.lastIndex = pos;
|
|
749
|
+
return pattern.exec(src);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/engine/markdown/inline/entities.ts
|
|
753
|
+
var NAMED = /* @__PURE__ */ new Map([
|
|
754
|
+
["amp", "&"],
|
|
755
|
+
["lt", "<"],
|
|
756
|
+
["gt", ">"],
|
|
757
|
+
["quot", '"'],
|
|
758
|
+
["apos", "'"],
|
|
759
|
+
["nbsp", "\xA0"],
|
|
760
|
+
["copy", "\xA9"],
|
|
761
|
+
["reg", "\xAE"],
|
|
762
|
+
["trade", "\u2122"],
|
|
763
|
+
["hellip", "\u2026"],
|
|
764
|
+
["mdash", "\u2014"],
|
|
765
|
+
["ndash", "\u2013"],
|
|
766
|
+
["lsquo", "\u2018"],
|
|
767
|
+
["rsquo", "\u2019"],
|
|
768
|
+
["ldquo", "\u201C"],
|
|
769
|
+
["rdquo", "\u201D"],
|
|
770
|
+
["laquo", "\xAB"],
|
|
771
|
+
["raquo", "\xBB"],
|
|
772
|
+
["times", "\xD7"],
|
|
773
|
+
["divide", "\xF7"],
|
|
774
|
+
["deg", "\xB0"],
|
|
775
|
+
["middot", "\xB7"],
|
|
776
|
+
["bull", "\u2022"]
|
|
777
|
+
]);
|
|
778
|
+
var NUMERIC = /^#(?:([0-9]{1,7})|[xX]([0-9a-fA-F]{1,6}))$/;
|
|
779
|
+
var ENTITY_SOURCE = "&(#[xX][0-9a-fA-F]{1,6}|#[0-9]{1,7}|[A-Za-z][A-Za-z0-9]{1,31});";
|
|
780
|
+
var ENTITY_AT = new RegExp(ENTITY_SOURCE, "y");
|
|
781
|
+
var ENTITIES = new RegExp(ENTITY_SOURCE, "g");
|
|
782
|
+
var REPLACEMENT = "\uFFFD";
|
|
783
|
+
function fromCodePoint(code) {
|
|
784
|
+
const valid = code > 0 && code <= 1114111 && (code < 55296 || code > 57343);
|
|
785
|
+
return valid ? String.fromCodePoint(code) : REPLACEMENT;
|
|
786
|
+
}
|
|
787
|
+
function decodeEntity(name) {
|
|
788
|
+
const numeric = NUMERIC.exec(name);
|
|
789
|
+
if (numeric) return fromCodePoint(numeric[1] ? parseInt(numeric[1], 10) : parseInt(numeric[2], 16));
|
|
790
|
+
return _nullishCoalesce(NAMED.get(name), () => ( null));
|
|
791
|
+
}
|
|
792
|
+
function matchEntity(src, pos) {
|
|
793
|
+
const match = matchAt(ENTITY_AT, src, pos);
|
|
794
|
+
const value = match ? decodeEntity(match[1]) : null;
|
|
795
|
+
return match && value !== null ? { value, end: pos + match[0].length } : null;
|
|
796
|
+
}
|
|
797
|
+
function decodeEntities(value) {
|
|
798
|
+
return value.replace(ENTITIES, (source, name) => _nullishCoalesce(decodeEntity(name), () => ( source)));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// src/engine/markdown/inline/escapes.ts
|
|
802
|
+
var ASCII_PUNCTUATION = /^[!-/:-@[-`{-~]$/;
|
|
803
|
+
var ESCAPED = /\\([!-/:-@[-`{-~])/g;
|
|
804
|
+
function isEscapable(char) {
|
|
805
|
+
return char !== void 0 && ASCII_PUNCTUATION.test(char);
|
|
806
|
+
}
|
|
807
|
+
function unescapeMarkdown(value) {
|
|
808
|
+
return value.split(ESCAPED).map((part, index) => index % 2 === 1 ? part : decodeEntities(part)).join("");
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/engine/markdown/inline/link-syntax.ts
|
|
812
|
+
var URI_AUTOLINK = /<([A-Za-z][A-Za-z0-9+.-]{1,31}:[^<>\p{Cc} ]*)>/uy;
|
|
813
|
+
var DOMAIN_LABEL = "[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?";
|
|
814
|
+
var EMAIL_AUTOLINK = new RegExp(`<([A-Za-z0-9.!#$%&'*+/=?^_\`{|}~-]+@${DOMAIN_LABEL}(?:\\.${DOMAIN_LABEL})*)>`, "y");
|
|
815
|
+
var LABEL = /\[((?:[^\\[\]]|\\[\s\S]){0,999})\]/y;
|
|
816
|
+
var MAX_PAREN_DEPTH = 32;
|
|
817
|
+
var TITLE_CLOSERS = /* @__PURE__ */ new Map([
|
|
818
|
+
['"', '"'],
|
|
819
|
+
["'", "'"],
|
|
820
|
+
["(", ")"]
|
|
821
|
+
]);
|
|
822
|
+
function isSpaceOrControl(char) {
|
|
823
|
+
const code = char.charCodeAt(0);
|
|
824
|
+
return code <= 32 || code === 127;
|
|
825
|
+
}
|
|
826
|
+
function parseAngleDestination(src, pos) {
|
|
827
|
+
for (let p = pos + 1; p < src.length; p++) {
|
|
828
|
+
const char = src[p];
|
|
829
|
+
if (char === "\\" && p + 1 < src.length && src[p + 1] !== "\n") p++;
|
|
830
|
+
else if (char === ">") return { value: unescapeMarkdown(src.slice(pos + 1, p)), end: p + 1 };
|
|
831
|
+
else if (char === "<" || char === "\n") return null;
|
|
832
|
+
}
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
835
|
+
function parseLinkDestination(src, pos) {
|
|
836
|
+
if (src[pos] === "<") return parseAngleDestination(src, pos);
|
|
837
|
+
let depth = 0;
|
|
838
|
+
let p = pos;
|
|
839
|
+
for (; p < src.length; p++) {
|
|
840
|
+
const char = src[p];
|
|
841
|
+
if (char === "\\" && isEscapable(src[p + 1])) p++;
|
|
842
|
+
else if (char === "(" && depth === MAX_PAREN_DEPTH) return null;
|
|
843
|
+
else if (char === "(") depth++;
|
|
844
|
+
else if (char === ")" && depth === 0) break;
|
|
845
|
+
else if (char === ")") depth--;
|
|
846
|
+
else if (isSpaceOrControl(char)) break;
|
|
847
|
+
}
|
|
848
|
+
if (depth !== 0 || p === pos && src[p] !== ")") return null;
|
|
849
|
+
return { value: unescapeMarkdown(src.slice(pos, p)), end: p };
|
|
850
|
+
}
|
|
851
|
+
function parseLinkTitle(src, pos) {
|
|
852
|
+
const close = TITLE_CLOSERS.get(src[pos]);
|
|
853
|
+
if (!close) return null;
|
|
854
|
+
for (let p = pos + 1; p < src.length; p++) {
|
|
855
|
+
const char = src[p];
|
|
856
|
+
if (char === "\\") p++;
|
|
857
|
+
else if (char === close) return { value: unescapeMarkdown(src.slice(pos + 1, p)), end: p + 1 };
|
|
858
|
+
else if (close === ")" && char === "(") return null;
|
|
859
|
+
}
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
function parseAutolink(src, pos) {
|
|
863
|
+
const uri = matchAt(URI_AUTOLINK, src, pos);
|
|
864
|
+
if (uri) return { value: { href: uri[1], text: uri[1] }, end: pos + uri[0].length };
|
|
865
|
+
const email = matchAt(EMAIL_AUTOLINK, src, pos);
|
|
866
|
+
return email ? { value: { href: `mailto:${email[1]}`, text: email[1] }, end: pos + email[0].length } : null;
|
|
867
|
+
}
|
|
868
|
+
function parseLinkLabel(src, pos) {
|
|
869
|
+
const match = matchAt(LABEL, src, pos);
|
|
870
|
+
return match ? { value: match[1], end: pos + match[0].length } : null;
|
|
871
|
+
}
|
|
872
|
+
function skipLinkSpace(src, pos) {
|
|
873
|
+
let p = pos;
|
|
874
|
+
while (src[p] === " " || src[p] === " ") p++;
|
|
875
|
+
if (src[p] === "\n") p++;
|
|
876
|
+
while (src[p] === " " || src[p] === " ") p++;
|
|
877
|
+
return p;
|
|
878
|
+
}
|
|
879
|
+
function parseInlineLinkTail(src, pos) {
|
|
880
|
+
const destination = parseLinkDestination(src, skipLinkSpace(src, pos));
|
|
881
|
+
if (!destination) return null;
|
|
882
|
+
let p = skipLinkSpace(src, destination.end);
|
|
883
|
+
const title = p > destination.end ? parseLinkTitle(src, p) : null;
|
|
884
|
+
if (title) p = skipLinkSpace(src, title.end);
|
|
885
|
+
if (src[p] !== ")") return null;
|
|
886
|
+
const value = _optionalChain([title, 'optionalAccess', _10 => _10.value]) ? { href: destination.value, title: title.value } : { href: destination.value };
|
|
887
|
+
return { value, end: p + 1 };
|
|
888
|
+
}
|
|
889
|
+
function normalizeLabel(label) {
|
|
890
|
+
return label.trim().replace(/[ \t\r\n]+/g, " ").toLowerCase().toUpperCase();
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// src/engine/markdown/inline/scanner.ts
|
|
894
|
+
function normalizeRefs(refs) {
|
|
895
|
+
const result = /* @__PURE__ */ new Map();
|
|
896
|
+
for (const [label, target] of _nullishCoalesce(refs, () => ( []))) {
|
|
897
|
+
const key = normalizeLabel(label);
|
|
898
|
+
if (key && !result.has(key)) result.set(key, target);
|
|
899
|
+
}
|
|
900
|
+
return result;
|
|
901
|
+
}
|
|
902
|
+
function createScanner(src, options) {
|
|
903
|
+
return {
|
|
904
|
+
src,
|
|
905
|
+
softBreak: options.softBreak === "space" ? " " : "\n",
|
|
906
|
+
refs: normalizeRefs(options.refs),
|
|
907
|
+
items: [],
|
|
908
|
+
delimiters: [],
|
|
909
|
+
brackets: [],
|
|
910
|
+
closeMisses: /* @__PURE__ */ new Map(),
|
|
911
|
+
pos: 0
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
function pushText(scanner, value, advance) {
|
|
915
|
+
scanner.items.push({ kind: "text", text: value });
|
|
916
|
+
scanner.pos += advance;
|
|
917
|
+
}
|
|
918
|
+
function findClose(scanner, key, from, find) {
|
|
919
|
+
if (from >= (_nullishCoalesce(scanner.closeMisses.get(key), () => ( Infinity)))) return -1;
|
|
920
|
+
const close = find(from);
|
|
921
|
+
if (close < 0) scanner.closeMisses.set(key, from);
|
|
922
|
+
return close;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// src/engine/markdown/inline/close-bracket.ts
|
|
926
|
+
var MENTION = "mention:";
|
|
927
|
+
function matchReference(scanner, opener, after) {
|
|
928
|
+
if (scanner.refs.size === 0) return null;
|
|
929
|
+
const label = parseLinkLabel(scanner.src, after);
|
|
930
|
+
if (_optionalChain([label, 'optionalAccess', _11 => _11.value])) {
|
|
931
|
+
const target2 = scanner.refs.get(normalizeLabel(label.value));
|
|
932
|
+
return target2 ? { value: target2, end: label.end } : null;
|
|
933
|
+
}
|
|
934
|
+
const ownLabel = parseLinkLabel(scanner.src, opener.start - 1);
|
|
935
|
+
if (_optionalChain([ownLabel, 'optionalAccess', _12 => _12.end]) !== after) return null;
|
|
936
|
+
const target = scanner.refs.get(normalizeLabel(ownLabel.value));
|
|
937
|
+
return target ? { value: target, end: label ? label.end : after } : null;
|
|
938
|
+
}
|
|
939
|
+
function matchLink(scanner, opener) {
|
|
940
|
+
const after = scanner.pos + 1;
|
|
941
|
+
const inline = scanner.src[after] === "(" ? parseInlineLinkTail(scanner.src, after + 1) : null;
|
|
942
|
+
return _nullishCoalesce(inline, () => ( matchReference(scanner, opener, after)));
|
|
943
|
+
}
|
|
944
|
+
function plainText(items) {
|
|
945
|
+
let result = "";
|
|
946
|
+
for (const item of items) {
|
|
947
|
+
if (item.kind === "text" && !item.marks) result += item.text;
|
|
948
|
+
else if (item.kind === "delimiter" && item.opens.length + item.closes.length === 0) {
|
|
949
|
+
result += item.char.repeat(item.count);
|
|
950
|
+
} else return null;
|
|
951
|
+
}
|
|
952
|
+
return result;
|
|
953
|
+
}
|
|
954
|
+
function mentionAtom(href, label) {
|
|
955
|
+
if (!href.startsWith(MENTION) || !_optionalChain([label, 'optionalAccess', _13 => _13.startsWith, 'call', _14 => _14("@")])) return null;
|
|
956
|
+
const reference = href.slice(MENTION.length);
|
|
957
|
+
const colon = reference.indexOf(":");
|
|
958
|
+
const id = reference.slice(colon + 1);
|
|
959
|
+
if (!id) return null;
|
|
960
|
+
const attrs = { id, label: label.slice(1) };
|
|
961
|
+
return { kind: "atom", type: "mention", attrs: colon < 0 ? attrs : { ...attrs, kind: reference.slice(0, colon) } };
|
|
962
|
+
}
|
|
963
|
+
function formLink(scanner, opener, target) {
|
|
964
|
+
const { items } = scanner;
|
|
965
|
+
const href = sanitizeHref(target.href);
|
|
966
|
+
if (href === null) {
|
|
967
|
+
items[opener.index] = { kind: "text", text: "" };
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const mention2 = mentionAtom(href, plainText(items.slice(opener.index + 1)));
|
|
971
|
+
if (mention2) {
|
|
972
|
+
items.length = opener.index;
|
|
973
|
+
items.push(mention2);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
const attrs = target.title ? { href, title: target.title } : { href };
|
|
977
|
+
const range = { mark: { type: "link", attrs } };
|
|
978
|
+
items[opener.index] = { kind: "open", range };
|
|
979
|
+
items.push({ kind: "close", range });
|
|
980
|
+
}
|
|
981
|
+
function deactivateOpeners(brackets) {
|
|
982
|
+
for (let at = brackets.length - 1; at >= 0 && brackets[at].active; at--) brackets[at].active = false;
|
|
983
|
+
}
|
|
984
|
+
function closeBracket(scanner) {
|
|
985
|
+
const opener = scanner.brackets.pop();
|
|
986
|
+
const target = _optionalChain([opener, 'optionalAccess', _15 => _15.active]) && !opener.image ? matchLink(scanner, opener) : null;
|
|
987
|
+
if (!opener || !target) {
|
|
988
|
+
pushText(scanner, "]", 1);
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
processEmphasis(scanner.delimiters, opener.bottom);
|
|
992
|
+
formLink(scanner, opener, target.value);
|
|
993
|
+
scanner.pos = target.end;
|
|
994
|
+
deactivateOpeners(scanner.brackets);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// src/engine/markdown/inline/code-span.ts
|
|
998
|
+
var BACKTICK_RUNS = /`+/g;
|
|
999
|
+
function findCodeClose(src, from, fence) {
|
|
1000
|
+
BACKTICK_RUNS.lastIndex = from;
|
|
1001
|
+
for (let run = BACKTICK_RUNS.exec(src); run; run = BACKTICK_RUNS.exec(src)) {
|
|
1002
|
+
if (run[0].length === fence) return run.index;
|
|
1003
|
+
}
|
|
1004
|
+
return -1;
|
|
1005
|
+
}
|
|
1006
|
+
function codeSpanText(raw) {
|
|
1007
|
+
const content = raw.replace(/\n/g, " ");
|
|
1008
|
+
const padded = content.startsWith(" ") && content.endsWith(" ") && /[^ ]/.test(content);
|
|
1009
|
+
return padded ? content.slice(1, -1) : content;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// src/engine/markdown/inline/active-marks.ts
|
|
1013
|
+
function upperBound(marks, mark) {
|
|
1014
|
+
let low = 0;
|
|
1015
|
+
let high = marks.length;
|
|
1016
|
+
while (low < high) {
|
|
1017
|
+
const middle = low + high >>> 1;
|
|
1018
|
+
if (compareMarks(marks[middle], mark) <= 0) low = middle + 1;
|
|
1019
|
+
else high = middle;
|
|
1020
|
+
}
|
|
1021
|
+
return low;
|
|
1022
|
+
}
|
|
1023
|
+
function indexOfKey(marks, mark) {
|
|
1024
|
+
return upperBound(marks, mark) - 1;
|
|
1025
|
+
}
|
|
1026
|
+
function createActiveMarks() {
|
|
1027
|
+
const stacks = /* @__PURE__ */ new Map();
|
|
1028
|
+
const closedBelowTop = /* @__PURE__ */ new Set();
|
|
1029
|
+
const shown = [];
|
|
1030
|
+
const copied = /* @__PURE__ */ new Map();
|
|
1031
|
+
const changed = /* @__PURE__ */ new Set();
|
|
1032
|
+
let copy = [];
|
|
1033
|
+
const track = (key, top) => {
|
|
1034
|
+
const last = copied.get(key);
|
|
1035
|
+
if (last === top || last && top && sameMark(last, top)) changed.delete(key);
|
|
1036
|
+
else changed.add(key);
|
|
1037
|
+
};
|
|
1038
|
+
const open = (range) => {
|
|
1039
|
+
const key = markKey(range.mark);
|
|
1040
|
+
const stack = stacks.get(key);
|
|
1041
|
+
if (stack) {
|
|
1042
|
+
shown[indexOfKey(shown, range.mark)] = range.mark;
|
|
1043
|
+
stack.push(range);
|
|
1044
|
+
} else {
|
|
1045
|
+
shown.splice(upperBound(shown, range.mark), 0, range.mark);
|
|
1046
|
+
stacks.set(key, [range]);
|
|
1047
|
+
}
|
|
1048
|
+
track(key, range.mark);
|
|
1049
|
+
};
|
|
1050
|
+
const close = (range) => {
|
|
1051
|
+
const key = markKey(range.mark);
|
|
1052
|
+
const stack = stacks.get(key);
|
|
1053
|
+
if (_optionalChain([stack, 'optionalAccess', _16 => _16.at, 'call', _17 => _17(-1)]) !== range) {
|
|
1054
|
+
closedBelowTop.add(range);
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
stack.pop();
|
|
1058
|
+
while (stack.length > 0 && closedBelowTop.delete(stack[stack.length - 1])) stack.pop();
|
|
1059
|
+
const index = indexOfKey(shown, range.mark);
|
|
1060
|
+
const top = _optionalChain([stack, 'access', _18 => _18.at, 'call', _19 => _19(-1), 'optionalAccess', _20 => _20.mark]);
|
|
1061
|
+
if (top) {
|
|
1062
|
+
shown[index] = top;
|
|
1063
|
+
} else {
|
|
1064
|
+
shown.splice(index, 1);
|
|
1065
|
+
stacks.delete(key);
|
|
1066
|
+
}
|
|
1067
|
+
track(key, top);
|
|
1068
|
+
};
|
|
1069
|
+
const current = () => {
|
|
1070
|
+
if (changed.size === 0) return copy;
|
|
1071
|
+
copy = [...shown];
|
|
1072
|
+
for (const key of changed) {
|
|
1073
|
+
const stack = stacks.get(key);
|
|
1074
|
+
if (stack) copied.set(key, stack[stack.length - 1].mark);
|
|
1075
|
+
else copied.delete(key);
|
|
1076
|
+
}
|
|
1077
|
+
changed.clear();
|
|
1078
|
+
return copy;
|
|
1079
|
+
};
|
|
1080
|
+
return { open, close, current };
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/engine/markdown/inline/inline-items.ts
|
|
1084
|
+
function flattenItems(items) {
|
|
1085
|
+
const { open, close, current } = createActiveMarks();
|
|
1086
|
+
const nodes = [];
|
|
1087
|
+
let run = "";
|
|
1088
|
+
let runMarks = [];
|
|
1089
|
+
const flush = () => {
|
|
1090
|
+
if (run) nodes.push({ kind: "text", text: run, marks: runMarks });
|
|
1091
|
+
run = "";
|
|
1092
|
+
};
|
|
1093
|
+
const emit = (value, own = []) => {
|
|
1094
|
+
if (!value) return;
|
|
1095
|
+
const ranges = own.map((mark) => ({ mark }));
|
|
1096
|
+
ranges.forEach(open);
|
|
1097
|
+
const marks = current();
|
|
1098
|
+
if (marks !== runMarks) flush();
|
|
1099
|
+
run += value;
|
|
1100
|
+
runMarks = marks;
|
|
1101
|
+
ranges.forEach(close);
|
|
1102
|
+
};
|
|
1103
|
+
const emitAtom = (type, attrs) => {
|
|
1104
|
+
flush();
|
|
1105
|
+
nodes.push({ kind: "atom", type, attrs, marks: current() });
|
|
1106
|
+
};
|
|
1107
|
+
for (const item of items) {
|
|
1108
|
+
if (item.kind === "text") emit(item.text, item.marks);
|
|
1109
|
+
else if (item.kind === "atom") emitAtom(item.type, item.attrs);
|
|
1110
|
+
else if (item.kind === "open") open(item.range);
|
|
1111
|
+
else if (item.kind === "close") close(item.range);
|
|
1112
|
+
else if (item.kind === "delimiter") {
|
|
1113
|
+
item.closes.forEach(close);
|
|
1114
|
+
emit(item.char.repeat(item.count));
|
|
1115
|
+
item.opens.forEach(open);
|
|
1116
|
+
} else if (!item.range) emit(item.source);
|
|
1117
|
+
else if (item.tag.close) close(item.range);
|
|
1118
|
+
else open(item.range);
|
|
1119
|
+
}
|
|
1120
|
+
flush();
|
|
1121
|
+
return normalizeInline(nodes);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/engine/markdown/inline/math-span.ts
|
|
1125
|
+
var SPACE = /\s/;
|
|
1126
|
+
var DIGIT = /[0-9]/;
|
|
1127
|
+
function opensMath(src, pos) {
|
|
1128
|
+
const next = src[pos + 1];
|
|
1129
|
+
if (next === void 0 || SPACE.test(next)) return false;
|
|
1130
|
+
return !(DIGIT.test(next) && (pos === 0 || SPACE.test(src[pos - 1])));
|
|
1131
|
+
}
|
|
1132
|
+
function dollarRunEnd(src, pos) {
|
|
1133
|
+
let end = pos;
|
|
1134
|
+
while (src[end] === "$") end++;
|
|
1135
|
+
return end;
|
|
1136
|
+
}
|
|
1137
|
+
function findMathClose(src, from) {
|
|
1138
|
+
for (let p = src.indexOf("$", from); p >= 0; p = src.indexOf("$", p + 1)) {
|
|
1139
|
+
const before = src[p - 1];
|
|
1140
|
+
if (before !== "\\" && !SPACE.test(before) && !DIGIT.test(_nullishCoalesce(src[p + 1], () => ( "")))) return p;
|
|
1141
|
+
}
|
|
1142
|
+
return -1;
|
|
1143
|
+
}
|
|
1144
|
+
function mathLatex(src, open, close) {
|
|
1145
|
+
return src.slice(open + 1, close).replace(/\\\$/g, "$");
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// src/engine/markdown/inline/html-tags.ts
|
|
1149
|
+
var OPEN_TAG = /<([A-Za-z][A-Za-z0-9]*)((?:[ \t\n]+[A-Za-z_:][\w.:-]*="[^"]*")*)[ \t\n]*(\/?)>/y;
|
|
1150
|
+
var CLOSE_TAG = /<\/([A-Za-z][A-Za-z0-9]*)[ \t\n]*>/y;
|
|
1151
|
+
var ATTRIBUTE = /([A-Za-z_:][\w.:-]*)="([^"]*)"/g;
|
|
1152
|
+
var ATTR_PREFIX = "data-attr-";
|
|
1153
|
+
var SPAN_KINDS = ["data-color", "data-bg", "data-comment", "data-mark", "data-atom"];
|
|
1154
|
+
var PLAIN_MARKS = /* @__PURE__ */ new Map([
|
|
1155
|
+
["u", "underline"],
|
|
1156
|
+
["b", "bold"],
|
|
1157
|
+
["strong", "bold"],
|
|
1158
|
+
["i", "italic"],
|
|
1159
|
+
["em", "italic"],
|
|
1160
|
+
["s", "strike"],
|
|
1161
|
+
["del", "strike"],
|
|
1162
|
+
["strike", "strike"],
|
|
1163
|
+
["code", "code"],
|
|
1164
|
+
["sub", "sub"],
|
|
1165
|
+
["sup", "sup"]
|
|
1166
|
+
]);
|
|
1167
|
+
var PAIRED = /* @__PURE__ */ new Set([...PLAIN_MARKS.keys(), "mark", "span"]);
|
|
1168
|
+
function readAttributes(source) {
|
|
1169
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
1170
|
+
for (const [, name, value] of source.matchAll(ATTRIBUTE)) {
|
|
1171
|
+
if (attributes.has(name)) return null;
|
|
1172
|
+
attributes.set(name, decodeEntities(value));
|
|
1173
|
+
}
|
|
1174
|
+
return attributes;
|
|
1175
|
+
}
|
|
1176
|
+
function customAttrs(attributes, kind) {
|
|
1177
|
+
const entries = [...attributes].filter(([name]) => name !== kind);
|
|
1178
|
+
if (entries.some(([name]) => !name.startsWith(ATTR_PREFIX) || name === ATTR_PREFIX)) return null;
|
|
1179
|
+
return Object.fromEntries(entries.map(([name, value]) => [name.slice(ATTR_PREFIX.length), value]));
|
|
1180
|
+
}
|
|
1181
|
+
function customSpan(kind, type, attributes) {
|
|
1182
|
+
const attrs = customAttrs(attributes, kind);
|
|
1183
|
+
if (!attrs || !type) return null;
|
|
1184
|
+
if (kind === "data-atom") return { atom: { type, attrs } };
|
|
1185
|
+
if (isCoreMark(type)) return null;
|
|
1186
|
+
return { mark: Object.keys(attrs).length > 0 ? { type, attrs } : { type } };
|
|
1187
|
+
}
|
|
1188
|
+
function spanTag(attributes) {
|
|
1189
|
+
const kinds = [...attributes].filter(([name]) => SPAN_KINDS.includes(name));
|
|
1190
|
+
if (kinds.length !== 1) return null;
|
|
1191
|
+
const [[kind, value]] = kinds;
|
|
1192
|
+
if (kind === "data-mark" || kind === "data-atom") return customSpan(kind, value, attributes);
|
|
1193
|
+
if (attributes.size !== 1) return null;
|
|
1194
|
+
if (kind === "data-comment") return value ? { mark: { type: "comment", attrs: { id: value } } } : null;
|
|
1195
|
+
if (!isPaletteColor(value)) return null;
|
|
1196
|
+
return { mark: { type: kind === "data-color" ? "color" : "background", attrs: { color: value } } };
|
|
1197
|
+
}
|
|
1198
|
+
function highlightTag(attributes) {
|
|
1199
|
+
if ([...attributes.keys()].some((name) => name !== "data-color")) return null;
|
|
1200
|
+
const color = _nullishCoalesce(attributes.get("data-color"), () => ( ""));
|
|
1201
|
+
return { mark: isPaletteColor(color) ? { type: "highlight", attrs: { color } } : { type: "highlight" } };
|
|
1202
|
+
}
|
|
1203
|
+
function describeOpenTag(name, attributes, selfClosing) {
|
|
1204
|
+
if (name === "br") return attributes.size === 0 ? { lineBreak: true } : null;
|
|
1205
|
+
if (selfClosing) return null;
|
|
1206
|
+
const type = PLAIN_MARKS.get(name);
|
|
1207
|
+
if (type) return attributes.size === 0 ? { mark: { type } } : null;
|
|
1208
|
+
if (name === "mark") return highlightTag(attributes);
|
|
1209
|
+
if (name === "span") return spanTag(attributes);
|
|
1210
|
+
return null;
|
|
1211
|
+
}
|
|
1212
|
+
function parseInlineTag(src, pos) {
|
|
1213
|
+
const close = matchAt(CLOSE_TAG, src, pos);
|
|
1214
|
+
if (close) {
|
|
1215
|
+
const name2 = close[1].toLowerCase();
|
|
1216
|
+
return PAIRED.has(name2) ? { tag: { close: true, name: name2 }, end: pos + close[0].length } : null;
|
|
1217
|
+
}
|
|
1218
|
+
const open = matchAt(OPEN_TAG, src, pos);
|
|
1219
|
+
const attributes = open && readAttributes(open[2]);
|
|
1220
|
+
if (!open || !attributes) return null;
|
|
1221
|
+
const name = open[1].toLowerCase();
|
|
1222
|
+
const meaning = describeOpenTag(name, attributes, open[3] === "/");
|
|
1223
|
+
return meaning && { tag: { close: false, name, ...meaning }, end: pos + open[0].length };
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// src/engine/markdown/inline/open-angle.ts
|
|
1227
|
+
function findSpanClose(src, from) {
|
|
1228
|
+
for (let at = src.indexOf("<", from); at >= 0; at = src.indexOf("<", at + 1)) {
|
|
1229
|
+
const parsed = parseInlineTag(src, at);
|
|
1230
|
+
if (_optionalChain([parsed, 'optionalAccess', _21 => _21.tag, 'access', _22 => _22.close]) && parsed.tag.name === "span") return parsed.end;
|
|
1231
|
+
}
|
|
1232
|
+
return -1;
|
|
1233
|
+
}
|
|
1234
|
+
function atomSpan(scanner, atom2, openEnd) {
|
|
1235
|
+
const closeEnd = findClose(scanner, "span", openEnd, (from) => findSpanClose(scanner.src, from));
|
|
1236
|
+
if (closeEnd < 0) {
|
|
1237
|
+
pushText(scanner, scanner.src.slice(scanner.pos, openEnd), openEnd - scanner.pos);
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
scanner.items.push({ kind: "atom", type: atom2.type, attrs: atom2.attrs });
|
|
1241
|
+
scanner.pos = closeEnd;
|
|
1242
|
+
}
|
|
1243
|
+
function autolinkItem(text2, href) {
|
|
1244
|
+
return href === null ? { kind: "text", text: text2 } : { kind: "text", text: text2, marks: [{ type: "link", attrs: { href } }] };
|
|
1245
|
+
}
|
|
1246
|
+
function openAngle(scanner) {
|
|
1247
|
+
const { src, pos, items } = scanner;
|
|
1248
|
+
const autolink = parseAutolink(src, pos);
|
|
1249
|
+
if (autolink) {
|
|
1250
|
+
items.push(autolinkItem(autolink.value.text, sanitizeHref(autolink.value.href)));
|
|
1251
|
+
scanner.pos = autolink.end;
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
const parsed = parseInlineTag(src, pos);
|
|
1255
|
+
if (!parsed) pushText(scanner, "<", 1);
|
|
1256
|
+
else if (parsed.tag.lineBreak) pushText(scanner, "\n", parsed.end - pos);
|
|
1257
|
+
else if (parsed.tag.atom) atomSpan(scanner, parsed.tag.atom, parsed.end);
|
|
1258
|
+
else {
|
|
1259
|
+
items.push({ kind: "tag", source: src.slice(pos, parsed.end), tag: parsed.tag });
|
|
1260
|
+
scanner.pos = parsed.end;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// src/engine/markdown/inline/pair-tags.ts
|
|
1265
|
+
function stackOf(openByName, name) {
|
|
1266
|
+
const existing = openByName.get(name);
|
|
1267
|
+
if (existing) return existing;
|
|
1268
|
+
const stack = [];
|
|
1269
|
+
openByName.set(name, stack);
|
|
1270
|
+
return stack;
|
|
1271
|
+
}
|
|
1272
|
+
function pairTags(items) {
|
|
1273
|
+
const openByName = /* @__PURE__ */ new Map();
|
|
1274
|
+
for (const item of items) {
|
|
1275
|
+
if (item.kind !== "tag") continue;
|
|
1276
|
+
const { close, name, mark } = item.tag;
|
|
1277
|
+
if (!close) {
|
|
1278
|
+
if (mark) stackOf(openByName, name).push({ item, mark });
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
const opener = _optionalChain([openByName, 'access', _23 => _23.get, 'call', _24 => _24(name), 'optionalAccess', _25 => _25.pop, 'call', _26 => _26()]);
|
|
1282
|
+
if (!opener) continue;
|
|
1283
|
+
const range = { mark: opener.mark };
|
|
1284
|
+
opener.item.range = range;
|
|
1285
|
+
item.range = range;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// src/engine/markdown/inline/parse-inline.ts
|
|
1290
|
+
var PLAIN = /[^\\`*_~[\]!<&$\n]+/y;
|
|
1291
|
+
var CODE = { type: "code" };
|
|
1292
|
+
function breakLine(scanner, value) {
|
|
1293
|
+
scanner.items.push({ kind: "text", text: value });
|
|
1294
|
+
let next = scanner.pos + 1;
|
|
1295
|
+
while (scanner.src[next] === " " || scanner.src[next] === " ") next++;
|
|
1296
|
+
scanner.pos = next;
|
|
1297
|
+
}
|
|
1298
|
+
function plainRun(scanner, run) {
|
|
1299
|
+
if (scanner.src[scanner.pos + run.length] !== "\n") {
|
|
1300
|
+
pushText(scanner, run, run.length);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
pushText(scanner, run.replace(/[ \t]+$/, ""), run.length);
|
|
1304
|
+
breakLine(scanner, run.endsWith(" ") ? "\n" : scanner.softBreak);
|
|
1305
|
+
}
|
|
1306
|
+
function backslash(scanner) {
|
|
1307
|
+
const next = scanner.src[scanner.pos + 1];
|
|
1308
|
+
if (next === "\n") {
|
|
1309
|
+
scanner.pos += 1;
|
|
1310
|
+
breakLine(scanner, "\n");
|
|
1311
|
+
} else if (isEscapable(next)) {
|
|
1312
|
+
pushText(scanner, next, 2);
|
|
1313
|
+
} else {
|
|
1314
|
+
pushText(scanner, "\\", 1);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
function runLength(src, pos, char) {
|
|
1318
|
+
let end = pos;
|
|
1319
|
+
while (src[end] === char) end++;
|
|
1320
|
+
return end - pos;
|
|
1321
|
+
}
|
|
1322
|
+
function codeSpan(scanner) {
|
|
1323
|
+
const { src, pos } = scanner;
|
|
1324
|
+
const fence = runLength(src, pos, "`");
|
|
1325
|
+
const close = findClose(scanner, `code${fence}`, pos + fence, (from) => findCodeClose(src, from, fence));
|
|
1326
|
+
if (close < 0) {
|
|
1327
|
+
pushText(scanner, "`".repeat(fence), fence);
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
scanner.items.push({ kind: "text", text: codeSpanText(src.slice(pos + fence, close)), marks: [CODE] });
|
|
1331
|
+
scanner.pos = close + fence;
|
|
1332
|
+
}
|
|
1333
|
+
function codePointBefore(src, pos) {
|
|
1334
|
+
return _nullishCoalesce(Array.from(src.slice(Math.max(0, pos - 2), pos)).pop(), () => ( ""));
|
|
1335
|
+
}
|
|
1336
|
+
function codePointAt(src, pos) {
|
|
1337
|
+
const code = src.codePointAt(pos);
|
|
1338
|
+
return code === void 0 ? "" : String.fromCodePoint(code);
|
|
1339
|
+
}
|
|
1340
|
+
function delimiterRun(scanner, char) {
|
|
1341
|
+
const { src, pos } = scanner;
|
|
1342
|
+
const length = runLength(src, pos, char);
|
|
1343
|
+
const end = pos + length;
|
|
1344
|
+
if (char === "~" && length > 2) {
|
|
1345
|
+
pushText(scanner, src.slice(pos, end), length);
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const flanking = classifyDelimiterRun(codePointBefore(src, pos), codePointAt(src, end), char);
|
|
1349
|
+
const delimiter = {
|
|
1350
|
+
kind: "delimiter",
|
|
1351
|
+
char,
|
|
1352
|
+
length,
|
|
1353
|
+
count: length,
|
|
1354
|
+
...flanking,
|
|
1355
|
+
opens: [],
|
|
1356
|
+
closes: []
|
|
1357
|
+
};
|
|
1358
|
+
scanner.items.push(delimiter);
|
|
1359
|
+
if (delimiter.canOpen || delimiter.canClose) scanner.delimiters.push(delimiter);
|
|
1360
|
+
scanner.pos = end;
|
|
1361
|
+
}
|
|
1362
|
+
function openBracket(scanner, image) {
|
|
1363
|
+
const width = image ? 2 : 1;
|
|
1364
|
+
const { items, pos, delimiters } = scanner;
|
|
1365
|
+
scanner.brackets.push({ index: items.length, start: pos + width, image, bottom: delimiters.length, active: true });
|
|
1366
|
+
pushText(scanner, image ? "![" : "[", width);
|
|
1367
|
+
}
|
|
1368
|
+
function entity(scanner) {
|
|
1369
|
+
const decoded = matchEntity(scanner.src, scanner.pos);
|
|
1370
|
+
if (decoded) pushText(scanner, decoded.value, decoded.end - scanner.pos);
|
|
1371
|
+
else pushText(scanner, "&", 1);
|
|
1372
|
+
}
|
|
1373
|
+
function math2(scanner) {
|
|
1374
|
+
const { src, pos } = scanner;
|
|
1375
|
+
if (src[pos + 1] === "$") {
|
|
1376
|
+
const end = dollarRunEnd(src, pos);
|
|
1377
|
+
pushText(scanner, src.slice(pos, end), end - pos);
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const close = opensMath(src, pos) ? findClose(scanner, "math", pos + 2, (from) => findMathClose(src, from)) : -1;
|
|
1381
|
+
if (close < 0) {
|
|
1382
|
+
pushText(scanner, "$", 1);
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
scanner.items.push({ kind: "atom", type: "math", attrs: { latex: mathLatex(src, pos, close) } });
|
|
1386
|
+
scanner.pos = close + 1;
|
|
1387
|
+
}
|
|
1388
|
+
function scanSpecial(scanner, char) {
|
|
1389
|
+
if (char === "\\") backslash(scanner);
|
|
1390
|
+
else if (char === "`") codeSpan(scanner);
|
|
1391
|
+
else if (char === "*" || char === "_" || char === "~") delimiterRun(scanner, char);
|
|
1392
|
+
else if (char === "[") openBracket(scanner, false);
|
|
1393
|
+
else if (char === "!" && scanner.src[scanner.pos + 1] === "[") openBracket(scanner, true);
|
|
1394
|
+
else if (char === "]") closeBracket(scanner);
|
|
1395
|
+
else if (char === "<") openAngle(scanner);
|
|
1396
|
+
else if (char === "&") entity(scanner);
|
|
1397
|
+
else if (char === "$") math2(scanner);
|
|
1398
|
+
else if (char === "\n") breakLine(scanner, scanner.softBreak);
|
|
1399
|
+
else pushText(scanner, char, 1);
|
|
1400
|
+
}
|
|
1401
|
+
function parseInline(markdown, options = {}) {
|
|
1402
|
+
const scanner = createScanner(markdown, options);
|
|
1403
|
+
while (scanner.pos < markdown.length) {
|
|
1404
|
+
const plain = matchAt(PLAIN, markdown, scanner.pos);
|
|
1405
|
+
if (plain) plainRun(scanner, plain[0]);
|
|
1406
|
+
else scanSpecial(scanner, markdown[scanner.pos]);
|
|
1407
|
+
}
|
|
1408
|
+
processEmphasis(scanner.delimiters, 0);
|
|
1409
|
+
pairTags(scanner.items);
|
|
1410
|
+
return flattenItems(scanner.items);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// src/engine/markdown/inline/escape-text.ts
|
|
1414
|
+
var ALWAYS_ESCAPED = /[\\`*_[\]<~$]/;
|
|
1415
|
+
var WORD_CHAR = /^[\p{L}\p{N}]$/u;
|
|
1416
|
+
var LITERAL_AFTER_BACKSLASH = /^[^\s!-/:-@[-`{-~]$/;
|
|
1417
|
+
var ENTITY_LIKE = /&#?[A-Za-z0-9]+;/y;
|
|
1418
|
+
var ORDERED_MARKER = /[0-9]+(?=[.)])/y;
|
|
1419
|
+
var LINE_START_SYNTAX = /* @__PURE__ */ new Set(["#", ">", "=", "+", "-"]);
|
|
1420
|
+
var WHITESPACE_ENTITY = { " ": " ", " ": "	" };
|
|
1421
|
+
function needsEscape(text2, index) {
|
|
1422
|
+
const char = text2[index];
|
|
1423
|
+
if (char === "_") return !(WORD_CHAR.test(_nullishCoalesce(text2[index - 1], () => ( ""))) && WORD_CHAR.test(_nullishCoalesce(text2[index + 1], () => ( ""))));
|
|
1424
|
+
if (char === "\\") return !LITERAL_AFTER_BACKSLASH.test(_nullishCoalesce(text2[index + 1], () => ( "")));
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
function escapeEntityAmpersands(value) {
|
|
1428
|
+
return value.replace(/&(?=#?[A-Za-z0-9]+;)/g, "\\&");
|
|
1429
|
+
}
|
|
1430
|
+
function breaksWithTag(text2, index, ctx) {
|
|
1431
|
+
if (ctx.hardBreak === "br") return true;
|
|
1432
|
+
const startsRegion = index === 0 ? !ctx.previous || ctx.previous === "\n" : text2[index - 1] === "\n";
|
|
1433
|
+
const endsRegion = index === text2.length - 1 && !ctx.following;
|
|
1434
|
+
return startsRegion || endsRegion;
|
|
1435
|
+
}
|
|
1436
|
+
function escapeText(text2, ctx) {
|
|
1437
|
+
const last = text2.length - 1;
|
|
1438
|
+
let atLineStart = ctx.lineStart;
|
|
1439
|
+
let out = "";
|
|
1440
|
+
for (let i = 0; i <= last; i++) {
|
|
1441
|
+
const char = text2[i];
|
|
1442
|
+
if (char === "\n") {
|
|
1443
|
+
const tag = breaksWithTag(text2, i, ctx);
|
|
1444
|
+
out += tag ? "<br>" : "\\\n";
|
|
1445
|
+
atLineStart = !tag;
|
|
1446
|
+
continue;
|
|
1447
|
+
}
|
|
1448
|
+
const lineStart = atLineStart;
|
|
1449
|
+
atLineStart = false;
|
|
1450
|
+
const ordered = lineStart && ctx.escapeLineStart ? matchAt(ORDERED_MARKER, text2, i) : null;
|
|
1451
|
+
if (ordered) {
|
|
1452
|
+
out += `${ordered[0]}\\${text2[i + ordered[0].length]}`;
|
|
1453
|
+
i += ordered[0].length;
|
|
1454
|
+
} else if (char === " " || char === " ") {
|
|
1455
|
+
const lineEnd = text2[i + 1] === "\n" || i === last && ctx.lineEnd;
|
|
1456
|
+
out += lineStart || lineEnd ? WHITESPACE_ENTITY[char] : char;
|
|
1457
|
+
} else if (ALWAYS_ESCAPED.test(char) && needsEscape(text2, i)) {
|
|
1458
|
+
out += `\\${char}`;
|
|
1459
|
+
} else if (char === "&") {
|
|
1460
|
+
out += matchAt(ENTITY_LIKE, text2, i) ? "\\&" : "&";
|
|
1461
|
+
} else if (char === "!") {
|
|
1462
|
+
const bracket = i === last ? ctx.next[0] === "[" : text2[i + 1] === "[";
|
|
1463
|
+
out += bracket ? "\\!" : "!";
|
|
1464
|
+
} else if (char === "|" && ctx.escapePipes) {
|
|
1465
|
+
out += "\\|";
|
|
1466
|
+
} else if (lineStart && ctx.escapeLineStart && LINE_START_SYNTAX.has(char)) {
|
|
1467
|
+
out += `\\${char}`;
|
|
1468
|
+
} else {
|
|
1469
|
+
out += char;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return out;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// src/engine/markdown/inline/data-attributes.ts
|
|
1476
|
+
function dataAttributes(attrs, prefix = "data-attr-") {
|
|
1477
|
+
return Object.keys(_nullishCoalesce(attrs, () => ( {}))).sort(compareCodeUnits).map((key) => [`${prefix}${key}`, attrs[key]]);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// src/engine/render/html-node.ts
|
|
1481
|
+
var ATTRIBUTE_NAME = /^[A-Za-z][A-Za-z0-9_.:-]*$/;
|
|
1482
|
+
var writtenAttrs = (attrs) => attrs.filter((attr) => attr[1] !== void 0 && ATTRIBUTE_NAME.test(attr[0]));
|
|
1483
|
+
var textOf = (nodes) => nodes.map((node) => typeof node === "string" ? node : node.tag === "br" ? " " : textOf(node.children)).join("");
|
|
1484
|
+
var nodeText = (nodes) => textOf(nodes).replace(/\s+/g, " ").trim();
|
|
1485
|
+
var element = (tag, attrs = [], children = [], html) => ({
|
|
1486
|
+
tag,
|
|
1487
|
+
attrs,
|
|
1488
|
+
children,
|
|
1489
|
+
html
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
// src/engine/render/plain-mark-tags.ts
|
|
1493
|
+
var PLAIN_MARK_TAGS = /* @__PURE__ */ new Map([
|
|
1494
|
+
["bold", "strong"],
|
|
1495
|
+
["italic", "em"],
|
|
1496
|
+
["underline", "u"],
|
|
1497
|
+
["strike", "s"],
|
|
1498
|
+
["sub", "sub"],
|
|
1499
|
+
["sup", "sup"],
|
|
1500
|
+
["code", "code"]
|
|
1501
|
+
]);
|
|
1502
|
+
|
|
1503
|
+
// src/engine/render/mark-node.ts
|
|
1504
|
+
function markElement(mark) {
|
|
1505
|
+
const plain = PLAIN_MARK_TAGS.get(mark.type);
|
|
1506
|
+
if (plain) return element(plain);
|
|
1507
|
+
const attrs = _nullishCoalesce(mark.attrs, () => ( {}));
|
|
1508
|
+
switch (mark.type) {
|
|
1509
|
+
case "link": {
|
|
1510
|
+
const href = sanitizeHref(_nullishCoalesce(attrs.href, () => ( "")));
|
|
1511
|
+
return href === null ? null : element("a", [["href", href], ["title", attrs.title], ["rel", "noopener noreferrer"]]);
|
|
1512
|
+
}
|
|
1513
|
+
case "comment":
|
|
1514
|
+
return element("span", [["data-comment", _nullishCoalesce(attrs.id, () => ( ""))]]);
|
|
1515
|
+
case "highlight":
|
|
1516
|
+
return element("mark", [["data-color", attrs.color || void 0]]);
|
|
1517
|
+
case "color":
|
|
1518
|
+
return element("span", [["data-color", _nullishCoalesce(attrs.color, () => ( ""))]]);
|
|
1519
|
+
case "background":
|
|
1520
|
+
return element("span", [["data-bg", _nullishCoalesce(attrs.color, () => ( ""))]]);
|
|
1521
|
+
default:
|
|
1522
|
+
return element("span", [["data-mark", mark.type], ...dataAttributes(attrs)]);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// src/engine/markdown/inline/html-marks.ts
|
|
1527
|
+
function escapeAttribute(value, escapePipes) {
|
|
1528
|
+
const escaped = value.replace(/&/g, "&").replace(/"/g, """).replace(/\n/g, " ");
|
|
1529
|
+
return escapePipes ? escaped.replace(/\|/g, "|") : escaped;
|
|
1530
|
+
}
|
|
1531
|
+
function htmlTag(name, attributes, escapePipes) {
|
|
1532
|
+
const written = attributes.map(([key, value]) => ` ${key}="${escapeAttribute(value, escapePipes)}"`).join("");
|
|
1533
|
+
return { open: `<${name}${written}>`, close: `</${name}>` };
|
|
1534
|
+
}
|
|
1535
|
+
function markTag(mark, escapePipes) {
|
|
1536
|
+
const { tag, attrs } = markElement(mark);
|
|
1537
|
+
const written = attrs.filter((attr) => attr[1] !== void 0);
|
|
1538
|
+
return htmlTag(mark.type === "strike" ? "del" : tag, written, escapePipes);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// src/engine/markdown/inline/link-markdown.ts
|
|
1542
|
+
function escapeFor(value, characters, escapePipes) {
|
|
1543
|
+
const escaped = value.replace(characters, "\\$&");
|
|
1544
|
+
const piped = escapePipes ? escaped.replace(/\|/g, "\\|") : escaped;
|
|
1545
|
+
return escapeEntityAmpersands(piped).replace(/\n/g, " ");
|
|
1546
|
+
}
|
|
1547
|
+
function readsBackAs(destination, href) {
|
|
1548
|
+
const parsed = parseLinkDestination(`${destination})`, 0);
|
|
1549
|
+
return _optionalChain([parsed, 'optionalAccess', _27 => _27.value]) === href && parsed.end === destination.length;
|
|
1550
|
+
}
|
|
1551
|
+
function linkDestination(href, escapePipes) {
|
|
1552
|
+
const raw = escapeFor(href, /\\/g, escapePipes);
|
|
1553
|
+
return readsBackAs(raw, href) ? raw : `<${escapeFor(href, /[\\<>]/g, escapePipes)}>`;
|
|
1554
|
+
}
|
|
1555
|
+
function linkClose(mark, escapePipes) {
|
|
1556
|
+
const href = _nullishCoalesce(_optionalChain([mark, 'access', _28 => _28.attrs, 'optionalAccess', _29 => _29.href]), () => ( ""));
|
|
1557
|
+
const title = _optionalChain([mark, 'access', _30 => _30.attrs, 'optionalAccess', _31 => _31.title]);
|
|
1558
|
+
if (!title) return `](${linkDestination(href, escapePipes)})`;
|
|
1559
|
+
const destination = href === "" ? "<>" : linkDestination(href, escapePipes);
|
|
1560
|
+
return `](${destination} "${escapeFor(title, /[\\"]/g, escapePipes)}")`;
|
|
1561
|
+
}
|
|
1562
|
+
function autolinkMarkdown(text2, mark) {
|
|
1563
|
+
if (_optionalChain([mark, 'access', _32 => _32.attrs, 'optionalAccess', _33 => _33.title])) return null;
|
|
1564
|
+
const candidate = `<${text2}>`;
|
|
1565
|
+
const parsed = parseAutolink(candidate, 0);
|
|
1566
|
+
if (_optionalChain([parsed, 'optionalAccess', _34 => _34.end]) !== candidate.length) return null;
|
|
1567
|
+
return parsed.value.text === text2 && parsed.value.href === _optionalChain([mark, 'access', _35 => _35.attrs, 'optionalAccess', _36 => _36.href]) ? candidate : null;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// src/engine/markdown/inline/atom-markdown.ts
|
|
1571
|
+
var MENTION_KEYS = /* @__PURE__ */ new Set(["id", "label", "kind"]);
|
|
1572
|
+
var DIGIT2 = /[0-9]/;
|
|
1573
|
+
var MATH_EDGE_HAZARD = /^\s|\s$|\\$/;
|
|
1574
|
+
var TRAILING_SPACE = /\s$/;
|
|
1575
|
+
function hasMentionShape(attrs) {
|
|
1576
|
+
const { id, label, kind } = attrs;
|
|
1577
|
+
if (!Object.keys(attrs).every((key) => MENTION_KEYS.has(key))) return false;
|
|
1578
|
+
if (!id || label === void 0 || kind !== void 0 && (!kind || kind.includes(":"))) return false;
|
|
1579
|
+
return kind !== void 0 || !id.includes(":");
|
|
1580
|
+
}
|
|
1581
|
+
function mentionHref({ id, kind }) {
|
|
1582
|
+
return kind === void 0 ? `mention:${id}` : `mention:${kind}:${id}`;
|
|
1583
|
+
}
|
|
1584
|
+
function mentionMarkdown(attrs, options) {
|
|
1585
|
+
const label = escapeText(attrs.label, {
|
|
1586
|
+
lineStart: false,
|
|
1587
|
+
lineEnd: false,
|
|
1588
|
+
escapeLineStart: options.escapeLineStart,
|
|
1589
|
+
escapePipes: options.escapePipes,
|
|
1590
|
+
hardBreak: options.hardBreak,
|
|
1591
|
+
next: "]",
|
|
1592
|
+
previous: "@",
|
|
1593
|
+
following: "]"
|
|
1594
|
+
});
|
|
1595
|
+
return `[@${label}](${linkDestination(mentionHref(attrs), options.escapePipes)})`;
|
|
1596
|
+
}
|
|
1597
|
+
function isPrettyMath(attrs, before, after, options) {
|
|
1598
|
+
const { latex } = attrs;
|
|
1599
|
+
if (Object.keys(attrs).length !== 1 || !latex || /[$\n]/.test(latex)) return false;
|
|
1600
|
+
if (options.escapePipes && latex.includes("|")) return false;
|
|
1601
|
+
const pricelike = DIGIT2.test(latex[0]) && (before === "" || TRAILING_SPACE.test(before));
|
|
1602
|
+
return !MATH_EDGE_HAZARD.test(latex) && !DIGIT2.test(_nullishCoalesce(after[0], () => ( ""))) && !pricelike;
|
|
1603
|
+
}
|
|
1604
|
+
function writesMention(node, options) {
|
|
1605
|
+
if (options.strict || node.type !== "mention" || !hasMentionShape(node.attrs)) return false;
|
|
1606
|
+
const href = mentionHref(node.attrs);
|
|
1607
|
+
return sanitizeHref(href) === href && !node.marks.some((mark) => mark.type === "link");
|
|
1608
|
+
}
|
|
1609
|
+
function atomMarkdown(node, before, after, options) {
|
|
1610
|
+
if (writesMention(node, options)) return mentionMarkdown(node.attrs, options);
|
|
1611
|
+
if (!options.strict && node.type === "math" && isPrettyMath(node.attrs, before, after, options)) {
|
|
1612
|
+
return `$${node.attrs.latex}$`;
|
|
1613
|
+
}
|
|
1614
|
+
const attributes = [["data-atom", node.type], ...dataAttributes(node.attrs)];
|
|
1615
|
+
const { open, close } = htmlTag("span", attributes, options.escapePipes);
|
|
1616
|
+
return open + close;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// src/engine/markdown/inline/code-markdown.ts
|
|
1620
|
+
var BACKTICK_RUN = /`+/g;
|
|
1621
|
+
var NEEDS_PADDING = /^[ `]|[ `]$/;
|
|
1622
|
+
function codeSpan2(content) {
|
|
1623
|
+
const lengths = new Set((_nullishCoalesce(content.match(BACKTICK_RUN), () => ( []))).map((run) => run.length));
|
|
1624
|
+
let fence = 1;
|
|
1625
|
+
while (lengths.has(fence)) fence++;
|
|
1626
|
+
const padding = NEEDS_PADDING.test(content) && /[^ ]/.test(content) ? " " : "";
|
|
1627
|
+
const ticks = "`".repeat(fence);
|
|
1628
|
+
return `${ticks}${padding}${content}${padding}${ticks}`;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// src/engine/markdown/inline/literal-ranges.ts
|
|
1632
|
+
function allText(children) {
|
|
1633
|
+
let content = "";
|
|
1634
|
+
for (const child of children) {
|
|
1635
|
+
if (child.kind !== "leaf" || child.node.kind !== "text") return null;
|
|
1636
|
+
content += child.node.text;
|
|
1637
|
+
}
|
|
1638
|
+
return content;
|
|
1639
|
+
}
|
|
1640
|
+
function autolinkOf(range, options) {
|
|
1641
|
+
const text2 = options.strict || range.mark.type !== "link" ? null : allText(range.children);
|
|
1642
|
+
if (text2 === null || options.escapePipes && text2.includes("|")) return null;
|
|
1643
|
+
return autolinkMarkdown(text2, range.mark);
|
|
1644
|
+
}
|
|
1645
|
+
function codeSpanOf(range, options) {
|
|
1646
|
+
const content = range.mark.type === "code" ? allText(range.children) : null;
|
|
1647
|
+
if (content === null || options.escapePipes && content.includes("|")) return null;
|
|
1648
|
+
return codeSpan2(content);
|
|
1649
|
+
}
|
|
1650
|
+
function renderLiteral(range, options) {
|
|
1651
|
+
return _nullishCoalesce(autolinkOf(range, options), () => ( codeSpanOf(range, options)));
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/engine/markdown/inline/edge-chars.ts
|
|
1655
|
+
var OPENER = "<";
|
|
1656
|
+
function textStart(text2) {
|
|
1657
|
+
const code = text2.codePointAt(0);
|
|
1658
|
+
if (code === void 0) return "";
|
|
1659
|
+
const first = String.fromCodePoint(code);
|
|
1660
|
+
if (first === "\n") return first;
|
|
1661
|
+
return ALWAYS_ESCAPED.test(first) ? "\\" : first;
|
|
1662
|
+
}
|
|
1663
|
+
function startOf(child, options) {
|
|
1664
|
+
if (child.kind === "range") return child.mark.type === "link" && !autolinkOf(child, options) ? "[" : OPENER;
|
|
1665
|
+
const { node } = child;
|
|
1666
|
+
if (node.kind === "text") return textStart(node.text);
|
|
1667
|
+
return writesMention(node, options) ? "[" : OPENER;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// src/engine/markdown/inline/inline-tree.ts
|
|
1671
|
+
function buildTree(nodes) {
|
|
1672
|
+
const root = [];
|
|
1673
|
+
const open = [];
|
|
1674
|
+
nodes.forEach((node, index) => {
|
|
1675
|
+
let shared = 0;
|
|
1676
|
+
while (shared < open.length && shared < node.marks.length && sameMark(open[shared].mark, node.marks[shared])) {
|
|
1677
|
+
shared++;
|
|
1678
|
+
}
|
|
1679
|
+
open.length = shared;
|
|
1680
|
+
for (const mark of node.marks.slice(shared)) {
|
|
1681
|
+
const range = { kind: "range", mark, children: [] };
|
|
1682
|
+
(_nullishCoalesce(_optionalChain([open, 'access', _37 => _37.at, 'call', _38 => _38(-1), 'optionalAccess', _39 => _39.children]), () => ( root))).push(range);
|
|
1683
|
+
open.push(range);
|
|
1684
|
+
}
|
|
1685
|
+
(_nullishCoalesce(_optionalChain([open, 'access', _40 => _40.at, 'call', _41 => _41(-1), 'optionalAccess', _42 => _42.children]), () => ( root))).push({ kind: "leaf", node, index });
|
|
1686
|
+
});
|
|
1687
|
+
return root;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
// src/engine/markdown/inline/emphasis-delimiter.ts
|
|
1691
|
+
var CANDIDATES = {
|
|
1692
|
+
bold: ["**", "__"],
|
|
1693
|
+
italic: ["_", "*"],
|
|
1694
|
+
strike: ["~~"]
|
|
1695
|
+
};
|
|
1696
|
+
function firstCodePoint(value) {
|
|
1697
|
+
const code = value.codePointAt(0);
|
|
1698
|
+
return code === void 0 ? "" : String.fromCodePoint(code);
|
|
1699
|
+
}
|
|
1700
|
+
function lastCodePoint(value) {
|
|
1701
|
+
return _nullishCoalesce(Array.from(value.slice(-2)).pop(), () => ( ""));
|
|
1702
|
+
}
|
|
1703
|
+
function endsWithDelimiter(value, char) {
|
|
1704
|
+
if (!value.endsWith(char)) return false;
|
|
1705
|
+
let slashes = 0;
|
|
1706
|
+
for (let at = value.length - 2; at >= 0 && value[at] === "\\"; at--) slashes++;
|
|
1707
|
+
return slashes % 2 === 0;
|
|
1708
|
+
}
|
|
1709
|
+
function fuses(char, before, inner) {
|
|
1710
|
+
return endsWithDelimiter(before, char) || inner.startsWith(char) || endsWithDelimiter(inner, char);
|
|
1711
|
+
}
|
|
1712
|
+
function chooseDelimiter(type, before, inner, after) {
|
|
1713
|
+
const previous = lastCodePoint(before);
|
|
1714
|
+
const first = firstCodePoint(inner);
|
|
1715
|
+
const last = lastCodePoint(inner);
|
|
1716
|
+
const following = firstCodePoint(after);
|
|
1717
|
+
const chosen = CANDIDATES[type].find((delimiter) => {
|
|
1718
|
+
const char = delimiter[0];
|
|
1719
|
+
if (fuses(char, before, inner)) return false;
|
|
1720
|
+
return classifyDelimiterRun(previous, first, char).canOpen && classifyDelimiterRun(last, following, char).canClose;
|
|
1721
|
+
});
|
|
1722
|
+
return _nullishCoalesce(chosen, () => ( null));
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
// src/engine/markdown/inline/range-wrapper.ts
|
|
1726
|
+
function isEmphasis(type) {
|
|
1727
|
+
return type === "bold" || type === "italic" || type === "strike";
|
|
1728
|
+
}
|
|
1729
|
+
function linkOpen(mark, inner) {
|
|
1730
|
+
return _optionalChain([mark, 'access', _43 => _43.attrs, 'optionalAccess', _44 => _44.href, 'optionalAccess', _45 => _45.startsWith, 'call', _46 => _46("mention:")]) && inner.startsWith("@") ? "[<u></u>" : "[";
|
|
1731
|
+
}
|
|
1732
|
+
function wrapRange(mark, before, inner, after, options) {
|
|
1733
|
+
if (mark.type === "link") return { open: linkOpen(mark, inner), close: linkClose(mark, options.escapePipes) };
|
|
1734
|
+
if (options.strict || !isEmphasis(mark.type)) return markTag(mark, options.escapePipes);
|
|
1735
|
+
const following = after === "\n" ? "\\" : after;
|
|
1736
|
+
const delimiter = chooseDelimiter(mark.type, before, inner, following);
|
|
1737
|
+
return delimiter ? { open: delimiter, close: delimiter } : markTag(mark, options.escapePipes);
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
// src/engine/markdown/inline/render-inline.ts
|
|
1741
|
+
var TAIL_LENGTH = 8;
|
|
1742
|
+
function tailOf(before, piece) {
|
|
1743
|
+
return (piece.length >= TAIL_LENGTH ? piece : before + piece).slice(-TAIL_LENGTH);
|
|
1744
|
+
}
|
|
1745
|
+
function append(frame, piece) {
|
|
1746
|
+
frame.out += piece;
|
|
1747
|
+
frame.tail = tailOf(frame.tail, piece);
|
|
1748
|
+
}
|
|
1749
|
+
function rangeFrame(range, before, after) {
|
|
1750
|
+
const tail = tailOf(before, OPENER);
|
|
1751
|
+
return { range, children: range.children, before, after, closing: OPENER, at: 0, out: "", tail };
|
|
1752
|
+
}
|
|
1753
|
+
function lastContent(node) {
|
|
1754
|
+
if (!node) return "";
|
|
1755
|
+
return node.kind === "text" ? node.text.slice(-1) : "\uFFFC";
|
|
1756
|
+
}
|
|
1757
|
+
function firstContent(node) {
|
|
1758
|
+
if (!node) return "";
|
|
1759
|
+
return node.kind === "text" ? node.text.slice(0, 1) : "\uFFFC";
|
|
1760
|
+
}
|
|
1761
|
+
function renderInline(nodes, options) {
|
|
1762
|
+
function renderLeaf({ node, index }, before, after) {
|
|
1763
|
+
if (node.kind === "atom") return atomMarkdown(node, before, after, options);
|
|
1764
|
+
return escapeText(node.text, {
|
|
1765
|
+
lineStart: before === "" || before.endsWith("\\\n"),
|
|
1766
|
+
lineEnd: after === "" || after === "\n",
|
|
1767
|
+
escapeLineStart: options.escapeLineStart,
|
|
1768
|
+
escapePipes: options.escapePipes,
|
|
1769
|
+
hardBreak: options.hardBreak,
|
|
1770
|
+
next: after,
|
|
1771
|
+
previous: lastContent(nodes[index - 1]),
|
|
1772
|
+
following: firstContent(nodes[index + 1])
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
const root = { children: buildTree(nodes), before: "", after: "", closing: "", at: 0, out: "", tail: "" };
|
|
1776
|
+
const stack = [root];
|
|
1777
|
+
for (; ; ) {
|
|
1778
|
+
const frame = stack[stack.length - 1];
|
|
1779
|
+
if (frame.at < frame.children.length) {
|
|
1780
|
+
const child = frame.children[frame.at++];
|
|
1781
|
+
const next = frame.at < frame.children.length ? startOf(frame.children[frame.at], options) : frame.closing;
|
|
1782
|
+
const literal = child.kind === "range" ? renderLiteral(child, options) : renderLeaf(child, frame.tail, next);
|
|
1783
|
+
if (literal !== null) append(frame, literal);
|
|
1784
|
+
else if (child.kind === "range") stack.push(rangeFrame(child, frame.tail, next));
|
|
1785
|
+
} else {
|
|
1786
|
+
stack.pop();
|
|
1787
|
+
if (!frame.range) return frame.out;
|
|
1788
|
+
const { open, close } = wrapRange(frame.range.mark, frame.before, frame.out, frame.after, options);
|
|
1789
|
+
append(stack[stack.length - 1], open + frame.out + close);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// src/engine/markdown/inline/serialize-inline.ts
|
|
1795
|
+
function serializeInline(inline, options = {}) {
|
|
1796
|
+
const nodes = normalizeInline(inline);
|
|
1797
|
+
const base = {
|
|
1798
|
+
escapeLineStart: _nullishCoalesce(options.escapeLineStart, () => ( false)),
|
|
1799
|
+
escapePipes: _nullishCoalesce(options.escapePipes, () => ( false)),
|
|
1800
|
+
hardBreak: _nullishCoalesce(options.hardBreak, () => ( "backslash"))
|
|
1801
|
+
};
|
|
1802
|
+
const pretty = renderInline(nodes, { ...base, strict: false });
|
|
1803
|
+
return equalInline(parseInline(pretty), nodes) ? pretty : renderInline(nodes, { ...base, strict: true });
|
|
1804
|
+
}
|
|
1805
|
+
var inlineCodec = { parse: parseInline, serialize: serializeInline };
|
|
1806
|
+
|
|
1807
|
+
// src/engine/model/new-id.ts
|
|
1808
|
+
function newId() {
|
|
1809
|
+
const webCrypto = globalThis.crypto;
|
|
1810
|
+
if (webCrypto && typeof webCrypto.randomUUID === "function") return webCrypto.randomUUID();
|
|
1811
|
+
const random = () => Math.random().toString(36).slice(2, 10);
|
|
1812
|
+
return `blk-${Date.now().toString(36)}-${random()}${random()}`;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// src/engine/markdown/block/lines.ts
|
|
1816
|
+
var LINE_BREAK = /\r\n|\r|\n/;
|
|
1817
|
+
var NULL_CHAR = /\0/g;
|
|
1818
|
+
var TAB_STOP = 4;
|
|
1819
|
+
var CODE_INDENT = 4;
|
|
1820
|
+
function splitLines(markdown) {
|
|
1821
|
+
return markdown.replace(NULL_CHAR, "\uFFFD").split(LINE_BREAK);
|
|
1822
|
+
}
|
|
1823
|
+
var isSpaceOrTab = (char) => char === " " || char === " ";
|
|
1824
|
+
var isBlankChar = (char) => char === " " || char === " " || char === "\n";
|
|
1825
|
+
function trimBlankEnd(text2) {
|
|
1826
|
+
let end = text2.length;
|
|
1827
|
+
while (end > 0 && isBlankChar(text2[end - 1])) end--;
|
|
1828
|
+
return text2.slice(0, end);
|
|
1829
|
+
}
|
|
1830
|
+
function trimBlankStart(text2) {
|
|
1831
|
+
let start = 0;
|
|
1832
|
+
while (start < text2.length && isBlankChar(text2[start])) start++;
|
|
1833
|
+
return text2.slice(start);
|
|
1834
|
+
}
|
|
1835
|
+
var trimBlank = (text2) => trimBlankStart(trimBlankEnd(text2));
|
|
1836
|
+
var Cursor = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this); }
|
|
1837
|
+
__init() {this.line = ""}
|
|
1838
|
+
__init2() {this.offset = 0}
|
|
1839
|
+
__init3() {this.column = 0}
|
|
1840
|
+
__init4() {this.partialTab = false}
|
|
1841
|
+
reset(line) {
|
|
1842
|
+
this.line = line;
|
|
1843
|
+
this.offset = 0;
|
|
1844
|
+
this.column = 0;
|
|
1845
|
+
this.partialTab = false;
|
|
1846
|
+
}
|
|
1847
|
+
scan() {
|
|
1848
|
+
let index = this.offset;
|
|
1849
|
+
let column = this.column;
|
|
1850
|
+
for (; index < this.line.length; index++) {
|
|
1851
|
+
const char = this.line[index];
|
|
1852
|
+
if (char === " ") column++;
|
|
1853
|
+
else if (char === " ") column += TAB_STOP - column % TAB_STOP;
|
|
1854
|
+
else break;
|
|
1855
|
+
}
|
|
1856
|
+
return { index, column };
|
|
1857
|
+
}
|
|
1858
|
+
get indent() {
|
|
1859
|
+
return this.scan().column - this.column;
|
|
1860
|
+
}
|
|
1861
|
+
get indented() {
|
|
1862
|
+
return this.indent >= CODE_INDENT;
|
|
1863
|
+
}
|
|
1864
|
+
get blank() {
|
|
1865
|
+
return this.scan().index >= this.line.length;
|
|
1866
|
+
}
|
|
1867
|
+
get text() {
|
|
1868
|
+
return this.line.slice(this.scan().index);
|
|
1869
|
+
}
|
|
1870
|
+
get next() {
|
|
1871
|
+
return this.line[this.offset];
|
|
1872
|
+
}
|
|
1873
|
+
advanceToNonspace() {
|
|
1874
|
+
const { index, column } = this.scan();
|
|
1875
|
+
this.offset = index;
|
|
1876
|
+
this.column = column;
|
|
1877
|
+
this.partialTab = false;
|
|
1878
|
+
}
|
|
1879
|
+
advance(count, columns = false) {
|
|
1880
|
+
let remaining = count;
|
|
1881
|
+
while (remaining > 0 && this.offset < this.line.length) {
|
|
1882
|
+
if (this.line[this.offset] !== " ") {
|
|
1883
|
+
this.partialTab = false;
|
|
1884
|
+
this.offset++;
|
|
1885
|
+
this.column++;
|
|
1886
|
+
remaining--;
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1889
|
+
const width = TAB_STOP - this.column % TAB_STOP;
|
|
1890
|
+
if (!columns) {
|
|
1891
|
+
this.partialTab = false;
|
|
1892
|
+
this.column += width;
|
|
1893
|
+
this.offset++;
|
|
1894
|
+
remaining--;
|
|
1895
|
+
continue;
|
|
1896
|
+
}
|
|
1897
|
+
const step = Math.min(width, remaining);
|
|
1898
|
+
this.partialTab = width > remaining;
|
|
1899
|
+
this.column += step;
|
|
1900
|
+
if (!this.partialTab) this.offset++;
|
|
1901
|
+
remaining -= step;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
rest() {
|
|
1905
|
+
if (!this.partialTab) return this.line.slice(this.offset);
|
|
1906
|
+
return " ".repeat(TAB_STOP - this.column % TAB_STOP) + this.line.slice(this.offset + 1);
|
|
1907
|
+
}
|
|
1908
|
+
mark() {
|
|
1909
|
+
return { offset: this.offset, column: this.column, partialTab: this.partialTab };
|
|
1910
|
+
}
|
|
1911
|
+
restore(snapshot) {
|
|
1912
|
+
this.offset = snapshot.offset;
|
|
1913
|
+
this.column = snapshot.column;
|
|
1914
|
+
this.partialTab = snapshot.partialTab;
|
|
1915
|
+
}
|
|
1916
|
+
}, _class);
|
|
1917
|
+
|
|
1918
|
+
// src/engine/markdown/block/block-tree.ts
|
|
1919
|
+
function canContain(parent, child) {
|
|
1920
|
+
switch (parent.kind) {
|
|
1921
|
+
case "list":
|
|
1922
|
+
return child === "item";
|
|
1923
|
+
case "document":
|
|
1924
|
+
case "quote":
|
|
1925
|
+
case "item":
|
|
1926
|
+
case "details":
|
|
1927
|
+
return child !== "item";
|
|
1928
|
+
default:
|
|
1929
|
+
return false;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
var joinLines = (lines) => trimBlankEnd(lines.join("\n"));
|
|
1933
|
+
function textLinesOf(node) {
|
|
1934
|
+
if (_optionalChain([node, 'optionalAccess', _47 => _47.kind]) === "paragraph") return node.lines;
|
|
1935
|
+
return _optionalChain([node, 'optionalAccess', _48 => _48.kind]) === "html" ? node.lines.map((line) => trimBlankStart(line)) : null;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
// src/engine/markdown/block/references.ts
|
|
1939
|
+
function skipSpaces(src, pos) {
|
|
1940
|
+
let at = pos;
|
|
1941
|
+
while (src[at] === " " || src[at] === " ") at++;
|
|
1942
|
+
return at;
|
|
1943
|
+
}
|
|
1944
|
+
function skipSpacesAndOneNewline(src, pos) {
|
|
1945
|
+
const at = skipSpaces(src, pos);
|
|
1946
|
+
return src[at] === "\n" ? skipSpaces(src, at + 1) : at;
|
|
1947
|
+
}
|
|
1948
|
+
function endOfLine(src, pos) {
|
|
1949
|
+
const at = skipSpaces(src, pos);
|
|
1950
|
+
if (at >= src.length) return src.length;
|
|
1951
|
+
return src[at] === "\n" ? at + 1 : -1;
|
|
1952
|
+
}
|
|
1953
|
+
function parseDefinition(src) {
|
|
1954
|
+
const label = parseLinkLabel(src, 0);
|
|
1955
|
+
if (!label || label.value.trim() === "" || src[label.end] !== ":") return null;
|
|
1956
|
+
const destination = parseLinkDestination(src, skipSpacesAndOneNewline(src, label.end + 1));
|
|
1957
|
+
if (!destination) return null;
|
|
1958
|
+
const titleAt = skipSpacesAndOneNewline(src, destination.end);
|
|
1959
|
+
const title = titleAt > destination.end ? parseLinkTitle(src, titleAt) : null;
|
|
1960
|
+
const titleEnd = title ? endOfLine(src, title.end) : -1;
|
|
1961
|
+
if (title && titleEnd >= 0) {
|
|
1962
|
+
const target = title.value ? { href: destination.value, title: title.value } : { href: destination.value };
|
|
1963
|
+
return { label: label.value, target, end: titleEnd };
|
|
1964
|
+
}
|
|
1965
|
+
const end = endOfLine(src, destination.end);
|
|
1966
|
+
return end < 0 ? null : { label: label.value, target: { href: destination.value }, end };
|
|
1967
|
+
}
|
|
1968
|
+
function takeReferenceDefinitions(lines, refs) {
|
|
1969
|
+
if (!_optionalChain([lines, 'access', _49 => _49[0], 'optionalAccess', _50 => _50.startsWith, 'call', _51 => _51("[")])) return lines;
|
|
1970
|
+
let text2 = lines.join("\n");
|
|
1971
|
+
while (text2.startsWith("[")) {
|
|
1972
|
+
const definition = parseDefinition(text2);
|
|
1973
|
+
if (!definition) break;
|
|
1974
|
+
const key = normalizeLabel(definition.label);
|
|
1975
|
+
if (!refs.has(key)) refs.set(key, definition.target);
|
|
1976
|
+
text2 = text2.slice(definition.end);
|
|
1977
|
+
}
|
|
1978
|
+
return text2 === "" ? [] : text2.split("\n");
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
// src/engine/markdown/block/summary-text.ts
|
|
1982
|
+
var OPENING_TAG = /^\s*<summary(?:\s[^>]*)?>/i;
|
|
1983
|
+
var FINAL_CLOSING_TAG = /<\/summary>[ \t]*$/i;
|
|
1984
|
+
var FIRST_CLOSING_TAG = /<\/summary>[\s\S]*$/i;
|
|
1985
|
+
function summaryText(lines) {
|
|
1986
|
+
const text2 = lines.join("\n").replace(OPENING_TAG, "");
|
|
1987
|
+
return trimBlank(text2.replace(FINAL_CLOSING_TAG.test(text2) ? FINAL_CLOSING_TAG : FIRST_CLOSING_TAG, ""));
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
// src/engine/markdown/block/parser-state.ts
|
|
1991
|
+
var MAX_NESTING = 64;
|
|
1992
|
+
function createParser() {
|
|
1993
|
+
const document = { kind: "document", children: [] };
|
|
1994
|
+
return { document, stack: [document], refs: /* @__PURE__ */ new Map(), cursor: new Cursor(), matched: 1 };
|
|
1995
|
+
}
|
|
1996
|
+
var tipOf = (parser) => parser.stack[parser.stack.length - 1];
|
|
1997
|
+
var canNest = (parser) => parser.stack.length < MAX_NESTING;
|
|
1998
|
+
var childrenOf = (node) => node.children;
|
|
1999
|
+
function closeTip(parser) {
|
|
2000
|
+
const node = parser.stack.pop();
|
|
2001
|
+
if (_optionalChain([node, 'optionalAccess', _52 => _52.kind]) === "paragraph") {
|
|
2002
|
+
node.lines = takeReferenceDefinitions(node.lines, parser.refs);
|
|
2003
|
+
if (node.lines.length === 0) childrenOf(tipOf(parser)).pop();
|
|
2004
|
+
} else if (_optionalChain([node, 'optionalAccess', _53 => _53.kind]) === "html" && node.summaryOf) {
|
|
2005
|
+
childrenOf(tipOf(parser)).pop();
|
|
2006
|
+
node.summaryOf.summary = summaryText(node.lines);
|
|
2007
|
+
} else if (_optionalChain([node, 'optionalAccess', _54 => _54.kind]) === "code" && node.fence === null) {
|
|
2008
|
+
while (node.lines.length > 0 && /^ *$/.test(node.lines[node.lines.length - 1])) node.lines.pop();
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
function closeUnmatched(parser) {
|
|
2012
|
+
while (parser.stack.length > parser.matched) closeTip(parser);
|
|
2013
|
+
}
|
|
2014
|
+
function addChild(parser, node) {
|
|
2015
|
+
closeUnmatched(parser);
|
|
2016
|
+
while (!canContain(tipOf(parser), node.kind)) closeTip(parser);
|
|
2017
|
+
childrenOf(tipOf(parser)).push(node);
|
|
2018
|
+
parser.stack.push(node);
|
|
2019
|
+
parser.matched = parser.stack.length;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
// src/engine/markdown/block/container-blocks.ts
|
|
2023
|
+
var BULLET2 = /^[*+-]/;
|
|
2024
|
+
var ORDERED2 = /^(\d{1,9})([.)])/;
|
|
2025
|
+
var MAX_MARKER_SPACES = 5;
|
|
2026
|
+
function consumeQuoteMarker(cursor) {
|
|
2027
|
+
cursor.advanceToNonspace();
|
|
2028
|
+
cursor.advance(1);
|
|
2029
|
+
if (isSpaceOrTab(cursor.next)) cursor.advance(1, true);
|
|
2030
|
+
}
|
|
2031
|
+
var quoteStart = (parser) => {
|
|
2032
|
+
const { cursor } = parser;
|
|
2033
|
+
if (cursor.indented || !cursor.text.startsWith(">") || !canNest(parser)) return "none";
|
|
2034
|
+
consumeQuoteMarker(cursor);
|
|
2035
|
+
addChild(parser, { kind: "quote", children: [] });
|
|
2036
|
+
return "container";
|
|
2037
|
+
};
|
|
2038
|
+
function continueQuote(parser) {
|
|
2039
|
+
const { cursor } = parser;
|
|
2040
|
+
if (cursor.indented || !cursor.text.startsWith(">")) return "unmatched";
|
|
2041
|
+
consumeQuoteMarker(cursor);
|
|
2042
|
+
return "matched";
|
|
2043
|
+
}
|
|
2044
|
+
function continueItem(parser, item) {
|
|
2045
|
+
const { cursor } = parser;
|
|
2046
|
+
if (cursor.blank) {
|
|
2047
|
+
if (item.children.length === 0) return "unmatched";
|
|
2048
|
+
cursor.advanceToNonspace();
|
|
2049
|
+
} else if (cursor.indent >= item.contentOffset) {
|
|
2050
|
+
cursor.advance(item.contentOffset, true);
|
|
2051
|
+
} else {
|
|
2052
|
+
return "unmatched";
|
|
2053
|
+
}
|
|
2054
|
+
return "matched";
|
|
2055
|
+
}
|
|
2056
|
+
var sameList = (a, b) => a.ordered === b.ordered && a.char === b.char;
|
|
2057
|
+
function readMarker(text2, interrupting) {
|
|
2058
|
+
const bullet = BULLET2.exec(text2);
|
|
2059
|
+
if (bullet) return { marker: { ordered: false, char: bullet[0], number: 0 }, width: 1 };
|
|
2060
|
+
const ordered = ORDERED2.exec(text2);
|
|
2061
|
+
if (!ordered || interrupting && Number(ordered[1]) !== 1) return null;
|
|
2062
|
+
return { marker: { ordered: true, char: ordered[2], number: Number(ordered[1]) }, width: ordered[0].length };
|
|
2063
|
+
}
|
|
2064
|
+
function consumeMarkerSpacing(cursor, width) {
|
|
2065
|
+
const afterMarker = cursor.mark();
|
|
2066
|
+
const startColumn = cursor.column;
|
|
2067
|
+
do
|
|
2068
|
+
cursor.advance(1, true);
|
|
2069
|
+
while (cursor.column - startColumn < MAX_MARKER_SPACES && isSpaceOrTab(cursor.next));
|
|
2070
|
+
const spaces = cursor.column - startColumn;
|
|
2071
|
+
if (spaces >= MAX_MARKER_SPACES || spaces < 1 || cursor.offset >= cursor.line.length) {
|
|
2072
|
+
cursor.restore(afterMarker);
|
|
2073
|
+
if (isSpaceOrTab(cursor.next)) cursor.advance(1, true);
|
|
2074
|
+
return width + 1;
|
|
2075
|
+
}
|
|
2076
|
+
return width + spaces;
|
|
2077
|
+
}
|
|
2078
|
+
var itemStart = (parser, container) => {
|
|
2079
|
+
const { cursor } = parser;
|
|
2080
|
+
if (cursor.indented || !canNest(parser)) return "none";
|
|
2081
|
+
const interrupting = container.kind === "paragraph";
|
|
2082
|
+
const text2 = cursor.text;
|
|
2083
|
+
const read = readMarker(text2, interrupting);
|
|
2084
|
+
if (!read) return "none";
|
|
2085
|
+
const next = text2[read.width];
|
|
2086
|
+
if (next !== void 0 && !isSpaceOrTab(next)) return "none";
|
|
2087
|
+
if (interrupting && trimBlank(text2.slice(read.width)) === "") return "none";
|
|
2088
|
+
const markerOffset = cursor.indent;
|
|
2089
|
+
cursor.advanceToNonspace();
|
|
2090
|
+
cursor.advance(read.width, true);
|
|
2091
|
+
const contentOffset = markerOffset + consumeMarkerSpacing(cursor, read.width);
|
|
2092
|
+
closeUnmatched(parser);
|
|
2093
|
+
const list = tipOf(parser);
|
|
2094
|
+
if (list.kind !== "list" || !sameList(list.marker, read.marker)) {
|
|
2095
|
+
addChild(parser, { kind: "list", marker: read.marker, children: [] });
|
|
2096
|
+
}
|
|
2097
|
+
addChild(parser, { kind: "item", marker: read.marker, contentOffset, children: [] });
|
|
2098
|
+
return "container";
|
|
2099
|
+
};
|
|
2100
|
+
|
|
2101
|
+
// src/engine/markdown/block/details-blocks.ts
|
|
2102
|
+
var DETAILS_OPEN = /^<details(\s[^>]*)?>/i;
|
|
2103
|
+
var DETAILS_CLOSE = /^<\/details>[ \t]*$/i;
|
|
2104
|
+
var SUMMARY_OPEN = /^<summary(?:\s[^>]*)?>/i;
|
|
2105
|
+
var SUMMARY_CLOSE = /<\/summary>(?:[ \t]*$|(?![\s\S]*\\$))/i;
|
|
2106
|
+
var OPEN_ATTRIBUTE = /(?:^|\s)open(?=[\s=/]|$)/i;
|
|
2107
|
+
function findOpenDetails(parser, limit) {
|
|
2108
|
+
const { cursor, stack } = parser;
|
|
2109
|
+
if (cursor.indented || !DETAILS_CLOSE.test(cursor.text)) return -1;
|
|
2110
|
+
for (let at = limit - 1; at > 0; at--) if (stack[at].kind === "details") return at;
|
|
2111
|
+
return -1;
|
|
2112
|
+
}
|
|
2113
|
+
var detailsStart = (parser) => {
|
|
2114
|
+
const { cursor } = parser;
|
|
2115
|
+
const match = cursor.indented || !canNest(parser) ? null : DETAILS_OPEN.exec(cursor.text);
|
|
2116
|
+
if (!match) return "none";
|
|
2117
|
+
cursor.advanceToNonspace();
|
|
2118
|
+
cursor.advance(match[0].length);
|
|
2119
|
+
addChild(parser, { kind: "details", open: OPEN_ATTRIBUTE.test(_nullishCoalesce(match[1], () => ( ""))), summary: null, children: [] });
|
|
2120
|
+
return "container";
|
|
2121
|
+
};
|
|
2122
|
+
var summaryStart = (parser, container) => {
|
|
2123
|
+
const { cursor } = parser;
|
|
2124
|
+
const fresh = container.kind === "details" && container.summary === null && container.children.length === 0;
|
|
2125
|
+
if (!fresh || cursor.indented || !SUMMARY_OPEN.test(cursor.text)) return "none";
|
|
2126
|
+
addChild(parser, { kind: "html", ends: SUMMARY_CLOSE, lines: [], summaryOf: container });
|
|
2127
|
+
return "leaf";
|
|
2128
|
+
};
|
|
2129
|
+
var detailsEnd = (parser) => {
|
|
2130
|
+
const at = findOpenDetails(parser, parser.matched);
|
|
2131
|
+
if (at < 0) return "none";
|
|
2132
|
+
while (parser.stack.length > at) closeTip(parser);
|
|
2133
|
+
parser.matched = parser.stack.length;
|
|
2134
|
+
return "done";
|
|
2135
|
+
};
|
|
2136
|
+
|
|
2137
|
+
// src/engine/markdown/block/quoin-comment.ts
|
|
2138
|
+
var TYPE = "[A-Za-z][\\w.:-]*";
|
|
2139
|
+
var COMMENT = new RegExp(`^<!--\\s*quoin:(${TYPE})(?:\\s+(\\{.*\\}))?\\s*-->[ \\t]*$`);
|
|
2140
|
+
var TYPE_NAME = new RegExp(`^${TYPE}$`);
|
|
2141
|
+
var isQuoinType = (type) => TYPE_NAME.test(type);
|
|
2142
|
+
function parseQuoinComment(line) {
|
|
2143
|
+
const match = COMMENT.exec(line);
|
|
2144
|
+
if (!match) return null;
|
|
2145
|
+
const type = match[1] === "toc" ? "TOC" : match[1];
|
|
2146
|
+
if (match[2] === void 0) return { type, data: {}, indent: 0 };
|
|
2147
|
+
let payload;
|
|
2148
|
+
try {
|
|
2149
|
+
payload = JSON.parse(match[2]);
|
|
2150
|
+
} catch (e) {
|
|
2151
|
+
return null;
|
|
2152
|
+
}
|
|
2153
|
+
const { data = {}, indent = 0 } = payload;
|
|
2154
|
+
if (!isRecord(data) || typeof indent !== "number" || !Number.isInteger(indent) || indent < 0) return null;
|
|
2155
|
+
return { type, data, indent };
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
// src/engine/markdown/block/html-blocks.ts
|
|
2159
|
+
var BLOCK_TAGS = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
|
|
2160
|
+
var TAG_NAME = "[A-Za-z][A-Za-z0-9-]*";
|
|
2161
|
+
var ATTRIBUTE2 = `\\s+[A-Za-z_:][A-Za-z0-9_.:-]*(?:\\s*=\\s*(?:[^"'=<>\`\\x00-\\x20]+|'[^']*'|"[^"]*"))?`;
|
|
2162
|
+
var COMPLETE_TAG = new RegExp(`^(?:<${TAG_NAME}(?:${ATTRIBUTE2})*\\s*/?>|</${TAG_NAME}\\s*>)\\s*$`);
|
|
2163
|
+
var HTML_KINDS = [
|
|
2164
|
+
{ start: /^<(?:script|pre|textarea|style)(?:\s|>|$)/i, end: /<\/(?:script|pre|textarea|style)>/i, interrupts: true },
|
|
2165
|
+
{ start: /^<!--/, end: /-->/, interrupts: true },
|
|
2166
|
+
{ start: /^<\?/, end: /\?>/, interrupts: true },
|
|
2167
|
+
{ start: /^<![A-Za-z]/, end: />/, interrupts: true },
|
|
2168
|
+
{ start: /^<!\[CDATA\[/, end: /\]\]>/, interrupts: true },
|
|
2169
|
+
{ start: new RegExp(`^</?(?:${BLOCK_TAGS})(?:\\s|/?>|$)`, "i"), end: null, interrupts: true },
|
|
2170
|
+
{ start: COMPLETE_TAG, end: null, interrupts: false }
|
|
2171
|
+
];
|
|
2172
|
+
var startsHtmlBlock = (line) => HTML_KINDS.some(({ start }) => start.test(line));
|
|
2173
|
+
var htmlBlockStart = (parser, container) => {
|
|
2174
|
+
const { cursor } = parser;
|
|
2175
|
+
if (cursor.indented || !cursor.text.startsWith("<")) return "none";
|
|
2176
|
+
const text2 = cursor.text;
|
|
2177
|
+
const lazy = parser.matched < parser.stack.length && !cursor.blank && tipOf(parser).kind === "paragraph";
|
|
2178
|
+
const canStandAlone = container.kind !== "paragraph" && !lazy;
|
|
2179
|
+
const kind = HTML_KINDS.find(({ start, interrupts }) => start.test(text2) && (interrupts || canStandAlone));
|
|
2180
|
+
if (!kind) return "none";
|
|
2181
|
+
addChild(parser, { kind: "html", ends: kind.end, lines: [] });
|
|
2182
|
+
return "leaf";
|
|
2183
|
+
};
|
|
2184
|
+
var quoinCommentStart = (parser) => {
|
|
2185
|
+
const { cursor } = parser;
|
|
2186
|
+
const comment = cursor.indented ? null : parseQuoinComment(cursor.text);
|
|
2187
|
+
if (!comment) return "none";
|
|
2188
|
+
addChild(parser, { kind: "quoin", ...comment });
|
|
2189
|
+
return "done";
|
|
2190
|
+
};
|
|
2191
|
+
function continueHtml(parser, node, index) {
|
|
2192
|
+
if (node.ends !== null && !node.summaryOf) return "matched";
|
|
2193
|
+
if (parser.cursor.blank) return "unmatched";
|
|
2194
|
+
return node.ends === null && findOpenDetails(parser, index) >= 0 ? "unmatched" : "matched";
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
// src/engine/markdown/block/leaf-blocks.ts
|
|
2198
|
+
var ATX_HEADING = /^#{1,6}(?:[ \t]+|$)/;
|
|
2199
|
+
var MATH_FENCE = /^\$\$[ \t]*$/;
|
|
2200
|
+
var CLOSING_FENCE = /^(`{3,}|~{3,}|\${2,})[ \t]*$/;
|
|
2201
|
+
var THEMATIC_BREAK = /^(?:(?:\*[ \t]*){3,}|(?:_[ \t]*){3,}|(?:-[ \t]*){3,})$/;
|
|
2202
|
+
var SETEXT_UNDERLINE = /^(?:=+|-+)[ \t]*$/;
|
|
2203
|
+
function headingText(raw) {
|
|
2204
|
+
const end = trimBlankEnd(raw).length;
|
|
2205
|
+
let start = end;
|
|
2206
|
+
while (start > 0 && raw[start - 1] === "#") start--;
|
|
2207
|
+
const closing = start < end && (start === 0 || isSpaceOrTab(raw[start - 1]));
|
|
2208
|
+
return trimBlank(raw.slice(0, closing ? start : end));
|
|
2209
|
+
}
|
|
2210
|
+
function openingFence(text2) {
|
|
2211
|
+
const char = text2[0];
|
|
2212
|
+
if (char !== "`" && char !== "~") return null;
|
|
2213
|
+
let length = 0;
|
|
2214
|
+
while (text2[length] === char) length++;
|
|
2215
|
+
const hasBacktickInfo = char === "`" && text2.includes("`", length);
|
|
2216
|
+
return length < 3 || hasBacktickInfo ? null : { char, length };
|
|
2217
|
+
}
|
|
2218
|
+
var isVerbatim = (node) => node.kind === "code" || node.kind === "math" || node.kind === "html";
|
|
2219
|
+
var atxHeadingStart = (parser) => {
|
|
2220
|
+
const { cursor } = parser;
|
|
2221
|
+
const match = cursor.indented ? null : ATX_HEADING.exec(cursor.text);
|
|
2222
|
+
if (!match) return "none";
|
|
2223
|
+
const text2 = headingText(cursor.text.slice(match[0].length));
|
|
2224
|
+
addChild(parser, { kind: "heading", level: match[0].trim().length, text: text2 });
|
|
2225
|
+
return "done";
|
|
2226
|
+
};
|
|
2227
|
+
var codeFenceStart = (parser) => {
|
|
2228
|
+
const { cursor } = parser;
|
|
2229
|
+
const text2 = cursor.text;
|
|
2230
|
+
const opening = cursor.indented ? null : openingFence(text2);
|
|
2231
|
+
if (!opening) return "none";
|
|
2232
|
+
const fence = { ...opening, offset: cursor.indent };
|
|
2233
|
+
addChild(parser, { kind: "code", fence, info: unescapeMarkdown(trimBlank(text2.slice(opening.length))), lines: [] });
|
|
2234
|
+
return "done";
|
|
2235
|
+
};
|
|
2236
|
+
var mathFenceStart = (parser) => {
|
|
2237
|
+
const { cursor } = parser;
|
|
2238
|
+
if (cursor.indented || !MATH_FENCE.test(cursor.text)) return "none";
|
|
2239
|
+
addChild(parser, { kind: "math", fence: { char: "$", length: 2, offset: cursor.indent }, lines: [] });
|
|
2240
|
+
return "done";
|
|
2241
|
+
};
|
|
2242
|
+
var thematicBreakStart = (parser) => {
|
|
2243
|
+
const { cursor } = parser;
|
|
2244
|
+
if (cursor.indented || !THEMATIC_BREAK.test(cursor.text)) return "none";
|
|
2245
|
+
addChild(parser, { kind: "break" });
|
|
2246
|
+
return "done";
|
|
2247
|
+
};
|
|
2248
|
+
var setextHeadingStart = (parser, container) => {
|
|
2249
|
+
const { cursor } = parser;
|
|
2250
|
+
if (container.kind !== "paragraph" || cursor.indented || !SETEXT_UNDERLINE.test(cursor.text)) return "none";
|
|
2251
|
+
const lines = takeReferenceDefinitions(container.lines, parser.refs);
|
|
2252
|
+
container.lines = lines;
|
|
2253
|
+
if (lines.length === 0) return "none";
|
|
2254
|
+
container.lines = [];
|
|
2255
|
+
addChild(parser, { kind: "heading", level: cursor.text.startsWith("=") ? 1 : 2, text: trimBlank(lines.join("\n")) });
|
|
2256
|
+
return "done";
|
|
2257
|
+
};
|
|
2258
|
+
var indentedCodeStart = (parser, container) => {
|
|
2259
|
+
const { cursor } = parser;
|
|
2260
|
+
const tip = tipOf(parser);
|
|
2261
|
+
if (!cursor.indented || cursor.blank || tip.kind === "paragraph" || container.kind === "table") return "none";
|
|
2262
|
+
cursor.advance(CODE_INDENT, true);
|
|
2263
|
+
addChild(parser, { kind: "code", fence: null, info: "", lines: [] });
|
|
2264
|
+
return "leaf";
|
|
2265
|
+
};
|
|
2266
|
+
function closesFence(fence, text2) {
|
|
2267
|
+
const match = CLOSING_FENCE.exec(text2);
|
|
2268
|
+
return match !== null && match[1][0] === fence.char && match[1].length >= fence.length;
|
|
2269
|
+
}
|
|
2270
|
+
function continueCode(parser, fence) {
|
|
2271
|
+
const { cursor } = parser;
|
|
2272
|
+
if (fence === null) {
|
|
2273
|
+
if (cursor.indented) cursor.advance(CODE_INDENT, true);
|
|
2274
|
+
else if (cursor.blank) cursor.advanceToNonspace();
|
|
2275
|
+
else return "unmatched";
|
|
2276
|
+
return "matched";
|
|
2277
|
+
}
|
|
2278
|
+
if (!cursor.indented && closesFence(fence, cursor.text)) {
|
|
2279
|
+
parser.stack.pop();
|
|
2280
|
+
return "consumed";
|
|
2281
|
+
}
|
|
2282
|
+
cursor.advance(Math.min(fence.offset, cursor.indent), true);
|
|
2283
|
+
return "matched";
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
// src/engine/markdown/block/tables.ts
|
|
2287
|
+
var DELIMITER_CELL = /^:?-+:?$/;
|
|
2288
|
+
function endsInHardBreak(line) {
|
|
2289
|
+
let backslashes = 0;
|
|
2290
|
+
while (line[line.length - 1 - backslashes] === "\\") backslashes++;
|
|
2291
|
+
return backslashes % 2 === 1;
|
|
2292
|
+
}
|
|
2293
|
+
function splitRow(line) {
|
|
2294
|
+
const text2 = trimBlank(line);
|
|
2295
|
+
const cells = [];
|
|
2296
|
+
let cell = "";
|
|
2297
|
+
for (let at = 0; at < text2.length; at++) {
|
|
2298
|
+
if (text2[at] === "\\" && at + 1 < text2.length) {
|
|
2299
|
+
cell += text2[at] + text2[at + 1];
|
|
2300
|
+
at++;
|
|
2301
|
+
} else if (text2[at] === "|") {
|
|
2302
|
+
cells.push(cell);
|
|
2303
|
+
cell = "";
|
|
2304
|
+
} else {
|
|
2305
|
+
cell += text2[at];
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
cells.push(cell);
|
|
2309
|
+
if (text2.startsWith("|")) cells.shift();
|
|
2310
|
+
if (cell === "" && text2.endsWith("|")) cells.pop();
|
|
2311
|
+
return cells.map(trimBlank);
|
|
2312
|
+
}
|
|
2313
|
+
function alignOf(cell) {
|
|
2314
|
+
const left = cell.startsWith(":");
|
|
2315
|
+
const right = cell.endsWith(":");
|
|
2316
|
+
if (left && right) return "center";
|
|
2317
|
+
if (left) return "left";
|
|
2318
|
+
return right ? "right" : null;
|
|
2319
|
+
}
|
|
2320
|
+
function parseDelimiterRow(line) {
|
|
2321
|
+
if (!line.includes("|")) return null;
|
|
2322
|
+
const cells = splitRow(line);
|
|
2323
|
+
return cells.length > 0 && cells.every((cell) => DELIMITER_CELL.test(cell)) ? cells.map(alignOf) : null;
|
|
2324
|
+
}
|
|
2325
|
+
var tableStart = (parser, container) => {
|
|
2326
|
+
const { cursor } = parser;
|
|
2327
|
+
if (container.kind !== "paragraph" || cursor.indented || container.lines.length === 0) return "none";
|
|
2328
|
+
const headerLine = container.lines[container.lines.length - 1];
|
|
2329
|
+
const align = parseDelimiterRow(cursor.text);
|
|
2330
|
+
if (!align || endsInHardBreak(headerLine)) return "none";
|
|
2331
|
+
const header = splitRow(headerLine);
|
|
2332
|
+
if (header.length !== align.length) return "none";
|
|
2333
|
+
container.lines.pop();
|
|
2334
|
+
addChild(parser, { kind: "table", align, header, rows: [] });
|
|
2335
|
+
return "done";
|
|
2336
|
+
};
|
|
2337
|
+
function addTableRow(table, line) {
|
|
2338
|
+
const cells = splitRow(line);
|
|
2339
|
+
table.rows.push(table.header.map((_, column) => _nullishCoalesce(cells[column], () => ( ""))));
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
// src/engine/markdown/block/parse-blocks.ts
|
|
2343
|
+
var STARTS = [
|
|
2344
|
+
quoteStart,
|
|
2345
|
+
atxHeadingStart,
|
|
2346
|
+
codeFenceStart,
|
|
2347
|
+
mathFenceStart,
|
|
2348
|
+
quoinCommentStart,
|
|
2349
|
+
summaryStart,
|
|
2350
|
+
detailsEnd,
|
|
2351
|
+
detailsStart,
|
|
2352
|
+
htmlBlockStart,
|
|
2353
|
+
tableStart,
|
|
2354
|
+
setextHeadingStart,
|
|
2355
|
+
thematicBreakStart,
|
|
2356
|
+
itemStart,
|
|
2357
|
+
indentedCodeStart
|
|
2358
|
+
];
|
|
2359
|
+
function continueBlock(parser, node, index) {
|
|
2360
|
+
switch (node.kind) {
|
|
2361
|
+
case "quote":
|
|
2362
|
+
return continueQuote(parser);
|
|
2363
|
+
case "item":
|
|
2364
|
+
return continueItem(parser, node);
|
|
2365
|
+
case "list":
|
|
2366
|
+
case "details":
|
|
2367
|
+
return "matched";
|
|
2368
|
+
case "code":
|
|
2369
|
+
case "math":
|
|
2370
|
+
return continueCode(parser, node.fence);
|
|
2371
|
+
case "html":
|
|
2372
|
+
return continueHtml(parser, node, index);
|
|
2373
|
+
case "paragraph":
|
|
2374
|
+
case "table":
|
|
2375
|
+
return parser.cursor.blank ? "unmatched" : "matched";
|
|
2376
|
+
default:
|
|
2377
|
+
return "unmatched";
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
function matchOpenBlocks(parser) {
|
|
2381
|
+
let matched = 1;
|
|
2382
|
+
while (matched < parser.stack.length) {
|
|
2383
|
+
const outcome = continueBlock(parser, parser.stack[matched], matched);
|
|
2384
|
+
if (outcome === "consumed") return false;
|
|
2385
|
+
if (outcome === "unmatched") break;
|
|
2386
|
+
matched++;
|
|
2387
|
+
}
|
|
2388
|
+
parser.matched = matched;
|
|
2389
|
+
return true;
|
|
2390
|
+
}
|
|
2391
|
+
function openNewBlocks(parser) {
|
|
2392
|
+
let container = parser.stack[parser.matched - 1];
|
|
2393
|
+
while (!isVerbatim(container)) {
|
|
2394
|
+
let result = "none";
|
|
2395
|
+
for (const start of STARTS) {
|
|
2396
|
+
result = start(parser, container);
|
|
2397
|
+
if (result !== "none") break;
|
|
2398
|
+
}
|
|
2399
|
+
if (result === "done") return false;
|
|
2400
|
+
if (result === "none") {
|
|
2401
|
+
parser.cursor.advanceToNonspace();
|
|
2402
|
+
break;
|
|
2403
|
+
}
|
|
2404
|
+
container = tipOf(parser);
|
|
2405
|
+
if (result === "leaf") break;
|
|
2406
|
+
}
|
|
2407
|
+
return true;
|
|
2408
|
+
}
|
|
2409
|
+
function addLine(parser, node) {
|
|
2410
|
+
const { cursor } = parser;
|
|
2411
|
+
if (node.kind === "paragraph") node.lines.push(trimBlankStart(cursor.rest()));
|
|
2412
|
+
else if (node.kind === "code" || node.kind === "math") node.lines.push(cursor.rest());
|
|
2413
|
+
else if (node.kind === "table") addTableRow(node, cursor.rest());
|
|
2414
|
+
else if (node.kind === "html") {
|
|
2415
|
+
const line = cursor.rest();
|
|
2416
|
+
node.lines.push(line);
|
|
2417
|
+
if (_optionalChain([node, 'access', _55 => _55.ends, 'optionalAccess', _56 => _56.test, 'call', _57 => _57(line)])) closeTip(parser);
|
|
2418
|
+
} else if (!cursor.blank) {
|
|
2419
|
+
addChild(parser, { kind: "paragraph", lines: [] });
|
|
2420
|
+
cursor.advanceToNonspace();
|
|
2421
|
+
addLine(parser, tipOf(parser));
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
function feedLine(parser, raw) {
|
|
2425
|
+
parser.cursor.reset(raw);
|
|
2426
|
+
if (!matchOpenBlocks(parser) || !openNewBlocks(parser)) return;
|
|
2427
|
+
const tip = tipOf(parser);
|
|
2428
|
+
if (parser.matched < parser.stack.length && !parser.cursor.blank && tip.kind === "paragraph") {
|
|
2429
|
+
addLine(parser, tip);
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
closeUnmatched(parser);
|
|
2433
|
+
addLine(parser, tipOf(parser));
|
|
2434
|
+
}
|
|
2435
|
+
function parseBlocks(markdown) {
|
|
2436
|
+
const parser = createParser();
|
|
2437
|
+
for (const line of splitLines(markdown)) feedLine(parser, line);
|
|
2438
|
+
while (parser.stack.length > 1) closeTip(parser);
|
|
2439
|
+
return { document: parser.document, refs: parser.refs };
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
// src/engine/markdown/block/alert.ts
|
|
2443
|
+
var ALERT_LINE = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\][ \t]*$/;
|
|
2444
|
+
var ALERT_TONES = {
|
|
2445
|
+
NOTE: "info",
|
|
2446
|
+
TIP: "tip",
|
|
2447
|
+
IMPORTANT: "success",
|
|
2448
|
+
WARNING: "warning",
|
|
2449
|
+
CAUTION: "danger"
|
|
2450
|
+
};
|
|
2451
|
+
function alertOf(quote) {
|
|
2452
|
+
const [first, ...children] = quote.children;
|
|
2453
|
+
const match = _optionalChain([first, 'optionalAccess', _58 => _58.kind]) === "paragraph" ? ALERT_LINE.exec(first.lines[0]) : null;
|
|
2454
|
+
if (_optionalChain([first, 'optionalAccess', _59 => _59.kind]) !== "paragraph" || !match) return null;
|
|
2455
|
+
const paragraphs = first.lines.length > 1 ? [joinLines(first.lines.slice(1))] : [];
|
|
2456
|
+
let used = 0;
|
|
2457
|
+
for (const node of children) {
|
|
2458
|
+
if (node.kind !== "paragraph") break;
|
|
2459
|
+
paragraphs.push(joinLines(node.lines));
|
|
2460
|
+
used++;
|
|
2461
|
+
}
|
|
2462
|
+
return { tone: ALERT_TONES[match[1]], paragraphs, rest: children.slice(used) };
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
// src/engine/markdown/block/drafts.ts
|
|
2466
|
+
function draft(type, data, indent) {
|
|
2467
|
+
return indent > 0 ? { type, data, indent } : { type, data };
|
|
2468
|
+
}
|
|
2469
|
+
function lineDraft(line, body, indent) {
|
|
2470
|
+
return draft("MARKDOWN", { markdown: lineMarkdown(line, body) }, indent);
|
|
2471
|
+
}
|
|
2472
|
+
var deeper = (ctx) => ({ ...ctx, indent: ctx.indent + 1 });
|
|
2473
|
+
|
|
2474
|
+
// src/engine/markdown/block/inline-text.ts
|
|
2475
|
+
var BRACKET_LABEL = /\[((?:[^\\[\]]|\\[\s\S]){0,999})\]/g;
|
|
2476
|
+
function refsUsedBy(source, refs) {
|
|
2477
|
+
const used = /* @__PURE__ */ new Map();
|
|
2478
|
+
if (refs.size === 0) return used;
|
|
2479
|
+
for (const [, label] of source.matchAll(BRACKET_LABEL)) {
|
|
2480
|
+
const target = refs.get(normalizeLabel(label));
|
|
2481
|
+
if (target) used.set(label, target);
|
|
2482
|
+
}
|
|
2483
|
+
return used;
|
|
2484
|
+
}
|
|
2485
|
+
function parseText(source, { softBreak, refs }) {
|
|
2486
|
+
return parseInline(source, { softBreak, refs: refsUsedBy(source, refs) });
|
|
2487
|
+
}
|
|
2488
|
+
function canonicalInline(source, options, hardBreak) {
|
|
2489
|
+
return serializeInline(parseText(source, options), { escapeLineStart: true, hardBreak });
|
|
2490
|
+
}
|
|
2491
|
+
var ESCAPED_PIPE = /\\\|/g;
|
|
2492
|
+
function canonicalCell(source, options) {
|
|
2493
|
+
return serializeInline(parseText(source.replace(ESCAPED_PIPE, "|"), options), { escapePipes: true, hardBreak: "br" });
|
|
2494
|
+
}
|
|
2495
|
+
function canonicalParagraphs(paragraphs, options) {
|
|
2496
|
+
const parts = paragraphs.map((source) => parseText(source, options));
|
|
2497
|
+
const joined = parts.flatMap((part, index) => index === 0 ? part : [text("\n"), ...part]);
|
|
2498
|
+
return serializeInline(normalizeInline(joined), { escapeLineStart: true });
|
|
2499
|
+
}
|
|
2500
|
+
function plainTextOf(source) {
|
|
2501
|
+
return inlineText(parseInline(source, { softBreak: "space" }), () => "");
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
// src/engine/markdown/block/image-paragraph.ts
|
|
2505
|
+
function labelEnd(source, open) {
|
|
2506
|
+
let depth = 0;
|
|
2507
|
+
for (let at = open; at < source.length; at++) {
|
|
2508
|
+
if (source[at] === "\\") at++;
|
|
2509
|
+
else if (source[at] === "[") depth++;
|
|
2510
|
+
else if (source[at] === "]" && --depth === 0) return at;
|
|
2511
|
+
}
|
|
2512
|
+
return -1;
|
|
2513
|
+
}
|
|
2514
|
+
function imageParagraph(source) {
|
|
2515
|
+
if (!source.startsWith("![")) return null;
|
|
2516
|
+
const end = labelEnd(source, 1);
|
|
2517
|
+
if (end < 0 || source[end + 1] !== "(") return null;
|
|
2518
|
+
const tail = parseInlineLinkTail(source, end + 2);
|
|
2519
|
+
if (!tail || tail.end !== source.length) return null;
|
|
2520
|
+
const url = sanitizeHref(tail.value.href);
|
|
2521
|
+
if (!url) return null;
|
|
2522
|
+
const alt = plainTextOf(source.slice(2, end));
|
|
2523
|
+
return tail.value.title ? { alt, url, title: tail.value.title } : { alt, url };
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
// src/engine/markdown/block/leaf-drafts.ts
|
|
2527
|
+
var textLine = (ctx) => ({ kind: ctx.quote ? "quote" : "paragraph" });
|
|
2528
|
+
function paragraphDraft(node, ctx) {
|
|
2529
|
+
const source = joinLines(node.lines);
|
|
2530
|
+
const image = imageParagraph(source);
|
|
2531
|
+
if (!image) return lineDraft(textLine(ctx), canonicalInline(source, ctx.text), ctx.indent);
|
|
2532
|
+
const caption = image.title ? { caption: image.title } : {};
|
|
2533
|
+
return draft("IMAGE", { storageKey: "", alt: image.alt, url: image.url, ...caption }, ctx.indent);
|
|
2534
|
+
}
|
|
2535
|
+
function headingDraft(node, ctx) {
|
|
2536
|
+
if (ctx.quote) return lineDraft({ kind: "quote" }, canonicalInline(node.text, ctx.text), ctx.indent);
|
|
2537
|
+
const body = canonicalInline(node.text, ctx.text, "br");
|
|
2538
|
+
return lineDraft({ kind: "heading", level: node.level }, body, ctx.indent);
|
|
2539
|
+
}
|
|
2540
|
+
function htmlDraft(node, ctx) {
|
|
2541
|
+
return lineDraft(textLine(ctx), canonicalInline(trimBlank(node.lines.join("\n")), ctx.text), ctx.indent);
|
|
2542
|
+
}
|
|
2543
|
+
function codeDraft(node, ctx) {
|
|
2544
|
+
return draft("CODE", { language: node.info.split(/[ \t]+/)[0], code: node.lines.join("\n") }, ctx.indent);
|
|
2545
|
+
}
|
|
2546
|
+
function mathDraft(node, ctx) {
|
|
2547
|
+
return draft("MATH", { latex: node.lines.join("\n") }, ctx.indent);
|
|
2548
|
+
}
|
|
2549
|
+
function tableDraft(node, ctx) {
|
|
2550
|
+
const rows = [node.header, ...node.rows].map((row) => row.map((cell) => canonicalCell(cell, ctx.text)));
|
|
2551
|
+
return draft("TABLE", { rows, header: true, align: node.align }, ctx.indent);
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
// src/engine/markdown/block/tree-to-blocks.ts
|
|
2555
|
+
function itemLine(item, lines, ctx) {
|
|
2556
|
+
if (ctx.quote) return { line: { kind: "quote" }, lines };
|
|
2557
|
+
if (item.marker.ordered) return { line: { kind: "ordered", start: item.marker.number }, lines };
|
|
2558
|
+
const task = lines.length > 0 ? parseLine(`- ${lines[0]}`) : null;
|
|
2559
|
+
if (_optionalChain([task, 'optionalAccess', _60 => _60.kind]) !== "task") return { line: { kind: "bullet" }, lines };
|
|
2560
|
+
return { line: { kind: "task", checked: task.checked }, lines: [trimBlankStart(task.rest), ...lines.slice(1)] };
|
|
2561
|
+
}
|
|
2562
|
+
function itemDrafts(item, ctx) {
|
|
2563
|
+
const [first, ...others] = item.children;
|
|
2564
|
+
const lead = textLinesOf(first);
|
|
2565
|
+
const { line, lines } = itemLine(item, _nullishCoalesce(lead, () => ( [])), ctx);
|
|
2566
|
+
const body = lead ? canonicalInline(joinLines(lines), ctx.text) : "";
|
|
2567
|
+
const head = lead || !ctx.quote ? [lineDraft(line, body, ctx.indent)] : [];
|
|
2568
|
+
return [...head, ...convertAll(lead ? others : item.children, deeper(ctx))];
|
|
2569
|
+
}
|
|
2570
|
+
function quoteDrafts(quote, ctx) {
|
|
2571
|
+
const alert = alertOf(quote);
|
|
2572
|
+
const quoted = { ...ctx, quote: true };
|
|
2573
|
+
if (!alert) return convertAll(quote.children, quoted);
|
|
2574
|
+
const body = canonicalParagraphs(alert.paragraphs, ctx.text);
|
|
2575
|
+
return [draft("CALLOUT", { tone: alert.tone, body }, ctx.indent), ...convertAll(alert.rest, quoted)];
|
|
2576
|
+
}
|
|
2577
|
+
function detailsDrafts(details, ctx) {
|
|
2578
|
+
const summary = details.summary === null ? "" : canonicalInline(details.summary, { ...ctx.text, softBreak: "space" });
|
|
2579
|
+
const toggle = draft("TOGGLE", { markdown: summary, open: details.open }, ctx.indent);
|
|
2580
|
+
return [toggle, ...convertAll(details.children, deeper(ctx))];
|
|
2581
|
+
}
|
|
2582
|
+
function convert(node, ctx) {
|
|
2583
|
+
switch (node.kind) {
|
|
2584
|
+
case "paragraph":
|
|
2585
|
+
return [paragraphDraft(node, ctx)];
|
|
2586
|
+
case "heading":
|
|
2587
|
+
return [headingDraft(node, ctx)];
|
|
2588
|
+
case "break":
|
|
2589
|
+
return [draft("DIVIDER", {}, ctx.indent)];
|
|
2590
|
+
case "code":
|
|
2591
|
+
return [codeDraft(node, ctx)];
|
|
2592
|
+
case "math":
|
|
2593
|
+
return [mathDraft(node, ctx)];
|
|
2594
|
+
case "html":
|
|
2595
|
+
return [htmlDraft(node, ctx)];
|
|
2596
|
+
case "table":
|
|
2597
|
+
return [tableDraft(node, ctx)];
|
|
2598
|
+
case "quoin":
|
|
2599
|
+
return [draft(node.type, node.data, ctx.indent + node.indent)];
|
|
2600
|
+
case "quote":
|
|
2601
|
+
return quoteDrafts(node, ctx);
|
|
2602
|
+
case "details":
|
|
2603
|
+
return detailsDrafts(node, ctx);
|
|
2604
|
+
case "item":
|
|
2605
|
+
return itemDrafts(node, ctx);
|
|
2606
|
+
case "list":
|
|
2607
|
+
case "document":
|
|
2608
|
+
return convertAll(node.children, ctx);
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
function convertAll(nodes, ctx) {
|
|
2612
|
+
return nodes.flatMap((node) => convert(node, ctx));
|
|
2613
|
+
}
|
|
2614
|
+
function treeToBlocks(document, text2) {
|
|
2615
|
+
return convert(document, { indent: 0, quote: false, text: text2 });
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
// src/engine/markdown/block/from-markdown.ts
|
|
2619
|
+
function fromMarkdown(markdown, options = {}) {
|
|
2620
|
+
const { document, refs } = parseBlocks(markdown);
|
|
2621
|
+
const drafts = treeToBlocks(document, { softBreak: _nullishCoalesce(options.softBreak, () => ( "space")), refs });
|
|
2622
|
+
const makeId = _nullishCoalesce(options.newId, () => ( newId));
|
|
2623
|
+
return drafts.map((block) => ({ id: makeId(), ...block }));
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
// src/engine/model/doc.ts
|
|
2627
|
+
function createDoc(blocks) {
|
|
2628
|
+
const index = /* @__PURE__ */ new Map();
|
|
2629
|
+
blocks.forEach((block, i) => {
|
|
2630
|
+
if (index.has(block.id)) throw new Error(`duplicate block id "${block.id}"`);
|
|
2631
|
+
index.set(block.id, i);
|
|
2632
|
+
});
|
|
2633
|
+
return { blocks, index };
|
|
2634
|
+
}
|
|
2635
|
+
function indexOfBlock(doc, id) {
|
|
2636
|
+
return _nullishCoalesce(doc.index.get(id), () => ( -1));
|
|
2637
|
+
}
|
|
2638
|
+
function requireBlockIndex(doc, id) {
|
|
2639
|
+
const index = indexOfBlock(doc, id);
|
|
2640
|
+
if (index < 0) throw new Error(`no block "${id}"`);
|
|
2641
|
+
return index;
|
|
2642
|
+
}
|
|
2643
|
+
function blockById(doc, id) {
|
|
2644
|
+
const index = doc.index.get(id);
|
|
2645
|
+
return index === void 0 ? void 0 : doc.blocks[index];
|
|
2646
|
+
}
|
|
2647
|
+
function updateBlock(doc, id, update) {
|
|
2648
|
+
const index = requireBlockIndex(doc, id);
|
|
2649
|
+
const next = update(doc.blocks[index]);
|
|
2650
|
+
const blocks = doc.blocks.map((block, i) => i === index ? next : block);
|
|
2651
|
+
return next.id === id ? { blocks, index: doc.index } : createDoc(blocks);
|
|
2652
|
+
}
|
|
2653
|
+
function replaceBlocks(doc, index, deleteCount, inserted) {
|
|
2654
|
+
if (index < 0 || deleteCount < 0 || index + deleteCount > doc.blocks.length) {
|
|
2655
|
+
throw new RangeError(`cannot remove ${deleteCount} blocks at ${index} from ${doc.blocks.length}`);
|
|
2656
|
+
}
|
|
2657
|
+
return createDoc([...doc.blocks.slice(0, index), ...inserted, ...doc.blocks.slice(index + deleteCount)]);
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
// src/engine/blocks/legacy-split.ts
|
|
2661
|
+
var PLAIN_LINE = /^\p{L}(?:[^\r\n]*[^\s\\])?$/u;
|
|
2662
|
+
var BLANK_PIECE = { id: "", type: "MARKDOWN", data: { markdown: "" } };
|
|
2663
|
+
function pieceIds(id, count, taken) {
|
|
2664
|
+
const ids = [id];
|
|
2665
|
+
for (let suffix = 2; ids.length < count; suffix++) {
|
|
2666
|
+
if (!taken.has(`${id}-${suffix}`)) ids.push(`${id}-${suffix}`);
|
|
2667
|
+
}
|
|
2668
|
+
return ids;
|
|
2669
|
+
}
|
|
2670
|
+
function readPieces(markdown) {
|
|
2671
|
+
const pieces = fromMarkdown(markdown, { softBreak: "newline", newId: () => "" });
|
|
2672
|
+
return pieces.length === 0 && markdown !== "" && markdown.trim() === "" ? [BLANK_PIECE] : pieces;
|
|
2673
|
+
}
|
|
2674
|
+
function splitLegacyBlock(block, baseIndent, taken = /* @__PURE__ */ new Set()) {
|
|
2675
|
+
const { markdown, ...extras } = block.data;
|
|
2676
|
+
if (block.type !== "MARKDOWN" || typeof markdown !== "string" || PLAIN_LINE.test(markdown)) return null;
|
|
2677
|
+
const pieces = readPieces(markdown);
|
|
2678
|
+
if (pieces.length === 0) return null;
|
|
2679
|
+
if (pieces.length === 1 && pieces[0].type === "MARKDOWN" && pieces[0].data.markdown === markdown) return null;
|
|
2680
|
+
const ids = pieceIds(block.id, pieces.length, taken);
|
|
2681
|
+
return pieces.map((piece, index) => {
|
|
2682
|
+
const data = index === 0 ? { ...extras, ...piece.data } : piece.data;
|
|
2683
|
+
const indent = baseIndent + (_nullishCoalesce(piece.indent, () => ( 0)));
|
|
2684
|
+
const id = ids[index];
|
|
2685
|
+
return indent > 0 ? { ...piece, id, data, indent } : { ...piece, id, data };
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
// src/engine/blocks/unique-ids.ts
|
|
2690
|
+
function freeId(preferred, taken) {
|
|
2691
|
+
if (!taken.has(preferred)) return preferred;
|
|
2692
|
+
let suffix = 2;
|
|
2693
|
+
while (taken.has(`${preferred}-${suffix}`)) suffix++;
|
|
2694
|
+
return `${preferred}-${suffix}`;
|
|
2695
|
+
}
|
|
2696
|
+
function withUniqueIds(blocks, newId2) {
|
|
2697
|
+
const taken = new Set(blocks.map((block) => block.id));
|
|
2698
|
+
const placed = /* @__PURE__ */ new Set();
|
|
2699
|
+
return blocks.map((block) => {
|
|
2700
|
+
if (!placed.has(block.id)) {
|
|
2701
|
+
placed.add(block.id);
|
|
2702
|
+
return block;
|
|
2703
|
+
}
|
|
2704
|
+
const id = freeId(newId2(), taken);
|
|
2705
|
+
taken.add(id);
|
|
2706
|
+
return { ...block, id };
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
// src/engine/blocks/unknown-spec.ts
|
|
2711
|
+
function unknownBlockSpec(type) {
|
|
2712
|
+
return {
|
|
2713
|
+
type,
|
|
2714
|
+
flow: "void",
|
|
2715
|
+
fromData: (data) => ({ attrs: { data }, regions: {} }),
|
|
2716
|
+
toData: ({ attrs }) => _nullishCoalesce(attrs.data, () => ( {})),
|
|
2717
|
+
initial: () => ({ attrs: { data: {} }, regions: {} })
|
|
2718
|
+
};
|
|
2719
|
+
}
|
|
2720
|
+
function specFor(schema, type) {
|
|
2721
|
+
return _nullishCoalesce(schema.blocks.get(type), () => ( unknownBlockSpec(type)));
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/engine/blocks/codec.ts
|
|
2725
|
+
var NO_IDS = /* @__PURE__ */ new Set();
|
|
2726
|
+
function createBlockCodec(schema, options = {}) {
|
|
2727
|
+
const context = { inline: inlineCodec, newId: _nullishCoalesce(options.newId, () => ( newId)) };
|
|
2728
|
+
const engineBlocks = /* @__PURE__ */ new WeakMap();
|
|
2729
|
+
const quoinBlocks = /* @__PURE__ */ new WeakMap();
|
|
2730
|
+
const splitGroups = /* @__PURE__ */ new WeakMap();
|
|
2731
|
+
function convert2(block) {
|
|
2732
|
+
const { attrs, regions } = specFor(schema, block.type).fromData(block.data, context);
|
|
2733
|
+
return { id: block.id, type: block.type, indent: countOf(block.indent), attrs, regions };
|
|
2734
|
+
}
|
|
2735
|
+
function engineBlocksAmong(block, taken) {
|
|
2736
|
+
const cached = engineBlocks.get(block);
|
|
2737
|
+
if (_optionalChain([cached, 'optionalAccess', _61 => _61.every, 'call', _62 => _62((piece, index) => index === 0 || !taken.has(piece.id))])) return [...cached];
|
|
2738
|
+
const pieces = splitLegacyBlock(block, countOf(block.indent), taken);
|
|
2739
|
+
if (pieces) {
|
|
2740
|
+
const blocks = pieces.map(convert2);
|
|
2741
|
+
engineBlocks.set(block, blocks);
|
|
2742
|
+
for (const piece of blocks) splitGroups.set(piece, { original: block, blocks });
|
|
2743
|
+
return [...blocks];
|
|
2744
|
+
}
|
|
2745
|
+
const engine = convert2(block);
|
|
2746
|
+
engineBlocks.set(block, [engine]);
|
|
2747
|
+
quoinBlocks.set(engine, block);
|
|
2748
|
+
return [engine];
|
|
2749
|
+
}
|
|
2750
|
+
function toQuoin(block) {
|
|
2751
|
+
const cached = quoinBlocks.get(block);
|
|
2752
|
+
if (cached) return cached;
|
|
2753
|
+
const data = specFor(schema, block.type).toData(block, context);
|
|
2754
|
+
const quoin = { id: block.id, type: block.type, data };
|
|
2755
|
+
if (block.indent > 0) quoin.indent = block.indent;
|
|
2756
|
+
quoinBlocks.set(block, quoin);
|
|
2757
|
+
engineBlocks.set(quoin, [block]);
|
|
2758
|
+
return quoin;
|
|
2759
|
+
}
|
|
2760
|
+
const toEngineBlocks = (block) => engineBlocksAmong(block, NO_IDS);
|
|
2761
|
+
function docFromBlocks(blocks) {
|
|
2762
|
+
const taken = new Set(blocks.map((block) => block.id));
|
|
2763
|
+
return createDoc(withUniqueIds(blocks.flatMap((block) => engineBlocksAmong(block, taken)), context.newId));
|
|
2764
|
+
}
|
|
2765
|
+
function blocksFromDoc(doc) {
|
|
2766
|
+
const result = [];
|
|
2767
|
+
for (let at = 0; at < doc.blocks.length; ) {
|
|
2768
|
+
const group = splitGroups.get(doc.blocks[at]);
|
|
2769
|
+
const intact = _optionalChain([group, 'optionalAccess', _63 => _63.blocks, 'access', _64 => _64.every, 'call', _65 => _65((piece, offset) => doc.blocks[at + offset] === piece)]);
|
|
2770
|
+
if (group && intact) {
|
|
2771
|
+
result.push(group.original);
|
|
2772
|
+
at += group.blocks.length;
|
|
2773
|
+
} else {
|
|
2774
|
+
result.push(toQuoin(doc.blocks[at]));
|
|
2775
|
+
at++;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
return result;
|
|
2779
|
+
}
|
|
2780
|
+
return { toEngineBlocks, toQuoin, docFromBlocks, blocksFromDoc, context };
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
// src/engine/render/block-groups.ts
|
|
2784
|
+
var MAX_NESTING2 = 32;
|
|
2785
|
+
function listKind(block) {
|
|
2786
|
+
const { kind } = block.attrs;
|
|
2787
|
+
if (block.type !== "MARKDOWN") return void 0;
|
|
2788
|
+
return kind === "bullet" || kind === "ordered" || kind === "task" ? kind : void 0;
|
|
2789
|
+
}
|
|
2790
|
+
var isQuote = (block) => block.type === "MARKDOWN" && block.attrs.kind === "quote";
|
|
2791
|
+
function append2(groups, entry) {
|
|
2792
|
+
const last = groups[groups.length - 1];
|
|
2793
|
+
const list = listKind(entry.block);
|
|
2794
|
+
if (list) {
|
|
2795
|
+
if (_optionalChain([last, 'optionalAccess', _66 => _66.kind]) === "list" && last.list === list) last.items.push(entry);
|
|
2796
|
+
else groups.push({ kind: "list", list, items: [entry] });
|
|
2797
|
+
} else if (isQuote(entry.block)) {
|
|
2798
|
+
if (_optionalChain([last, 'optionalAccess', _67 => _67.kind]) === "quote" && last.items[0].block.indent === entry.block.indent) last.items.push(entry);
|
|
2799
|
+
else groups.push({ kind: "quote", items: [entry] });
|
|
2800
|
+
} else {
|
|
2801
|
+
groups.push({ kind: "single", entry });
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
function groupBlocks(blocks) {
|
|
2805
|
+
const root = [];
|
|
2806
|
+
const frames = [];
|
|
2807
|
+
for (const block of blocks) {
|
|
2808
|
+
while (frames.length > 0 && frames[frames.length - 1].owner.block.indent >= block.indent) frames.pop();
|
|
2809
|
+
const frame = frames[frames.length - 1];
|
|
2810
|
+
const entry = { block, excess: block.indent - (_nullishCoalesce(_optionalChain([frame, 'optionalAccess', _68 => _68.depth]), () => ( 0))), children: [] };
|
|
2811
|
+
append2(_nullishCoalesce(_optionalChain([frame, 'optionalAccess', _69 => _69.owner, 'access', _70 => _70.children]), () => ( root)), entry);
|
|
2812
|
+
if ((listKind(block) || block.type === "TOGGLE") && frames.length < MAX_NESTING2) {
|
|
2813
|
+
frames.push({ owner: entry, depth: block.indent + 1 });
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
return root;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
// src/engine/render/block-attrs.ts
|
|
2820
|
+
var indentAttr = (excess) => ["data-indent", excess > 0 ? String(excess) : void 0];
|
|
2821
|
+
function alignAttr(align) {
|
|
2822
|
+
const value = alignOrUndefined(align);
|
|
2823
|
+
return ["style", value === void 0 ? void 0 : `text-align:${value}`];
|
|
2824
|
+
}
|
|
2825
|
+
var colorAttrs = (attrs) => [
|
|
2826
|
+
["data-color", paletteOrUndefined(attrs.color)],
|
|
2827
|
+
["data-bg", paletteOrUndefined(attrs.background)]
|
|
2828
|
+
];
|
|
2829
|
+
|
|
2830
|
+
// src/engine/render/table-cells.ts
|
|
2831
|
+
function tableCells(block) {
|
|
2832
|
+
const cols = countOf(block.attrs.cols);
|
|
2833
|
+
return Array.from(
|
|
2834
|
+
{ length: countOf(block.attrs.rows) },
|
|
2835
|
+
(_, row) => Array.from({ length: cols }, (_2, col) => _nullishCoalesce(block.regions[cellKey(row, col)], () => ( [])))
|
|
2836
|
+
);
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// src/engine/render/block-plain-text.ts
|
|
2840
|
+
function inlinePlainText(inline, schema) {
|
|
2841
|
+
return inlineText(inline, (node) => _nullishCoalesce(_optionalChain([schema, 'access', _71 => _71.atoms, 'access', _72 => _72.get, 'call', _73 => _73(node.type), 'optionalAccess', _74 => _74.plainText, 'call', _75 => _75(node.attrs)]), () => ( "")));
|
|
2842
|
+
}
|
|
2843
|
+
function tablePlainText(block, schema) {
|
|
2844
|
+
return tableCells(block).map((row) => row.map((cell) => inlinePlainText(cell, schema)).join(" ")).join("\n");
|
|
2845
|
+
}
|
|
2846
|
+
function blockPlainText(block, schema) {
|
|
2847
|
+
const spec = schema.blocks.get(block.type);
|
|
2848
|
+
if (_optionalChain([spec, 'optionalAccess', _76 => _76.toPlainText])) return spec.toPlainText(block);
|
|
2849
|
+
const { attrs } = block;
|
|
2850
|
+
switch (block.type) {
|
|
2851
|
+
case "CODE":
|
|
2852
|
+
return str(attrs.code);
|
|
2853
|
+
case "IMAGE":
|
|
2854
|
+
return str(attrs.alt);
|
|
2855
|
+
case "FILE":
|
|
2856
|
+
return str(attrs.filename);
|
|
2857
|
+
case "EMBED":
|
|
2858
|
+
return str(attrs.url);
|
|
2859
|
+
case "BOOKMARK":
|
|
2860
|
+
return str(attrs.title) || str(attrs.url);
|
|
2861
|
+
case "MATH":
|
|
2862
|
+
return str(attrs.latex);
|
|
2863
|
+
case "TABLE":
|
|
2864
|
+
return tablePlainText(block, schema);
|
|
2865
|
+
default:
|
|
2866
|
+
return _optionalChain([spec, 'optionalAccess', _77 => _77.primaryRegion]) ? inlinePlainText(_nullishCoalesce(block.regions[spec.primaryRegion], () => ( [])), schema) : "";
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
// src/engine/render/heading-tree.ts
|
|
2871
|
+
function nestHeadings(headings) {
|
|
2872
|
+
const roots = [];
|
|
2873
|
+
const open = [];
|
|
2874
|
+
for (const heading of headings) {
|
|
2875
|
+
while (open.length > 0 && open[open.length - 1].heading.level >= heading.level) open.pop();
|
|
2876
|
+
const node = { heading, children: [] };
|
|
2877
|
+
(_nullishCoalesce(_optionalChain([open, 'access', _78 => _78[open.length - 1], 'optionalAccess', _79 => _79.children]), () => ( roots))).push(node);
|
|
2878
|
+
open.push(node);
|
|
2879
|
+
}
|
|
2880
|
+
return roots;
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
// src/engine/render/heading-level.ts
|
|
2884
|
+
function headingLevel(level) {
|
|
2885
|
+
if (typeof level !== "number" || !Number.isInteger(level)) return 1;
|
|
2886
|
+
return Math.min(6, Math.max(1, level));
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
// src/engine/render/headings.ts
|
|
2890
|
+
var headingId = (blockId) => `h-${blockId}`;
|
|
2891
|
+
function headingLevel2(block) {
|
|
2892
|
+
if (block.type !== "MARKDOWN" || block.attrs.kind !== "heading") return null;
|
|
2893
|
+
return headingLevel(block.attrs.level);
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
// src/engine/render/toc-node.ts
|
|
2897
|
+
function collectHeadings(blocks, schema) {
|
|
2898
|
+
return blocks.flatMap((block) => {
|
|
2899
|
+
const level = headingLevel2(block);
|
|
2900
|
+
const text2 = level === null ? "" : blockPlainText(block, schema);
|
|
2901
|
+
return level === null || text2 === "" ? [] : [{ blockId: block.id, level, text: text2 }];
|
|
2902
|
+
});
|
|
2903
|
+
}
|
|
2904
|
+
function listNode(nodes) {
|
|
2905
|
+
const items = nodes.map(({ heading, children }) => {
|
|
2906
|
+
const link2 = element("a", [["href", `#${headingId(heading.blockId)}`]], [heading.text]);
|
|
2907
|
+
return element("li", [], children.length > 0 ? [link2, listNode(children)] : [link2]);
|
|
2908
|
+
});
|
|
2909
|
+
return element("ul", [], items);
|
|
2910
|
+
}
|
|
2911
|
+
function tocNode(headings, excess) {
|
|
2912
|
+
return element("nav", [["data-toc", ""], indentAttr(excess)], headings.length > 0 ? [listNode(nestHeadings(headings))] : []);
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
// src/engine/render/engine-blocks.ts
|
|
2916
|
+
function engineBlocksOf(blocks, schema) {
|
|
2917
|
+
const used = new Set(blocks.map((block) => block.id));
|
|
2918
|
+
let next = 0;
|
|
2919
|
+
const newId2 = () => {
|
|
2920
|
+
let id;
|
|
2921
|
+
do
|
|
2922
|
+
id = `split-${next++}`;
|
|
2923
|
+
while (used.has(id));
|
|
2924
|
+
return id;
|
|
2925
|
+
};
|
|
2926
|
+
const codec = createBlockCodec(schema, { newId: newId2 });
|
|
2927
|
+
return codec.docFromBlocks(blocks).blocks;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
// src/engine/render/inline-nodes.ts
|
|
2931
|
+
function atomNode(node, options) {
|
|
2932
|
+
const { attrs } = node;
|
|
2933
|
+
if (node.type === "mention") {
|
|
2934
|
+
return element("span", [["data-mention", _nullishCoalesce(attrs.id, () => ( ""))], ["data-kind", attrs.kind || void 0]], [`@${_nullishCoalesce(attrs.label, () => ( ""))}`]);
|
|
2935
|
+
}
|
|
2936
|
+
if (node.type === "math") {
|
|
2937
|
+
const latex = _nullishCoalesce(attrs.latex, () => ( ""));
|
|
2938
|
+
const math3 = ["data-math", ""];
|
|
2939
|
+
return options.renderMath ? element("span", [math3], [latex], options.renderMath(latex, { displayMode: false })) : element("span", [math3], [latex]);
|
|
2940
|
+
}
|
|
2941
|
+
return element("span", [["data-atom", node.type], ...dataAttributes(attrs)]);
|
|
2942
|
+
}
|
|
2943
|
+
var textNodes = (value) => value.split("\n").flatMap((line, at) => at === 0 ? [line] : [element("br"), line]);
|
|
2944
|
+
function inlineNodes(inline, options = {}) {
|
|
2945
|
+
const root = [];
|
|
2946
|
+
const open = [];
|
|
2947
|
+
const current = () => _nullishCoalesce(_optionalChain([open, 'access', _80 => _80[open.length - 1], 'optionalAccess', _81 => _81.children]), () => ( root));
|
|
2948
|
+
for (const node of inline) {
|
|
2949
|
+
let shared = 0;
|
|
2950
|
+
while (shared < open.length && shared < node.marks.length && sameMark(open[shared].mark, node.marks[shared])) {
|
|
2951
|
+
shared++;
|
|
2952
|
+
}
|
|
2953
|
+
open.length = shared;
|
|
2954
|
+
for (const mark of node.marks.slice(shared)) {
|
|
2955
|
+
const wrapper = markElement(mark);
|
|
2956
|
+
if (wrapper) current().push(wrapper);
|
|
2957
|
+
open.push({ mark, children: _nullishCoalesce(_optionalChain([wrapper, 'optionalAccess', _82 => _82.children]), () => ( current())) });
|
|
2958
|
+
}
|
|
2959
|
+
current().push(...node.kind === "text" ? textNodes(node.text) : [atomNode(node, options)]);
|
|
2960
|
+
}
|
|
2961
|
+
return root;
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
// src/engine/render/html-env.ts
|
|
2965
|
+
var inlineOf = (inline, env) => inlineNodes(_nullishCoalesce(inline, () => ( [])), { renderMath: env.renderMath });
|
|
2966
|
+
|
|
2967
|
+
// src/engine/render/embed-provider.ts
|
|
2968
|
+
var EMBED_FRAME = {
|
|
2969
|
+
sandbox: "allow-scripts allow-same-origin allow-presentation allow-popups",
|
|
2970
|
+
loading: "lazy",
|
|
2971
|
+
referrerpolicy: "strict-origin-when-cross-origin"
|
|
2972
|
+
};
|
|
2973
|
+
var WEB = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
2974
|
+
var SECURE = /* @__PURE__ */ new Set(["https:"]);
|
|
2975
|
+
function parse(address) {
|
|
2976
|
+
try {
|
|
2977
|
+
return new URL(address);
|
|
2978
|
+
} catch (e2) {
|
|
2979
|
+
return null;
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
function plainWebUrl(address, protocols) {
|
|
2983
|
+
const url = parse(address);
|
|
2984
|
+
return url && protocols.has(url.protocol) && url.username === "" && url.password === "" && url.port === "" ? url : null;
|
|
2985
|
+
}
|
|
2986
|
+
function embedFrame(href, providers) {
|
|
2987
|
+
const page = plainWebUrl(href, WEB);
|
|
2988
|
+
if (!page) return null;
|
|
2989
|
+
for (const provider of providers) {
|
|
2990
|
+
const result = provider.match(page);
|
|
2991
|
+
const frame = typeof result === "string" ? plainWebUrl(result, SECURE) : null;
|
|
2992
|
+
if (frame) return { src: frame.href, name: provider.name };
|
|
2993
|
+
}
|
|
2994
|
+
return null;
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
// src/engine/render/media-nodes.ts
|
|
2998
|
+
var numberAttr = (value) => _optionalChain([optionalNumber, 'call', _83 => _83(value), 'optionalAccess', _84 => _84.toString, 'call', _85 => _85()]);
|
|
2999
|
+
var paragraph = (view, inner) => element("p", [indentAttr(view.excess)], [inner]);
|
|
3000
|
+
var link = (href, label) => element("a", [["href", href], ["rel", "noopener noreferrer"]], [label]);
|
|
3001
|
+
function assetSource(block, env) {
|
|
3002
|
+
const key = str(block.attrs.storageKey);
|
|
3003
|
+
const src = key === "" ? null : env.resolveAssetUrl(key);
|
|
3004
|
+
return src ? sanitizeAssetUrl(src) : null;
|
|
3005
|
+
}
|
|
3006
|
+
function imageSource(block, env) {
|
|
3007
|
+
const url = str(block.attrs.url);
|
|
3008
|
+
return url === "" ? assetSource(block, env) : sanitizeHref(url);
|
|
3009
|
+
}
|
|
3010
|
+
function imageNode(block, view, env) {
|
|
3011
|
+
const src = imageSource(block, env);
|
|
3012
|
+
if (!src) return "";
|
|
3013
|
+
const { attrs } = block;
|
|
3014
|
+
const image = element("img", [
|
|
3015
|
+
["src", src],
|
|
3016
|
+
["alt", str(attrs.alt)],
|
|
3017
|
+
["width", numberAttr(attrs.width)],
|
|
3018
|
+
["height", numberAttr(attrs.height)],
|
|
3019
|
+
["loading", "lazy"],
|
|
3020
|
+
["decoding", "async"]
|
|
3021
|
+
]);
|
|
3022
|
+
const caption = _nullishCoalesce(block.regions.caption, () => ( []));
|
|
3023
|
+
const figcaption = caption.length > 0 ? [element("figcaption", [], inlineOf(caption, env))] : [];
|
|
3024
|
+
return element("figure", [alignAttr(attrs.align), indentAttr(view.excess)], [image, ...figcaption]);
|
|
3025
|
+
}
|
|
3026
|
+
function fileNode(block, view, env) {
|
|
3027
|
+
const href = assetSource(block, env);
|
|
3028
|
+
if (!href) return "";
|
|
3029
|
+
return paragraph(view, element("a", [["href", href], ["download", true]], [str(block.attrs.filename)]));
|
|
3030
|
+
}
|
|
3031
|
+
function embedNode(block, view, env) {
|
|
3032
|
+
const href = sanitizeHref(str(block.attrs.url));
|
|
3033
|
+
if (!href) return "";
|
|
3034
|
+
const frame = env.embeds === "iframe" ? embedFrame(href, env.embedProviders) : null;
|
|
3035
|
+
if (frame) {
|
|
3036
|
+
const attrs = [["src", frame.src], ["title", env.frameTitle(frame.name)], ...Object.entries(EMBED_FRAME)];
|
|
3037
|
+
return element("iframe", [...attrs, indentAttr(view.excess)]);
|
|
3038
|
+
}
|
|
3039
|
+
return paragraph(view, link(href, href));
|
|
3040
|
+
}
|
|
3041
|
+
function bookmarkNode(block, view) {
|
|
3042
|
+
const href = sanitizeHref(str(block.attrs.url));
|
|
3043
|
+
return href ? paragraph(view, link(href, str(block.attrs.title) || href)) : "";
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
// src/engine/render/table-node.ts
|
|
3047
|
+
function tableNode(block, view, env) {
|
|
3048
|
+
const rows = tableCells(block);
|
|
3049
|
+
const aligns = Array.isArray(block.attrs.align) ? block.attrs.align : [];
|
|
3050
|
+
const row = (tag, cells) => element("tr", [], cells.map((cell, col) => element(tag, [alignAttr(aligns[col])], inlineOf(cell, env))));
|
|
3051
|
+
const headed = block.attrs.header !== false && rows.length > 0;
|
|
3052
|
+
const head = headed ? [element("thead", [], [row("th", rows[0])])] : [];
|
|
3053
|
+
const bodyRows = headed ? rows.slice(1) : rows;
|
|
3054
|
+
const body = bodyRows.length > 0 ? [element("tbody", [], bodyRows.map((cells) => row("td", cells)))] : [];
|
|
3055
|
+
return element("table", [indentAttr(view.excess)], [...head, ...body]);
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
// src/engine/render/block-node.ts
|
|
3059
|
+
function lineNode(block, view, env) {
|
|
3060
|
+
const body = inlineOf(block.regions.text, env);
|
|
3061
|
+
const style = [alignAttr(block.attrs.align), ...colorAttrs(block.attrs), indentAttr(view.excess)];
|
|
3062
|
+
switch (block.attrs.kind) {
|
|
3063
|
+
case "heading":
|
|
3064
|
+
return element(`h${_nullishCoalesce(headingLevel2(block), () => ( 1))}`, [["id", headingId(block.id)], ...style], body);
|
|
3065
|
+
case "bullet":
|
|
3066
|
+
case "ordered":
|
|
3067
|
+
return element("li", style, [...body, ...view.children]);
|
|
3068
|
+
case "task": {
|
|
3069
|
+
const checked = block.attrs.checked === true;
|
|
3070
|
+
const box = element("input", [
|
|
3071
|
+
["type", "checkbox"],
|
|
3072
|
+
["disabled", true],
|
|
3073
|
+
["checked", checked || void 0],
|
|
3074
|
+
["aria-label", nodeText(body) || env.taskLabel]
|
|
3075
|
+
]);
|
|
3076
|
+
return element("li", [["data-checked", String(checked)], ...style], [box, " ", ...body, ...view.children]);
|
|
3077
|
+
}
|
|
3078
|
+
default:
|
|
3079
|
+
return element("p", style, body);
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
function calloutNode(block, view, env) {
|
|
3083
|
+
const icon = str(block.attrs.icon);
|
|
3084
|
+
const mark = icon === "" ? [] : [element("span", [["data-icon", ""]], [icon])];
|
|
3085
|
+
const body = element("p", [], inlineOf(block.regions.body, env));
|
|
3086
|
+
const attrs = [["role", "note"], ["data-tone", str(block.attrs.tone)], indentAttr(view.excess)];
|
|
3087
|
+
return element("aside", attrs, [...mark, body]);
|
|
3088
|
+
}
|
|
3089
|
+
function codeNode(block, view) {
|
|
3090
|
+
const language = str(block.attrs.language);
|
|
3091
|
+
const className = language === "" ? void 0 : `language-${language}`;
|
|
3092
|
+
const code = element("code", [["class", className]], [str(block.attrs.code)]);
|
|
3093
|
+
return element("pre", [indentAttr(view.excess)], [code]);
|
|
3094
|
+
}
|
|
3095
|
+
function mathNode(block, view, env) {
|
|
3096
|
+
const latex = str(block.attrs.latex);
|
|
3097
|
+
if (!env.renderMath) return element("pre", [indentAttr(view.excess)], [latex]);
|
|
3098
|
+
return element("div", [["data-math", ""], indentAttr(view.excess)], [], env.renderMath(latex, { displayMode: true }));
|
|
3099
|
+
}
|
|
3100
|
+
function toggleNode(block, view, env) {
|
|
3101
|
+
const summary = element("summary", [], inlineOf(block.regions.text, env));
|
|
3102
|
+
const attrs = [["open", block.attrs.open === true || void 0], indentAttr(view.excess)];
|
|
3103
|
+
return element("details", attrs, [summary, ...view.children]);
|
|
3104
|
+
}
|
|
3105
|
+
function blockNode(block, view, env) {
|
|
3106
|
+
switch (block.type) {
|
|
3107
|
+
case "MARKDOWN":
|
|
3108
|
+
return lineNode(block, view, env);
|
|
3109
|
+
case "CALLOUT":
|
|
3110
|
+
return calloutNode(block, view, env);
|
|
3111
|
+
case "CODE":
|
|
3112
|
+
return codeNode(block, view);
|
|
3113
|
+
case "IMAGE":
|
|
3114
|
+
return imageNode(block, view, env);
|
|
3115
|
+
case "FILE":
|
|
3116
|
+
return fileNode(block, view, env);
|
|
3117
|
+
case "DIVIDER":
|
|
3118
|
+
return element("hr", [indentAttr(view.excess)]);
|
|
3119
|
+
case "TOGGLE":
|
|
3120
|
+
return toggleNode(block, view, env);
|
|
3121
|
+
case "TABLE":
|
|
3122
|
+
return tableNode(block, view, env);
|
|
3123
|
+
case "EMBED":
|
|
3124
|
+
return embedNode(block, view, env);
|
|
3125
|
+
case "BOOKMARK":
|
|
3126
|
+
return bookmarkNode(block, view);
|
|
3127
|
+
case "MATH":
|
|
3128
|
+
return mathNode(block, view, env);
|
|
3129
|
+
case "TOC":
|
|
3130
|
+
return tocNode(env.headings, view.excess);
|
|
3131
|
+
default:
|
|
3132
|
+
return element("div", [["data-type", block.type], indentAttr(view.excess)]);
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
// src/engine/render/embed-providers.ts
|
|
3137
|
+
var ID = /^[\w-]{1,64}$/;
|
|
3138
|
+
var DIGITS2 = /^\d{1,20}$/;
|
|
3139
|
+
var SPOTIFY_ID = /^[A-Za-z0-9]{1,64}$/;
|
|
3140
|
+
var SPOTIFY_KINDS = /* @__PURE__ */ new Set(["track", "album", "playlist", "episode", "show"]);
|
|
3141
|
+
var FIGMA_KINDS = /* @__PURE__ */ new Set(["file", "design", "proto", "board"]);
|
|
3142
|
+
var pathParts = (url) => url.pathname.split("/").filter((part) => part !== "");
|
|
3143
|
+
var idFrom = (candidate, pattern = ID) => candidate !== null && candidate !== void 0 && pattern.test(candidate) ? candidate : null;
|
|
3144
|
+
var youtube = {
|
|
3145
|
+
name: "youtube",
|
|
3146
|
+
match(url) {
|
|
3147
|
+
const parts = pathParts(url);
|
|
3148
|
+
let id = null;
|
|
3149
|
+
if (url.hostname === "youtu.be") {
|
|
3150
|
+
id = parts.length === 1 ? idFrom(parts[0]) : null;
|
|
3151
|
+
} else if (["youtube.com", "www.youtube.com", "m.youtube.com"].includes(url.hostname)) {
|
|
3152
|
+
if (parts.length === 1 && parts[0] === "watch") id = idFrom(url.searchParams.get("v"));
|
|
3153
|
+
else if (parts.length === 2 && (parts[0] === "embed" || parts[0] === "shorts")) id = idFrom(parts[1]);
|
|
3154
|
+
}
|
|
3155
|
+
return id === null ? null : `https://www.youtube-nocookie.com/embed/${id}`;
|
|
3156
|
+
}
|
|
3157
|
+
};
|
|
3158
|
+
var vimeo = {
|
|
3159
|
+
name: "vimeo",
|
|
3160
|
+
match(url) {
|
|
3161
|
+
const parts = pathParts(url);
|
|
3162
|
+
let id = null;
|
|
3163
|
+
if (["vimeo.com", "www.vimeo.com"].includes(url.hostname)) {
|
|
3164
|
+
id = parts.length === 1 ? idFrom(parts[0], DIGITS2) : null;
|
|
3165
|
+
} else if (url.hostname === "player.vimeo.com") {
|
|
3166
|
+
id = parts.length === 2 && parts[0] === "video" ? idFrom(parts[1], DIGITS2) : null;
|
|
3167
|
+
}
|
|
3168
|
+
return id === null ? null : `https://player.vimeo.com/video/${id}`;
|
|
3169
|
+
}
|
|
3170
|
+
};
|
|
3171
|
+
var loom = {
|
|
3172
|
+
name: "loom",
|
|
3173
|
+
match(url) {
|
|
3174
|
+
const parts = pathParts(url);
|
|
3175
|
+
const onLoom = ["loom.com", "www.loom.com"].includes(url.hostname);
|
|
3176
|
+
const id = onLoom && parts.length === 2 && parts[0] === "share" ? idFrom(parts[1]) : null;
|
|
3177
|
+
return id === null ? null : `https://www.loom.com/embed/${id}`;
|
|
3178
|
+
}
|
|
3179
|
+
};
|
|
3180
|
+
var figma = {
|
|
3181
|
+
name: "figma",
|
|
3182
|
+
match(url) {
|
|
3183
|
+
const parts = pathParts(url);
|
|
3184
|
+
const onFigma = ["figma.com", "www.figma.com"].includes(url.hostname);
|
|
3185
|
+
if (!onFigma || parts.length < 2 || !FIGMA_KINDS.has(parts[0]) || idFrom(parts[1]) === null) return null;
|
|
3186
|
+
return `https://www.figma.com/embed?embed_host=quoin&url=${encodeURIComponent(url.href)}`;
|
|
3187
|
+
}
|
|
3188
|
+
};
|
|
3189
|
+
var codepen = {
|
|
3190
|
+
name: "codepen",
|
|
3191
|
+
match(url) {
|
|
3192
|
+
const parts = pathParts(url);
|
|
3193
|
+
if (url.hostname !== "codepen.io" || parts.length !== 3 || parts[1] !== "pen") return null;
|
|
3194
|
+
const [user, , id] = parts;
|
|
3195
|
+
return idFrom(user) === null || idFrom(id) === null ? null : `https://codepen.io/${user}/embed/${id}`;
|
|
3196
|
+
}
|
|
3197
|
+
};
|
|
3198
|
+
var spotify = {
|
|
3199
|
+
name: "spotify",
|
|
3200
|
+
match(url) {
|
|
3201
|
+
const parts = pathParts(url);
|
|
3202
|
+
if (url.hostname !== "open.spotify.com" || parts.length !== 2 || !SPOTIFY_KINDS.has(parts[0])) return null;
|
|
3203
|
+
return idFrom(parts[1], SPOTIFY_ID) === null ? null : `https://open.spotify.com/embed/${parts[0]}/${parts[1]}`;
|
|
3204
|
+
}
|
|
3205
|
+
};
|
|
3206
|
+
var soundcloud = {
|
|
3207
|
+
name: "soundcloud",
|
|
3208
|
+
match(url) {
|
|
3209
|
+
const onSoundcloud = ["soundcloud.com", "www.soundcloud.com", "m.soundcloud.com"].includes(url.hostname);
|
|
3210
|
+
return onSoundcloud && pathParts(url).length >= 2 ? `https://w.soundcloud.com/player/?url=${encodeURIComponent(url.href)}` : null;
|
|
3211
|
+
}
|
|
3212
|
+
};
|
|
3213
|
+
var coreEmbedProviders = [youtube, vimeo, loom, figma, codepen, spotify, soundcloud];
|
|
3214
|
+
|
|
3215
|
+
// src/engine/render/group-nodes.ts
|
|
3216
|
+
function listElement({ list, items }, children) {
|
|
3217
|
+
if (list !== "ordered") return element("ul", [["data-type", list === "task" ? list : void 0]], children);
|
|
3218
|
+
const { start } = items[0].block.attrs;
|
|
3219
|
+
return element("ol", [["start", Number.isInteger(start) && start !== 1 ? String(start) : void 0]], children);
|
|
3220
|
+
}
|
|
3221
|
+
function groupNodes(groups, env, render) {
|
|
3222
|
+
const entryNode = ({ block, excess, children }) => render(block, { excess, children: groupNodes(children, env, render) }, env);
|
|
3223
|
+
return groups.map((group) => {
|
|
3224
|
+
if (group.kind === "single") return entryNode(group.entry);
|
|
3225
|
+
if (group.kind === "quote") {
|
|
3226
|
+
const lines = group.items.map(({ block }) => render(block, { excess: 0, children: [] }, env));
|
|
3227
|
+
return element("blockquote", [indentAttr(group.items[0].excess)], lines);
|
|
3228
|
+
}
|
|
3229
|
+
return listElement(group, group.items.map(entryNode));
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
|
|
3233
|
+
// src/engine/render/document-nodes.ts
|
|
3234
|
+
function documentNodes(blocks, options = {}, render = blockNode) {
|
|
3235
|
+
const schema = _nullishCoalesce(options.schema, () => ( createSchema()));
|
|
3236
|
+
const engine = engineBlocksOf(blocks, schema);
|
|
3237
|
+
const env = {
|
|
3238
|
+
resolveAssetUrl: _nullishCoalesce(options.resolveAssetUrl, () => ( sanitizeHref)),
|
|
3239
|
+
renderMath: options.renderMath,
|
|
3240
|
+
embeds: _nullishCoalesce(options.embeds, () => ( "link")),
|
|
3241
|
+
embedProviders: [..._nullishCoalesce(options.embedProviders, () => ( [])), ...coreEmbedProviders],
|
|
3242
|
+
headings: collectHeadings(engine, schema),
|
|
3243
|
+
taskLabel: _nullishCoalesce(options.taskLabel, () => ( "Task")),
|
|
3244
|
+
frameTitle: _nullishCoalesce(options.frameTitle, () => ( String))
|
|
3245
|
+
};
|
|
3246
|
+
return groupNodes(groupBlocks(engine), env, render);
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
|
|
3250
|
+
|
|
3251
|
+
|
|
3252
|
+
|
|
3253
|
+
|
|
3254
|
+
|
|
3255
|
+
|
|
3256
|
+
|
|
3257
|
+
|
|
3258
|
+
|
|
3259
|
+
|
|
3260
|
+
|
|
3261
|
+
|
|
3262
|
+
|
|
3263
|
+
|
|
3264
|
+
|
|
3265
|
+
|
|
3266
|
+
|
|
3267
|
+
|
|
3268
|
+
|
|
3269
|
+
|
|
3270
|
+
|
|
3271
|
+
|
|
3272
|
+
|
|
3273
|
+
|
|
3274
|
+
|
|
3275
|
+
|
|
3276
|
+
|
|
3277
|
+
|
|
3278
|
+
|
|
3279
|
+
|
|
3280
|
+
|
|
3281
|
+
|
|
3282
|
+
|
|
3283
|
+
|
|
3284
|
+
|
|
3285
|
+
|
|
3286
|
+
|
|
3287
|
+
|
|
3288
|
+
|
|
3289
|
+
|
|
3290
|
+
|
|
3291
|
+
|
|
3292
|
+
|
|
3293
|
+
|
|
3294
|
+
|
|
3295
|
+
|
|
3296
|
+
|
|
3297
|
+
|
|
3298
|
+
|
|
3299
|
+
|
|
3300
|
+
|
|
3301
|
+
|
|
3302
|
+
|
|
3303
|
+
|
|
3304
|
+
|
|
3305
|
+
|
|
3306
|
+
|
|
3307
|
+
|
|
3308
|
+
|
|
3309
|
+
|
|
3310
|
+
|
|
3311
|
+
|
|
3312
|
+
|
|
3313
|
+
|
|
3314
|
+
|
|
3315
|
+
|
|
3316
|
+
|
|
3317
|
+
|
|
3318
|
+
|
|
3319
|
+
|
|
3320
|
+
|
|
3321
|
+
|
|
3322
|
+
|
|
3323
|
+
|
|
3324
|
+
|
|
3325
|
+
|
|
3326
|
+
|
|
3327
|
+
|
|
3328
|
+
|
|
3329
|
+
|
|
3330
|
+
|
|
3331
|
+
|
|
3332
|
+
|
|
3333
|
+
|
|
3334
|
+
exports.sameAttrs = sameAttrs; exports.compareRegionNames = compareRegionNames; exports.sameItems = sameItems; exports.markKey = markKey; exports.sameMark = sameMark; exports.sameMarkSet = sameMarkSet; exports.addMark = addMark; exports.removeMark = removeMark; exports.hasMark = hasMark; exports.text = text; exports.atom = atom; exports.nodeLength = nodeLength; exports.normalizeInline = normalizeInline; exports.inlineLength = inlineLength; exports.inlineText = inlineText; exports.sliceInline = sliceInline; exports.replaceInline = replaceInline; exports.addMarkRange = addMarkRange; exports.removeMarkRange = removeMarkRange; exports.marksAt = marksAt; exports.equalNode = equalNode; exports.equalInline = equalInline; exports.PALETTE = PALETTE; exports.isPaletteColor = isPaletteColor; exports.isRecord = isRecord; exports.str = str; exports.optionalString = optionalString; exports.optionalNumber = optionalNumber; exports.paletteOrUndefined = paletteOrUndefined; exports.alignOrUndefined = alignOrUndefined; exports.MAX_MARKER_NUMBER = MAX_MARKER_NUMBER; exports.orderedStart = orderedStart; exports.parseLine = parseLine; exports.countOf = countOf; exports.cellKey = cellKey; exports.coreBlockSpecs = coreBlockSpecs; exports.coreAtomSpecs = coreAtomSpecs; exports.coreMarkSpecs = coreMarkSpecs; exports.createSchema = createSchema; exports.SCHEME = SCHEME; exports.sanitizeHref = sanitizeHref; exports.sanitizeAssetUrl = sanitizeAssetUrl; exports.opensMath = opensMath; exports.dollarRunEnd = dollarRunEnd; exports.findMathClose = findMathClose; exports.mathLatex = mathLatex; exports.parseInline = parseInline; exports.dataAttributes = dataAttributes; exports.writtenAttrs = writtenAttrs; exports.nodeText = nodeText; exports.element = element; exports.markElement = markElement; exports.linkClose = linkClose; exports.serializeInline = serializeInline; exports.createDoc = createDoc; exports.indexOfBlock = indexOfBlock; exports.requireBlockIndex = requireBlockIndex; exports.blockById = blockById; exports.updateBlock = updateBlock; exports.replaceBlocks = replaceBlocks; exports.newId = newId; exports.isQuoinType = isQuoinType; exports.startsHtmlBlock = startsHtmlBlock; exports.ALERT_TONES = ALERT_TONES; exports.fromMarkdown = fromMarkdown; exports.specFor = specFor; exports.createBlockCodec = createBlockCodec; exports.listKind = listKind; exports.groupBlocks = groupBlocks; exports.headingLevel = headingLevel; exports.headingId = headingId; exports.headingLevel2 = headingLevel2; exports.inlineOf = inlineOf; exports.EMBED_FRAME = EMBED_FRAME; exports.embedFrame = embedFrame; exports.tableCells = tableCells; exports.inlinePlainText = inlinePlainText; exports.blockPlainText = blockPlainText; exports.nestHeadings = nestHeadings; exports.collectHeadings = collectHeadings; exports.blockNode = blockNode; exports.coreEmbedProviders = coreEmbedProviders; exports.engineBlocksOf = engineBlocksOf; exports.documentNodes = documentNodes;
|
|
3335
|
+
//# sourceMappingURL=chunk-ND5XJVK2.cjs.map
|