@orkestrel/markdown 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.cjs +803 -272
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1459 -8
- package/dist/src/core/index.d.ts +1459 -8
- package/dist/src/core/index.js +803 -272
- package/dist/src/core/index.js.map +1 -1
- package/package.json +17 -13
- package/dist/src/core/Markdown.d.ts +0 -86
- package/dist/src/core/constants.d.ts +0 -17
- package/dist/src/core/factories.d.ts +0 -92
- package/dist/src/core/helpers.d.ts +0 -451
- package/dist/src/core/parsers.d.ts +0 -66
- package/dist/src/core/shapers.d.ts +0 -105
- package/dist/src/core/types.d.ts +0 -269
- package/dist/src/core/validators.d.ts +0 -287
package/dist/src/core/index.js
CHANGED
|
@@ -862,15 +862,6 @@ function scanInline(source, from, to, depth = 0) {
|
|
|
862
862
|
const nodes = [];
|
|
863
863
|
let index = from;
|
|
864
864
|
let pending = "";
|
|
865
|
-
const flush = () => {
|
|
866
|
-
if (pending.length > 0) {
|
|
867
|
-
nodes.push({
|
|
868
|
-
element: "text",
|
|
869
|
-
value: pending
|
|
870
|
-
});
|
|
871
|
-
pending = "";
|
|
872
|
-
}
|
|
873
|
-
};
|
|
874
865
|
while (index < to) {
|
|
875
866
|
const character = source[index] ?? "";
|
|
876
867
|
if (character === "\\" && index + 1 < to && isEscapable(source[index + 1] ?? "")) {
|
|
@@ -878,40 +869,51 @@ function scanInline(source, from, to, depth = 0) {
|
|
|
878
869
|
index += 2;
|
|
879
870
|
continue;
|
|
880
871
|
}
|
|
872
|
+
let scanned;
|
|
873
|
+
let end = index;
|
|
881
874
|
if (character === "`") {
|
|
882
875
|
const span = scanCode(source, index, to);
|
|
883
876
|
if (span) {
|
|
884
|
-
|
|
885
|
-
nodes.push({
|
|
877
|
+
scanned = {
|
|
886
878
|
element: "codeSpan",
|
|
887
879
|
value: span.value
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
continue;
|
|
880
|
+
};
|
|
881
|
+
end = span.end;
|
|
891
882
|
}
|
|
892
883
|
}
|
|
893
884
|
if (character === "[") {
|
|
894
885
|
const link = scanLink(source, index, to, depth);
|
|
895
886
|
if (link) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
index = link.end;
|
|
899
|
-
continue;
|
|
887
|
+
scanned = link.node;
|
|
888
|
+
end = link.end;
|
|
900
889
|
}
|
|
901
890
|
}
|
|
902
891
|
if (character === "*" || character === "_") {
|
|
903
892
|
const emphasis = scanEmphasis(source, index, to, depth);
|
|
904
893
|
if (emphasis) {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
index = emphasis.end;
|
|
908
|
-
continue;
|
|
894
|
+
scanned = emphasis.node;
|
|
895
|
+
end = emphasis.end;
|
|
909
896
|
}
|
|
910
897
|
}
|
|
898
|
+
if (scanned !== void 0) {
|
|
899
|
+
if (pending.length > 0) {
|
|
900
|
+
nodes.push({
|
|
901
|
+
element: "text",
|
|
902
|
+
value: pending
|
|
903
|
+
});
|
|
904
|
+
pending = "";
|
|
905
|
+
}
|
|
906
|
+
nodes.push(scanned);
|
|
907
|
+
index = end;
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
911
910
|
pending += character;
|
|
912
911
|
index += 1;
|
|
913
912
|
}
|
|
914
|
-
|
|
913
|
+
if (pending.length > 0) nodes.push({
|
|
914
|
+
element: "text",
|
|
915
|
+
value: pending
|
|
916
|
+
});
|
|
915
917
|
return nodes;
|
|
916
918
|
}
|
|
917
919
|
/**
|
|
@@ -970,10 +972,7 @@ function sanitizeUrl(href) {
|
|
|
970
972
|
* @remarks
|
|
971
973
|
* Total: never throws. At {@link MAX_DEPTH} a value-bearing node (`text` / `codeSpan`)
|
|
972
974
|
* degrades to its escaped `value`; any other node degrades to `''` instead of
|
|
973
|
-
* recursing further, so pathologically deep input cannot exhaust the call stack.
|
|
974
|
-
* recursive engine and its per-shape sub-steps (inline concatenation, table cell,
|
|
975
|
-
* tight list-item) are nested inner functions - the only exported surface is
|
|
976
|
-
* `renderHTML` itself.
|
|
975
|
+
* recursing further, so pathologically deep input cannot exhaust the call stack.
|
|
977
976
|
*
|
|
978
977
|
* @param node - The AST node to render (a full document, or any sub-node)
|
|
979
978
|
* @returns The rendered, XSS-safe HTML string
|
|
@@ -987,47 +986,158 @@ function sanitizeUrl(href) {
|
|
|
987
986
|
* ```
|
|
988
987
|
*/
|
|
989
988
|
function renderHTML(node) {
|
|
990
|
-
|
|
991
|
-
|
|
989
|
+
const stack = [{
|
|
990
|
+
node,
|
|
991
|
+
depth: 0,
|
|
992
|
+
expanded: false,
|
|
993
|
+
count: 0
|
|
994
|
+
}];
|
|
995
|
+
const values = [];
|
|
996
|
+
while (stack.length > 0) {
|
|
997
|
+
const frame = stack.pop();
|
|
998
|
+
if (frame === void 0) continue;
|
|
999
|
+
const current = frame.node;
|
|
1000
|
+
if (!frame.expanded) {
|
|
1001
|
+
if (frame.depth >= 64) {
|
|
1002
|
+
values.push("value" in current && typeof current.value === "string" ? escapeHtml(current.value) : "");
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
const children = [];
|
|
1006
|
+
let depth = frame.depth + 1;
|
|
1007
|
+
switch (current.element) {
|
|
1008
|
+
case "document":
|
|
1009
|
+
case "heading":
|
|
1010
|
+
case "paragraph":
|
|
1011
|
+
case "blockquote":
|
|
1012
|
+
for (const child of current.children) if (child !== void 0) children.push(child);
|
|
1013
|
+
break;
|
|
1014
|
+
case "listItem": {
|
|
1015
|
+
const only = current.children[0];
|
|
1016
|
+
if (current.children.length === 1 && only !== void 0 && only.element === "paragraph") {
|
|
1017
|
+
for (const child of only.children) if (child !== void 0) children.push(child);
|
|
1018
|
+
} else for (const child of current.children) if (child !== void 0) children.push(child);
|
|
1019
|
+
break;
|
|
1020
|
+
}
|
|
1021
|
+
case "emphasis":
|
|
1022
|
+
case "link":
|
|
1023
|
+
for (const child of current.children) if (child !== void 0) children.push(child);
|
|
1024
|
+
depth += 1;
|
|
1025
|
+
break;
|
|
1026
|
+
case "list":
|
|
1027
|
+
for (const child of current.items) if (child !== void 0) children.push(child);
|
|
1028
|
+
break;
|
|
1029
|
+
case "table":
|
|
1030
|
+
for (const cell of current.header) if (cell !== void 0) {
|
|
1031
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1032
|
+
}
|
|
1033
|
+
for (const row of current.rows) if (row !== void 0) {
|
|
1034
|
+
for (const cell of row) if (cell !== void 0) {
|
|
1035
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
depth += 1;
|
|
1039
|
+
break;
|
|
1040
|
+
}
|
|
1041
|
+
stack.push({
|
|
1042
|
+
...frame,
|
|
1043
|
+
expanded: true,
|
|
1044
|
+
count: children.length
|
|
1045
|
+
});
|
|
1046
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
1047
|
+
const child = children[index];
|
|
1048
|
+
if (child !== void 0) stack.push({
|
|
1049
|
+
node: child,
|
|
1050
|
+
depth,
|
|
1051
|
+
expanded: false,
|
|
1052
|
+
count: 0
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
|
|
1058
|
+
let value = "";
|
|
992
1059
|
switch (current.element) {
|
|
993
|
-
case "document":
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
case "
|
|
997
|
-
|
|
998
|
-
|
|
1060
|
+
case "document":
|
|
1061
|
+
value = children.join("\n");
|
|
1062
|
+
break;
|
|
1063
|
+
case "heading":
|
|
1064
|
+
value = `<h${current.level}>${children.join("")}</h${current.level}>`;
|
|
1065
|
+
break;
|
|
1066
|
+
case "paragraph":
|
|
1067
|
+
value = `<p>${children.join("")}</p>`;
|
|
1068
|
+
break;
|
|
1069
|
+
case "thematicBreak":
|
|
1070
|
+
value = "<hr>";
|
|
1071
|
+
break;
|
|
1072
|
+
case "blockquote":
|
|
1073
|
+
value = `<blockquote>\n${children.join("\n")}\n</blockquote>`;
|
|
1074
|
+
break;
|
|
1075
|
+
case "codeBlock":
|
|
1076
|
+
value = `<pre>${current.lang === void 0 ? "<code>" : `<code class="language-${escapeHtml(current.lang)}">`}${escapeHtml(current.code)}</code></pre>`;
|
|
1077
|
+
break;
|
|
999
1078
|
case "list": {
|
|
1000
|
-
const items =
|
|
1001
|
-
if (!current.ordered)
|
|
1002
|
-
|
|
1079
|
+
const items = children.join("\n");
|
|
1080
|
+
if (!current.ordered) {
|
|
1081
|
+
value = `<ul>\n${items}\n</ul>`;
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
value = `<ol${current.start !== 1 ? ` start="${current.start}"` : ""}>\n${items}\n</ol>`;
|
|
1085
|
+
break;
|
|
1003
1086
|
}
|
|
1004
|
-
case "listItem":
|
|
1087
|
+
case "listItem":
|
|
1088
|
+
value = `<li>${children.join(current.children.length === 1 && current.children[0]?.element === "paragraph" ? "" : "\n")}</li>`;
|
|
1089
|
+
break;
|
|
1005
1090
|
case "table": {
|
|
1006
|
-
|
|
1007
|
-
const
|
|
1008
|
-
|
|
1091
|
+
let offset = 0;
|
|
1092
|
+
const header = [];
|
|
1093
|
+
for (const [column, cell] of current.header.entries()) {
|
|
1094
|
+
if (cell === void 0) continue;
|
|
1095
|
+
const align = current.align[column];
|
|
1096
|
+
const style = align === "left" || align === "right" || align === "center" ? ` style="text-align:${align}"` : "";
|
|
1097
|
+
let count = 0;
|
|
1098
|
+
for (const child of cell) if (child !== void 0) count += 1;
|
|
1099
|
+
header.push(`<th${style}>${children.slice(offset, offset + count).join("")}</th>`);
|
|
1100
|
+
offset += count;
|
|
1101
|
+
}
|
|
1102
|
+
const rows = [];
|
|
1103
|
+
for (const row of current.rows) {
|
|
1104
|
+
const cells = [];
|
|
1105
|
+
for (const [column, cell] of row.entries()) {
|
|
1106
|
+
if (cell === void 0) continue;
|
|
1107
|
+
const align = current.align[column];
|
|
1108
|
+
const style = align === "left" || align === "right" || align === "center" ? ` style="text-align:${align}"` : "";
|
|
1109
|
+
let count = 0;
|
|
1110
|
+
for (const child of cell) if (child !== void 0) count += 1;
|
|
1111
|
+
cells.push(`<td${style}>${children.slice(offset, offset + count).join("")}</td>`);
|
|
1112
|
+
offset += count;
|
|
1113
|
+
}
|
|
1114
|
+
rows.push(`<tr>${cells.join("")}</tr>`);
|
|
1115
|
+
}
|
|
1116
|
+
const body = rows.join("\n");
|
|
1117
|
+
const bodyHtml = isNonEmptyArray(current.rows) ? `\n<tbody>\n${body}\n</tbody>` : "";
|
|
1118
|
+
value = `<table>\n<thead>\n<tr>${header.join("")}</tr>\n</thead>${bodyHtml}\n</table>`;
|
|
1119
|
+
break;
|
|
1009
1120
|
}
|
|
1010
|
-
case "text":
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
case "
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
const only = children[0];
|
|
1026
|
-
if (only !== void 0 && only.element === "paragraph") return renderInline(only.children, depth);
|
|
1121
|
+
case "text":
|
|
1122
|
+
value = escapeHtml(current.value);
|
|
1123
|
+
break;
|
|
1124
|
+
case "emphasis":
|
|
1125
|
+
value = current.strong ? `<strong>${children.join("")}</strong>` : `<em>${children.join("")}</em>`;
|
|
1126
|
+
break;
|
|
1127
|
+
case "codeSpan":
|
|
1128
|
+
value = `<code>${escapeHtml(current.value)}</code>`;
|
|
1129
|
+
break;
|
|
1130
|
+
case "link":
|
|
1131
|
+
value = `<a href="${sanitizeUrl(current.href)}">${children.join("")}</a>`;
|
|
1132
|
+
break;
|
|
1133
|
+
default:
|
|
1134
|
+
value = "";
|
|
1135
|
+
break;
|
|
1027
1136
|
}
|
|
1028
|
-
|
|
1137
|
+
if (stack.length === 0) return value;
|
|
1138
|
+
values.push(value);
|
|
1029
1139
|
}
|
|
1030
|
-
return
|
|
1140
|
+
return "";
|
|
1031
1141
|
}
|
|
1032
1142
|
/**
|
|
1033
1143
|
* Render a {@link MarkdownNode} to its CANONICAL markdown source - the inverse
|
|
@@ -1057,125 +1167,220 @@ function renderHTML(node) {
|
|
|
1057
1167
|
* ```
|
|
1058
1168
|
*/
|
|
1059
1169
|
function renderMarkdown(node) {
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1170
|
+
const stack = [{
|
|
1171
|
+
node,
|
|
1172
|
+
depth: 0,
|
|
1173
|
+
expanded: false,
|
|
1174
|
+
count: 0,
|
|
1175
|
+
escaped: ""
|
|
1176
|
+
}];
|
|
1177
|
+
const values = [];
|
|
1178
|
+
while (stack.length > 0) {
|
|
1179
|
+
const frame = stack.pop();
|
|
1180
|
+
if (frame === void 0) continue;
|
|
1181
|
+
const current = frame.node;
|
|
1182
|
+
if (!frame.expanded) {
|
|
1183
|
+
let escaped = "";
|
|
1184
|
+
if ((frame.depth >= 64 || current.element === "text") && "value" in current && typeof current.value === "string") for (let index = 0; index < current.value.length; index += 1) {
|
|
1185
|
+
const character = current.value[index] ?? "";
|
|
1186
|
+
const atLineStart = index === 0 || current.value[index - 1] === "\n";
|
|
1187
|
+
if (character === "\\" || character === "*" || character === "_" || character === "`" || character === "[" || character === "]") {
|
|
1188
|
+
escaped += `\\${character}`;
|
|
1072
1189
|
continue;
|
|
1073
1190
|
}
|
|
1074
|
-
if (
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
const marker = value[end];
|
|
1082
|
-
if ((marker === "." || marker === ")") && value[end + 1] === " ") {
|
|
1083
|
-
out += `${value.slice(index, end)}\\${marker}`;
|
|
1084
|
-
index = end;
|
|
1191
|
+
if (atLineStart) {
|
|
1192
|
+
if (character === "#" || character === ">") {
|
|
1193
|
+
escaped += `\\${character}`;
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if ((character === "-" || character === "+") && (current.value[index + 1] ?? " ") === " ") {
|
|
1197
|
+
escaped += `\\${character}`;
|
|
1085
1198
|
continue;
|
|
1086
1199
|
}
|
|
1200
|
+
if (/[0-9]/.test(character)) {
|
|
1201
|
+
let end = index;
|
|
1202
|
+
while (end < current.value.length && /[0-9]/.test(current.value[end] ?? "")) end += 1;
|
|
1203
|
+
const marker = current.value[end];
|
|
1204
|
+
if ((marker === "." || marker === ")") && current.value[end + 1] === " ") {
|
|
1205
|
+
escaped += `${current.value.slice(index, end)}\\${marker}`;
|
|
1206
|
+
index = end;
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1087
1210
|
}
|
|
1211
|
+
escaped += character;
|
|
1212
|
+
}
|
|
1213
|
+
if (frame.depth >= 64) {
|
|
1214
|
+
values.push(escaped);
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
const children = [];
|
|
1218
|
+
let depth = frame.depth + 1;
|
|
1219
|
+
switch (current.element) {
|
|
1220
|
+
case "document":
|
|
1221
|
+
case "heading":
|
|
1222
|
+
case "paragraph":
|
|
1223
|
+
case "blockquote":
|
|
1224
|
+
case "listItem":
|
|
1225
|
+
case "emphasis":
|
|
1226
|
+
case "link":
|
|
1227
|
+
for (const child of current.children) if (child !== void 0) children.push(child);
|
|
1228
|
+
break;
|
|
1229
|
+
case "list":
|
|
1230
|
+
for (const child of current.items) if (child !== void 0) children.push(child);
|
|
1231
|
+
break;
|
|
1232
|
+
case "table":
|
|
1233
|
+
for (const cell of current.header) if (cell !== void 0) {
|
|
1234
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1235
|
+
}
|
|
1236
|
+
for (const row of current.rows) {
|
|
1237
|
+
if (row === void 0) continue;
|
|
1238
|
+
for (let column = 0; column < current.header.length; column += 1) {
|
|
1239
|
+
const cell = row[column];
|
|
1240
|
+
if (cell !== void 0) {
|
|
1241
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
depth += 1;
|
|
1246
|
+
break;
|
|
1247
|
+
}
|
|
1248
|
+
stack.push({
|
|
1249
|
+
...frame,
|
|
1250
|
+
expanded: true,
|
|
1251
|
+
count: children.length,
|
|
1252
|
+
escaped
|
|
1253
|
+
});
|
|
1254
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
1255
|
+
const child = children[index];
|
|
1256
|
+
if (child !== void 0) stack.push({
|
|
1257
|
+
node: child,
|
|
1258
|
+
depth,
|
|
1259
|
+
expanded: false,
|
|
1260
|
+
count: 0,
|
|
1261
|
+
escaped: ""
|
|
1262
|
+
});
|
|
1088
1263
|
}
|
|
1089
|
-
|
|
1264
|
+
continue;
|
|
1090
1265
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
function fenceFor(body, minimum) {
|
|
1094
|
-
let longest = 0;
|
|
1095
|
-
let run = 0;
|
|
1096
|
-
for (const character of body) if (character === "`") {
|
|
1097
|
-
run += 1;
|
|
1098
|
-
longest = Math.max(longest, run);
|
|
1099
|
-
} else run = 0;
|
|
1100
|
-
return "`".repeat(Math.max(minimum, longest + 1));
|
|
1101
|
-
}
|
|
1102
|
-
function renderInline(nodes, depth) {
|
|
1103
|
-
return nodes.map((child) => render(child, depth + 1)).join("");
|
|
1104
|
-
}
|
|
1105
|
-
function renderBlocks(blocks, depth) {
|
|
1106
|
-
return blocks.map((block) => render(block, depth + 1)).join("\n\n");
|
|
1107
|
-
}
|
|
1108
|
-
function renderItem(item, marker, depth) {
|
|
1109
|
-
const body = renderBlocks(item.children, depth + 1);
|
|
1110
|
-
const pad = " ".repeat(marker.length);
|
|
1111
|
-
return body.split("\n").map((line, index) => index === 0 ? marker + line : line === "" ? "" : pad + line).join("\n");
|
|
1112
|
-
}
|
|
1113
|
-
function renderCell(cell, depth) {
|
|
1114
|
-
return renderInline(cell, depth + 1).replace(/\|/g, "\\|");
|
|
1115
|
-
}
|
|
1116
|
-
function renderTable(current, depth) {
|
|
1117
|
-
const columns = current.header.length;
|
|
1118
|
-
return [
|
|
1119
|
-
`| ${current.header.map((cell) => renderCell(cell, depth)).join(" | ")} |`,
|
|
1120
|
-
`| ${current.align.map((align) => {
|
|
1121
|
-
if (align === "left") return ":--";
|
|
1122
|
-
if (align === "right") return "--:";
|
|
1123
|
-
if (align === "center") return ":-:";
|
|
1124
|
-
return "---";
|
|
1125
|
-
}).join(" | ")} |`,
|
|
1126
|
-
...current.rows.map((row) => {
|
|
1127
|
-
const cells = [];
|
|
1128
|
-
for (let column = 0; column < columns; column += 1) {
|
|
1129
|
-
const cell = row[column];
|
|
1130
|
-
cells.push(cell === void 0 ? "" : renderCell(cell, depth));
|
|
1131
|
-
}
|
|
1132
|
-
return `| ${cells.join(" | ")} |`;
|
|
1133
|
-
})
|
|
1134
|
-
].join("\n");
|
|
1135
|
-
}
|
|
1136
|
-
function render(current, depth) {
|
|
1137
|
-
if (depth >= 64) return "value" in current && typeof current.value === "string" ? escapeText(current.value) : "";
|
|
1266
|
+
const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
|
|
1267
|
+
let value = "";
|
|
1138
1268
|
switch (current.element) {
|
|
1139
|
-
case "
|
|
1269
|
+
case "codeBlock":
|
|
1270
|
+
case "codeSpan": {
|
|
1271
|
+
const body = current.element === "codeBlock" ? current.code : current.value;
|
|
1272
|
+
let longest = 0;
|
|
1273
|
+
let run = 0;
|
|
1274
|
+
for (const character of body) if (character === "`") {
|
|
1275
|
+
run += 1;
|
|
1276
|
+
longest = Math.max(longest, run);
|
|
1277
|
+
} else run = 0;
|
|
1278
|
+
const fence = "`".repeat(Math.max(current.element === "codeBlock" ? 3 : 1, longest + 1));
|
|
1279
|
+
if (current.element === "codeBlock") {
|
|
1280
|
+
value = `${fence}${current.lang === void 0 ? "" : current.lang}\n${current.code}\n${fence}`;
|
|
1281
|
+
break;
|
|
1282
|
+
}
|
|
1283
|
+
const pad = current.value.startsWith("`") || current.value.endsWith("`") ? " " : "";
|
|
1284
|
+
value = `${fence}${pad}${current.value}${pad}${fence}`;
|
|
1285
|
+
break;
|
|
1286
|
+
}
|
|
1287
|
+
case "document":
|
|
1288
|
+
value = children.join("\n\n");
|
|
1289
|
+
break;
|
|
1140
1290
|
case "heading": {
|
|
1141
|
-
const escaped =
|
|
1142
|
-
return `${
|
|
1291
|
+
const escaped = children.join("").replace(/(^|[^\\])(#+)$/, (_match, before, hashes) => {
|
|
1292
|
+
return `${before}\\${hashes[0] ?? ""}${hashes.slice(1)}`;
|
|
1143
1293
|
});
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
case "paragraph": return renderInline(current.children, depth);
|
|
1147
|
-
case "thematicBreak": return "---";
|
|
1148
|
-
case "blockquote": return renderBlocks(current.children, depth).split("\n").map((line) => line === "" ? ">" : `> ${line}`).join("\n");
|
|
1149
|
-
case "codeBlock": {
|
|
1150
|
-
const fence = fenceFor(current.code, 3);
|
|
1151
|
-
return `${fence}${current.lang === void 0 ? "" : current.lang}\n${current.code}\n${fence}`;
|
|
1294
|
+
value = `${"#".repeat(current.level)} ${escaped}`;
|
|
1295
|
+
break;
|
|
1152
1296
|
}
|
|
1297
|
+
case "paragraph":
|
|
1298
|
+
value = children.join("");
|
|
1299
|
+
break;
|
|
1300
|
+
case "thematicBreak":
|
|
1301
|
+
value = "---";
|
|
1302
|
+
break;
|
|
1303
|
+
case "blockquote":
|
|
1304
|
+
value = children.join("\n\n").split("\n").map((line) => line === "" ? ">" : `> ${line}`).join("\n");
|
|
1305
|
+
break;
|
|
1153
1306
|
case "list": {
|
|
1307
|
+
const items = [];
|
|
1154
1308
|
let ordinal = current.start;
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1309
|
+
for (const body of children) {
|
|
1310
|
+
const marker = current.ordered ? `${ordinal}. ` : "- ";
|
|
1311
|
+
ordinal += 1;
|
|
1312
|
+
const pad = " ".repeat(marker.length);
|
|
1313
|
+
items.push(body.split("\n").map((line, index) => index === 0 ? marker + line : line === "" ? "" : pad + line).join("\n"));
|
|
1314
|
+
}
|
|
1315
|
+
value = items.join("\n");
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
case "listItem":
|
|
1319
|
+
value = children.join("\n\n");
|
|
1320
|
+
break;
|
|
1321
|
+
case "table": {
|
|
1322
|
+
let offset = 0;
|
|
1323
|
+
const header = [];
|
|
1324
|
+
for (const cell of current.header) {
|
|
1325
|
+
if (cell === void 0) {
|
|
1326
|
+
header.push("");
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
let count = 0;
|
|
1330
|
+
for (const child of cell) if (child !== void 0) count += 1;
|
|
1331
|
+
header.push(children.slice(offset, offset + count).join("").replace(/\|/g, "\\|"));
|
|
1332
|
+
offset += count;
|
|
1333
|
+
}
|
|
1334
|
+
const delimiter = current.align.map((align) => {
|
|
1335
|
+
if (align === "left") return ":--";
|
|
1336
|
+
if (align === "right") return "--:";
|
|
1337
|
+
if (align === "center") return ":-:";
|
|
1338
|
+
return "---";
|
|
1339
|
+
});
|
|
1340
|
+
const rows = [];
|
|
1341
|
+
for (const row of current.rows) {
|
|
1342
|
+
const cells = [];
|
|
1343
|
+
for (let column = 0; column < current.header.length; column += 1) {
|
|
1344
|
+
const cell = row[column];
|
|
1345
|
+
if (cell === void 0) {
|
|
1346
|
+
cells.push("");
|
|
1347
|
+
continue;
|
|
1348
|
+
}
|
|
1349
|
+
let count = 0;
|
|
1350
|
+
for (const child of cell) if (child !== void 0) count += 1;
|
|
1351
|
+
cells.push(children.slice(offset, offset + count).join("").replace(/\|/g, "\\|"));
|
|
1352
|
+
offset += count;
|
|
1353
|
+
}
|
|
1354
|
+
rows.push(`| ${cells.join(" | ")} |`);
|
|
1355
|
+
}
|
|
1356
|
+
value = [
|
|
1357
|
+
`| ${header.join(" | ")} |`,
|
|
1358
|
+
`| ${delimiter.join(" | ")} |`,
|
|
1359
|
+
...rows
|
|
1360
|
+
].join("\n");
|
|
1361
|
+
break;
|
|
1158
1362
|
}
|
|
1159
|
-
case "
|
|
1160
|
-
|
|
1161
|
-
|
|
1363
|
+
case "text":
|
|
1364
|
+
value = frame.escaped;
|
|
1365
|
+
break;
|
|
1162
1366
|
case "emphasis": {
|
|
1163
1367
|
const marker = current.strong ? "**" : "*";
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
case "codeSpan": {
|
|
1167
|
-
const fence = fenceFor(current.value, 1);
|
|
1168
|
-
const pad = current.value.startsWith("`") || current.value.endsWith("`") ? " " : "";
|
|
1169
|
-
return `${fence}${pad}${current.value}${pad}${fence}`;
|
|
1368
|
+
value = `${marker}${children.join("")}${marker}`;
|
|
1369
|
+
break;
|
|
1170
1370
|
}
|
|
1171
1371
|
case "link": {
|
|
1172
1372
|
const href = current.href.replace(/[\\()]/g, (character) => `\\${character}`);
|
|
1173
|
-
|
|
1373
|
+
value = `[${children.join("")}](${href})`;
|
|
1374
|
+
break;
|
|
1174
1375
|
}
|
|
1175
|
-
default:
|
|
1376
|
+
default:
|
|
1377
|
+
value = "";
|
|
1378
|
+
break;
|
|
1176
1379
|
}
|
|
1380
|
+
if (stack.length === 0) return value;
|
|
1381
|
+
values.push(value);
|
|
1177
1382
|
}
|
|
1178
|
-
return
|
|
1383
|
+
return "";
|
|
1179
1384
|
}
|
|
1180
1385
|
/**
|
|
1181
1386
|
* Depth-first, pre-order, root-inclusive traversal of a {@link MarkdownNode} - yields
|
|
@@ -1197,10 +1402,17 @@ function renderMarkdown(node) {
|
|
|
1197
1402
|
* ```
|
|
1198
1403
|
*/
|
|
1199
1404
|
function* walkNodes(node) {
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1405
|
+
const stack = [{
|
|
1406
|
+
node,
|
|
1407
|
+
depth: 0
|
|
1408
|
+
}];
|
|
1409
|
+
while (stack.length > 0) {
|
|
1410
|
+
const frame = stack.pop();
|
|
1411
|
+
if (frame === void 0) continue;
|
|
1412
|
+
yield frame.node;
|
|
1413
|
+
if (frame.depth >= 64) continue;
|
|
1414
|
+
const children = [];
|
|
1415
|
+
switch (frame.node.element) {
|
|
1204
1416
|
case "document":
|
|
1205
1417
|
case "heading":
|
|
1206
1418
|
case "paragraph":
|
|
@@ -1208,19 +1420,30 @@ function* walkNodes(node) {
|
|
|
1208
1420
|
case "listItem":
|
|
1209
1421
|
case "emphasis":
|
|
1210
1422
|
case "link":
|
|
1211
|
-
for (const child of
|
|
1212
|
-
|
|
1423
|
+
for (const child of frame.node.children) if (child !== void 0) children.push(child);
|
|
1424
|
+
break;
|
|
1213
1425
|
case "list":
|
|
1214
|
-
for (const
|
|
1215
|
-
|
|
1426
|
+
for (const child of frame.node.items) if (child !== void 0) children.push(child);
|
|
1427
|
+
break;
|
|
1216
1428
|
case "table":
|
|
1217
|
-
for (const cell of
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1429
|
+
for (const cell of frame.node.header) if (cell !== void 0) {
|
|
1430
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1431
|
+
}
|
|
1432
|
+
for (const row of frame.node.rows) if (row !== void 0) {
|
|
1433
|
+
for (const cell of row) if (cell !== void 0) {
|
|
1434
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1439
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
1440
|
+
const child = children[index];
|
|
1441
|
+
if (child !== void 0) stack.push({
|
|
1442
|
+
node: child,
|
|
1443
|
+
depth: frame.depth + 1
|
|
1444
|
+
});
|
|
1221
1445
|
}
|
|
1222
1446
|
}
|
|
1223
|
-
yield* walk(node, 0);
|
|
1224
1447
|
}
|
|
1225
1448
|
/**
|
|
1226
1449
|
* Fold a {@link MarkdownNode} into a `T` via a total catamorphism - children are
|
|
@@ -1254,46 +1477,119 @@ function* walkNodes(node) {
|
|
|
1254
1477
|
* ```
|
|
1255
1478
|
*/
|
|
1256
1479
|
function foldNode(node, handlers, depth) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1480
|
+
const stack = [{
|
|
1481
|
+
node,
|
|
1482
|
+
depth,
|
|
1483
|
+
expanded: false,
|
|
1484
|
+
count: 0
|
|
1485
|
+
}];
|
|
1486
|
+
const values = [];
|
|
1487
|
+
while (stack.length > 0) {
|
|
1488
|
+
const frame = stack.pop();
|
|
1489
|
+
if (frame === void 0) continue;
|
|
1490
|
+
if (!frame.expanded) {
|
|
1491
|
+
const children = [];
|
|
1492
|
+
if (frame.depth < 64) switch (frame.node.element) {
|
|
1493
|
+
case "document":
|
|
1494
|
+
case "heading":
|
|
1495
|
+
case "paragraph":
|
|
1496
|
+
case "blockquote":
|
|
1497
|
+
case "listItem":
|
|
1498
|
+
case "emphasis":
|
|
1499
|
+
case "link":
|
|
1500
|
+
for (const child of frame.node.children) if (child !== void 0) children.push(child);
|
|
1501
|
+
break;
|
|
1502
|
+
case "list":
|
|
1503
|
+
for (const child of frame.node.items) if (child !== void 0) children.push(child);
|
|
1504
|
+
break;
|
|
1505
|
+
case "table":
|
|
1506
|
+
for (const cell of frame.node.header) if (cell !== void 0) {
|
|
1507
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1508
|
+
}
|
|
1509
|
+
for (const row of frame.node.rows) if (row !== void 0) {
|
|
1510
|
+
for (const cell of row) if (cell !== void 0) {
|
|
1511
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
break;
|
|
1515
|
+
}
|
|
1516
|
+
stack.push({
|
|
1517
|
+
...frame,
|
|
1518
|
+
expanded: true,
|
|
1519
|
+
count: children.length
|
|
1520
|
+
});
|
|
1521
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
1522
|
+
const child = children[index];
|
|
1523
|
+
if (child !== void 0) stack.push({
|
|
1524
|
+
node: child,
|
|
1525
|
+
depth: frame.depth + 1,
|
|
1526
|
+
expanded: false,
|
|
1527
|
+
count: 0
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
continue;
|
|
1272
1531
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
switch (
|
|
1532
|
+
const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
|
|
1533
|
+
let value;
|
|
1534
|
+
switch (frame.node.element) {
|
|
1276
1535
|
case "document":
|
|
1536
|
+
value = handlers.document(frame.node, children);
|
|
1537
|
+
break;
|
|
1277
1538
|
case "heading":
|
|
1539
|
+
value = handlers.heading(frame.node, children);
|
|
1540
|
+
break;
|
|
1278
1541
|
case "paragraph":
|
|
1542
|
+
value = handlers.paragraph(frame.node, children);
|
|
1543
|
+
break;
|
|
1544
|
+
case "thematicBreak":
|
|
1545
|
+
value = handlers.thematicBreak(frame.node, children);
|
|
1546
|
+
break;
|
|
1279
1547
|
case "blockquote":
|
|
1548
|
+
value = handlers.blockquote(frame.node, children);
|
|
1549
|
+
break;
|
|
1550
|
+
case "codeBlock":
|
|
1551
|
+
value = handlers.codeBlock(frame.node, children);
|
|
1552
|
+
break;
|
|
1553
|
+
case "list":
|
|
1554
|
+
value = handlers.list(frame.node, children);
|
|
1555
|
+
break;
|
|
1280
1556
|
case "listItem":
|
|
1557
|
+
value = handlers.listItem(frame.node, children);
|
|
1558
|
+
break;
|
|
1559
|
+
case "table":
|
|
1560
|
+
value = handlers.table(frame.node, children);
|
|
1561
|
+
break;
|
|
1562
|
+
case "text":
|
|
1563
|
+
value = handlers.text(frame.node, children);
|
|
1564
|
+
break;
|
|
1281
1565
|
case "emphasis":
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
case "
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1566
|
+
value = handlers.emphasis(frame.node, children);
|
|
1567
|
+
break;
|
|
1568
|
+
case "codeSpan":
|
|
1569
|
+
value = handlers.codeSpan(frame.node, children);
|
|
1570
|
+
break;
|
|
1571
|
+
case "link":
|
|
1572
|
+
value = handlers.link(frame.node, children);
|
|
1573
|
+
break;
|
|
1290
1574
|
}
|
|
1575
|
+
if (stack.length === 0) return value;
|
|
1576
|
+
values.push(value);
|
|
1291
1577
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
return
|
|
1578
|
+
switch (node.element) {
|
|
1579
|
+
case "document": return handlers.document(node, []);
|
|
1580
|
+
case "heading": return handlers.heading(node, []);
|
|
1581
|
+
case "paragraph": return handlers.paragraph(node, []);
|
|
1582
|
+
case "thematicBreak": return handlers.thematicBreak(node, []);
|
|
1583
|
+
case "blockquote": return handlers.blockquote(node, []);
|
|
1584
|
+
case "codeBlock": return handlers.codeBlock(node, []);
|
|
1585
|
+
case "list": return handlers.list(node, []);
|
|
1586
|
+
case "listItem": return handlers.listItem(node, []);
|
|
1587
|
+
case "table": return handlers.table(node, []);
|
|
1588
|
+
case "text": return handlers.text(node, []);
|
|
1589
|
+
case "emphasis": return handlers.emphasis(node, []);
|
|
1590
|
+
case "codeSpan": return handlers.codeSpan(node, []);
|
|
1591
|
+
case "link": return handlers.link(node, []);
|
|
1295
1592
|
}
|
|
1296
|
-
return fold(node, depth);
|
|
1297
1593
|
}
|
|
1298
1594
|
/**
|
|
1299
1595
|
* Rewrite a {@link MarkdownDocument} bottom-up (copy-on-write) - each node's children
|
|
@@ -1328,71 +1624,227 @@ function foldNode(node, handlers, depth) {
|
|
|
1328
1624
|
* ```
|
|
1329
1625
|
*/
|
|
1330
1626
|
function rewriteDocument(document, rewrite) {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1627
|
+
const stack = [{
|
|
1628
|
+
node: document,
|
|
1629
|
+
depth: -1,
|
|
1630
|
+
expanded: false,
|
|
1631
|
+
count: 0
|
|
1632
|
+
}];
|
|
1633
|
+
const values = [];
|
|
1634
|
+
while (stack.length > 0) {
|
|
1635
|
+
const frame = stack.pop();
|
|
1636
|
+
if (frame === void 0) continue;
|
|
1637
|
+
const current = frame.node;
|
|
1638
|
+
if (!frame.expanded) {
|
|
1639
|
+
if (current.element !== "document" && frame.depth >= 64) {
|
|
1640
|
+
values.push(current);
|
|
1641
|
+
continue;
|
|
1642
|
+
}
|
|
1643
|
+
const children = [];
|
|
1644
|
+
switch (current.element) {
|
|
1645
|
+
case "document":
|
|
1646
|
+
case "heading":
|
|
1647
|
+
case "paragraph":
|
|
1648
|
+
case "blockquote":
|
|
1649
|
+
case "listItem":
|
|
1650
|
+
case "emphasis":
|
|
1651
|
+
case "link":
|
|
1652
|
+
for (const child of current.children) if (child !== void 0) children.push(child);
|
|
1653
|
+
break;
|
|
1654
|
+
case "list":
|
|
1655
|
+
for (const child of current.items) if (child !== void 0) children.push(child);
|
|
1656
|
+
break;
|
|
1657
|
+
case "table":
|
|
1658
|
+
for (const cell of current.header) if (cell !== void 0) {
|
|
1659
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1660
|
+
}
|
|
1661
|
+
for (const row of current.rows) if (row !== void 0) {
|
|
1662
|
+
for (const cell of row) if (cell !== void 0) {
|
|
1663
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
break;
|
|
1667
|
+
}
|
|
1668
|
+
stack.push({
|
|
1669
|
+
...frame,
|
|
1670
|
+
expanded: true,
|
|
1671
|
+
count: children.length
|
|
1672
|
+
});
|
|
1673
|
+
const depth = current.element === "document" ? 0 : frame.depth + 1;
|
|
1674
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
1675
|
+
const child = children[index];
|
|
1676
|
+
if (child !== void 0) stack.push({
|
|
1677
|
+
node: child,
|
|
1678
|
+
depth,
|
|
1679
|
+
expanded: false,
|
|
1680
|
+
count: 0
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
continue;
|
|
1684
|
+
}
|
|
1685
|
+
const children = frame.count === 0 ? [] : values.splice(values.length - frame.count, frame.count);
|
|
1686
|
+
let rebuilt = current;
|
|
1687
|
+
switch (current.element) {
|
|
1688
|
+
case "document": {
|
|
1689
|
+
const blocks = [];
|
|
1690
|
+
let offset = 0;
|
|
1691
|
+
for (const block of current.children) {
|
|
1692
|
+
if (block === void 0) continue;
|
|
1693
|
+
const child = children[offset];
|
|
1694
|
+
blocks.push(child !== void 0 && isBlockNode(child) ? child : block);
|
|
1695
|
+
offset += 1;
|
|
1696
|
+
}
|
|
1697
|
+
const result = {
|
|
1698
|
+
element: "document",
|
|
1699
|
+
children: blocks
|
|
1700
|
+
};
|
|
1701
|
+
if (stack.length === 0) return result;
|
|
1702
|
+
values.push(result);
|
|
1703
|
+
continue;
|
|
1704
|
+
}
|
|
1705
|
+
case "heading":
|
|
1706
|
+
case "paragraph": {
|
|
1707
|
+
const inlines = [];
|
|
1708
|
+
let offset = 0;
|
|
1709
|
+
for (const inline of current.children) {
|
|
1710
|
+
if (inline === void 0) continue;
|
|
1711
|
+
const child = children[offset];
|
|
1712
|
+
inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
|
|
1713
|
+
offset += 1;
|
|
1714
|
+
}
|
|
1715
|
+
rebuilt = {
|
|
1716
|
+
...current,
|
|
1717
|
+
children: inlines
|
|
1718
|
+
};
|
|
1719
|
+
break;
|
|
1720
|
+
}
|
|
1721
|
+
case "blockquote": {
|
|
1722
|
+
const blocks = [];
|
|
1723
|
+
let offset = 0;
|
|
1724
|
+
for (const block of current.children) {
|
|
1725
|
+
if (block === void 0) continue;
|
|
1726
|
+
const child = children[offset];
|
|
1727
|
+
blocks.push(child !== void 0 && isBlockNode(child) ? child : block);
|
|
1728
|
+
offset += 1;
|
|
1729
|
+
}
|
|
1730
|
+
rebuilt = {
|
|
1731
|
+
...current,
|
|
1732
|
+
children: blocks
|
|
1733
|
+
};
|
|
1734
|
+
break;
|
|
1735
|
+
}
|
|
1736
|
+
case "listItem": {
|
|
1737
|
+
const blocks = [];
|
|
1738
|
+
let offset = 0;
|
|
1739
|
+
for (const block of current.children) {
|
|
1740
|
+
if (block === void 0) continue;
|
|
1741
|
+
const child = children[offset];
|
|
1742
|
+
blocks.push(child !== void 0 && isBlockNode(child) ? child : block);
|
|
1743
|
+
offset += 1;
|
|
1744
|
+
}
|
|
1745
|
+
rebuilt = {
|
|
1746
|
+
element: "listItem",
|
|
1747
|
+
children: blocks
|
|
1748
|
+
};
|
|
1749
|
+
break;
|
|
1750
|
+
}
|
|
1751
|
+
case "emphasis":
|
|
1752
|
+
case "link": {
|
|
1753
|
+
const inlines = [];
|
|
1754
|
+
let offset = 0;
|
|
1755
|
+
for (const inline of current.children) {
|
|
1756
|
+
if (inline === void 0) continue;
|
|
1757
|
+
const child = children[offset];
|
|
1758
|
+
inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
|
|
1759
|
+
offset += 1;
|
|
1760
|
+
}
|
|
1761
|
+
rebuilt = {
|
|
1762
|
+
...current,
|
|
1763
|
+
children: inlines
|
|
1764
|
+
};
|
|
1765
|
+
break;
|
|
1766
|
+
}
|
|
1767
|
+
case "list": {
|
|
1768
|
+
const items = [];
|
|
1769
|
+
let offset = 0;
|
|
1770
|
+
for (const item of current.items) {
|
|
1771
|
+
if (item === void 0) continue;
|
|
1772
|
+
const child = children[offset];
|
|
1773
|
+
items.push(child?.element === "listItem" ? child : item);
|
|
1774
|
+
offset += 1;
|
|
1775
|
+
}
|
|
1776
|
+
rebuilt = {
|
|
1777
|
+
...current,
|
|
1778
|
+
items
|
|
1779
|
+
};
|
|
1780
|
+
break;
|
|
1781
|
+
}
|
|
1782
|
+
case "table": {
|
|
1783
|
+
let offset = 0;
|
|
1784
|
+
const header = [];
|
|
1785
|
+
for (const cell of current.header) {
|
|
1786
|
+
if (cell === void 0) continue;
|
|
1787
|
+
const inlines = [];
|
|
1788
|
+
for (const inline of cell) {
|
|
1789
|
+
if (inline === void 0) continue;
|
|
1790
|
+
const child = children[offset];
|
|
1791
|
+
inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
|
|
1792
|
+
offset += 1;
|
|
1793
|
+
}
|
|
1794
|
+
header.push(inlines);
|
|
1795
|
+
}
|
|
1796
|
+
const rows = [];
|
|
1797
|
+
for (const row of current.rows) {
|
|
1798
|
+
if (row === void 0) continue;
|
|
1799
|
+
const cells = [];
|
|
1800
|
+
for (const cell of row) {
|
|
1801
|
+
if (cell === void 0) continue;
|
|
1802
|
+
const inlines = [];
|
|
1803
|
+
for (const inline of cell) {
|
|
1804
|
+
if (inline === void 0) continue;
|
|
1805
|
+
const child = children[offset];
|
|
1806
|
+
inlines.push(child !== void 0 && isInlineNode(child) ? child : inline);
|
|
1807
|
+
offset += 1;
|
|
1808
|
+
}
|
|
1809
|
+
cells.push(inlines);
|
|
1810
|
+
}
|
|
1811
|
+
rows.push(cells);
|
|
1812
|
+
}
|
|
1813
|
+
rebuilt = {
|
|
1814
|
+
...current,
|
|
1815
|
+
header,
|
|
1816
|
+
rows
|
|
1817
|
+
};
|
|
1818
|
+
break;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1349
1821
|
const result = rewrite(rebuilt);
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
function rebuildInline(node, depth) {
|
|
1353
|
-
switch (node.element) {
|
|
1354
|
-
case "emphasis": return {
|
|
1355
|
-
...node,
|
|
1356
|
-
children: node.children.map((child) => rewriteInline(child, depth + 1))
|
|
1357
|
-
};
|
|
1358
|
-
case "link": return {
|
|
1359
|
-
...node,
|
|
1360
|
-
children: node.children.map((child) => rewriteInline(child, depth + 1))
|
|
1361
|
-
};
|
|
1822
|
+
let accepted = rebuilt;
|
|
1823
|
+
switch (current.element) {
|
|
1362
1824
|
case "text":
|
|
1363
|
-
case "
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
case "heading":
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
case "paragraph": return {
|
|
1373
|
-
...node,
|
|
1374
|
-
children: node.children.map((child) => rewriteInline(child, depth + 1))
|
|
1375
|
-
};
|
|
1376
|
-
case "blockquote": return {
|
|
1377
|
-
...node,
|
|
1378
|
-
children: node.children.map((child) => rewriteBlock(child, depth + 1))
|
|
1379
|
-
};
|
|
1380
|
-
case "list": return {
|
|
1381
|
-
...node,
|
|
1382
|
-
items: node.items.map((item) => rewriteItem(item, depth + 1))
|
|
1383
|
-
};
|
|
1384
|
-
case "table": return {
|
|
1385
|
-
...node,
|
|
1386
|
-
header: node.header.map((cell) => cell.map((inline) => rewriteInline(inline, depth + 1))),
|
|
1387
|
-
rows: node.rows.map((row) => row.map((cell) => cell.map((inline) => rewriteInline(inline, depth + 1))))
|
|
1388
|
-
};
|
|
1825
|
+
case "emphasis":
|
|
1826
|
+
case "codeSpan":
|
|
1827
|
+
case "link":
|
|
1828
|
+
if (isInlineNode(result)) accepted = result;
|
|
1829
|
+
break;
|
|
1830
|
+
case "heading":
|
|
1831
|
+
case "paragraph":
|
|
1832
|
+
case "list":
|
|
1833
|
+
case "table":
|
|
1389
1834
|
case "codeBlock":
|
|
1390
|
-
case "
|
|
1835
|
+
case "blockquote":
|
|
1836
|
+
case "thematicBreak":
|
|
1837
|
+
if (isBlockNode(result)) accepted = result;
|
|
1838
|
+
break;
|
|
1839
|
+
case "listItem":
|
|
1840
|
+
if (result.element === "listItem") accepted = result;
|
|
1841
|
+
break;
|
|
1391
1842
|
}
|
|
1843
|
+
values.push(accepted);
|
|
1392
1844
|
}
|
|
1393
1845
|
return {
|
|
1394
1846
|
element: "document",
|
|
1395
|
-
children: document.children
|
|
1847
|
+
children: [...document.children]
|
|
1396
1848
|
};
|
|
1397
1849
|
}
|
|
1398
1850
|
/**
|
|
@@ -1417,26 +1869,55 @@ function rewriteDocument(document, rewrite) {
|
|
|
1417
1869
|
* ```
|
|
1418
1870
|
*/
|
|
1419
1871
|
function flattenText(node) {
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1872
|
+
const stack = [{
|
|
1873
|
+
node,
|
|
1874
|
+
depth: 0
|
|
1875
|
+
}];
|
|
1876
|
+
let value = "";
|
|
1877
|
+
while (stack.length > 0) {
|
|
1878
|
+
const frame = stack.pop();
|
|
1879
|
+
if (frame === void 0 || frame.depth >= 64) continue;
|
|
1880
|
+
const children = [];
|
|
1881
|
+
switch (frame.node.element) {
|
|
1882
|
+
case "text":
|
|
1883
|
+
case "codeSpan":
|
|
1884
|
+
value += frame.node.value;
|
|
1885
|
+
break;
|
|
1886
|
+
case "codeBlock":
|
|
1887
|
+
value += frame.node.code;
|
|
1888
|
+
break;
|
|
1426
1889
|
case "document":
|
|
1427
1890
|
case "heading":
|
|
1428
1891
|
case "paragraph":
|
|
1429
1892
|
case "blockquote":
|
|
1430
1893
|
case "listItem":
|
|
1431
1894
|
case "emphasis":
|
|
1432
|
-
case "link":
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
case "
|
|
1436
|
-
|
|
1895
|
+
case "link":
|
|
1896
|
+
for (const child of frame.node.children) if (child !== void 0) children.push(child);
|
|
1897
|
+
break;
|
|
1898
|
+
case "list":
|
|
1899
|
+
for (const child of frame.node.items) if (child !== void 0) children.push(child);
|
|
1900
|
+
break;
|
|
1901
|
+
case "table":
|
|
1902
|
+
for (const cell of frame.node.header) if (cell !== void 0) {
|
|
1903
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1904
|
+
}
|
|
1905
|
+
for (const row of frame.node.rows) if (row !== void 0) {
|
|
1906
|
+
for (const cell of row) if (cell !== void 0) {
|
|
1907
|
+
for (const child of cell) if (child !== void 0) children.push(child);
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
break;
|
|
1911
|
+
}
|
|
1912
|
+
for (let index = children.length - 1; index >= 0; index -= 1) {
|
|
1913
|
+
const child = children[index];
|
|
1914
|
+
if (child !== void 0) stack.push({
|
|
1915
|
+
node: child,
|
|
1916
|
+
depth: frame.depth + 1
|
|
1917
|
+
});
|
|
1437
1918
|
}
|
|
1438
1919
|
}
|
|
1439
|
-
return
|
|
1920
|
+
return value;
|
|
1440
1921
|
}
|
|
1441
1922
|
//#endregion
|
|
1442
1923
|
//#region src/core/parsers.ts
|
|
@@ -1595,6 +2076,51 @@ function collectList(lines, start, depth) {
|
|
|
1595
2076
|
const startOrdinal = first?.start ?? 1;
|
|
1596
2077
|
const topIndent = first?.indent ?? 0;
|
|
1597
2078
|
const items = [];
|
|
2079
|
+
const chain = [];
|
|
2080
|
+
let nested = true;
|
|
2081
|
+
for (let cursor = start; cursor < lines.length; cursor += 1) {
|
|
2082
|
+
const parsed = extractListItem(lines[cursor] ?? "");
|
|
2083
|
+
const previous = chain[chain.length - 1];
|
|
2084
|
+
if (parsed === void 0 || previous !== void 0 && (previous.content.length > 0 || parsed.indent !== previous.marker)) {
|
|
2085
|
+
nested = false;
|
|
2086
|
+
break;
|
|
2087
|
+
}
|
|
2088
|
+
chain.push(parsed);
|
|
2089
|
+
}
|
|
2090
|
+
const remaining = 64 - depth;
|
|
2091
|
+
if (nested && remaining > 0 && chain.length > remaining) {
|
|
2092
|
+
const terminal = chain[remaining - 1];
|
|
2093
|
+
if (terminal !== void 0) {
|
|
2094
|
+
const source = [terminal.content];
|
|
2095
|
+
for (let cursor = start + remaining; cursor < lines.length; cursor += 1) source.push((lines[cursor] ?? "").slice(terminal.marker));
|
|
2096
|
+
let children = [{
|
|
2097
|
+
element: "paragraph",
|
|
2098
|
+
children: [{
|
|
2099
|
+
element: "text",
|
|
2100
|
+
value: source.join("\n")
|
|
2101
|
+
}]
|
|
2102
|
+
}];
|
|
2103
|
+
let node;
|
|
2104
|
+
for (let cursor = remaining - 1; cursor >= 0; cursor -= 1) {
|
|
2105
|
+
const parsed = chain[cursor];
|
|
2106
|
+
if (parsed === void 0) continue;
|
|
2107
|
+
node = {
|
|
2108
|
+
element: "list",
|
|
2109
|
+
ordered: parsed.ordered,
|
|
2110
|
+
start: parsed.start,
|
|
2111
|
+
items: [{
|
|
2112
|
+
element: "listItem",
|
|
2113
|
+
children
|
|
2114
|
+
}]
|
|
2115
|
+
};
|
|
2116
|
+
children = [node];
|
|
2117
|
+
}
|
|
2118
|
+
if (node !== void 0) return {
|
|
2119
|
+
node,
|
|
2120
|
+
next: lines.length
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
1598
2124
|
let index = start;
|
|
1599
2125
|
while (index < lines.length) {
|
|
1600
2126
|
const parsed = extractListItem(lines[index] ?? "");
|
|
@@ -1877,7 +2403,12 @@ var Markdown = class Markdown {
|
|
|
1877
2403
|
let index = 0;
|
|
1878
2404
|
return new ReadableStream({ pull(controller) {
|
|
1879
2405
|
if (index < blocks.length) {
|
|
1880
|
-
|
|
2406
|
+
const block = blocks[index];
|
|
2407
|
+
if (block === void 0) {
|
|
2408
|
+
controller.close();
|
|
2409
|
+
return;
|
|
2410
|
+
}
|
|
2411
|
+
controller.enqueue(block);
|
|
1881
2412
|
index += 1;
|
|
1882
2413
|
} else controller.close();
|
|
1883
2414
|
} });
|