@vielzeug/scribe 0.0.0-stage → 26.11.14
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/LICENSE +21 -0
- package/README.md +38 -2
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +5 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_policy.cjs +2 -0
- package/dist/_policy.cjs.map +1 -0
- package/dist/_policy.d.ts +25 -0
- package/dist/_policy.d.ts.map +1 -0
- package/dist/_policy.js +42 -0
- package/dist/_policy.js.map +1 -0
- package/dist/_text.cjs +2 -0
- package/dist/_text.cjs.map +1 -0
- package/dist/_text.d.ts +20 -0
- package/dist/_text.d.ts.map +1 -0
- package/dist/_text.js +52 -0
- package/dist/_text.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/parse.cjs +10 -0
- package/dist/parse.cjs.map +1 -0
- package/dist/parse.d.ts +23 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +420 -0
- package/dist/parse.js.map +1 -0
- package/dist/render.cjs +16 -0
- package/dist/render.cjs.map +1 -0
- package/dist/render.d.ts +29 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +199 -0
- package/dist/render.js.map +1 -0
- package/dist/scribe.cjs +24 -0
- package/dist/scribe.cjs.map +1 -0
- package/dist/scribe.iife.js +24 -0
- package/dist/scribe.iife.js.map +1 -0
- package/dist/scribe.js +702 -0
- package/dist/scribe.js.map +1 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +46 -4
package/dist/parse.js
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import "./_dev.js";
|
|
2
|
+
import { sanitizeDestination as e } from "./_policy.js";
|
|
3
|
+
import { inlineText as t } from "./_text.js";
|
|
4
|
+
import { ScribeLimitError as n } from "./errors.js";
|
|
5
|
+
// src/parse.ts
|
|
6
|
+
var r = 2e5, i = 32, a = [
|
|
7
|
+
"http",
|
|
8
|
+
"https",
|
|
9
|
+
"mailto"
|
|
10
|
+
], o = /^[ \t]*$/, s = /^ {0,3}(`{3,}|~{3,})(.*)$/, c = /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?(?:[ \t]+#+)?[ \t]*$/, l = /^(?: {0,3}(?:\*[ \t]*){3,}| {0,3}(?:-[ \t]*){3,}| {0,3}(?:_[ \t]*){3,})$/, u = /^ {0,3}>[ \t]?(.*)$/, d = /^( {0,3})([-+*])([ \t]+)(.*)$/, f = /^( {0,3})(\d{1,9})([.)])([ \t]+)(.*)$/, p = /^[ \t]*\|?[ \t]*:?-+:?[ \t]*(?:\|[ \t]*:?-+:?[ \t]*)*\|?[ \t]*$/, m = /^[\p{L}\p{N}_-]+/u;
|
|
11
|
+
function indentOf(e) {
|
|
12
|
+
let t = 0;
|
|
13
|
+
for (let n of e) if (n === " ") t += 1;
|
|
14
|
+
else if (n === " ") t += 4;
|
|
15
|
+
else break;
|
|
16
|
+
return t;
|
|
17
|
+
}
|
|
18
|
+
function isTableStart(e, t) {
|
|
19
|
+
return e[t].includes("|") && e[t + 1] !== void 0 && p.test(e[t + 1]);
|
|
20
|
+
}
|
|
21
|
+
function splitCells(e) {
|
|
22
|
+
let t = e.trim();
|
|
23
|
+
t.startsWith("|") && (t = t.slice(1)), t.endsWith("|") && !t.endsWith("\\|") && (t = t.slice(0, -1));
|
|
24
|
+
let n = [], r = "";
|
|
25
|
+
for (let e = 0; e < t.length; e += 1) {
|
|
26
|
+
let i = t[e];
|
|
27
|
+
i === "\\" && t[e + 1] === "|" ? (r += "|", e += 1) : i === "|" ? (n.push(r.trim()), r = "") : r += i;
|
|
28
|
+
}
|
|
29
|
+
return n.push(r.trim()), n;
|
|
30
|
+
}
|
|
31
|
+
function parseDelimAlignments(e) {
|
|
32
|
+
return splitCells(e).map((e) => e.startsWith(":") && e.endsWith(":") ? "center" : e.endsWith(":") ? "right" : "left");
|
|
33
|
+
}
|
|
34
|
+
function parseBlocks(e, t) {
|
|
35
|
+
if (t.depth += 1, t.depth > i) throw new n(`block nesting exceeds the ${i}-level limit`);
|
|
36
|
+
let r = [], a = [], d = 0, flushParagraph = () => {
|
|
37
|
+
if (a.length === 0) return;
|
|
38
|
+
let e = {
|
|
39
|
+
children: parseInline(a.join("\n"), t),
|
|
40
|
+
type: "paragraph"
|
|
41
|
+
};
|
|
42
|
+
r.push(e), a = [];
|
|
43
|
+
};
|
|
44
|
+
for (; d < e.length;) {
|
|
45
|
+
let n = e[d];
|
|
46
|
+
if (o.test(n)) {
|
|
47
|
+
flushParagraph(), d += 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
let i = s.exec(n);
|
|
51
|
+
if (i) {
|
|
52
|
+
flushParagraph();
|
|
53
|
+
let t = i[1], n = i[0].indexOf(t[0]), a = m.exec(i[2].trim())?.[0], o = RegExp(`^ {0,3}\\${t[0]}{${t.length},}[ \\t]*$`), s = [];
|
|
54
|
+
for (d += 1; d < e.length && !o.test(e[d]);) s.push(e[d].slice(Math.min(indentOf(e[d]), n))), d += 1;
|
|
55
|
+
d += 1, r.push(a === void 0 ? {
|
|
56
|
+
text: s.join("\n"),
|
|
57
|
+
type: "codeBlock"
|
|
58
|
+
} : {
|
|
59
|
+
language: a,
|
|
60
|
+
text: s.join("\n"),
|
|
61
|
+
type: "codeBlock"
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
let f = c.exec(n);
|
|
66
|
+
if (f) {
|
|
67
|
+
flushParagraph(), r.push({
|
|
68
|
+
children: parseInline(f[2] ?? "", t),
|
|
69
|
+
level: f[1].length,
|
|
70
|
+
type: "heading"
|
|
71
|
+
}), d += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (l.test(n)) {
|
|
75
|
+
flushParagraph(), r.push({ type: "thematicBreak" }), d += 1;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (u.test(n)) {
|
|
79
|
+
flushParagraph();
|
|
80
|
+
let n = [];
|
|
81
|
+
for (; d < e.length;) {
|
|
82
|
+
let t = u.exec(e[d]);
|
|
83
|
+
if (t === null) break;
|
|
84
|
+
n.push(t[1]), d += 1;
|
|
85
|
+
}
|
|
86
|
+
r.push({
|
|
87
|
+
children: parseBlocks(n, t),
|
|
88
|
+
type: "blockquote"
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
let p = matchListMarker(n);
|
|
93
|
+
if (p !== null && (!p.ordered || p.start === 1 || a.length === 0)) {
|
|
94
|
+
flushParagraph();
|
|
95
|
+
let n = parseList(e, d, t, p);
|
|
96
|
+
r.push(n.block), d = n.next;
|
|
97
|
+
} else if (a.length === 0 && indentOf(n) >= 4) {
|
|
98
|
+
let t = [];
|
|
99
|
+
for (; d < e.length && (o.test(e[d]) || indentOf(e[d]) >= 4) && (!o.test(e[d]) || d + 1 < e.length && indentOf(e[d + 1]) >= 4);) t.push(e[d].slice(4)), d += 1;
|
|
100
|
+
r.push({
|
|
101
|
+
text: t.join("\n"),
|
|
102
|
+
type: "codeBlock"
|
|
103
|
+
});
|
|
104
|
+
} else if (a.length === 0 && isTableStart(e, d)) {
|
|
105
|
+
let n = splitCells(e[d]), i = parseDelimAlignments(e[d + 1]);
|
|
106
|
+
d += 2;
|
|
107
|
+
let a = [];
|
|
108
|
+
for (; d < e.length && !o.test(e[d]) && e[d].includes("|");) {
|
|
109
|
+
let n = splitCells(e[d]);
|
|
110
|
+
for (; n.length < i.length;) n.push("");
|
|
111
|
+
a.push(n.slice(0, i.length).map((e) => [...parseInline(e, t)])), d += 1;
|
|
112
|
+
}
|
|
113
|
+
r.push({
|
|
114
|
+
alignments: i,
|
|
115
|
+
header: n.slice(0, i.length).map((e) => [...parseInline(e, t)]),
|
|
116
|
+
rows: a,
|
|
117
|
+
type: "table"
|
|
118
|
+
});
|
|
119
|
+
} else a.push(n), d += 1;
|
|
120
|
+
}
|
|
121
|
+
return flushParagraph(), --t.depth, r;
|
|
122
|
+
}
|
|
123
|
+
function matchListMarker(e) {
|
|
124
|
+
let t = d.exec(e);
|
|
125
|
+
if (t !== null) return {
|
|
126
|
+
indent: t[1].length,
|
|
127
|
+
kind: t[2],
|
|
128
|
+
ordered: !1,
|
|
129
|
+
spaces: t[3].length,
|
|
130
|
+
start: 1,
|
|
131
|
+
width: 1
|
|
132
|
+
};
|
|
133
|
+
let n = f.exec(e);
|
|
134
|
+
return n === null ? null : {
|
|
135
|
+
indent: n[1].length,
|
|
136
|
+
kind: n[3],
|
|
137
|
+
ordered: !0,
|
|
138
|
+
spaces: n[4].length,
|
|
139
|
+
start: Number(n[2]),
|
|
140
|
+
width: n[2].length + 1
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function sameMarker(e, t) {
|
|
144
|
+
return e.ordered === t.ordered && e.kind === t.kind;
|
|
145
|
+
}
|
|
146
|
+
function parseList(e, t, n, r) {
|
|
147
|
+
let i = r.indent + r.width + (r.spaces >= 5 ? 1 : r.spaces), a = [], s = !1, c = 0, l = null, u = t;
|
|
148
|
+
for (; u < e.length;) {
|
|
149
|
+
let d = e[u];
|
|
150
|
+
if (o.test(d)) {
|
|
151
|
+
l !== null && (c += 1), u += 1;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
let f = indentOf(d) < i ? matchListMarker(d) : null, p = f !== null && sameMarker(f, r) && (l === null || u > t);
|
|
155
|
+
if (p && l !== null && (c > 0 && (s = !0), a.push({
|
|
156
|
+
children: parseBlocks(l, n),
|
|
157
|
+
type: "listItem"
|
|
158
|
+
}), l = null), p) l = [d.slice(i)], c = 0, u += 1;
|
|
159
|
+
else if (l !== null && indentOf(d) >= i) c > 0 && (s = !0), c = 0, l.push(d.slice(i)), u += 1;
|
|
160
|
+
else break;
|
|
161
|
+
}
|
|
162
|
+
return l !== null && a.push({
|
|
163
|
+
children: parseBlocks(l, n),
|
|
164
|
+
type: "listItem"
|
|
165
|
+
}), {
|
|
166
|
+
block: {
|
|
167
|
+
items: a,
|
|
168
|
+
ordered: r.ordered,
|
|
169
|
+
start: r.start,
|
|
170
|
+
tight: !s,
|
|
171
|
+
type: "list"
|
|
172
|
+
},
|
|
173
|
+
next: u
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
var isDelim = (e) => "kind" in e, h = /[\p{P}\p{S}]/u;
|
|
177
|
+
function parseInline(r, a) {
|
|
178
|
+
if (a.depth += 1, a.depth > i) throw new n(`inline nesting exceeds the ${i}-level limit`);
|
|
179
|
+
let o = [], s = "", flush = () => {
|
|
180
|
+
s !== "" && (o.push({
|
|
181
|
+
text: s,
|
|
182
|
+
type: "text"
|
|
183
|
+
}), s = "");
|
|
184
|
+
}, linkLike = (e) => {
|
|
185
|
+
if (r[e] !== "[") return null;
|
|
186
|
+
let t = 0, n = -1;
|
|
187
|
+
for (let i = e; i < r.length; i += 1) if (r[i] === "\\") i += 1;
|
|
188
|
+
else if (r[i] === "[") t += 1;
|
|
189
|
+
else if (r[i] === "]" && (--t, t === 0)) {
|
|
190
|
+
n = i;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
if (n === -1 || r[n + 1] !== "(") return null;
|
|
194
|
+
let i = n + 2, a = "", o;
|
|
195
|
+
if (r[i] === "<") {
|
|
196
|
+
let e = r.indexOf(">", i + 1);
|
|
197
|
+
if (e === -1) return null;
|
|
198
|
+
a = r.slice(i + 1, e), i = e + 1;
|
|
199
|
+
} else {
|
|
200
|
+
let e = 0;
|
|
201
|
+
for (; i < r.length && !/\s/.test(r[i]) && (r[i] !== ")" || e !== 0);) r[i] === "(" ? e += 1 : r[i] === ")" && --e, a += r[i], i += 1;
|
|
202
|
+
}
|
|
203
|
+
let s = /^\s+(['"])(.*?)\1\s*\)/.exec(r.slice(i));
|
|
204
|
+
if (s !== null) o = s[2], i += s[0].length;
|
|
205
|
+
else {
|
|
206
|
+
let e = /^\s*\)/.exec(r.slice(i));
|
|
207
|
+
if (e === null) return null;
|
|
208
|
+
i += e[0].length;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
dest: a,
|
|
212
|
+
end: i,
|
|
213
|
+
label: r.slice(e + 1, n),
|
|
214
|
+
title: o
|
|
215
|
+
};
|
|
216
|
+
}, c = 0;
|
|
217
|
+
for (; c < r.length;) {
|
|
218
|
+
let n = r[c];
|
|
219
|
+
if (n === "\\" && h.test(r[c + 1] ?? "")) s += r[c + 1], c += 2;
|
|
220
|
+
else if (n === "\\" && r[c + 1] === "\n") flush(), o.push({ type: "hardBreak" }), c += 2;
|
|
221
|
+
else if (n === "`") {
|
|
222
|
+
let e = 0;
|
|
223
|
+
for (; r[c + e] === "`";) e += 1;
|
|
224
|
+
let t = r.slice(c + e), n = RegExp(`(?<!\`)\`{${e}}(?!\`)`).exec(t);
|
|
225
|
+
if (n !== null) {
|
|
226
|
+
let r = t.slice(0, n.index);
|
|
227
|
+
r.length >= 2 && r.startsWith(" ") && r.endsWith(" ") && !/^ +$/.test(r) && (r = r.slice(1, -1)), flush(), o.push({
|
|
228
|
+
text: r,
|
|
229
|
+
type: "codeSpan"
|
|
230
|
+
}), c += e + n.index + e;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
s += "`".repeat(e), c += e;
|
|
234
|
+
} else if (n === "<") {
|
|
235
|
+
let t = /^<([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})>/.exec(r.slice(c));
|
|
236
|
+
if (t !== null) {
|
|
237
|
+
let n = `mailto:${t[1]}`;
|
|
238
|
+
if (e(n, a.protocols) !== null) {
|
|
239
|
+
flush(), o.push({
|
|
240
|
+
children: [{
|
|
241
|
+
text: t[1],
|
|
242
|
+
type: "text"
|
|
243
|
+
}],
|
|
244
|
+
href: n,
|
|
245
|
+
type: "link"
|
|
246
|
+
}), c += t[0].length;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
`${n}`;
|
|
250
|
+
}
|
|
251
|
+
let n = /^<([A-Za-z][A-Za-z0-9+.-]*:[^<>\n]*)>/.exec(r.slice(c));
|
|
252
|
+
if (n !== null) {
|
|
253
|
+
let t = e(n[1], a.protocols);
|
|
254
|
+
if (t !== null) {
|
|
255
|
+
flush(), o.push({
|
|
256
|
+
children: [{
|
|
257
|
+
text: n[1],
|
|
258
|
+
type: "text"
|
|
259
|
+
}],
|
|
260
|
+
href: t,
|
|
261
|
+
type: "link"
|
|
262
|
+
}), c += n[0].length;
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
`${n[1]}`, s += "<", c += 1;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
s += "<", c += 1;
|
|
269
|
+
} else if (n === "!" && r[c + 1] === "[" || n === "[") {
|
|
270
|
+
let r = linkLike(n === "!" ? c + 1 : c);
|
|
271
|
+
if (r !== null) {
|
|
272
|
+
let i = e(r.dest, a.protocols);
|
|
273
|
+
if (flush(), i !== null) {
|
|
274
|
+
if (n === "!") {
|
|
275
|
+
let e = {
|
|
276
|
+
alt: t(parseInline(r.label, a)),
|
|
277
|
+
src: i,
|
|
278
|
+
type: "image"
|
|
279
|
+
};
|
|
280
|
+
o.push(r.title === void 0 ? e : {
|
|
281
|
+
...e,
|
|
282
|
+
title: r.title
|
|
283
|
+
});
|
|
284
|
+
} else {
|
|
285
|
+
let e = {
|
|
286
|
+
children: parseInline(r.label, a),
|
|
287
|
+
href: i,
|
|
288
|
+
type: "link"
|
|
289
|
+
};
|
|
290
|
+
o.push(r.title === void 0 ? e : {
|
|
291
|
+
...e,
|
|
292
|
+
title: r.title
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} else `${r.dest}`, n === "!" ? o.push({
|
|
296
|
+
text: t(parseInline(r.label, a)),
|
|
297
|
+
type: "text"
|
|
298
|
+
}) : o.push(...parseInline(r.label, a));
|
|
299
|
+
c = r.end;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
s += n, c += 1;
|
|
303
|
+
} else if (n === "*" || n === "_" || n === "~") {
|
|
304
|
+
let e = 0;
|
|
305
|
+
for (; r[c + e] === n;) e += 1;
|
|
306
|
+
if (n !== "~" || e === 2) {
|
|
307
|
+
let t = c === 0 ? " " : r[c - 1], i = r[c + e] ?? " ", a = !/\s/.test(i) && (!h.test(i) || /\s/.test(t) || h.test(t)), s = !/\s/.test(t) && (!h.test(t) || /\s/.test(i) || h.test(i)), l = n === "_" ? a && (!s || h.test(t)) : a, u = n === "_" ? s && (!a || h.test(i)) : s;
|
|
308
|
+
if (l || u) {
|
|
309
|
+
flush(), o.push({
|
|
310
|
+
canClose: u,
|
|
311
|
+
canOpen: l,
|
|
312
|
+
char: n,
|
|
313
|
+
count: e,
|
|
314
|
+
kind: "delim"
|
|
315
|
+
}), c += e;
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
s += n.repeat(e), c += e;
|
|
320
|
+
} else {
|
|
321
|
+
if ((n === "h" || n === "H") && (c === 0 || /[\s_([{]/.test(r[c - 1]))) {
|
|
322
|
+
let t = /^https?:\/\/\S+/.exec(r.slice(c));
|
|
323
|
+
if (t !== null) {
|
|
324
|
+
let n = t[0].replace(/[.,;:!?]+$/, "");
|
|
325
|
+
n.endsWith(")") && !n.includes("(") && (n = n.slice(0, -1));
|
|
326
|
+
let r = e(n, a.protocols);
|
|
327
|
+
if (r !== null) {
|
|
328
|
+
flush(), o.push({
|
|
329
|
+
children: [{
|
|
330
|
+
text: n,
|
|
331
|
+
type: "text"
|
|
332
|
+
}],
|
|
333
|
+
href: r,
|
|
334
|
+
type: "link"
|
|
335
|
+
}), c += n.length;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (n === "\n") {
|
|
341
|
+
let e = /[ \t]*$/.exec(s)?.[0] ?? "";
|
|
342
|
+
e !== "" && (s = s.slice(0, -e.length)), flush(), o.push(e.length >= 2 ? { type: "hardBreak" } : { type: "softBreak" }), c += 1;
|
|
343
|
+
} else s += n, c += 1;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
flush();
|
|
347
|
+
let l = resolveEmphasis(o);
|
|
348
|
+
return --a.depth, mergeText(l);
|
|
349
|
+
}
|
|
350
|
+
function resolveEmphasis(e) {
|
|
351
|
+
for (let t = 0; t < e.length; t += 1) {
|
|
352
|
+
let n = e[t];
|
|
353
|
+
if (isDelim(n) && n.canClose && n.count !== 0) for (let r = t - 1; r >= 0; --r) {
|
|
354
|
+
let i = e[r];
|
|
355
|
+
if (!isDelim(i) || !i.canOpen || i.count === 0 || i.char !== n.char || n.char === "~" && (i.count !== 2 || n.count !== 2)) continue;
|
|
356
|
+
let a = n.char !== "~" && i.count >= 2 && n.count >= 2, o = n.char === "~" || a ? 2 : 1, s = resolveRemainder(e.slice(r + 1, t)), c = a ? {
|
|
357
|
+
children: s,
|
|
358
|
+
type: "strong"
|
|
359
|
+
} : n.char === "~" ? {
|
|
360
|
+
children: s,
|
|
361
|
+
type: "strikethrough"
|
|
362
|
+
} : {
|
|
363
|
+
children: s,
|
|
364
|
+
type: "emphasis"
|
|
365
|
+
}, l = [];
|
|
366
|
+
i.count > o && l.push({
|
|
367
|
+
canClose: !1,
|
|
368
|
+
canOpen: !0,
|
|
369
|
+
char: i.char,
|
|
370
|
+
count: i.count - o,
|
|
371
|
+
kind: "delim"
|
|
372
|
+
}), l.push(c), n.count > o && l.push({
|
|
373
|
+
canClose: !0,
|
|
374
|
+
canOpen: !1,
|
|
375
|
+
char: n.char,
|
|
376
|
+
count: n.count - o,
|
|
377
|
+
kind: "delim"
|
|
378
|
+
}), e.splice(r, t - r + 1, ...l), t = r - 1;
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return resolveRemainder(e);
|
|
383
|
+
}
|
|
384
|
+
function resolveRemainder(e) {
|
|
385
|
+
let t = [];
|
|
386
|
+
for (let n of e) isDelim(n) ? n.count > 0 && t.push({
|
|
387
|
+
text: n.char.repeat(n.count),
|
|
388
|
+
type: "text"
|
|
389
|
+
}) : t.push(n);
|
|
390
|
+
return mergeText(t);
|
|
391
|
+
}
|
|
392
|
+
function mergeText(e) {
|
|
393
|
+
let t = [];
|
|
394
|
+
for (let n of e) {
|
|
395
|
+
let e = t[t.length - 1];
|
|
396
|
+
n.type === "text" && e !== void 0 && e.type === "text" ? t[t.length - 1] = {
|
|
397
|
+
text: e.text + n.text,
|
|
398
|
+
type: "text"
|
|
399
|
+
} : t.push(n);
|
|
400
|
+
}
|
|
401
|
+
return t;
|
|
402
|
+
}
|
|
403
|
+
function deepFreeze(e) {
|
|
404
|
+
if (typeof e == "object" && e) {
|
|
405
|
+
for (let t of Object.values(e)) deepFreeze(t);
|
|
406
|
+
Object.freeze(e);
|
|
407
|
+
}
|
|
408
|
+
return e;
|
|
409
|
+
}
|
|
410
|
+
function parseProse(e, t = {}) {
|
|
411
|
+
if (e.length > r) throw new n(`input exceeds the ${r}-character limit`);
|
|
412
|
+
let i = {
|
|
413
|
+
depth: 0,
|
|
414
|
+
protocols: new Set((t.linkProtocols ?? a).map((e) => e.toLowerCase()))
|
|
415
|
+
};
|
|
416
|
+
return deepFreeze({ blocks: parseBlocks(e.replace(/\r\n?/g, "\n").replaceAll(" ", " ").split("\n"), i) });
|
|
417
|
+
}
|
|
418
|
+
export { parseProse };
|
|
419
|
+
|
|
420
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","names":["MAX_INPUT_LENGTH","MAX_DEPTH","DEFAULT_PROTOCOLS","RE_BLANK","RE_FENCE","RE_HEADING","RE_HR","RE_QUOTE","RE_UL","RE_OL","RE_TABLE_DELIM","RE_LANG","column","char","line","lines","index","text","row","cells","cell","i","delimiterRow","ctx","ScribeLimitError","blocks","paragraph","node","fence","marker","fenceIndent","lang","closeRe","content","heading","quoted","quote","list","header","alignments","rows","ul","ol","a","b","contentIndent","initial","items","loose","pendingBlanks","current","start","isItemStart","token","RE_PUNCT","tokens","buffer","src","at","depth","close","k","j","dest","title","angleEnd","parenDepth","bare","run","rest","found","email","mailto","sanitizeDestination","autolink","href","parsed","image","inlineText","link","prev","next","leftFlanking","rightFlanking","canOpen","canClose","url","trailing","resolved","ci","closer","oi","opener","strong","consumed","inner","wrapped","replacement","out","nodes","last","value","markdown","options","protocol"],"sources":["../src/parse.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { sanitizeDestination } from './_policy';\nimport { inlineText } from './_text';\nimport { ScribeLimitError } from './errors';\nimport type {\n ProseAlignment,\n ProseBlock,\n ProseCodeSpan,\n ProseDoc,\n ProseEmphasis,\n ProseHardBreak,\n ProseHeading,\n ProseHeadingLevel,\n ProseImage,\n ProseInline,\n ProseLink,\n ProseList,\n ProseListItem,\n ProseParagraph,\n ProseParseOptions,\n ProseSoftBreak,\n ProseStrikethrough,\n ProseStrong,\n ProseTable,\n ProseTableCell,\n ProseText,\n ProseThematicBreak,\n} from './types';\n\n/** Inputs beyond this size are rejected outright; prose documents never reach it. */\nconst MAX_INPUT_LENGTH = 200_000;\n/** Block/inline nesting (blockquote in list in blockquote …) is bounded to keep recursion shallow. */\nconst MAX_DEPTH = 32;\nconst DEFAULT_PROTOCOLS: readonly string[] = ['http', 'https', 'mailto'];\n\ninterface Ctx {\n depth: number;\n readonly protocols: ReadonlySet<string>;\n}\n\n// ---------------------------------------------------------------------------\n// Block-level patterns (indentation is counted in expanded-tab columns)\n// ---------------------------------------------------------------------------\n\nconst RE_BLANK = /^[ \\t]*$/;\nconst RE_FENCE = /^ {0,3}(`{3,}|~{3,})(.*)$/;\nconst RE_HEADING = /^ {0,3}(#{1,6})(?:[ \\t]+(.*?))?(?:[ \\t]+#+)?[ \\t]*$/;\nconst RE_HR = /^(?: {0,3}(?:\\*[ \\t]*){3,}| {0,3}(?:-[ \\t]*){3,}| {0,3}(?:_[ \\t]*){3,})$/;\nconst RE_QUOTE = /^ {0,3}>[ \\t]?(.*)$/;\nconst RE_UL = /^( {0,3})([-+*])([ \\t]+)(.*)$/;\nconst RE_OL = /^( {0,3})(\\d{1,9})([.)])([ \\t]+)(.*)$/;\nconst RE_TABLE_DELIM = /^[ \\t]*\\|?[ \\t]*:?-+:?[ \\t]*(?:\\|[ \\t]*:?-+:?[ \\t]*)*\\|?[ \\t]*$/;\nconst RE_LANG = /^[\\p{L}\\p{N}_-]+/u;\n\nfunction indentOf(line: string): number {\n let column = 0;\n for (const char of line) {\n if (char === ' ') column += 1;\n else if (char === '\\t') column += 4;\n else break;\n }\n return column;\n}\n\nfunction isTableStart(lines: readonly string[], index: number): boolean {\n return lines[index].includes('|') && lines[index + 1] !== undefined && RE_TABLE_DELIM.test(lines[index + 1]);\n}\n\n/** Split a GFM table row on unescaped pipes, dropping one optional leading/trailing pipe. */\nfunction splitCells(row: string): string[] {\n let text = row.trim();\n if (text.startsWith('|')) text = text.slice(1);\n if (text.endsWith('|') && !text.endsWith('\\\\|')) text = text.slice(0, -1);\n const cells: string[] = [];\n let cell = '';\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i];\n if (char === '\\\\' && text[i + 1] === '|') {\n cell += '|';\n i += 1;\n } else if (char === '|') {\n cells.push(cell.trim());\n cell = '';\n } else {\n cell += char;\n }\n }\n cells.push(cell.trim());\n return cells;\n}\n\nfunction parseDelimAlignments(delimiterRow: string): ProseAlignment[] {\n return splitCells(delimiterRow).map((cell) => {\n if (cell.startsWith(':') && cell.endsWith(':')) return 'center';\n if (cell.endsWith(':')) return 'right';\n return 'left';\n });\n}\n\n// ---------------------------------------------------------------------------\n// Block parser\n// ---------------------------------------------------------------------------\n\nfunction parseBlocks(lines: readonly string[], ctx: Ctx): ProseBlock[] {\n ctx.depth += 1;\n if (ctx.depth > MAX_DEPTH) {\n throw new ScribeLimitError(`block nesting exceeds the ${MAX_DEPTH}-level limit`);\n }\n const blocks: ProseBlock[] = [];\n let paragraph: string[] = [];\n let i = 0;\n\n const flushParagraph = (): void => {\n if (paragraph.length === 0) return;\n const node: ProseParagraph = { children: parseInline(paragraph.join('\\n'), ctx), type: 'paragraph' };\n blocks.push(node);\n paragraph = [];\n };\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (RE_BLANK.test(line)) {\n flushParagraph();\n i += 1;\n continue;\n }\n\n const fence = RE_FENCE.exec(line);\n if (fence) {\n flushParagraph();\n const marker = fence[1];\n const fenceIndent = fence[0].indexOf(marker[0]);\n const lang = RE_LANG.exec(fence[2].trim())?.[0];\n const closeRe = new RegExp(`^ {0,3}\\\\${marker[0]}{${marker.length},}[ \\\\t]*$`);\n const content: string[] = [];\n i += 1;\n while (i < lines.length && !closeRe.test(lines[i])) {\n content.push(lines[i].slice(Math.min(indentOf(lines[i]), fenceIndent)));\n i += 1;\n }\n i += 1; // closing fence (or EOF)\n blocks.push(\n lang === undefined\n ? { text: content.join('\\n'), type: 'codeBlock' }\n : { language: lang, text: content.join('\\n'), type: 'codeBlock' },\n );\n continue;\n }\n\n const heading = RE_HEADING.exec(line);\n if (heading) {\n flushParagraph();\n blocks.push({\n children: parseInline(heading[2] ?? '', ctx),\n level: heading[1].length as ProseHeadingLevel,\n type: 'heading',\n } satisfies ProseHeading);\n i += 1;\n continue;\n }\n\n if (RE_HR.test(line)) {\n flushParagraph();\n blocks.push({ type: 'thematicBreak' } satisfies ProseThematicBreak);\n i += 1;\n continue;\n }\n\n if (RE_QUOTE.test(line)) {\n flushParagraph();\n const quoted: string[] = [];\n while (i < lines.length) {\n const quote = RE_QUOTE.exec(lines[i]);\n if (quote === null) break;\n quoted.push(quote[1]);\n i += 1;\n }\n blocks.push({ children: parseBlocks(quoted, ctx), type: 'blockquote' });\n continue;\n }\n\n const marker = matchListMarker(line);\n // A bullet list, or an ordered list starting at 1, may start (and interrupt a paragraph);\n // a line like `2. more` right below a paragraph is a paragraph continuation.\n if (marker !== null && (!marker.ordered || marker.start === 1 || paragraph.length === 0)) {\n flushParagraph();\n const list = parseList(lines, i, ctx, marker);\n blocks.push(list.block);\n i = list.next;\n continue;\n }\n\n if (paragraph.length === 0 && indentOf(line) >= 4) {\n const content: string[] = [];\n while (i < lines.length && (RE_BLANK.test(lines[i]) || indentOf(lines[i]) >= 4)) {\n if (RE_BLANK.test(lines[i]) && !(i + 1 < lines.length && indentOf(lines[i + 1]) >= 4)) break;\n content.push(lines[i].slice(4));\n i += 1;\n }\n blocks.push({ text: content.join('\\n'), type: 'codeBlock' });\n continue;\n }\n\n if (paragraph.length === 0 && isTableStart(lines, i)) {\n const header = splitCells(lines[i]);\n const alignments = parseDelimAlignments(lines[i + 1]);\n i += 2;\n const rows: ProseTableCell[][] = [];\n while (i < lines.length && !RE_BLANK.test(lines[i]) && lines[i].includes('|')) {\n const cells = splitCells(lines[i]);\n while (cells.length < alignments.length) cells.push('');\n rows.push(cells.slice(0, alignments.length).map((cell) => [...parseInline(cell, ctx)]));\n i += 1;\n }\n blocks.push({\n alignments,\n header: header\n .slice(0, alignments.length)\n .map((cell) => [...parseInline(cell, ctx)]) satisfies ProseTableCell[],\n rows,\n type: 'table',\n } satisfies ProseTable);\n continue;\n }\n\n paragraph.push(line);\n i += 1;\n }\n\n flushParagraph();\n ctx.depth -= 1;\n return blocks;\n}\n\ninterface ListMarker {\n /** Leading spaces before the marker, in expanded columns. */\n readonly indent: number;\n /** The bullet char (`-`, `+`, `*`) or the ordered delimiter (`.` or `)`). */\n readonly kind: string;\n readonly ordered: boolean;\n /** Spaces between marker and content. */\n readonly spaces: number;\n readonly start: number;\n /** Total marker width (`-` = 1, `12.` = 3). */\n readonly width: number;\n}\n\nfunction matchListMarker(line: string): ListMarker | null {\n const ul = RE_UL.exec(line);\n if (ul !== null) {\n return { indent: ul[1].length, kind: ul[2], ordered: false, spaces: ul[3].length, start: 1, width: 1 };\n }\n const ol = RE_OL.exec(line);\n if (ol !== null) {\n return {\n indent: ol[1].length,\n kind: ol[3],\n ordered: true,\n spaces: ol[4].length,\n start: Number(ol[2]),\n width: ol[2].length + 1,\n };\n }\n return null;\n}\n\nfunction sameMarker(a: ListMarker, b: ListMarker): boolean {\n return a.ordered === b.ordered && a.kind === b.kind;\n}\n\nfunction parseList(\n lines: readonly string[],\n start: number,\n ctx: Ctx,\n initial: ListMarker,\n): { block: ProseList; next: number } {\n // Content column after the marker; >=5 spaces after the marker keep an extra indent so the\n // first line can still be an indented code block, matching CommonMark's tab rule.\n const contentIndent = initial.indent + initial.width + (initial.spaces >= 5 ? 1 : initial.spaces);\n\n const items: ProseListItem[] = [];\n let loose = false;\n let pendingBlanks = 0;\n let current: string[] | null = null;\n let i = start;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (RE_BLANK.test(line)) {\n if (current !== null) pendingBlanks += 1;\n i += 1;\n continue;\n }\n\n // A marker strictly left of the content column is a sibling item; one at or beyond the\n // content column is item content (a nested list).\n const marker = indentOf(line) < contentIndent ? matchListMarker(line) : null;\n const isItemStart = marker !== null && sameMarker(marker, initial) && (current === null || i > start);\n\n if (isItemStart && current !== null) {\n if (pendingBlanks > 0) loose = true;\n items.push({ children: parseBlocks(current, ctx), type: 'listItem' });\n current = null;\n }\n\n if (isItemStart) {\n current = [line.slice(contentIndent)];\n pendingBlanks = 0;\n i += 1;\n continue;\n }\n\n if (current !== null && indentOf(line) >= contentIndent) {\n if (pendingBlanks > 0) loose = true;\n pendingBlanks = 0;\n current.push(line.slice(contentIndent));\n i += 1;\n continue;\n }\n\n break; // no lazy continuation: the list ends here\n }\n\n if (current !== null) {\n items.push({ children: parseBlocks(current, ctx), type: 'listItem' });\n }\n\n return {\n block: {\n items,\n ordered: initial.ordered,\n start: initial.start,\n tight: !loose,\n type: 'list',\n } satisfies ProseList,\n next: i,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inline parser\n// ---------------------------------------------------------------------------\n\ninterface DelimTok {\n readonly canClose: boolean;\n readonly canOpen: boolean;\n readonly char: '*' | '_' | '~';\n count: number;\n readonly kind: 'delim';\n}\n\ntype Tok = ProseInline | DelimTok;\n\nconst isDelim = (token: Tok): token is DelimTok => 'kind' in token;\nconst RE_PUNCT = /[\\p{P}\\p{S}]/u;\n\nfunction parseInline(src: string, ctx: Ctx): ProseInline[] {\n ctx.depth += 1;\n if (ctx.depth > MAX_DEPTH) {\n throw new ScribeLimitError(`inline nesting exceeds the ${MAX_DEPTH}-level limit`);\n }\n const tokens: Tok[] = [];\n let buffer = '';\n\n const flush = (): void => {\n if (buffer === '') return;\n tokens.push({ text: buffer, type: 'text' } satisfies ProseText);\n buffer = '';\n };\n\n const linkLike = (at: number): { label: string; dest: string; title?: string; end: number } | null => {\n if (src[at] !== '[') return null;\n let depth = 0;\n let close = -1;\n for (let k = at; k < src.length; k += 1) {\n if (src[k] === '\\\\') k += 1;\n else if (src[k] === '[') depth += 1;\n else if (src[k] === ']') {\n depth -= 1;\n if (depth === 0) {\n close = k;\n break;\n }\n }\n }\n if (close === -1 || src[close + 1] !== '(') return null;\n let j = close + 2;\n let dest = '';\n let title: string | undefined;\n if (src[j] === '<') {\n const angleEnd = src.indexOf('>', j + 1);\n if (angleEnd === -1) return null;\n dest = src.slice(j + 1, angleEnd);\n j = angleEnd + 1;\n } else {\n let parenDepth = 0;\n while (j < src.length && !/\\s/.test(src[j])) {\n if (src[j] === ')' && parenDepth === 0) break;\n if (src[j] === '(') parenDepth += 1;\n else if (src[j] === ')') parenDepth -= 1;\n dest += src[j];\n j += 1;\n }\n }\n const quoted = /^\\s+(['\"])(.*?)\\1\\s*\\)/.exec(src.slice(j));\n if (quoted !== null) {\n title = quoted[2];\n j += quoted[0].length;\n } else {\n const bare = /^\\s*\\)/.exec(src.slice(j));\n if (bare === null) return null;\n j += bare[0].length;\n }\n return { dest, end: j, label: src.slice(at + 1, close), title };\n };\n\n let i = 0;\n while (i < src.length) {\n const char = src[i];\n\n if (char === '\\\\' && RE_PUNCT.test(src[i + 1] ?? '')) {\n buffer += src[i + 1];\n i += 2;\n continue;\n }\n if (char === '\\\\' && src[i + 1] === '\\n') {\n flush();\n tokens.push({ type: 'hardBreak' } satisfies ProseHardBreak);\n i += 2;\n continue;\n }\n\n if (char === '`') {\n let run = 0;\n while (src[i + run] === '`') run += 1;\n const rest = src.slice(i + run);\n const closeRe = new RegExp(`(?<!\\`)\\`{${run}}(?!\\`)`);\n const found = closeRe.exec(rest);\n if (found !== null) {\n let content = rest.slice(0, found.index);\n if (content.length >= 2 && content.startsWith(' ') && content.endsWith(' ') && !/^ +$/.test(content)) {\n content = content.slice(1, -1);\n }\n flush();\n tokens.push({ text: content, type: 'codeSpan' } satisfies ProseCodeSpan);\n i += run + found.index + run;\n continue;\n }\n buffer += '`'.repeat(run);\n i += run;\n continue;\n }\n\n if (char === '<') {\n const email = /^<([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})>/.exec(src.slice(i));\n if (email !== null) {\n const mailto = `mailto:${email[1]}`;\n if (sanitizeDestination(mailto, ctx.protocols) !== null) {\n flush();\n tokens.push({\n children: [{ text: email[1], type: 'text' }],\n href: mailto,\n type: 'link',\n } satisfies ProseLink);\n i += email[0].length;\n continue;\n }\n warn(`rejected autolink destination \"${mailto}\"`);\n }\n const autolink = /^<([A-Za-z][A-Za-z0-9+.-]*:[^<>\\n]*)>/.exec(src.slice(i));\n if (autolink !== null) {\n const href = sanitizeDestination(autolink[1], ctx.protocols);\n if (href !== null) {\n flush();\n tokens.push({\n children: [{ text: autolink[1], type: 'text' }],\n href,\n type: 'link',\n } satisfies ProseLink);\n i += autolink[0].length;\n continue;\n }\n warn(`rejected autolink destination \"${autolink[1]}\"`);\n buffer += '<';\n i += 1;\n continue;\n }\n buffer += '<';\n i += 1;\n continue;\n }\n\n if ((char === '!' && src[i + 1] === '[') || char === '[') {\n const at = char === '!' ? i + 1 : i;\n const parsed = linkLike(at);\n if (parsed !== null) {\n const href = sanitizeDestination(parsed.dest, ctx.protocols);\n flush();\n if (href !== null) {\n if (char === '!') {\n const image: ProseImage = { alt: inlineText(parseInline(parsed.label, ctx)), src: href, type: 'image' };\n tokens.push(parsed.title === undefined ? image : { ...image, title: parsed.title });\n } else {\n const link: ProseLink = { children: parseInline(parsed.label, ctx), href, type: 'link' };\n tokens.push(parsed.title === undefined ? link : { ...link, title: parsed.title });\n }\n } else {\n warn(`rejected link destination \"${parsed.dest}\"`);\n if (char === '!') {\n tokens.push({ text: inlineText(parseInline(parsed.label, ctx)), type: 'text' } satisfies ProseText);\n } else {\n tokens.push(...parseInline(parsed.label, ctx));\n }\n }\n i = parsed.end;\n continue;\n }\n buffer += char;\n i += 1;\n continue;\n }\n\n if (char === '*' || char === '_' || char === '~') {\n let run = 0;\n while (src[i + run] === char) run += 1;\n if (char !== '~' || run === 2) {\n const prev = i === 0 ? ' ' : src[i - 1];\n const next = src[i + run] ?? ' ';\n const leftFlanking = !/\\s/.test(next) && (!RE_PUNCT.test(next) || /\\s/.test(prev) || RE_PUNCT.test(prev));\n const rightFlanking = !/\\s/.test(prev) && (!RE_PUNCT.test(prev) || /\\s/.test(next) || RE_PUNCT.test(next));\n const canOpen = char === '_' ? leftFlanking && (!rightFlanking || RE_PUNCT.test(prev)) : leftFlanking;\n const canClose = char === '_' ? rightFlanking && (!leftFlanking || RE_PUNCT.test(next)) : rightFlanking;\n if (canOpen || canClose) {\n flush();\n tokens.push({ canClose, canOpen, char, count: run, kind: 'delim' });\n i += run;\n continue;\n }\n }\n buffer += char.repeat(run);\n i += run;\n continue;\n }\n\n if ((char === 'h' || char === 'H') && (i === 0 || /[\\s_([{]/.test(src[i - 1]))) {\n const bare = /^https?:\\/\\/\\S+/.exec(src.slice(i));\n if (bare !== null) {\n let url = bare[0].replace(/[.,;:!?]+$/, '');\n if (url.endsWith(')') && !url.includes('(')) url = url.slice(0, -1);\n const href = sanitizeDestination(url, ctx.protocols);\n if (href !== null) {\n flush();\n tokens.push({ children: [{ text: url, type: 'text' }], href, type: 'link' } satisfies ProseLink);\n i += url.length;\n continue;\n }\n }\n }\n\n if (char === '\\n') {\n const trailing = /[ \\t]*$/.exec(buffer)?.[0] ?? '';\n if (trailing !== '') buffer = buffer.slice(0, -trailing.length);\n flush();\n tokens.push(\n (trailing.length >= 2 ? { type: 'hardBreak' } : { type: 'softBreak' }) satisfies\n | ProseHardBreak\n | ProseSoftBreak,\n );\n i += 1;\n continue;\n }\n\n buffer += char;\n i += 1;\n }\n\n flush();\n const resolved = resolveEmphasis(tokens);\n ctx.depth -= 1;\n return mergeText(resolved);\n}\n\n/** Match delimiter runs left-to-right; leftover delimiters become literal text. */\nfunction resolveEmphasis(tokens: Tok[]): ProseInline[] {\n for (let ci = 0; ci < tokens.length; ci += 1) {\n const closer = tokens[ci];\n if (!isDelim(closer) || !closer.canClose || closer.count === 0) continue;\n for (let oi = ci - 1; oi >= 0; oi -= 1) {\n const opener = tokens[oi];\n if (!isDelim(opener) || !opener.canOpen || opener.count === 0 || opener.char !== closer.char) continue;\n if (closer.char === '~' && (opener.count !== 2 || closer.count !== 2)) continue;\n const strong = closer.char !== '~' && opener.count >= 2 && closer.count >= 2;\n const consumed = closer.char === '~' ? 2 : strong ? 2 : 1;\n const inner = resolveRemainder(tokens.slice(oi + 1, ci));\n const wrapped: ProseStrong | ProseEmphasis | ProseStrikethrough = strong\n ? { children: inner, type: 'strong' }\n : closer.char === '~'\n ? { children: inner, type: 'strikethrough' }\n : { children: inner, type: 'emphasis' };\n const replacement: Tok[] = [];\n if (opener.count > consumed) {\n replacement.push({\n canClose: false,\n canOpen: true,\n char: opener.char,\n count: opener.count - consumed,\n kind: 'delim',\n });\n }\n replacement.push(wrapped);\n if (closer.count > consumed) {\n replacement.push({\n canClose: true,\n canOpen: false,\n char: closer.char,\n count: closer.count - consumed,\n kind: 'delim',\n });\n }\n tokens.splice(oi, ci - oi + 1, ...replacement);\n ci = oi - 1;\n break;\n }\n }\n return resolveRemainder(tokens);\n}\n\nfunction resolveRemainder(tokens: readonly Tok[]): ProseInline[] {\n const out: ProseInline[] = [];\n for (const token of tokens) {\n if (isDelim(token)) {\n if (token.count > 0) out.push({ text: token.char.repeat(token.count), type: 'text' });\n continue;\n }\n out.push(token);\n }\n return mergeText(out);\n}\n\nfunction mergeText(nodes: readonly ProseInline[]): ProseInline[] {\n const out: ProseInline[] = [];\n for (const node of nodes) {\n const last = out[out.length - 1];\n if (node.type === 'text' && last !== undefined && last.type === 'text') {\n out[out.length - 1] = { text: last.text + node.text, type: 'text' };\n } else {\n out.push(node);\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object') {\n for (const inner of Object.values(value as Record<string, unknown>)) deepFreeze(inner);\n Object.freeze(value);\n }\n return value;\n}\n\n/**\n * Parse `markdown` into a frozen {@link ProseDoc}.\n *\n * The profile is a fixed GFM-flavored subset: ATX headings, paragraphs, fenced and indented\n * code, blockquotes, ordered/unordered lists, GFM pipe tables, thematic breaks, code spans,\n * emphasis/strong, strikethrough, inline links and images, autolinks (angle-bracket URIs, angle-bracket emails as `mailto:`, and bare `http(s)`),\n * and hard/soft breaks. Raw HTML, reference links, setext headings, HTML entities, footnotes,\n * and task lists are **not** part of the profile: they render as literal text. Tabs are\n * expanded to four spaces. Blockquotes and list items require every line to carry its marker\n * or content indent (no lazy paragraph continuation), and a GFM table must start on its own\n * line after a blank line.\n *\n * Link and image destinations are policy-checked here: relative URLs are always allowed,\n * `data:` is always rejected, and other schemes must appear in `options.linkProtocols`\n * (default `http`, `https`, `mailto`). A rejected destination degrades to the link's label\n * text (or the image's alt text) and logs a dev-only warning; it never throws.\n *\n * @throws {ScribeLimitError} when the input exceeds 200,000 characters or nests beyond\n * 32 block/inline levels.\n */\nexport function parseProse(markdown: string, options: ProseParseOptions = {}): ProseDoc {\n if (markdown.length > MAX_INPUT_LENGTH) {\n throw new ScribeLimitError(`input exceeds the ${MAX_INPUT_LENGTH}-character limit`);\n }\n const ctx: Ctx = {\n depth: 0,\n protocols: new Set((options.linkProtocols ?? DEFAULT_PROTOCOLS).map((protocol) => protocol.toLowerCase())),\n };\n const lines = markdown.replace(/\\r\\n?/g, '\\n').replaceAll('\\t', ' ').split('\\n');\n return deepFreeze({ blocks: parseBlocks(lines, ctx) });\n}\n"],"mappings":"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"}
|
package/dist/render.cjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const e=require("./_policy.cjs"),t=require("./_text.cjs");function titleAttr(t){return t===void 0?``:` title="${e.escapeHtml(t)}"`}function inlineHtml(t){let n=``;for(let r of t)switch(r.type){case`text`:n+=e.escapeHtml(r.text);break;case`codeSpan`:n+=`<code>${e.escapeHtml(r.text)}</code>`;break;case`strong`:n+=`<strong>${inlineHtml(r.children)}</strong>`;break;case`emphasis`:n+=`<em>${inlineHtml(r.children)}</em>`;break;case`strikethrough`:n+=`<del>${inlineHtml(r.children)}</del>`;break;case`link`:n+=`<a href="${e.escapeHtml(r.href)}"${titleAttr(r.title)}>${inlineHtml(r.children)}</a>`;break;case`image`:n+=`<img src="${e.escapeHtml(r.src)}" alt="${e.escapeHtml(r.alt)}"${titleAttr(r.title)}>`;break;case`softBreak`:n+=`
|
|
2
|
+
`;break;case`hardBreak`:n+=`<br />
|
|
3
|
+
`}return n}function headingAttrs(e,n,r){return r?` id="${n.slug(t.inlineText(e))}"`:``}function blocksHtml(t,n,r,i){let a=[];for(let o of t)switch(o.type){case`paragraph`:{let e=inlineHtml(o.children);a.push(i?e:`<p>${e}</p>`);break}case`heading`:{let e=o.level;a.push(`<h${e}${headingAttrs(o.children,n,r)}>${inlineHtml(o.children)}</h${e}>`);break}case`codeBlock`:{let t=o.language===void 0?``:` class="language-${e.escapeHtml(o.language)}"`;a.push(`<pre><code${t}>${e.escapeHtml(o.text)}\n</code></pre>`);break}case`blockquote`:a.push(`<blockquote>\n${blocksHtml(o.children,n,r,!1)}\n</blockquote>`);break;case`list`:{let e=o.ordered?`ol`:`ul`,t=o.ordered&&o.start!==1?` start="${o.start}"`:``,i=o.items.map(e=>`<li>${blocksHtml(e.children,n,r,o.tight)}</li>`).join(`
|
|
4
|
+
`);a.push(`<${e}${t}>\n${i}\n</${e}>`);break}case`thematicBreak`:a.push(`<hr />`);break;case`table`:{let cellAttrs=e=>{let t=o.alignments[e];return t===void 0||t===`left`?``:` align="${t}"`},e=`<tr>${o.header.map((e,t)=>`<th${cellAttrs(t)}>${inlineHtml(e)}</th>`).join(``)}</tr>`,t=o.rows.map(e=>`<tr>${e.map((e,t)=>`<td${cellAttrs(t)}>${inlineHtml(e)}</td>`).join(``)}</tr>`).join(`
|
|
5
|
+
`);a.push(`<table>\n<thead>\n${e}\n</thead>\n<tbody>\n${t.length===0?``:`${t}\n`}</tbody>\n</table>`);break}}return a.join(`
|
|
6
|
+
`)}function renderProseHtml(e,n={}){return blocksHtml(e.blocks,t.createSlugger(),n.headingIds===!0,!1)}function inlineDom(e,t){let n=[];for(let r of t)switch(r.type){case`text`:n.push(e.createTextNode(r.text));break;case`codeSpan`:{let t=e.createElement(`code`);t.append(e.createTextNode(r.text)),n.push(t);break}case`strong`:case`emphasis`:case`strikethrough`:{let t=e.createElement(r.type===`strikethrough`?`del`:r.type===`strong`?`strong`:`em`);t.append(...inlineDom(e,r.children)),n.push(t);break}case`link`:{let t=e.createElement(`a`);t.setAttribute(`href`,r.href),r.title!==void 0&&t.setAttribute(`title`,r.title),t.append(...inlineDom(e,r.children)),n.push(t);break}case`image`:{let t=e.createElement(`img`);t.setAttribute(`src`,r.src),t.setAttribute(`alt`,r.alt),r.title!==void 0&&t.setAttribute(`title`,r.title),n.push(t);break}case`softBreak`:n.push(e.createTextNode(`
|
|
7
|
+
`));break;case`hardBreak`:n.push(e.createElement(`br`))}return n}function blocksDom(e,n,r,i,a){let o=e.createDocumentFragment();for(let s of n)switch(s.type){case`paragraph`:if(a)o.append(...inlineDom(e,s.children));else{let t=e.createElement(`p`);t.append(...inlineDom(e,s.children)),o.append(t)}break;case`heading`:{let n=e.createElement(`h${s.level}`);i&&n.setAttribute(`id`,r.slug(t.inlineText(s.children))),n.append(...inlineDom(e,s.children)),o.append(n);break}case`codeBlock`:{let t=e.createElement(`pre`),n=e.createElement(`code`);s.language!==void 0&&n.classList.add(`language-${s.language}`),n.append(e.createTextNode(s.text)),t.append(n),o.append(t);break}case`blockquote`:{let t=e.createElement(`blockquote`);t.append(blocksDom(e,s.children,r,i,!1)),o.append(t);break}case`list`:{let t=e.createElement(s.ordered?`ol`:`ul`);s.ordered&&s.start!==1&&t.setAttribute(`start`,String(s.start));for(let n of s.items){let a=e.createElement(`li`);a.append(blocksDom(e,n.children,r,i,s.tight)),t.append(a)}o.append(t);break}case`thematicBreak`:o.append(e.createElement(`hr`));break;case`table`:{let t=e.createElement(`table`),n=e.createElement(`thead`),r=e.createElement(`tr`);s.header.forEach((t,n)=>{let i=e.createElement(`th`),a=s.alignments[n];a!==void 0&&a!==`left`&&i.setAttribute(`align`,a),i.append(...inlineDom(e,t)),r.append(i)}),n.append(r);let i=e.createElement(`tbody`);for(let t of s.rows){let n=e.createElement(`tr`);t.forEach((t,r)=>{let i=e.createElement(`td`),a=s.alignments[r];a!==void 0&&a!==`left`&&i.setAttribute(`align`,a),i.append(...inlineDom(e,t)),n.append(i)}),i.append(n)}t.append(n,i),o.append(t);break}}return o}function renderProseDom(e,n={}){return blocksDom(document,e.blocks,t.createSlugger(),n.headingIds===!0,!1)}function blockText(e){switch(e.type){case`paragraph`:return t.inlineText(e.children);case`heading`:return t.inlineText(e.children);case`codeBlock`:return e.text;case`blockquote`:return e.children.map(blockText).join(`
|
|
8
|
+
|
|
9
|
+
`);case`list`:return e.items.map((t,n)=>(e.ordered?`${e.start+n}. `:`- `)+t.children.map(blockText).join(`
|
|
10
|
+
|
|
11
|
+
`)).join(`
|
|
12
|
+
`);case`thematicBreak`:return``;case`table`:return[e.header,...e.rows].map(e=>e.map(e=>t.inlineText(e)).join(` | `)).join(`
|
|
13
|
+
`)}}function proseToText(e){return e.blocks.map(blockText).filter(e=>e!==``).join(`
|
|
14
|
+
|
|
15
|
+
`)}function proseOutline(e,n={}){return t.collectOutline(e.blocks,t.createSlugger(),n.maxLevel??6)}exports.proseOutline=proseOutline,exports.proseToText=proseToText,exports.renderProseDom=renderProseDom,exports.renderProseHtml=renderProseHtml;
|
|
16
|
+
//# sourceMappingURL=render.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.cjs","names":["escapeHtml","inlineText","createSlugger","collectOutline","require__policy","require__text","title","out","node","nodes","emitIds","slugger","children","parts","block","blocks","inner","unwrapParagraphs","level","cls","tag","startAttr","items","item","alignment","index","headerRow","cell","bodyRows","row","prose","options","doc","code","element","anchor","image","fragment","p","heading","pre","quote","list","li","table","thead","th","tbody","tr","td","text"],"sources":["../src/render.ts"],"sourcesContent":["import { escapeHtml } from './_policy';\nimport { collectOutline, createSlugger, inlineText, type ProseSlugger } from './_text';\nimport type {\n ProseBlock,\n ProseDoc,\n ProseInline,\n ProseOutlineEntry,\n ProseOutlineOptions,\n ProseRenderOptions,\n} from './types';\n\nfunction titleAttr(title: string | undefined): string {\n return title === undefined ? '' : ` title=\"${escapeHtml(title)}\"`;\n}\n\nfunction inlineHtml(nodes: readonly ProseInline[]): string {\n let out = '';\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n out += escapeHtml(node.text);\n break;\n case 'codeSpan':\n out += `<code>${escapeHtml(node.text)}</code>`;\n break;\n case 'strong':\n out += `<strong>${inlineHtml(node.children)}</strong>`;\n break;\n case 'emphasis':\n out += `<em>${inlineHtml(node.children)}</em>`;\n break;\n case 'strikethrough':\n out += `<del>${inlineHtml(node.children)}</del>`;\n break;\n case 'link':\n out += `<a href=\"${escapeHtml(node.href)}\"${titleAttr(node.title)}>${inlineHtml(node.children)}</a>`;\n break;\n case 'image':\n out += `<img src=\"${escapeHtml(node.src)}\" alt=\"${escapeHtml(node.alt)}\"${titleAttr(node.title)}>`;\n break;\n case 'softBreak':\n out += '\\n';\n break;\n case 'hardBreak':\n out += '<br />\\n';\n break;\n }\n }\n return out;\n}\n\nfunction headingAttrs(children: readonly ProseInline[], slugger: ProseSlugger, emitIds: boolean): string {\n return emitIds ? ` id=\"${slugger.slug(inlineText(children))}\"` : '';\n}\n\nfunction blocksHtml(\n blocks: readonly ProseBlock[],\n slugger: ProseSlugger,\n emitIds: boolean,\n unwrapParagraphs: boolean,\n): string {\n const parts: string[] = [];\n for (const block of blocks) {\n switch (block.type) {\n case 'paragraph': {\n const inner = inlineHtml(block.children);\n parts.push(unwrapParagraphs ? inner : `<p>${inner}</p>`);\n break;\n }\n case 'heading': {\n const level = block.level;\n parts.push(\n `<h${level}${headingAttrs(block.children, slugger, emitIds)}>${inlineHtml(block.children)}</h${level}>`,\n );\n break;\n }\n case 'codeBlock': {\n const cls = block.language === undefined ? '' : ` class=\"language-${escapeHtml(block.language)}\"`;\n parts.push(`<pre><code${cls}>${escapeHtml(block.text)}\\n</code></pre>`);\n break;\n }\n case 'blockquote':\n parts.push(`<blockquote>\\n${blocksHtml(block.children, slugger, emitIds, false)}\\n</blockquote>`);\n break;\n case 'list': {\n const tag = block.ordered ? 'ol' : 'ul';\n const startAttr = block.ordered && block.start !== 1 ? ` start=\"${block.start}\"` : '';\n const items = block.items\n .map((item) => `<li>${blocksHtml(item.children, slugger, emitIds, block.tight)}</li>`)\n .join('\\n');\n parts.push(`<${tag}${startAttr}>\\n${items}\\n</${tag}>`);\n break;\n }\n case 'thematicBreak':\n parts.push('<hr />');\n break;\n case 'table': {\n const cellAttrs = (index: number): string => {\n const alignment = block.alignments[index];\n return alignment === undefined || alignment === 'left' ? '' : ` align=\"${alignment}\"`;\n };\n const headerRow = `<tr>${block.header\n .map((cell, index) => `<th${cellAttrs(index)}>${inlineHtml(cell)}</th>`)\n .join('')}</tr>`;\n const bodyRows = block.rows\n .map(\n (row) => `<tr>${row.map((cell, index) => `<td${cellAttrs(index)}>${inlineHtml(cell)}</td>`).join('')}</tr>`,\n )\n .join('\\n');\n parts.push(\n `<table>\\n<thead>\\n${headerRow}\\n</thead>\\n<tbody>\\n${bodyRows.length === 0 ? '' : `${bodyRows}\\n`}</tbody>\\n</table>`,\n );\n break;\n }\n }\n }\n return parts.join('\\n');\n}\n\n/**\n * Render a parsed document to an HTML string. Every dynamic value is escaped; the only tags\n * emitted are the fixed set the renderer itself writes. Pair with a Content-Security-Policy\n * that disallows inline handlers for defense in depth — the string itself carries none.\n *\n * Requires a browser (or DOM) environment for {@link renderProseDom}; Node can use this\n * string renderer directly.\n */\nexport function renderProseHtml(prose: ProseDoc, options: ProseRenderOptions = {}): string {\n return blocksHtml(prose.blocks, createSlugger(), options.headingIds === true, false);\n}\n\nfunction inlineDom(doc: Document, nodes: readonly ProseInline[]): (Element | Text)[] {\n const out: (Element | Text)[] = [];\n for (const node of nodes) {\n switch (node.type) {\n case 'text':\n out.push(doc.createTextNode(node.text));\n break;\n case 'codeSpan': {\n const code = doc.createElement('code');\n code.append(doc.createTextNode(node.text));\n out.push(code);\n break;\n }\n case 'strong':\n case 'emphasis':\n case 'strikethrough': {\n const element = doc.createElement(\n node.type === 'strikethrough' ? 'del' : node.type === 'strong' ? 'strong' : 'em',\n );\n element.append(...inlineDom(doc, node.children));\n out.push(element);\n break;\n }\n case 'link': {\n const anchor = doc.createElement('a');\n anchor.setAttribute('href', node.href);\n if (node.title !== undefined) anchor.setAttribute('title', node.title);\n anchor.append(...inlineDom(doc, node.children));\n out.push(anchor);\n break;\n }\n case 'image': {\n const image = doc.createElement('img');\n image.setAttribute('src', node.src);\n image.setAttribute('alt', node.alt);\n if (node.title !== undefined) image.setAttribute('title', node.title);\n out.push(image);\n break;\n }\n case 'softBreak':\n out.push(doc.createTextNode('\\n'));\n break;\n case 'hardBreak':\n out.push(doc.createElement('br'));\n break;\n }\n }\n return out;\n}\n\nfunction blocksDom(\n doc: Document,\n blocks: readonly ProseBlock[],\n slugger: ProseSlugger,\n emitIds: boolean,\n unwrapParagraphs: boolean,\n): DocumentFragment {\n const fragment = doc.createDocumentFragment();\n for (const block of blocks) {\n switch (block.type) {\n case 'paragraph': {\n if (unwrapParagraphs) {\n fragment.append(...inlineDom(doc, block.children));\n } else {\n const p = doc.createElement('p');\n p.append(...inlineDom(doc, block.children));\n fragment.append(p);\n }\n break;\n }\n case 'heading': {\n const heading = doc.createElement(`h${block.level}`);\n if (emitIds) heading.setAttribute('id', slugger.slug(inlineText(block.children)));\n heading.append(...inlineDom(doc, block.children));\n fragment.append(heading);\n break;\n }\n case 'codeBlock': {\n const pre = doc.createElement('pre');\n const code = doc.createElement('code');\n if (block.language !== undefined) code.classList.add(`language-${block.language}`);\n code.append(doc.createTextNode(block.text));\n pre.append(code);\n fragment.append(pre);\n break;\n }\n case 'blockquote': {\n const quote = doc.createElement('blockquote');\n quote.append(blocksDom(doc, block.children, slugger, emitIds, false));\n fragment.append(quote);\n break;\n }\n case 'list': {\n const list = doc.createElement(block.ordered ? 'ol' : 'ul');\n if (block.ordered && block.start !== 1) list.setAttribute('start', String(block.start));\n for (const item of block.items) {\n const li = doc.createElement('li');\n li.append(blocksDom(doc, item.children, slugger, emitIds, block.tight));\n list.append(li);\n }\n fragment.append(list);\n break;\n }\n case 'thematicBreak':\n fragment.append(doc.createElement('hr'));\n break;\n case 'table': {\n const table = doc.createElement('table');\n const thead = doc.createElement('thead');\n const headerRow = doc.createElement('tr');\n block.header.forEach((cell, index) => {\n const th = doc.createElement('th');\n const alignment = block.alignments[index];\n if (alignment !== undefined && alignment !== 'left') th.setAttribute('align', alignment);\n th.append(...inlineDom(doc, cell));\n headerRow.append(th);\n });\n thead.append(headerRow);\n const tbody = doc.createElement('tbody');\n for (const row of block.rows) {\n const tr = doc.createElement('tr');\n row.forEach((cell, index) => {\n const td = doc.createElement('td');\n const alignment = block.alignments[index];\n if (alignment !== undefined && alignment !== 'left') td.setAttribute('align', alignment);\n td.append(...inlineDom(doc, cell));\n tr.append(td);\n });\n tbody.append(tr);\n }\n table.append(thead, tbody);\n fragment.append(table);\n break;\n }\n }\n }\n return fragment;\n}\n\n/**\n * Render a parsed document to a `DocumentFragment`. Text reaches the DOM exclusively through\n * `createTextNode`, so document content can never execute: no `innerHTML`, no attribute is ever\n * sourced from Markdown beyond `href`/`src`/`alt`/`title`/slug `id`s, and those already passed\n * the parse-time protocol policy. Requires a DOM environment.\n */\nexport function renderProseDom(prose: ProseDoc, options: ProseRenderOptions = {}): DocumentFragment {\n return blocksDom(document, prose.blocks, createSlugger(), options.headingIds === true, false);\n}\n\nfunction blockText(block: ProseBlock): string {\n switch (block.type) {\n case 'paragraph':\n return inlineText(block.children);\n case 'heading':\n return inlineText(block.children);\n case 'codeBlock':\n return block.text;\n case 'blockquote':\n return block.children.map(blockText).join('\\n\\n');\n case 'list':\n return block.items\n .map((item, index) => {\n const marker = block.ordered ? `${block.start + index}. ` : '- ';\n return marker + item.children.map(blockText).join('\\n\\n');\n })\n .join('\\n');\n case 'thematicBreak':\n return '';\n case 'table': {\n const rows = [block.header, ...block.rows].map((row) => row.map((cell) => inlineText(cell)).join(' | '));\n return rows.join('\\n');\n }\n }\n}\n\n/**\n * Render the document as plain text: for notifications, search indexing, and previews.\n * Links keep their label text, images their alt text.\n */\nexport function proseToText(prose: ProseDoc): string {\n return prose.blocks\n .map(blockText)\n .filter((text) => text !== '')\n .join('\\n\\n');\n}\n\n/**\n * The document's headings with stable slug ids, traversed exactly as `renderProse*` does with\n * `headingIds` (including headings nested in blockquotes and lists), so outline ids always\n * match the rendered document. Use for tables of contents.\n */\nexport function proseOutline(prose: ProseDoc, options: ProseOutlineOptions = {}): readonly ProseOutlineEntry[] {\n return collectOutline(prose.blocks, createSlugger(), options.maxLevel ?? 6);\n}\n"],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ProseDoc, ProseOutlineEntry, ProseOutlineOptions, ProseRenderOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Render a parsed document to an HTML string. Every dynamic value is escaped; the only tags
|
|
4
|
+
* emitted are the fixed set the renderer itself writes. Pair with a Content-Security-Policy
|
|
5
|
+
* that disallows inline handlers for defense in depth — the string itself carries none.
|
|
6
|
+
*
|
|
7
|
+
* Requires a browser (or DOM) environment for {@link renderProseDom}; Node can use this
|
|
8
|
+
* string renderer directly.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderProseHtml(prose: ProseDoc, options?: ProseRenderOptions): string;
|
|
11
|
+
/**
|
|
12
|
+
* Render a parsed document to a `DocumentFragment`. Text reaches the DOM exclusively through
|
|
13
|
+
* `createTextNode`, so document content can never execute: no `innerHTML`, no attribute is ever
|
|
14
|
+
* sourced from Markdown beyond `href`/`src`/`alt`/`title`/slug `id`s, and those already passed
|
|
15
|
+
* the parse-time protocol policy. Requires a DOM environment.
|
|
16
|
+
*/
|
|
17
|
+
export declare function renderProseDom(prose: ProseDoc, options?: ProseRenderOptions): DocumentFragment;
|
|
18
|
+
/**
|
|
19
|
+
* Render the document as plain text: for notifications, search indexing, and previews.
|
|
20
|
+
* Links keep their label text, images their alt text.
|
|
21
|
+
*/
|
|
22
|
+
export declare function proseToText(prose: ProseDoc): string;
|
|
23
|
+
/**
|
|
24
|
+
* The document's headings with stable slug ids, traversed exactly as `renderProse*` does with
|
|
25
|
+
* `headingIds` (including headings nested in blockquotes and lists), so outline ids always
|
|
26
|
+
* match the rendered document. Use for tables of contents.
|
|
27
|
+
*/
|
|
28
|
+
export declare function proseOutline(prose: ProseDoc, options?: ProseOutlineOptions): readonly ProseOutlineEntry[];
|
|
29
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,QAAQ,EAER,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AA8GjB;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAEzF;AA6ID;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,kBAAuB,GAAG,gBAAgB,CAElG;AA4BD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAKnD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAE,mBAAwB,GAAG,SAAS,iBAAiB,EAAE,CAE7G"}
|