@linloir/limr 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +36 -8
- package/README.md +36 -8
- package/benchmarks/results/layout.json +2593 -0
- package/benchmarks/results/markstream-code.json +1823 -0
- package/benchmarks/results/markstream-reading-repeat.json +1152 -0
- package/benchmarks/results/markstream.json +12486 -0
- package/benchmarks/results/streaming-browser.json +77 -0
- package/benchmarks/results/streaming.json +357 -0
- package/dist/base.css +83 -3
- package/dist/{chunk-TTISGBST.js → chunk-BG5QUQFR.js} +327 -72
- package/dist/chunk-BG5QUQFR.js.map +1 -0
- package/dist/chunk-BVHHOVMT.js +179 -0
- package/dist/chunk-BVHHOVMT.js.map +1 -0
- package/dist/chunk-FJZCQY2S.js +155 -0
- package/dist/chunk-FJZCQY2S.js.map +1 -0
- package/dist/chunk-FSI5OTBW.js +1 -0
- package/dist/{chunk-N77VD2YR.js → chunk-GU2RPESF.js} +145 -83
- package/dist/chunk-GU2RPESF.js.map +1 -0
- package/dist/{chunk-3ILUZKDB.js → chunk-SUAAUGAX.js} +1280 -501
- package/dist/chunk-SUAAUGAX.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +13 -5
- package/dist/extensions/index.d.ts +30 -5
- package/dist/extensions/index.js +15 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +27 -8
- package/dist/{engine-43u8B4yt.d.ts → knuth-plass-C8mgFm7W.d.ts} +67 -1
- package/dist/knuth-plass-layout-CHQCWKB5.js +449 -0
- package/dist/knuth-plass-layout-CHQCWKB5.js.map +1 -0
- package/dist/react/index.d.ts +5 -4
- package/dist/react/index.js +5 -3
- package/dist/styles.css +83 -3
- package/dist/{translations-DHnYMg4h.d.ts → translations-BXzSwLBJ.d.ts} +39 -2
- package/docs/en/README.md +8 -6
- package/docs/en/annotations.md +3 -1
- package/docs/en/api.md +9 -1
- package/docs/en/architecture.md +11 -3
- package/docs/en/extensions.md +53 -4
- package/docs/en/getting-started.md +2 -0
- package/docs/en/integration.md +26 -2
- package/docs/en/modules.md +9 -5
- package/docs/en/performance.md +42 -2
- package/docs/en/styles.md +21 -2
- package/docs/en/syntax.md +118 -15
- package/docs/zh-CN/README.md +8 -6
- package/docs/zh-CN/annotations.md +3 -1
- package/docs/zh-CN/api.md +9 -1
- package/docs/zh-CN/architecture.md +11 -3
- package/docs/zh-CN/extensions.md +55 -4
- package/docs/zh-CN/getting-started.md +2 -0
- package/docs/zh-CN/integration.md +26 -2
- package/docs/zh-CN/modules.md +9 -5
- package/docs/zh-CN/performance.md +42 -2
- package/docs/zh-CN/styles.md +21 -2
- package/docs/zh-CN/syntax.md +120 -15
- package/package.json +9 -1
- package/skills/limr-plugin-development/references/contract.md +9 -3
- package/skills/limr-use/references/integration.md +11 -3
- package/skills/limr-use/references/syntax.md +8 -5
- package/dist/chunk-3ILUZKDB.js.map +0 -1
- package/dist/chunk-N77VD2YR.js.map +0 -1
- package/dist/chunk-TTISGBST.js.map +0 -1
- package/dist/chunk-V2OG4Y3F.js +0 -1
- /package/dist/{chunk-V2OG4Y3F.js.map → chunk-FSI5OTBW.js.map} +0 -0
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
intersects,
|
|
3
|
+
lineStarts,
|
|
4
|
+
rangeOf,
|
|
5
|
+
slugify,
|
|
6
|
+
sourcePoint,
|
|
7
|
+
textContent,
|
|
8
|
+
walk
|
|
9
|
+
} from "./chunk-FJZCQY2S.js";
|
|
10
|
+
|
|
1
11
|
// src/core/parser.ts
|
|
2
12
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
3
13
|
import { mdxJsx } from "micromark-extension-mdx-jsx";
|
|
@@ -5,49 +15,240 @@ import { mdxJsxFromMarkdown } from "mdast-util-mdx-jsx";
|
|
|
5
15
|
import { directive } from "micromark-extension-directive";
|
|
6
16
|
import { directiveFromMarkdown } from "mdast-util-directive";
|
|
7
17
|
|
|
8
|
-
// src/core/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
function intersects(a, b) {
|
|
21
|
-
return a.start < b.end && b.start < a.end;
|
|
22
|
-
}
|
|
23
|
-
function lineStarts(source) {
|
|
24
|
-
const result = [0];
|
|
25
|
-
for (let i = 0; i < source.length; i++) {
|
|
26
|
-
if (source[i] === "\r") {
|
|
27
|
-
if (source[i + 1] === "\n") i++;
|
|
28
|
-
result.push(i + 1);
|
|
29
|
-
} else if (source[i] === "\n") result.push(i + 1);
|
|
18
|
+
// src/core/streaming.ts
|
|
19
|
+
import { decodeString } from "micromark-util-decode-string";
|
|
20
|
+
function insertions(source, edits) {
|
|
21
|
+
edits.sort((a, b) => a.at - b.at || (a.order ?? 0) - (b.order ?? 0));
|
|
22
|
+
const parts = [], points = [];
|
|
23
|
+
let at = 0, delta = 0;
|
|
24
|
+
for (const edit of edits) {
|
|
25
|
+
parts.push(source.slice(at, edit.at), edit.insert);
|
|
26
|
+
points.push({ from: edit.at + delta, to: edit.at + delta + edit.insert.length, at: edit.at, delta: delta + edit.insert.length });
|
|
27
|
+
at = edit.at;
|
|
28
|
+
delta += edit.insert.length;
|
|
30
29
|
}
|
|
31
|
-
|
|
30
|
+
parts.push(source.slice(at));
|
|
31
|
+
return {
|
|
32
|
+
value: parts.join(""),
|
|
33
|
+
original(offset) {
|
|
34
|
+
let lo = 0, hi = points.length;
|
|
35
|
+
while (lo < hi) {
|
|
36
|
+
const mid = lo + hi >>> 1;
|
|
37
|
+
if (points[mid].from <= offset) lo = mid + 1;
|
|
38
|
+
else hi = mid;
|
|
39
|
+
}
|
|
40
|
+
const point = points[lo - 1];
|
|
41
|
+
return Math.min(source.length, point ? offset < point.to ? point.at : offset - point.delta : offset);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
32
44
|
}
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
function prepareSource(source, names, tags, streaming, literals = /* @__PURE__ */ new Set()) {
|
|
46
|
+
if (!streaming && (!names.size || !source.includes("::")) || !/[<:`~$]/.test(source)) return { value: source, original: (at) => at, incomplete: /* @__PURE__ */ new Set() };
|
|
47
|
+
const edits = [], protectedRegions = [];
|
|
48
|
+
const incomplete = /* @__PURE__ */ new Set();
|
|
49
|
+
const containers = [], stack = [];
|
|
50
|
+
let fence;
|
|
51
|
+
let hidden;
|
|
52
|
+
let literal;
|
|
53
|
+
let maxDepth = 0;
|
|
54
|
+
const lines = /[^\r\n]*(?:\r\n|\r|\n|$)/g;
|
|
55
|
+
for (const match of source.matchAll(lines)) {
|
|
56
|
+
if (!match[0]) continue;
|
|
57
|
+
const line = match[0].replace(/[\r\n]+$/, ""), at = match.index;
|
|
58
|
+
const prefix = /^(?: {0,3}>[ \t]?)*(?: {0,3}(?:[-+*]|\d+[.)])[ \t]+)? {0,3}/.exec(line)[0];
|
|
59
|
+
const body = line.slice(prefix.length), start = at + prefix.length;
|
|
60
|
+
if (literal && !/^:{2,}[ \t]*$/.test(body)) continue;
|
|
61
|
+
if (literal) {
|
|
62
|
+
protectedRegions.push({ start: literal.content, end: at });
|
|
63
|
+
literal = void 0;
|
|
64
|
+
}
|
|
65
|
+
if (fence) {
|
|
66
|
+
if (new RegExp(`^${fence.marker}{${fence.size},}[ \\t]*$`).test(body)) {
|
|
67
|
+
protectedRegions.push({ start: fence.start, end: at + match[0].length });
|
|
68
|
+
fence = void 0;
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const openingFence = /^(`{3,}|~{3,}|\${2,})(.*)$/.exec(body);
|
|
73
|
+
if (openingFence && !(openingFence[1][0] === "`" && openingFence[2].includes("`"))) {
|
|
74
|
+
fence = { start, marker: openingFence[1][0] === "$" ? "\\$" : openingFence[1][0], size: openingFence[1].length };
|
|
75
|
+
if (streaming && !/[\r\n]$/.test(match[0])) hidden = { start };
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (/^[ \t]/.test(body)) {
|
|
79
|
+
protectedRegions.push({ start: at, end: at + match[0].length });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const open = /^(:{2,})([a-zA-Z][\w-]*)(.*)$/.exec(body);
|
|
83
|
+
if (open && names.has(open[2])) {
|
|
84
|
+
const rest = open[3].trim();
|
|
85
|
+
const validHeader = /^(?:\[(?:\\.|[^\]])*\])?(?:\{(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^{}"'])*\})?$/.test(rest);
|
|
86
|
+
if (!validHeader) {
|
|
87
|
+
if (streaming && at + match[0].length === source.length) hidden = { start, name: open[2] };
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const item = { start, marker: start, size: open[1].length, depth: stack.length };
|
|
91
|
+
containers.push(item);
|
|
92
|
+
stack.push(item);
|
|
93
|
+
maxDepth = Math.max(maxDepth, item.depth);
|
|
94
|
+
if (literals.has(open[2]) && /[\r\n]$/.test(match[0])) {
|
|
95
|
+
item.content = at + match[0].length;
|
|
96
|
+
item.prefix = prefix.replace(/[-+*]|\d+[.)]/g, (value) => " ".repeat(value.length));
|
|
97
|
+
literal = item;
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const closing = /^(:{2,})[ \t]*$/.exec(body);
|
|
102
|
+
if (closing && stack.length) {
|
|
103
|
+
if (closing[1].length > 2) {
|
|
104
|
+
let ancestor = -1;
|
|
105
|
+
for (let index = stack.length - 1; index >= 0; index--) if (stack[index].size > 2 && stack[index].size <= closing[1].length) {
|
|
106
|
+
ancestor = index;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
if (ancestor >= 0) for (const leaf of stack.splice(ancestor + 1)) leaf.leaf = true;
|
|
110
|
+
}
|
|
111
|
+
const item = stack[stack.length - 1];
|
|
112
|
+
if (closing[1].length >= item.size) {
|
|
113
|
+
item.close = start;
|
|
114
|
+
item.end = at + line.length;
|
|
115
|
+
stack.pop();
|
|
116
|
+
}
|
|
117
|
+
} else if (streaming && /^::[\w-]*$/.test(body) && at + match[0].length === source.length) hidden = { start };
|
|
39
118
|
}
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
119
|
+
if (fence) {
|
|
120
|
+
protectedRegions.push({ start: fence.start, end: source.length });
|
|
121
|
+
if (streaming) incomplete.add(fence.start);
|
|
122
|
+
}
|
|
123
|
+
if (literal) protectedRegions.push({ start: literal.content, end: source.length });
|
|
124
|
+
const active = containers.filter((item) => !item.leaf && (item.close !== void 0 || streaming));
|
|
125
|
+
const hasDouble = active.some((item) => item.size === 2);
|
|
126
|
+
const maxSize = Math.max(3, ...active.map((value) => value.size));
|
|
127
|
+
if (hasDouble) for (const item of active) {
|
|
128
|
+
const width = maxSize + maxDepth - item.depth;
|
|
129
|
+
if (width > item.size) edits.push({ at: item.marker, insert: ":".repeat(width - item.size) });
|
|
130
|
+
if (item.close !== void 0) {
|
|
131
|
+
const size = /^:+/.exec(source.slice(item.close))[0].length;
|
|
132
|
+
if (width > size) edits.push({ at: item.close, insert: ":".repeat(width - size) });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
for (const item of active) if (item.content !== void 0) {
|
|
136
|
+
const payload = source.slice(item.content, item.close ?? source.length);
|
|
137
|
+
const fence2 = "~".repeat(Math.max(3, ...[...payload.matchAll(/~+/g)].map((match) => match[0].length + 1)));
|
|
138
|
+
edits.push({ at: item.content, insert: `${item.prefix}${fence2}
|
|
139
|
+
`, order: -2 });
|
|
140
|
+
if (item.close !== void 0) edits.push({ at: item.close, insert: `${fence2}
|
|
141
|
+
${item.prefix}`, order: -1 });
|
|
142
|
+
}
|
|
143
|
+
if (streaming) for (const item of stack) incomplete.add(item.start);
|
|
144
|
+
const openTags = [];
|
|
145
|
+
if (streaming && tags.size && source.includes("<")) {
|
|
146
|
+
let region = 0, codeTicks = 0, codeStart = 0;
|
|
147
|
+
for (let i = 0; i < (hidden?.start ?? source.length); i++) {
|
|
148
|
+
while (protectedRegions[region] && protectedRegions[region].end <= i) region++;
|
|
149
|
+
if (protectedRegions[region]?.start <= i) {
|
|
150
|
+
i = protectedRegions[region].end - 1;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (source[i] === "\\") {
|
|
154
|
+
i++;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (!codeTicks && names.has("math") && source[i] === "$") {
|
|
158
|
+
const size = /^\$+/.exec(source.slice(i))[0].length;
|
|
159
|
+
const close = source.indexOf("$".repeat(size), i + size);
|
|
160
|
+
if (close < 0) {
|
|
161
|
+
hidden = { start: i };
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
i = close + size - 1;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (source[i] === "`") {
|
|
168
|
+
const size = /^`+/.exec(source.slice(i))[0].length;
|
|
169
|
+
if (!codeTicks) {
|
|
170
|
+
codeTicks = size;
|
|
171
|
+
codeStart = i;
|
|
172
|
+
} else if (codeTicks === size) codeTicks = 0;
|
|
173
|
+
i += size - 1;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (codeTicks || source[i] !== "<") continue;
|
|
177
|
+
const head = /^<(\/?)([a-zA-Z][\w-]*)/.exec(source.slice(i));
|
|
178
|
+
if (!head) {
|
|
179
|
+
if (/^<\/?$/.test(source.slice(i))) hidden = { start: i };
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const name = head[2];
|
|
183
|
+
if (!tags.has(name)) {
|
|
184
|
+
if ([...tags].some((tag) => tag.startsWith(name)) && i + head[0].length === source.length) hidden = { start: i };
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
let end = i + head[0].length, quote = "";
|
|
188
|
+
for (; end < source.length; end++) {
|
|
189
|
+
const char = source[end];
|
|
190
|
+
if (quote) {
|
|
191
|
+
if (char === quote) quote = "";
|
|
192
|
+
} else if (char === '"' || char === "'") quote = char;
|
|
193
|
+
else if (char === ">") break;
|
|
194
|
+
}
|
|
195
|
+
if (end === source.length) {
|
|
196
|
+
hidden = { start: i, name: head[1] ? void 0 : name };
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
if (head[1]) {
|
|
200
|
+
if (openTags.at(-1)?.name === name) openTags.pop();
|
|
201
|
+
} else if (source[end - 1] !== "/") openTags.push({ name, start: i, block: /^(?: {0,3}> ?)*\s*$/.test(source.slice(source.lastIndexOf("\n", i - 1) + 1, i)) && /^[ \t]*(?:\r?\n|$)/.test(source.slice(end + 1)) });
|
|
202
|
+
i = end;
|
|
203
|
+
}
|
|
204
|
+
if (codeTicks) hidden = { start: Math.min(codeStart, hidden?.start ?? source.length) };
|
|
205
|
+
}
|
|
206
|
+
for (const tag of openTags) incomplete.add(tag.start);
|
|
207
|
+
const cutoff = hidden?.start ?? source.length;
|
|
208
|
+
const mapped = insertions(source.slice(0, cutoff), edits.filter((edit) => edit.at < cutoff));
|
|
209
|
+
const suffix = openTags.reverse().map((tag) => `${tag.block ? "\n\n" : ""}</${tag.name}>`).join("");
|
|
210
|
+
return {
|
|
211
|
+
...mapped,
|
|
212
|
+
value: mapped.value + suffix,
|
|
213
|
+
incomplete,
|
|
214
|
+
hidden,
|
|
215
|
+
recoveryOffset: incomplete.size || hidden ? Math.min(...incomplete, hidden?.start ?? Infinity) : void 0
|
|
216
|
+
};
|
|
44
217
|
}
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
218
|
+
function concealIncomplete(root, source, lines) {
|
|
219
|
+
const tail = root.children?.at(-1);
|
|
220
|
+
if (tail?.type === "paragraph" && tail.position) {
|
|
221
|
+
const raw = source.slice(tail.position.start.offset);
|
|
222
|
+
if (/^ {0,3}\|[^\r\n]*(?:(?:\r\n|\r|\n)[|:\- \t]*)?$/.test(raw)) {
|
|
223
|
+
tail.children = [];
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
let cutoff = source.length;
|
|
228
|
+
walk(root.children?.at(-1) ?? root, (node) => {
|
|
229
|
+
if (node.type !== "text" || !node.position) return;
|
|
230
|
+
const { start, end } = node.position;
|
|
231
|
+
const raw = source.slice(start.offset);
|
|
232
|
+
for (const candidate of raw.slice(0, end.offset - start.offset).matchAll(/[!\[`*_~\$&^]/g)) {
|
|
233
|
+
const at = candidate.index;
|
|
234
|
+
let escapes = 0;
|
|
235
|
+
for (let before = at - 1; before >= 0 && raw[before] === "\\"; before--) escapes++;
|
|
236
|
+
if (escapes % 2) continue;
|
|
237
|
+
if (raw[at] === "_" && /[\p{L}\p{N}]/u.test(raw[at - 1] ?? "") && /[\p{L}\p{N}]/u.test(raw[at + 1] ?? "")) continue;
|
|
238
|
+
const tail2 = raw.slice(at).trimEnd();
|
|
239
|
+
if (/^(?:\^\[[^\]]*$|!?(?:\[[^\]]*$|\[[^\]]*\]\([^)]*$)|`+[^`]*$|\*{1,3}(?:\S[^*]*)?$|_{1,3}(?:\S[^_]*)?$|~{1,2}(?:\S[^~]*)?$|\$[^$]*$|&(?:#x?[\da-f]*|[a-z]*)$)/i.test(tail2)) {
|
|
240
|
+
cutoff = Math.min(cutoff, start.offset + at);
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
if (cutoff === source.length) return;
|
|
246
|
+
walk(root, (node) => {
|
|
247
|
+
if (node.children) node.children = node.children.filter((child) => (child.position?.start.offset ?? 0) < cutoff);
|
|
248
|
+
if (node.type !== "text" || !node.position || node.position.end.offset <= cutoff) return;
|
|
249
|
+
node.value = decodeString(source.slice(node.position.start.offset, cutoff));
|
|
250
|
+
node.position = { start: node.position.start, end: sourcePoint(cutoff, lines) };
|
|
251
|
+
});
|
|
51
252
|
}
|
|
52
253
|
|
|
53
254
|
// src/core/parser.ts
|
|
@@ -55,6 +256,7 @@ function validateExtensions(extensions) {
|
|
|
55
256
|
const names = /* @__PURE__ */ new Set();
|
|
56
257
|
const tags = /* @__PURE__ */ new Set();
|
|
57
258
|
const directives = /* @__PURE__ */ new Set();
|
|
259
|
+
const owners = /* @__PURE__ */ new Map();
|
|
58
260
|
for (const extension of extensions) {
|
|
59
261
|
if (names.has(extension.name)) throw new Error(`Duplicate LiMR extension: ${extension.name}. Use replaceExtension() to replace it explicitly.`);
|
|
60
262
|
names.add(extension.name);
|
|
@@ -64,46 +266,72 @@ function validateExtensions(extensions) {
|
|
|
64
266
|
known.add(name);
|
|
65
267
|
}
|
|
66
268
|
}
|
|
269
|
+
for (const name of [...extension.tags ?? [], ...extension.directives ?? []]) {
|
|
270
|
+
if (owners.has(name) && owners.get(name) !== extension) throw new Error(`Duplicate LiMR component syntax: ${name}`);
|
|
271
|
+
owners.set(name, extension);
|
|
272
|
+
}
|
|
67
273
|
}
|
|
68
274
|
}
|
|
69
275
|
function createParser(extensions) {
|
|
70
276
|
validateExtensions(extensions);
|
|
71
277
|
const tagDefinitions = new Map(extensions.flatMap((ext) => (ext.tags ?? []).map((name) => [name, ext])));
|
|
72
|
-
const directiveDefinitions = new Map(extensions.flatMap((ext) => (ext.directives ?? []).map((name) => [name, ext])));
|
|
278
|
+
const directiveDefinitions = new Map(extensions.flatMap((ext) => [.../* @__PURE__ */ new Set([...ext.tags ?? [], ...ext.directives ?? []])].map((name) => [name, ext])));
|
|
279
|
+
const names = new Set(directiveDefinitions.keys()), tags = new Set(tagDefinitions.keys());
|
|
280
|
+
const literals = new Set([...directiveDefinitions].filter(([, definition]) => definition.literal).map(([name]) => name));
|
|
73
281
|
const syntax = extensions.flatMap((ext) => [...ext.micromark ?? []]);
|
|
74
282
|
const mdast = extensions.flatMap((ext) => [...ext.mdast ?? []]);
|
|
283
|
+
const plainSyntax = [...syntax], plainMdast = [...mdast];
|
|
75
284
|
if (directiveDefinitions.size) {
|
|
76
285
|
syntax.push(directive());
|
|
77
286
|
mdast.push(directiveFromMarkdown());
|
|
78
287
|
}
|
|
79
288
|
const jsxSyntax = tagDefinitions.size ? [...syntax, { disable: { null: ["htmlFlow", "htmlText"] } }, mdxJsx()] : syntax;
|
|
80
289
|
const jsxMdast = tagDefinitions.size ? [...mdast, mdxJsxFromMarkdown()] : mdast;
|
|
290
|
+
const plainJsxSyntax = [...plainSyntax, { disable: { null: ["htmlFlow", "htmlText"] } }, mdxJsx()];
|
|
291
|
+
const plainJsxMdast = [...plainMdast, mdxJsxFromMarkdown()];
|
|
292
|
+
let literalCache;
|
|
81
293
|
return (fragment, offset, context, lines, environment = "") => {
|
|
82
294
|
const prefix = environment ? `${environment}
|
|
83
295
|
|
|
84
296
|
limr-definition-boundary
|
|
85
297
|
|
|
86
298
|
` : "";
|
|
87
|
-
const
|
|
299
|
+
const cached = literalCache;
|
|
300
|
+
const canAppendLiteral = context.streaming && cached && !prefix && cached.offset === offset && fragment.startsWith(cached.fragment) && !new RegExp(`(?:^|[\\r\\n]) {0,3}${cached.fence[0]}{${cached.fence.length},}[ \\t]*(?=[\\r\\n]|$)`).test(fragment.slice(Math.max(cached.content, cached.fragment.lastIndexOf("\n") + 1, cached.fragment.lastIndexOf("\r") + 1)));
|
|
301
|
+
const prepared = canAppendLiteral ? { value: fragment, original: (at) => at, incomplete: /* @__PURE__ */ new Set([0]), recoveryOffset: 0, hidden: void 0 } : prepareSource(fragment, names, tags, context.streaming, literals);
|
|
302
|
+
const input = prefix + prepared.value;
|
|
303
|
+
const hasDirectives = directiveDefinitions.size > 0 && /:[a-zA-Z]/.test(input);
|
|
304
|
+
const hasJsx = tagDefinitions.size > 0 && input.includes("<");
|
|
305
|
+
const activeSyntax = hasDirectives ? syntax : plainSyntax, activeMdast = hasDirectives ? mdast : plainMdast;
|
|
306
|
+
const mappedOffset = (at) => offset + prepared.original(Math.max(0, at - prefix.length));
|
|
307
|
+
const mappedLines = lines.length ? lines : lineStarts(context.source);
|
|
88
308
|
const diagnostics = [];
|
|
89
309
|
let attributeLines;
|
|
90
310
|
const attributePoint = (at) => sourcePoint(at, lines.length ? lines : attributeLines ??= lineStarts(context.source));
|
|
91
|
-
let recoveryOffset;
|
|
311
|
+
let recoveryOffset = prepared.recoveryOffset === void 0 ? void 0 : offset + prepared.recoveryOffset;
|
|
92
312
|
let root;
|
|
93
313
|
try {
|
|
94
|
-
root =
|
|
314
|
+
root = canAppendLiteral ? { type: "root", children: [{
|
|
315
|
+
...cached.node,
|
|
316
|
+
value: fragment.slice(cached.content).replace(/(?:\r\n|\r|\n)$/, ""),
|
|
317
|
+
position: { start: { offset: 0, line: 1, column: 1 }, end: { offset: fragment.length, line: 0, column: 0 } }
|
|
318
|
+
}] } : fromMarkdown(input, { extensions: hasJsx ? hasDirectives ? jsxSyntax : plainJsxSyntax : activeSyntax, mdastExtensions: hasJsx ? hasDirectives ? jsxMdast : plainJsxMdast : activeMdast });
|
|
95
319
|
} catch (error) {
|
|
96
|
-
root = fromMarkdown(input, { extensions:
|
|
320
|
+
root = fromMarkdown(input, { extensions: activeSyntax, mdastExtensions: activeMdast });
|
|
97
321
|
recoveryOffset = offset;
|
|
98
322
|
diagnostics.push({ message: error instanceof Error ? error.message : String(error), offset });
|
|
99
323
|
}
|
|
100
324
|
root.children = root.children?.filter((node) => (node.position?.start.offset ?? 0) >= prefix.length);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
325
|
+
const only = root.children?.length === 1 ? root.children[0] : void 0;
|
|
326
|
+
const fence = !prefix && only?.type === "code" && prepared.incomplete.has(0) && /^(`{3,}|~{3,})[^\r\n]*(?:\r\n|\r|\n)/.exec(fragment);
|
|
327
|
+
literalCache = fence ? { fragment, offset, node: { ...only }, fence: fence[1], content: fence[0].length } : void 0;
|
|
328
|
+
if (offset || prefix.length || tagDefinitions.size || directiveDefinitions.size || context.streaming) walk(root, (node) => {
|
|
329
|
+
if (node.position && (offset || prefix.length || prepared.value !== fragment || canAppendLiteral)) {
|
|
330
|
+
const start = mappedOffset(node.position.start.offset);
|
|
331
|
+
const end = Math.max(start, mappedOffset(node.position.end.offset));
|
|
332
|
+
node.position = { start: sourcePoint(start, mappedLines), end: sourcePoint(end, mappedLines) };
|
|
106
333
|
}
|
|
334
|
+
if (node.position && prepared.incomplete.has(node.position.start.offset - offset)) node.incomplete = true;
|
|
107
335
|
if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
|
|
108
336
|
const definition = tagDefinitions.get(node.name ?? "");
|
|
109
337
|
const rawAttributes = node.attributes;
|
|
@@ -113,8 +341,8 @@ limr-definition-boundary
|
|
|
113
341
|
if (attr.type === "mdxJsxAttribute" && (typeof attr.value === "string" || attr.value === null)) {
|
|
114
342
|
attributes[attr.name] = attr.value ?? true;
|
|
115
343
|
if (definition && typeof attr.value === "string" && attr.position) {
|
|
116
|
-
const start = attr.position.start.offset
|
|
117
|
-
const end = attr.position.end.offset
|
|
344
|
+
const start = mappedOffset(attr.position.start.offset);
|
|
345
|
+
const end = mappedOffset(attr.position.end.offset);
|
|
118
346
|
const raw = context.source.slice(start, end), opening = raw.search(/["']/);
|
|
119
347
|
if (opening >= 0) attributeNodes[attr.name] = { type: "text", value: attr.value, verbatimEscapes: true, position: { start: attributePoint(start + opening + 1), end: attributePoint(end - 1) } };
|
|
120
348
|
}
|
|
@@ -156,7 +384,20 @@ limr-definition-boundary
|
|
|
156
384
|
}
|
|
157
385
|
}
|
|
158
386
|
});
|
|
159
|
-
if (
|
|
387
|
+
if (prepared.hidden) {
|
|
388
|
+
const start = offset + prepared.hidden.start;
|
|
389
|
+
recoveryOffset = Math.min(recoveryOffset ?? start, root.children?.at(-1)?.position?.start.offset ?? start);
|
|
390
|
+
root.children?.push({
|
|
391
|
+
type: prepared.hidden.name ? "component" : "streamPending",
|
|
392
|
+
name: prepared.hidden.name,
|
|
393
|
+
incomplete: true,
|
|
394
|
+
position: { start: sourcePoint(start, mappedLines), end: sourcePoint(offset + fragment.length, mappedLines) },
|
|
395
|
+
children: [],
|
|
396
|
+
attributes: {}
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
if (context.streaming) concealIncomplete(root, context.source, mappedLines);
|
|
400
|
+
if (offset || prefix.length) root.position = { start: sourcePoint(offset, mappedLines), end: sourcePoint(offset + fragment.length, mappedLines) };
|
|
160
401
|
for (const extension of extensions) {
|
|
161
402
|
try {
|
|
162
403
|
extension.transform?.(root, context);
|
|
@@ -179,6 +420,19 @@ var DocumentEngine = class {
|
|
|
179
420
|
listeners = /* @__PURE__ */ new Set();
|
|
180
421
|
definitionSignature = "";
|
|
181
422
|
recoveryOffset;
|
|
423
|
+
lines = [0];
|
|
424
|
+
facts = /* @__PURE__ */ new WeakMap();
|
|
425
|
+
relevant(node) {
|
|
426
|
+
let result = this.facts.get(node);
|
|
427
|
+
if (!result) {
|
|
428
|
+
const nodes = [];
|
|
429
|
+
walk(node, (child) => {
|
|
430
|
+
if (child.annotation || ["heading", "definition", "footnoteDefinition", "footnoteReference", "annotationDefinition", "annotationReference"].includes(child.type)) nodes.push(child);
|
|
431
|
+
});
|
|
432
|
+
this.facts.set(node, result = nodes);
|
|
433
|
+
}
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
182
436
|
constructor(source = "", options = {}) {
|
|
183
437
|
this.id = options.id ?? `limr-${++sequence}`;
|
|
184
438
|
this.extensions = options.extensions ?? [];
|
|
@@ -210,29 +464,34 @@ var DocumentEngine = class {
|
|
|
210
464
|
const globalTransform = this.extensions.some((ext) => ext.transform && ext.scope !== "local");
|
|
211
465
|
const append = !force && previous?.streaming && source.startsWith(previous.source) && !globalTransform;
|
|
212
466
|
const finalizing = !!previous?.streaming && !streaming;
|
|
213
|
-
let start = append &&
|
|
467
|
+
let start = append && previous.blocks.length ? previous.blocks[previous.blocks.length - 1].range.start : 0;
|
|
214
468
|
const recovering = this.recoveryOffset !== void 0;
|
|
215
469
|
if (append && recovering) start = Math.min(start, this.recoveryOffset);
|
|
216
470
|
let reason = force || globalTransform ? "extension" : !previous ? "initial" : finalizing ? "finalize" : append ? "append" : "replace";
|
|
217
|
-
|
|
471
|
+
if (append && previous) {
|
|
472
|
+
const from = Math.max(0, previous.source.length - 1);
|
|
473
|
+
while (this.lines.length > 1 && this.lines.at(-1) > from) this.lines.pop();
|
|
474
|
+
for (const at of lineStarts(source.slice(from)).slice(1)) this.lines.push(from + at);
|
|
475
|
+
} else this.lines = lineStarts(source);
|
|
476
|
+
const lines = this.lines;
|
|
218
477
|
const context = { source, streaming, documentId: this.id };
|
|
219
478
|
let retained = start ? previous.blocks.filter((block) => block.range.end <= start) : [];
|
|
220
479
|
const environment = [];
|
|
221
|
-
for (const block of retained)
|
|
480
|
+
for (const block of retained) for (const node of this.relevant(block.node)) {
|
|
222
481
|
if (node.type === "definition" || node.type === "footnoteDefinition") {
|
|
223
482
|
const range = rangeOf(node);
|
|
224
483
|
environment.push(source.slice(range.start, range.end));
|
|
225
484
|
}
|
|
226
|
-
}
|
|
485
|
+
}
|
|
227
486
|
let parsed = this.parse(source.slice(start), start, context, lines, environment.join("\n\n"));
|
|
228
487
|
const getSignature = (nodes) => {
|
|
229
488
|
const entries = [];
|
|
230
|
-
for (const node of nodes)
|
|
489
|
+
for (const node of nodes) for (const child of this.relevant(node)) {
|
|
231
490
|
if (child.type === "definition" || child.type === "footnoteDefinition") {
|
|
232
491
|
const range = rangeOf(child);
|
|
233
492
|
entries.push(source.slice(range.start, range.end));
|
|
234
493
|
}
|
|
235
|
-
}
|
|
494
|
+
}
|
|
236
495
|
return entries.join("\0");
|
|
237
496
|
};
|
|
238
497
|
let signature = getSignature([...retained.map((block) => block.node), ...parsed.nodes]);
|
|
@@ -248,7 +507,7 @@ var DocumentEngine = class {
|
|
|
248
507
|
}
|
|
249
508
|
this.definitionSignature = signature;
|
|
250
509
|
this.recoveryOffset = parsed.recoveryOffset;
|
|
251
|
-
const oldAt = new Map(previous?.blocks.map((block) => [block.range.start, block]));
|
|
510
|
+
const oldAt = new Map(previous?.blocks.slice(retained.length).map((block) => [block.range.start, block]));
|
|
252
511
|
let reused = retained.length;
|
|
253
512
|
const blocks = [...retained];
|
|
254
513
|
for (let index = 0; index < parsed.nodes.length; index++) {
|
|
@@ -269,7 +528,7 @@ var DocumentEngine = class {
|
|
|
269
528
|
const annotations = /* @__PURE__ */ new Map();
|
|
270
529
|
const occurrences = [];
|
|
271
530
|
const slugCounts = /* @__PURE__ */ new Map();
|
|
272
|
-
for (const block of blocks)
|
|
531
|
+
for (const block of blocks) for (const node of this.relevant(block.node)) {
|
|
273
532
|
if (node.type === "heading") {
|
|
274
533
|
const text = textContent(node);
|
|
275
534
|
const base = slugify(text);
|
|
@@ -280,15 +539,15 @@ var DocumentEngine = class {
|
|
|
280
539
|
if (node.type === "definition" && !definitions.has(String(node.identifier))) definitions.set(String(node.identifier), node);
|
|
281
540
|
if (node.type === "footnoteDefinition" && !footnotes.has(String(node.identifier))) footnotes.set(String(node.identifier), node);
|
|
282
541
|
if (node.type === "footnoteReference" && !footnoteOrder.includes(String(node.identifier))) footnoteOrder.push(String(node.identifier));
|
|
283
|
-
if (node.
|
|
542
|
+
if (node.annotation) {
|
|
284
543
|
const annotation = node.annotation;
|
|
285
|
-
annotations.set(annotation.id, annotation);
|
|
544
|
+
if (node.type !== "footnoteDefinition" || !annotations.has(annotation.id)) annotations.set(annotation.id, annotation);
|
|
286
545
|
}
|
|
287
546
|
if (node.type === "annotationReference") {
|
|
288
547
|
const range = rangeOf(node);
|
|
289
|
-
occurrences.push({ id: `${this.id}-ref-${range.start}`, range, annotationIds: node.annotationIds, embedded: true });
|
|
548
|
+
occurrences.push({ id: `${this.id}-ref-${range.start}`, range, annotationIds: node.annotationIds, embedded: true, ...node.referenceRange ? { referenceRange: node.referenceRange } : {} });
|
|
290
549
|
}
|
|
291
|
-
}
|
|
550
|
+
}
|
|
292
551
|
this.snapshot = {
|
|
293
552
|
id: this.id,
|
|
294
553
|
revision: (previous?.revision ?? -1) + 1,
|
|
@@ -320,7 +579,7 @@ function replaceExtension(extensions, replacement) {
|
|
|
320
579
|
}
|
|
321
580
|
|
|
322
581
|
// src/core/selection.ts
|
|
323
|
-
import { decodeString } from "micromark-util-decode-string";
|
|
582
|
+
import { decodeString as decodeString2 } from "micromark-util-decode-string";
|
|
324
583
|
function mapText(source, value, range, options = {}) {
|
|
325
584
|
const raw = source.slice(range.start, range.end);
|
|
326
585
|
const starts = [], ends = [];
|
|
@@ -333,7 +592,7 @@ function mapText(source, value, range, options = {}) {
|
|
|
333
592
|
} else if (raw[at] === "&") {
|
|
334
593
|
const entity = /^&(?:#x[\da-f]+|#\d+|[a-z][\da-z]+);/i.exec(raw.slice(at));
|
|
335
594
|
if (entity) {
|
|
336
|
-
const result =
|
|
595
|
+
const result = decodeString2(entity[0]);
|
|
337
596
|
if (result !== entity[0]) {
|
|
338
597
|
length = entity[0].length;
|
|
339
598
|
decoded = result;
|
|
@@ -435,6 +694,7 @@ function selectionFromRange(document, raw, options = {}) {
|
|
|
435
694
|
var defaultHighlight = { color: "#F2C744", style: "background" };
|
|
436
695
|
var sameRange = (a, b) => a.start === b.start && a.end === b.end;
|
|
437
696
|
function annotationReferenceRange(document, occurrence) {
|
|
697
|
+
if (occurrence.referenceRange) return occurrence.referenceRange;
|
|
438
698
|
if (!occurrence.embedded) return occurrence.range;
|
|
439
699
|
let reference = occurrence.range;
|
|
440
700
|
const visit = (node) => {
|
|
@@ -460,11 +720,6 @@ function resolveAnnotationAnchors(annotation, document) {
|
|
|
460
720
|
}
|
|
461
721
|
|
|
462
722
|
export {
|
|
463
|
-
walk,
|
|
464
|
-
textContent,
|
|
465
|
-
rangeOf,
|
|
466
|
-
intersects,
|
|
467
|
-
safeUrl,
|
|
468
723
|
DocumentEngine,
|
|
469
724
|
createDocument,
|
|
470
725
|
replaceExtension,
|
|
@@ -475,4 +730,4 @@ export {
|
|
|
475
730
|
annotationReferenceRange,
|
|
476
731
|
resolveAnnotationAnchors
|
|
477
732
|
};
|
|
478
|
-
//# sourceMappingURL=chunk-
|
|
733
|
+
//# sourceMappingURL=chunk-BG5QUQFR.js.map
|