@ai-react-markdown/engine 2.11.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +715 -534
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -77
- package/dist/index.d.ts +72 -77
- package/dist/index.dev.cjs +715 -534
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +714 -534
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +714 -534
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.dev.js
CHANGED
|
@@ -172,8 +172,51 @@ var defaultUrlTransform = (value) => {
|
|
|
172
172
|
return "";
|
|
173
173
|
};
|
|
174
174
|
|
|
175
|
-
// src/components/incrementalParse/
|
|
176
|
-
|
|
175
|
+
// src/components/incrementalParse/freezeScanState.ts
|
|
176
|
+
function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
|
|
177
|
+
return {
|
|
178
|
+
defListEnabled,
|
|
179
|
+
mathFlow,
|
|
180
|
+
referenceTaint,
|
|
181
|
+
confirmedOffset: 0,
|
|
182
|
+
candidates: [],
|
|
183
|
+
defs: /* @__PURE__ */ new Map(),
|
|
184
|
+
footnoteDefs: /* @__PURE__ */ new Map(),
|
|
185
|
+
unresolvedRefs: [],
|
|
186
|
+
tagBalance: /* @__PURE__ */ new Map(),
|
|
187
|
+
openTotal: 0,
|
|
188
|
+
p5Tok: { kind: "data" },
|
|
189
|
+
formPointerMaybeSet: false,
|
|
190
|
+
openStack: [],
|
|
191
|
+
mdBlock: { kind: "none" },
|
|
192
|
+
blankRun: 0,
|
|
193
|
+
lastBlankStart: -1,
|
|
194
|
+
hazardVerdict: false,
|
|
195
|
+
prevLineBlank: true,
|
|
196
|
+
// doc start counts as a block start
|
|
197
|
+
prevLineWasText: false,
|
|
198
|
+
prevLineWasValidDef: false,
|
|
199
|
+
prevLineOpenContent: false,
|
|
200
|
+
tableMaybeOpen: false,
|
|
201
|
+
containerMaybeOpen: false,
|
|
202
|
+
paragraphHasUnpairedRun: false,
|
|
203
|
+
openBracket: null,
|
|
204
|
+
p5SealPending: false,
|
|
205
|
+
defBlockMaybeOpen: false,
|
|
206
|
+
fnDefResumable: false,
|
|
207
|
+
phasePoisonedAt: Infinity,
|
|
208
|
+
pendingTruncatedTags: [],
|
|
209
|
+
pendingTruncatedCloses: [],
|
|
210
|
+
pendingTag: null
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function pendingFenceCloser(checkpoint) {
|
|
214
|
+
const cp = checkpoint;
|
|
215
|
+
if (cp.phasePoisonedAt !== Infinity) return "";
|
|
216
|
+
if (cp.mdBlock.kind === "fence" && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);
|
|
217
|
+
if (cp.mdBlock.kind === "math" && cp.mdBlock.indent === 0) return "$".repeat(cp.mdBlock.len);
|
|
218
|
+
return "";
|
|
219
|
+
}
|
|
177
220
|
|
|
178
221
|
// src/components/incrementalParse/mdLineText.ts
|
|
179
222
|
var MD_BLANK_RE = /^[ \t\r]*$/;
|
|
@@ -181,6 +224,9 @@ var isMdBlank = (text) => MD_BLANK_RE.test(text);
|
|
|
181
224
|
var mdTrim = (text) => text.replace(/^[ \t\r]+|[ \t\r]+$/g, "");
|
|
182
225
|
var mdTrimStart = (text) => text.replace(/^[ \t\r]+/, "");
|
|
183
226
|
|
|
227
|
+
// src/components/incrementalParse/freezeLineSyntax.ts
|
|
228
|
+
import { htmlBlockNames } from "micromark-util-html-tag-name";
|
|
229
|
+
|
|
184
230
|
// src/components/incrementalParse/referenceTaint.ts
|
|
185
231
|
import { normalizeIdentifier } from "micromark-util-normalize-identifier";
|
|
186
232
|
var FOOTNOTE_DEF_RE = /^ {0,3}\[\^[^\]]*\]:/;
|
|
@@ -366,7 +412,7 @@ function settleRefsAndEarliestUnresolved(cp) {
|
|
|
366
412
|
return earliestUnresolved;
|
|
367
413
|
}
|
|
368
414
|
|
|
369
|
-
// src/components/incrementalParse/
|
|
415
|
+
// src/components/incrementalParse/freezeLineSyntax.ts
|
|
370
416
|
var TYPE6_NAMES = new Set(htmlBlockNames);
|
|
371
417
|
var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
|
|
372
418
|
var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
|
|
@@ -618,43 +664,6 @@ function maskIntraLineCodeSpans(text, carryOpen) {
|
|
|
618
664
|
out += text.slice(cursor);
|
|
619
665
|
return { masked: out, unpaired: false };
|
|
620
666
|
}
|
|
621
|
-
function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
|
|
622
|
-
return {
|
|
623
|
-
defListEnabled,
|
|
624
|
-
mathFlow,
|
|
625
|
-
referenceTaint,
|
|
626
|
-
confirmedOffset: 0,
|
|
627
|
-
candidates: [],
|
|
628
|
-
defs: /* @__PURE__ */ new Map(),
|
|
629
|
-
footnoteDefs: /* @__PURE__ */ new Map(),
|
|
630
|
-
unresolvedRefs: [],
|
|
631
|
-
tagBalance: /* @__PURE__ */ new Map(),
|
|
632
|
-
openTotal: 0,
|
|
633
|
-
p5Tok: { kind: "data" },
|
|
634
|
-
formPointerMaybeSet: false,
|
|
635
|
-
openStack: [],
|
|
636
|
-
mdBlock: { kind: "none" },
|
|
637
|
-
blankRun: 0,
|
|
638
|
-
lastBlankStart: -1,
|
|
639
|
-
hazardVerdict: false,
|
|
640
|
-
prevLineBlank: true,
|
|
641
|
-
// doc start counts as a block start
|
|
642
|
-
prevLineWasText: false,
|
|
643
|
-
prevLineWasValidDef: false,
|
|
644
|
-
prevLineOpenContent: false,
|
|
645
|
-
tableMaybeOpen: false,
|
|
646
|
-
containerMaybeOpen: false,
|
|
647
|
-
paragraphHasUnpairedRun: false,
|
|
648
|
-
openBracket: null,
|
|
649
|
-
p5SealPending: false,
|
|
650
|
-
defBlockMaybeOpen: false,
|
|
651
|
-
fnDefResumable: false,
|
|
652
|
-
phasePoisonedAt: Infinity,
|
|
653
|
-
pendingTruncatedTags: [],
|
|
654
|
-
pendingTruncatedCloses: [],
|
|
655
|
-
pendingTag: null
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
667
|
function classifyBlockStart(text, indent, defListEnabled) {
|
|
659
668
|
if (indent >= 4) return true;
|
|
660
669
|
if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;
|
|
@@ -662,71 +671,23 @@ function classifyBlockStart(text, indent, defListEnabled) {
|
|
|
662
671
|
if (indent === 0) return false;
|
|
663
672
|
return null;
|
|
664
673
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
textEnd = nl;
|
|
683
|
-
end = nl;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);
|
|
687
|
-
const lineText = text.slice(start, textEnd);
|
|
688
|
-
const ln = {
|
|
689
|
-
start,
|
|
690
|
-
end,
|
|
691
|
-
text: lineText,
|
|
692
|
-
blank: confirmed && isMdBlank(lineText),
|
|
693
|
-
indent: computeIndent(lineText)
|
|
694
|
-
};
|
|
695
|
-
if (!confirmed) {
|
|
696
|
-
tailLine = ln;
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
processConfirmedLine(cp, ln, text);
|
|
700
|
-
cp.confirmedOffset = end + 1;
|
|
701
|
-
start = end + 1;
|
|
702
|
-
}
|
|
703
|
-
const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);
|
|
704
|
-
const defListSettled = (c) => {
|
|
705
|
-
if (!options.defListEnabled || c.blankRun >= 2) return true;
|
|
706
|
-
if (c.defListSettled !== null) return c.defListSettled;
|
|
707
|
-
if (tailLine) return !canBecomeDdLine(tailLine.text, false);
|
|
708
|
-
return false;
|
|
709
|
-
};
|
|
710
|
-
const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);
|
|
711
|
-
let boundary = 0;
|
|
712
|
-
for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {
|
|
713
|
-
const c = cp.candidates[i];
|
|
714
|
-
if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;
|
|
715
|
-
if (c.offset > cp.phasePoisonedAt) continue;
|
|
716
|
-
if (c.offset > earliestUnresolved) continue;
|
|
717
|
-
if (!defListSettled(c)) continue;
|
|
718
|
-
boundary = c.offset;
|
|
719
|
-
break;
|
|
720
|
-
}
|
|
721
|
-
return { boundary, checkpoint: cp };
|
|
722
|
-
}
|
|
723
|
-
function pendingFenceCloser(checkpoint) {
|
|
724
|
-
const cp = checkpoint;
|
|
725
|
-
if (cp.phasePoisonedAt !== Infinity) return "";
|
|
726
|
-
if (cp.mdBlock.kind === "fence" && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);
|
|
727
|
-
if (cp.mdBlock.kind === "math" && cp.mdBlock.indent === 0) return "$".repeat(cp.mdBlock.len);
|
|
728
|
-
return "";
|
|
729
|
-
}
|
|
674
|
+
var SCANNER_NAME_LISTS = [
|
|
675
|
+
["type1", TYPE1_NAMES],
|
|
676
|
+
["rawText", RAW_TEXT_ELEMENTS],
|
|
677
|
+
["type6", TYPE6_NAMES],
|
|
678
|
+
["void", VOID_TAGS],
|
|
679
|
+
["documentStructure", DOCUMENT_STRUCTURE_NAMES],
|
|
680
|
+
// Added with F28, and it is the list that would have made F28 visible: the
|
|
681
|
+
// derived census alphabet partitions names by their membership across THIS
|
|
682
|
+
// table, so before it existed `frame` shared one 39-name class with `div`
|
|
683
|
+
// and could never be sampled apart from it.
|
|
684
|
+
["noElement", NO_ELEMENT_NAMES],
|
|
685
|
+
["tablePart", TABLE_PART_NAMES],
|
|
686
|
+
["scopeBarrier", SCOPE_BARRIER_NAMES],
|
|
687
|
+
["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
|
|
688
|
+
];
|
|
689
|
+
|
|
690
|
+
// src/components/incrementalParse/freezeLineTransition.ts
|
|
730
691
|
function floatingResidue(text, commentOpenAtStart) {
|
|
731
692
|
let out = "";
|
|
732
693
|
let open = commentOpenAtStart;
|
|
@@ -1376,24 +1337,66 @@ function processConfirmedLine(cp, ln, text) {
|
|
|
1376
1337
|
}
|
|
1377
1338
|
}
|
|
1378
1339
|
}
|
|
1379
|
-
var SCANNER_NAME_LISTS = [
|
|
1380
|
-
["type1", TYPE1_NAMES],
|
|
1381
|
-
["rawText", RAW_TEXT_ELEMENTS],
|
|
1382
|
-
["type6", TYPE6_NAMES],
|
|
1383
|
-
["void", VOID_TAGS],
|
|
1384
|
-
["documentStructure", DOCUMENT_STRUCTURE_NAMES],
|
|
1385
|
-
// Added with F28, and it is the list that would have made F28 visible: the
|
|
1386
|
-
// derived census alphabet partitions names by their membership across THIS
|
|
1387
|
-
// table, so before it existed `frame` shared one 39-name class with `div`
|
|
1388
|
-
// and could never be sampled apart from it.
|
|
1389
|
-
["noElement", NO_ELEMENT_NAMES],
|
|
1390
|
-
["tablePart", TABLE_PART_NAMES],
|
|
1391
|
-
["scopeBarrier", SCOPE_BARRIER_NAMES],
|
|
1392
|
-
["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
|
|
1393
|
-
];
|
|
1394
1340
|
|
|
1395
|
-
// src/components/incrementalParse/
|
|
1396
|
-
|
|
1341
|
+
// src/components/incrementalParse/computeFreezeBoundary.ts
|
|
1342
|
+
function computeFreezeBoundary(text, options, resume) {
|
|
1343
|
+
const mathFlow = options.mathFlow ?? true;
|
|
1344
|
+
const referenceTaint = options.referenceTaint ?? true;
|
|
1345
|
+
const prev = resume;
|
|
1346
|
+
const cp = prev && prev.defListEnabled === options.defListEnabled && prev.mathFlow === mathFlow && prev.referenceTaint === referenceTaint && prev.confirmedOffset <= text.length ? prev : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
|
|
1347
|
+
let start = cp.confirmedOffset;
|
|
1348
|
+
let tailLine = null;
|
|
1349
|
+
while (start < text.length) {
|
|
1350
|
+
let end = text.length;
|
|
1351
|
+
let textEnd = text.length;
|
|
1352
|
+
{
|
|
1353
|
+
const nl = text.indexOf("\n", start);
|
|
1354
|
+
const cr = text.indexOf("\r", start);
|
|
1355
|
+
if (cr !== -1 && (nl === -1 || cr < nl)) {
|
|
1356
|
+
textEnd = cr;
|
|
1357
|
+
end = text.charCodeAt(cr + 1) === 10 ? cr + 1 : cr;
|
|
1358
|
+
} else if (nl !== -1) {
|
|
1359
|
+
textEnd = nl;
|
|
1360
|
+
end = nl;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);
|
|
1364
|
+
const lineText = text.slice(start, textEnd);
|
|
1365
|
+
const ln = {
|
|
1366
|
+
start,
|
|
1367
|
+
end,
|
|
1368
|
+
text: lineText,
|
|
1369
|
+
blank: confirmed && isMdBlank(lineText),
|
|
1370
|
+
indent: computeIndent(lineText)
|
|
1371
|
+
};
|
|
1372
|
+
if (!confirmed) {
|
|
1373
|
+
tailLine = ln;
|
|
1374
|
+
break;
|
|
1375
|
+
}
|
|
1376
|
+
processConfirmedLine(cp, ln, text);
|
|
1377
|
+
cp.confirmedOffset = end + 1;
|
|
1378
|
+
start = end + 1;
|
|
1379
|
+
}
|
|
1380
|
+
const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);
|
|
1381
|
+
const defListSettled = (c) => {
|
|
1382
|
+
if (!options.defListEnabled || c.blankRun >= 2) return true;
|
|
1383
|
+
if (c.defListSettled !== null) return c.defListSettled;
|
|
1384
|
+
if (tailLine) return !canBecomeDdLine(tailLine.text, false);
|
|
1385
|
+
return false;
|
|
1386
|
+
};
|
|
1387
|
+
const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);
|
|
1388
|
+
let boundary = 0;
|
|
1389
|
+
for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {
|
|
1390
|
+
const c = cp.candidates[i];
|
|
1391
|
+
if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;
|
|
1392
|
+
if (c.offset > cp.phasePoisonedAt) continue;
|
|
1393
|
+
if (c.offset > earliestUnresolved) continue;
|
|
1394
|
+
if (!defListSettled(c)) continue;
|
|
1395
|
+
boundary = c.offset;
|
|
1396
|
+
break;
|
|
1397
|
+
}
|
|
1398
|
+
return { boundary, checkpoint: cp };
|
|
1399
|
+
}
|
|
1397
1400
|
|
|
1398
1401
|
// src/components/hastPredicates.ts
|
|
1399
1402
|
function isFootnoteSection(node) {
|
|
@@ -1441,121 +1444,7 @@ function attributeHastChildren(mdast, hast, stopAt = Infinity) {
|
|
|
1441
1444
|
}
|
|
1442
1445
|
}
|
|
1443
1446
|
|
|
1444
|
-
// src/components/incrementalParse/
|
|
1445
|
-
function collectPrefixInjection(mdast, content, boundary, resume) {
|
|
1446
|
-
const resumeValid = resume != null && resume.boundary <= boundary;
|
|
1447
|
-
if (resumeValid && resume.uninjectable) return { events: resume.events, uninjectable: true };
|
|
1448
|
-
const resumeAt = resumeValid ? resume.boundary : 0;
|
|
1449
|
-
const events = resumeAt > 0 ? cloneEventsForAppend(resume.events) : [];
|
|
1450
|
-
let uninjectable = false;
|
|
1451
|
-
let cacheable = true;
|
|
1452
|
-
const pushRef = (token) => {
|
|
1453
|
-
const last = events[events.length - 1];
|
|
1454
|
-
if (last && last.kind === "refs") last.tokens.push(token);
|
|
1455
|
-
else events.push({ kind: "refs", tokens: [token] });
|
|
1456
|
-
};
|
|
1457
|
-
const visit7 = (node, nested) => {
|
|
1458
|
-
const type = node.type;
|
|
1459
|
-
if (type === "definition") {
|
|
1460
|
-
const start = node.position?.start?.offset;
|
|
1461
|
-
const end = node.position?.end?.offset;
|
|
1462
|
-
if (start !== void 0 && end !== void 0 && start < boundary) {
|
|
1463
|
-
const slice = content.slice(start, end);
|
|
1464
|
-
if (nested && slice.includes("\n")) uninjectable = true;
|
|
1465
|
-
else events.push({ kind: "def", source: slice });
|
|
1466
|
-
}
|
|
1467
|
-
return;
|
|
1468
|
-
}
|
|
1469
|
-
if (type === "footnoteDefinition") {
|
|
1470
|
-
const start = node.position?.start;
|
|
1471
|
-
const end = node.position?.end?.offset;
|
|
1472
|
-
if (start?.offset === void 0 || end === void 0 || start.offset >= boundary) return;
|
|
1473
|
-
if (nested) {
|
|
1474
|
-
uninjectable = true;
|
|
1475
|
-
return;
|
|
1476
|
-
}
|
|
1477
|
-
const lineStart = start.offset - (start.column - 1);
|
|
1478
|
-
events.push({
|
|
1479
|
-
kind: "footnoteDef",
|
|
1480
|
-
source: content.slice(lineStart, end),
|
|
1481
|
-
origStart: lineStart,
|
|
1482
|
-
origLine: start.line
|
|
1483
|
-
});
|
|
1484
|
-
return;
|
|
1485
|
-
}
|
|
1486
|
-
if (type === "footnoteReference") {
|
|
1487
|
-
const start = node.position?.start?.offset;
|
|
1488
|
-
const end = node.position?.end?.offset;
|
|
1489
|
-
if (start === void 0 || end === void 0) {
|
|
1490
|
-
uninjectable = true;
|
|
1491
|
-
return;
|
|
1492
|
-
}
|
|
1493
|
-
pushRef(content.slice(start, end));
|
|
1494
|
-
return;
|
|
1495
|
-
}
|
|
1496
|
-
const children = node.children;
|
|
1497
|
-
if (children) {
|
|
1498
|
-
for (const child of children) visit7(child, true);
|
|
1499
|
-
}
|
|
1500
|
-
};
|
|
1501
|
-
let lastStart = -1;
|
|
1502
|
-
for (const child of mdast.children) {
|
|
1503
|
-
const start = child.position?.start?.offset;
|
|
1504
|
-
if (start !== void 0) {
|
|
1505
|
-
if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };
|
|
1506
|
-
lastStart = start;
|
|
1507
|
-
}
|
|
1508
|
-
if (start === void 0) {
|
|
1509
|
-
if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);
|
|
1510
|
-
cacheable = false;
|
|
1511
|
-
visit7(child, false);
|
|
1512
|
-
continue;
|
|
1513
|
-
}
|
|
1514
|
-
if (start >= boundary || start < resumeAt) continue;
|
|
1515
|
-
visit7(child, false);
|
|
1516
|
-
}
|
|
1517
|
-
return { events, uninjectable, cacheable };
|
|
1518
|
-
}
|
|
1519
|
-
function cloneEventsForAppend(events) {
|
|
1520
|
-
const out = events.slice();
|
|
1521
|
-
const last = out[out.length - 1];
|
|
1522
|
-
if (last && last.kind === "refs") out[out.length - 1] = { kind: "refs", tokens: last.tokens.slice() };
|
|
1523
|
-
return out;
|
|
1524
|
-
}
|
|
1525
|
-
var TERMINATOR_LABEL = "__aimd_injection_terminator__";
|
|
1526
|
-
var INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;
|
|
1527
|
-
function tailMentionsTerminator(tailSource) {
|
|
1528
|
-
return normalizeIdentifier2(tailSource).replace(/\[ /g, "[").includes(`[${normalizeIdentifier2(TERMINATOR_LABEL)}`);
|
|
1529
|
-
}
|
|
1530
|
-
function buildInjectionPrefix(events) {
|
|
1531
|
-
if (events.length === 0) return { text: "", segments: [] };
|
|
1532
|
-
let text = "";
|
|
1533
|
-
let line = 1;
|
|
1534
|
-
const segments = [];
|
|
1535
|
-
for (const event of events) {
|
|
1536
|
-
if (text.length > 0) {
|
|
1537
|
-
text += "\n\n";
|
|
1538
|
-
line += 2;
|
|
1539
|
-
}
|
|
1540
|
-
const injStart = text.length;
|
|
1541
|
-
const source = event.kind === "refs" ? event.tokens.join(" ") : event.source;
|
|
1542
|
-
if (event.kind === "footnoteDef") {
|
|
1543
|
-
segments.push({
|
|
1544
|
-
injStart,
|
|
1545
|
-
injEnd: injStart + source.length,
|
|
1546
|
-
offsetDelta: event.origStart - injStart,
|
|
1547
|
-
lineDelta: event.origLine - line
|
|
1548
|
-
});
|
|
1549
|
-
}
|
|
1550
|
-
text += source;
|
|
1551
|
-
line += countNewlines(source);
|
|
1552
|
-
}
|
|
1553
|
-
return { text: `${text}
|
|
1554
|
-
|
|
1555
|
-
${INJECTION_TERMINATOR}
|
|
1556
|
-
|
|
1557
|
-
`, segments };
|
|
1558
|
-
}
|
|
1447
|
+
// src/components/incrementalParse/spliceCoordinates.ts
|
|
1559
1448
|
function rebaseTree(node, offsetDelta, lineDelta) {
|
|
1560
1449
|
rebaseTreeDual(node, EMPTY_SEGMENTS, offsetDelta, lineDelta);
|
|
1561
1450
|
}
|
|
@@ -1584,6 +1473,23 @@ function rebaseDualWalk(node, segments, maxEnd, offsetDelta, lineDelta) {
|
|
|
1584
1473
|
for (const child of children) rebaseDualWalk(child, segments, maxEnd, offsetDelta, lineDelta);
|
|
1585
1474
|
}
|
|
1586
1475
|
}
|
|
1476
|
+
function rebasePoint(point, offsetDelta, lineDelta) {
|
|
1477
|
+
return {
|
|
1478
|
+
line: point.line + lineDelta,
|
|
1479
|
+
column: point.column,
|
|
1480
|
+
offset: point.offset !== void 0 ? point.offset + offsetDelta : void 0
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function countNewlines(text, end = text.length) {
|
|
1484
|
+
let count = 0;
|
|
1485
|
+
for (let i = text.indexOf("\n"); i !== -1 && i < end; i = text.indexOf("\n", i + 1)) count += 1;
|
|
1486
|
+
for (let i = text.indexOf("\r"); i !== -1 && i < end; i = text.indexOf("\r", i + 1)) {
|
|
1487
|
+
if (text.charCodeAt(i + 1) !== 10) count += 1;
|
|
1488
|
+
}
|
|
1489
|
+
return count;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/components/incrementalParse/spliceHtmlGuards.ts
|
|
1587
1493
|
var TABLE_PART_TAG_RE = /<(?:td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\b/i;
|
|
1588
1494
|
var TABLE_TOKEN_RE = /<(\/?)(table|td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\b/gi;
|
|
1589
1495
|
function hasStrayTablePart(values) {
|
|
@@ -1665,127 +1571,26 @@ function rawTextRegionCrossesOut(values) {
|
|
|
1665
1571
|
}
|
|
1666
1572
|
return false;
|
|
1667
1573
|
}
|
|
1668
|
-
function
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
}
|
|
1680
|
-
const attrs = attributeHastChildren(prevMdast, prevHast, boundary);
|
|
1681
|
-
const cutRegion = [];
|
|
1682
|
-
for (let i = 0; i < prevHast.children.length; i++) {
|
|
1683
|
-
if (attrs[i] < boundary) {
|
|
1684
|
-
const node2 = prevHast.children[i];
|
|
1685
|
-
const end = node2.position?.end?.offset;
|
|
1686
|
-
if (end !== void 0 && end > boundary) return null;
|
|
1687
|
-
if (isTrailingLiteralText(node2)) {
|
|
1688
|
-
const prev = i > 0 ? prevHast.children[i - 1] : void 0;
|
|
1689
|
-
if (!prev || prev.type !== "element" || prev.position === void 0) return null;
|
|
1690
|
-
if (!ownsTrailingLiteral(prev, node2, prefixMdast))
|
|
1691
|
-
return null;
|
|
1692
|
-
}
|
|
1693
|
-
cutRegion.push(node2);
|
|
1694
|
-
continue;
|
|
1695
|
-
}
|
|
1696
|
-
const node = prevHast.children[i];
|
|
1697
|
-
if (i > 0 && attrs[i - 1] < boundary && prevHast.children[i - 1].type === "element" && isTrailingLiteralText(node) && // …and only when that element really IS an html block's output: a
|
|
1698
|
-
// raw literal can only trail an `html` mdast node. A position-less
|
|
1699
|
-
// text after a `<p>` is the NEXT block's remnant — a stray end tag
|
|
1700
|
-
// (`</t>\na`) parse5 dropped, whose text merged with the wrap
|
|
1701
|
-
// separator — owned by the tail, which re-parses it; freezing it
|
|
1702
|
-
// here duplicated it (v2.4.0 review P3). Falls through to the
|
|
1703
|
-
// remnant look-ahead below, which bails to a full parse. And the
|
|
1704
|
-
// literal must really be THAT block's trailing text: the block's raw
|
|
1705
|
-
// source ends with it. A dropped-tag block right after a frozen html
|
|
1706
|
-
// element (`</details>\n\n</t>\ntext`) puts its remnant in the same
|
|
1707
|
-
// position, and freezing it duplicated it (release soak of the fix).
|
|
1708
|
-
ownsTrailingLiteral(prevHast.children[i - 1], node, prefixMdast)) {
|
|
1709
|
-
cutRegion.push(node);
|
|
1710
|
-
break;
|
|
1711
|
-
}
|
|
1712
|
-
for (let j = i; j < prevHast.children.length; j++) {
|
|
1713
|
-
const look = prevHast.children[j];
|
|
1714
|
-
if (look.type === "element" || look.position !== void 0) break;
|
|
1715
|
-
if (isTrailingLiteralText(look)) return null;
|
|
1716
|
-
}
|
|
1717
|
-
break;
|
|
1718
|
-
}
|
|
1719
|
-
const tailMdastChildren = tailMdast.children.filter((child) => {
|
|
1720
|
-
const start = child.position?.start?.offset;
|
|
1721
|
-
return !(start !== void 0 && start < injectedLen);
|
|
1722
|
-
});
|
|
1723
|
-
const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));
|
|
1724
|
-
const prefixHtmlValues = prefixMdast.flatMap((c) => c.type === "html" ? [c.value] : []);
|
|
1725
|
-
if (hasStrayTablePart(prefixHtmlValues)) return null;
|
|
1726
|
-
if (rawTextRegionCrossesOut(prefixHtmlValues)) return null;
|
|
1727
|
-
const leadingHtml = [];
|
|
1728
|
-
for (const child of tailMdastChildren) {
|
|
1729
|
-
if (isWrapInvisible(child)) continue;
|
|
1730
|
-
if (child.type !== "html") break;
|
|
1731
|
-
if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;
|
|
1732
|
-
leadingHtml.push(child.value);
|
|
1574
|
+
function isSanitizeStrippedConstruct(value) {
|
|
1575
|
+
const v = value.trim();
|
|
1576
|
+
return v.startsWith("<!--") && v.endsWith("-->") || v.startsWith("<?") && v.endsWith("?>") || v.startsWith("<![CDATA[") && v.endsWith("]]>") || /^<![A-Za-z]/.test(v) && !/^<!doctype/i.test(v) && v.endsWith(">");
|
|
1577
|
+
}
|
|
1578
|
+
function isExactSanitizeStrippedConstruct(value) {
|
|
1579
|
+
if (value.startsWith("<!--")) {
|
|
1580
|
+
if (value.length < 7 || !value.endsWith("-->")) return false;
|
|
1581
|
+
const close = value.indexOf("-->", 4);
|
|
1582
|
+
const bangClose = value.indexOf("--!>", 4);
|
|
1583
|
+
if (close !== value.length - 3) return false;
|
|
1584
|
+
return bangClose === -1 || bangClose > close;
|
|
1733
1585
|
}
|
|
1734
|
-
if (
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
const hastChildren = aligned.children;
|
|
1738
|
-
const interiorFinalLiteral = aligned.interiorFinalLiteral;
|
|
1739
|
-
const stripResult = stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible);
|
|
1740
|
-
if (stripResult === null) return null;
|
|
1741
|
-
const strippedTailHast = stripResult.rest;
|
|
1742
|
-
for (const child of tailMdastChildren) rebaseTree(child, offsetDelta, lineDelta);
|
|
1743
|
-
for (const child of strippedTailHast) rebaseTreeDual(child, injectedSegments, offsetDelta, lineDelta);
|
|
1744
|
-
const mdastChildren = prefixMdast.concat(tailMdastChildren);
|
|
1745
|
-
const seamMergeVerdict = stripResult.remnantMerged ?? tailLeadingTextIsHoist(tailMdastChildren, strippedTailHast);
|
|
1746
|
-
if (seamMergeVerdict === null) return null;
|
|
1747
|
-
const seamMergeAllowed = seamMergeVerdict;
|
|
1748
|
-
let firstTailChild = true;
|
|
1749
|
-
for (const child of strippedTailHast) {
|
|
1750
|
-
const tailEnd = hastChildren[hastChildren.length - 1];
|
|
1751
|
-
if (firstTailChild && child.type === "text" && child.position !== void 0) {
|
|
1752
|
-
return null;
|
|
1753
|
-
}
|
|
1754
|
-
if (firstTailChild && tailEnd && tailEnd.type === "text" && child.type === "text" && child.position === void 0) {
|
|
1755
|
-
if (interiorFinalLiteral && tailEnd.value.trim() !== "") {
|
|
1756
|
-
if (seamMergeAllowed) return null;
|
|
1757
|
-
firstTailChild = false;
|
|
1758
|
-
hastChildren.push(child);
|
|
1759
|
-
continue;
|
|
1760
|
-
}
|
|
1761
|
-
const literalSeam = tailEnd.value.trim() !== "" && !tailWrapVisible;
|
|
1762
|
-
if (seamMergeAllowed || literalSeam) {
|
|
1763
|
-
hastChildren[hastChildren.length - 1] = { type: "text", value: tailEnd.value + child.value };
|
|
1764
|
-
firstTailChild = false;
|
|
1765
|
-
continue;
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
firstTailChild = false;
|
|
1769
|
-
hastChildren.push(child);
|
|
1586
|
+
if (/^<!doctype/i.test(value)) return false;
|
|
1587
|
+
if (value.startsWith("<?") || /^<!(?:[A-Za-z]|\[CDATA\[)/.test(value)) {
|
|
1588
|
+
return value.indexOf(">") === value.length - 1;
|
|
1770
1589
|
}
|
|
1771
|
-
|
|
1772
|
-
const docStart = { line: 1, column: 1, offset: 0 };
|
|
1773
|
-
const mdastRootPosition = tailMdast.position ? { start: docStart, end: rebasePoint(tailMdast.position.end, offsetDelta, lineDelta) } : prevMdast.position;
|
|
1774
|
-
const hastRootPosition = mdastRootPosition;
|
|
1775
|
-
const mdast = { type: "root", children: mdastChildren };
|
|
1776
|
-
if (mdastRootPosition) mdast.position = mdastRootPosition;
|
|
1777
|
-
const hast = { type: "root", children: hastChildren };
|
|
1778
|
-
if (hastRootPosition) hast.position = hastRootPosition;
|
|
1779
|
-
if (prevHast.data !== void 0) hast.data = prevHast.data;
|
|
1780
|
-
return { mdast, hast };
|
|
1781
|
-
}
|
|
1782
|
-
function rebasePoint(point, offsetDelta, lineDelta) {
|
|
1783
|
-
return {
|
|
1784
|
-
line: point.line + lineDelta,
|
|
1785
|
-
column: point.column,
|
|
1786
|
-
offset: point.offset !== void 0 ? point.offset + offsetDelta : void 0
|
|
1787
|
-
};
|
|
1590
|
+
return false;
|
|
1788
1591
|
}
|
|
1592
|
+
|
|
1593
|
+
// src/components/incrementalParse/prefixAlignment.ts
|
|
1789
1594
|
function isWrapInvisible(node) {
|
|
1790
1595
|
return node.type === "definition" || node.type === "footnoteDefinition";
|
|
1791
1596
|
}
|
|
@@ -1927,96 +1732,303 @@ function stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible) {
|
|
|
1927
1732
|
idx += 1;
|
|
1928
1733
|
continue;
|
|
1929
1734
|
}
|
|
1930
|
-
const start = node.position?.start?.offset;
|
|
1931
|
-
if (start === void 0 || start >= injectedLen) return null;
|
|
1932
|
-
consumed += 1;
|
|
1933
|
-
idx += 1;
|
|
1735
|
+
const start = node.position?.start?.offset;
|
|
1736
|
+
if (start === void 0 || start >= injectedLen) return null;
|
|
1737
|
+
consumed += 1;
|
|
1738
|
+
idx += 1;
|
|
1739
|
+
}
|
|
1740
|
+
if (consumed < injectedVisibleCount) return null;
|
|
1741
|
+
let remnant = "";
|
|
1742
|
+
let remnantMerged = null;
|
|
1743
|
+
if (tailWrapVisible) {
|
|
1744
|
+
const gap = children[idx];
|
|
1745
|
+
if (!gap || !isSeparatorText(gap)) return null;
|
|
1746
|
+
remnant = gap.value.slice(1);
|
|
1747
|
+
remnantMerged = remnant !== "";
|
|
1748
|
+
idx += 1;
|
|
1749
|
+
}
|
|
1750
|
+
const rest = children.slice(idx);
|
|
1751
|
+
if (remnant !== "") rest.unshift({ type: "text", value: remnant });
|
|
1752
|
+
return { rest, remnantMerged };
|
|
1753
|
+
}
|
|
1754
|
+
function tailLeadingTextIsHoist(tailMdastChildren, tailHastChildren) {
|
|
1755
|
+
const firstText = tailHastChildren[0];
|
|
1756
|
+
const firstVisible = tailMdastChildren.find((c) => !isWrapInvisible(c));
|
|
1757
|
+
if (firstVisible?.type === "html" && STRAY_SYNTHESIZED_END_TAG_RE.test(firstVisible.value)) return null;
|
|
1758
|
+
if (!firstText) return false;
|
|
1759
|
+
if (!isSeparatorText(firstText)) {
|
|
1760
|
+
if (firstText.type === "text" && firstText.position === void 0 && firstVisible?.type === "html") {
|
|
1761
|
+
if (/^\s*<\/[A-Za-z][A-Za-z0-9-]*\s*>/.test(firstVisible.value)) return true;
|
|
1762
|
+
if (isSanitizeStrippedConstruct(firstVisible.value)) return false;
|
|
1763
|
+
return null;
|
|
1764
|
+
}
|
|
1765
|
+
return false;
|
|
1766
|
+
}
|
|
1767
|
+
if (!firstVisible) return false;
|
|
1768
|
+
const firstContent = tailHastChildren.find((c) => !isSeparatorText(c));
|
|
1769
|
+
if (firstContent) {
|
|
1770
|
+
const start = firstContent.position?.start?.offset;
|
|
1771
|
+
const vStart = firstVisible.position?.start?.offset;
|
|
1772
|
+
const vEnd = firstVisible.position?.end?.offset;
|
|
1773
|
+
if (start !== void 0 && vStart !== void 0 && vEnd !== void 0) {
|
|
1774
|
+
if (start >= vStart && start < vEnd) return true;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
if (firstVisible.type === "math") return false;
|
|
1778
|
+
if (firstVisible.type === "html" && isSanitizeStrippedConstruct(firstVisible.value)) return false;
|
|
1779
|
+
return null;
|
|
1780
|
+
}
|
|
1781
|
+
function isSeparatorText(node) {
|
|
1782
|
+
return node.type === "text" && node.position === void 0 && node.value.trim() === "";
|
|
1783
|
+
}
|
|
1784
|
+
function ownsTrailingLiteral(el, literal, prefixMdast) {
|
|
1785
|
+
const start = el.position?.start?.offset;
|
|
1786
|
+
if (start === void 0) return false;
|
|
1787
|
+
const owner = prefixMdast.find((c) => c.type === "html" && c.position?.start?.offset === start);
|
|
1788
|
+
if (!owner || owner.type !== "html") return false;
|
|
1789
|
+
const text = literal.value.trim();
|
|
1790
|
+
return text !== "" && owner.value.trimEnd().endsWith(text);
|
|
1791
|
+
}
|
|
1792
|
+
function isTrailingLiteralText(node) {
|
|
1793
|
+
return node.type === "text" && node.position === void 0 && node.value.trim() !== "";
|
|
1794
|
+
}
|
|
1795
|
+
function countTrailingNewlines(value) {
|
|
1796
|
+
let n = 0;
|
|
1797
|
+
for (let i = value.length - 1; i >= 0 && value[i] === "\n"; i--) n += 1;
|
|
1798
|
+
return n;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
// src/components/incrementalParse/prefixInjection.ts
|
|
1802
|
+
import { normalizeIdentifier as normalizeIdentifier2 } from "micromark-util-normalize-identifier";
|
|
1803
|
+
function collectPrefixInjection(mdast, content, boundary, resume) {
|
|
1804
|
+
const resumeValid = resume != null && resume.boundary <= boundary;
|
|
1805
|
+
if (resumeValid && resume.uninjectable) return { events: resume.events, uninjectable: true };
|
|
1806
|
+
const resumeAt = resumeValid ? resume.boundary : 0;
|
|
1807
|
+
const events = resumeAt > 0 ? cloneEventsForAppend(resume.events) : [];
|
|
1808
|
+
let uninjectable = false;
|
|
1809
|
+
let cacheable = true;
|
|
1810
|
+
const pushRef = (token) => {
|
|
1811
|
+
const last = events[events.length - 1];
|
|
1812
|
+
if (last && last.kind === "refs") last.tokens.push(token);
|
|
1813
|
+
else events.push({ kind: "refs", tokens: [token] });
|
|
1814
|
+
};
|
|
1815
|
+
const visit7 = (node, nested) => {
|
|
1816
|
+
const type = node.type;
|
|
1817
|
+
if (type === "definition") {
|
|
1818
|
+
const start = node.position?.start?.offset;
|
|
1819
|
+
const end = node.position?.end?.offset;
|
|
1820
|
+
if (start !== void 0 && end !== void 0 && start < boundary) {
|
|
1821
|
+
const slice = content.slice(start, end);
|
|
1822
|
+
if (nested && slice.includes("\n")) uninjectable = true;
|
|
1823
|
+
else events.push({ kind: "def", source: slice });
|
|
1824
|
+
}
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (type === "footnoteDefinition") {
|
|
1828
|
+
const start = node.position?.start;
|
|
1829
|
+
const end = node.position?.end?.offset;
|
|
1830
|
+
if (start?.offset === void 0 || end === void 0 || start.offset >= boundary) return;
|
|
1831
|
+
if (nested) {
|
|
1832
|
+
uninjectable = true;
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
const lineStart = start.offset - (start.column - 1);
|
|
1836
|
+
events.push({
|
|
1837
|
+
kind: "footnoteDef",
|
|
1838
|
+
source: content.slice(lineStart, end),
|
|
1839
|
+
origStart: lineStart,
|
|
1840
|
+
origLine: start.line
|
|
1841
|
+
});
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
if (type === "footnoteReference") {
|
|
1845
|
+
const start = node.position?.start?.offset;
|
|
1846
|
+
const end = node.position?.end?.offset;
|
|
1847
|
+
if (start === void 0 || end === void 0) {
|
|
1848
|
+
uninjectable = true;
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
pushRef(content.slice(start, end));
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
const children = node.children;
|
|
1855
|
+
if (children) {
|
|
1856
|
+
for (const child of children) visit7(child, true);
|
|
1857
|
+
}
|
|
1858
|
+
};
|
|
1859
|
+
let lastStart = -1;
|
|
1860
|
+
for (const child of mdast.children) {
|
|
1861
|
+
const start = child.position?.start?.offset;
|
|
1862
|
+
if (start !== void 0) {
|
|
1863
|
+
if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };
|
|
1864
|
+
lastStart = start;
|
|
1865
|
+
}
|
|
1866
|
+
if (start === void 0) {
|
|
1867
|
+
if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);
|
|
1868
|
+
cacheable = false;
|
|
1869
|
+
visit7(child, false);
|
|
1870
|
+
continue;
|
|
1871
|
+
}
|
|
1872
|
+
if (start >= boundary || start < resumeAt) continue;
|
|
1873
|
+
visit7(child, false);
|
|
1874
|
+
}
|
|
1875
|
+
return { events, uninjectable, cacheable };
|
|
1876
|
+
}
|
|
1877
|
+
function cloneEventsForAppend(events) {
|
|
1878
|
+
const out = events.slice();
|
|
1879
|
+
const last = out[out.length - 1];
|
|
1880
|
+
if (last && last.kind === "refs") out[out.length - 1] = { kind: "refs", tokens: last.tokens.slice() };
|
|
1881
|
+
return out;
|
|
1882
|
+
}
|
|
1883
|
+
var TERMINATOR_LABEL = "__aimd_injection_terminator__";
|
|
1884
|
+
var INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;
|
|
1885
|
+
function tailMentionsTerminator(tailSource) {
|
|
1886
|
+
return normalizeIdentifier2(tailSource).replace(/\[ /g, "[").includes(`[${normalizeIdentifier2(TERMINATOR_LABEL)}`);
|
|
1887
|
+
}
|
|
1888
|
+
function buildInjectionPrefix(events) {
|
|
1889
|
+
if (events.length === 0) return { text: "", segments: [] };
|
|
1890
|
+
let text = "";
|
|
1891
|
+
let line = 1;
|
|
1892
|
+
const segments = [];
|
|
1893
|
+
for (const event of events) {
|
|
1894
|
+
if (text.length > 0) {
|
|
1895
|
+
text += "\n\n";
|
|
1896
|
+
line += 2;
|
|
1897
|
+
}
|
|
1898
|
+
const injStart = text.length;
|
|
1899
|
+
const source = event.kind === "refs" ? event.tokens.join(" ") : event.source;
|
|
1900
|
+
if (event.kind === "footnoteDef") {
|
|
1901
|
+
segments.push({
|
|
1902
|
+
injStart,
|
|
1903
|
+
injEnd: injStart + source.length,
|
|
1904
|
+
offsetDelta: event.origStart - injStart,
|
|
1905
|
+
lineDelta: event.origLine - line
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
text += source;
|
|
1909
|
+
line += countNewlines(source);
|
|
1910
|
+
}
|
|
1911
|
+
return { text: `${text}
|
|
1912
|
+
|
|
1913
|
+
${INJECTION_TERMINATOR}
|
|
1914
|
+
|
|
1915
|
+
`, segments };
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
// src/components/incrementalParse/spliceParse.ts
|
|
1919
|
+
function spliceTrees(input) {
|
|
1920
|
+
const { prevMdast, prevHast, tailMdast, tailHast, content, boundary, injectionPrefix, injectedSegments } = input;
|
|
1921
|
+
const injectedLen = injectionPrefix.length;
|
|
1922
|
+
const injectedLines = countNewlines(injectionPrefix);
|
|
1923
|
+
const prefixLines = countNewlines(content, boundary);
|
|
1924
|
+
const offsetDelta = boundary - injectedLen;
|
|
1925
|
+
const lineDelta = prefixLines - injectedLines;
|
|
1926
|
+
const prefixMdast = [];
|
|
1927
|
+
for (const child of prevMdast.children) {
|
|
1928
|
+
const start = child.position?.start?.offset;
|
|
1929
|
+
if (start !== void 0 && start < boundary) prefixMdast.push(child);
|
|
1930
|
+
}
|
|
1931
|
+
const attrs = attributeHastChildren(prevMdast, prevHast, boundary);
|
|
1932
|
+
const cutRegion = [];
|
|
1933
|
+
for (let i = 0; i < prevHast.children.length; i++) {
|
|
1934
|
+
if (attrs[i] < boundary) {
|
|
1935
|
+
const node2 = prevHast.children[i];
|
|
1936
|
+
const end = node2.position?.end?.offset;
|
|
1937
|
+
if (end !== void 0 && end > boundary) return null;
|
|
1938
|
+
if (isTrailingLiteralText(node2)) {
|
|
1939
|
+
const prev = i > 0 ? prevHast.children[i - 1] : void 0;
|
|
1940
|
+
if (!prev || prev.type !== "element" || prev.position === void 0) return null;
|
|
1941
|
+
if (!ownsTrailingLiteral(prev, node2, prefixMdast))
|
|
1942
|
+
return null;
|
|
1943
|
+
}
|
|
1944
|
+
cutRegion.push(node2);
|
|
1945
|
+
continue;
|
|
1946
|
+
}
|
|
1947
|
+
const node = prevHast.children[i];
|
|
1948
|
+
if (i > 0 && attrs[i - 1] < boundary && prevHast.children[i - 1].type === "element" && isTrailingLiteralText(node) && // …and only when that element really IS an html block's output: a
|
|
1949
|
+
// raw literal can only trail an `html` mdast node. A position-less
|
|
1950
|
+
// text after a `<p>` is the NEXT block's remnant — a stray end tag
|
|
1951
|
+
// (`</t>\na`) parse5 dropped, whose text merged with the wrap
|
|
1952
|
+
// separator — owned by the tail, which re-parses it; freezing it
|
|
1953
|
+
// here duplicated it (v2.4.0 review P3). Falls through to the
|
|
1954
|
+
// remnant look-ahead below, which bails to a full parse. And the
|
|
1955
|
+
// literal must really be THAT block's trailing text: the block's raw
|
|
1956
|
+
// source ends with it. A dropped-tag block right after a frozen html
|
|
1957
|
+
// element (`</details>\n\n</t>\ntext`) puts its remnant in the same
|
|
1958
|
+
// position, and freezing it duplicated it (release soak of the fix).
|
|
1959
|
+
ownsTrailingLiteral(prevHast.children[i - 1], node, prefixMdast)) {
|
|
1960
|
+
cutRegion.push(node);
|
|
1961
|
+
break;
|
|
1962
|
+
}
|
|
1963
|
+
for (let j = i; j < prevHast.children.length; j++) {
|
|
1964
|
+
const look = prevHast.children[j];
|
|
1965
|
+
if (look.type === "element" || look.position !== void 0) break;
|
|
1966
|
+
if (isTrailingLiteralText(look)) return null;
|
|
1967
|
+
}
|
|
1968
|
+
break;
|
|
1934
1969
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1970
|
+
const tailMdastChildren = tailMdast.children.filter((child) => {
|
|
1971
|
+
const start = child.position?.start?.offset;
|
|
1972
|
+
return !(start !== void 0 && start < injectedLen);
|
|
1973
|
+
});
|
|
1974
|
+
const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));
|
|
1975
|
+
const prefixHtmlValues = prefixMdast.flatMap((c) => c.type === "html" ? [c.value] : []);
|
|
1976
|
+
if (hasStrayTablePart(prefixHtmlValues)) return null;
|
|
1977
|
+
if (rawTextRegionCrossesOut(prefixHtmlValues)) return null;
|
|
1978
|
+
const leadingHtml = [];
|
|
1979
|
+
for (const child of tailMdastChildren) {
|
|
1980
|
+
if (isWrapInvisible(child)) continue;
|
|
1981
|
+
if (child.type !== "html") break;
|
|
1982
|
+
if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;
|
|
1983
|
+
leadingHtml.push(child.value);
|
|
1944
1984
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1985
|
+
if (headRoutedCaptureUnclosed(leadingHtml)) return null;
|
|
1986
|
+
const aligned = alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible);
|
|
1987
|
+
if (aligned === null) return null;
|
|
1988
|
+
const hastChildren = aligned.children;
|
|
1989
|
+
const interiorFinalLiteral = aligned.interiorFinalLiteral;
|
|
1990
|
+
const stripResult = stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible);
|
|
1991
|
+
if (stripResult === null) return null;
|
|
1992
|
+
const strippedTailHast = stripResult.rest;
|
|
1993
|
+
for (const child of tailMdastChildren) rebaseTree(child, offsetDelta, lineDelta);
|
|
1994
|
+
for (const child of strippedTailHast) rebaseTreeDual(child, injectedSegments, offsetDelta, lineDelta);
|
|
1995
|
+
const mdastChildren = prefixMdast.concat(tailMdastChildren);
|
|
1996
|
+
const seamMergeVerdict = stripResult.remnantMerged ?? tailLeadingTextIsHoist(tailMdastChildren, strippedTailHast);
|
|
1997
|
+
if (seamMergeVerdict === null) return null;
|
|
1998
|
+
const seamMergeAllowed = seamMergeVerdict;
|
|
1999
|
+
let firstTailChild = true;
|
|
2000
|
+
for (const child of strippedTailHast) {
|
|
2001
|
+
const tailEnd = hastChildren[hastChildren.length - 1];
|
|
2002
|
+
if (firstTailChild && child.type === "text" && child.position !== void 0) {
|
|
1958
2003
|
return null;
|
|
1959
2004
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2005
|
+
if (firstTailChild && tailEnd && tailEnd.type === "text" && child.type === "text" && child.position === void 0) {
|
|
2006
|
+
if (interiorFinalLiteral && tailEnd.value.trim() !== "") {
|
|
2007
|
+
if (seamMergeAllowed) return null;
|
|
2008
|
+
firstTailChild = false;
|
|
2009
|
+
hastChildren.push(child);
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
const literalSeam = tailEnd.value.trim() !== "" && !tailWrapVisible;
|
|
2013
|
+
if (seamMergeAllowed || literalSeam) {
|
|
2014
|
+
hastChildren[hastChildren.length - 1] = { type: "text", value: tailEnd.value + child.value };
|
|
2015
|
+
firstTailChild = false;
|
|
2016
|
+
continue;
|
|
2017
|
+
}
|
|
1970
2018
|
}
|
|
2019
|
+
firstTailChild = false;
|
|
2020
|
+
hastChildren.push(child);
|
|
1971
2021
|
}
|
|
1972
|
-
if (
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
if (value.length < 7 || !value.endsWith("-->")) return false;
|
|
1983
|
-
const close = value.indexOf("-->", 4);
|
|
1984
|
-
const bangClose = value.indexOf("--!>", 4);
|
|
1985
|
-
if (close !== value.length - 3) return false;
|
|
1986
|
-
return bangClose === -1 || bangClose > close;
|
|
1987
|
-
}
|
|
1988
|
-
if (/^<!doctype/i.test(value)) return false;
|
|
1989
|
-
if (value.startsWith("<?") || /^<!(?:[A-Za-z]|\[CDATA\[)/.test(value)) {
|
|
1990
|
-
return value.indexOf(">") === value.length - 1;
|
|
1991
|
-
}
|
|
1992
|
-
return false;
|
|
1993
|
-
}
|
|
1994
|
-
function isSeparatorText(node) {
|
|
1995
|
-
return node.type === "text" && node.position === void 0 && node.value.trim() === "";
|
|
1996
|
-
}
|
|
1997
|
-
function ownsTrailingLiteral(el, literal, prefixMdast) {
|
|
1998
|
-
const start = el.position?.start?.offset;
|
|
1999
|
-
if (start === void 0) return false;
|
|
2000
|
-
const owner = prefixMdast.find((c) => c.type === "html" && c.position?.start?.offset === start);
|
|
2001
|
-
if (!owner || owner.type !== "html") return false;
|
|
2002
|
-
const text = literal.value.trim();
|
|
2003
|
-
return text !== "" && owner.value.trimEnd().endsWith(text);
|
|
2004
|
-
}
|
|
2005
|
-
function isTrailingLiteralText(node) {
|
|
2006
|
-
return node.type === "text" && node.position === void 0 && node.value.trim() !== "";
|
|
2007
|
-
}
|
|
2008
|
-
function countTrailingNewlines(value) {
|
|
2009
|
-
let n = 0;
|
|
2010
|
-
for (let i = value.length - 1; i >= 0 && value[i] === "\n"; i--) n += 1;
|
|
2011
|
-
return n;
|
|
2012
|
-
}
|
|
2013
|
-
function countNewlines(text, end = text.length) {
|
|
2014
|
-
let count = 0;
|
|
2015
|
-
for (let i = text.indexOf("\n"); i !== -1 && i < end; i = text.indexOf("\n", i + 1)) count += 1;
|
|
2016
|
-
for (let i = text.indexOf("\r"); i !== -1 && i < end; i = text.indexOf("\r", i + 1)) {
|
|
2017
|
-
if (text.charCodeAt(i + 1) !== 10) count += 1;
|
|
2018
|
-
}
|
|
2019
|
-
return count;
|
|
2022
|
+
if (!hastChildren.some((child) => child.position !== void 0)) return null;
|
|
2023
|
+
const docStart = { line: 1, column: 1, offset: 0 };
|
|
2024
|
+
const mdastRootPosition = tailMdast.position ? { start: docStart, end: rebasePoint(tailMdast.position.end, offsetDelta, lineDelta) } : prevMdast.position;
|
|
2025
|
+
const hastRootPosition = mdastRootPosition;
|
|
2026
|
+
const mdast = { type: "root", children: mdastChildren };
|
|
2027
|
+
if (mdastRootPosition) mdast.position = mdastRootPosition;
|
|
2028
|
+
const hast = { type: "root", children: hastChildren };
|
|
2029
|
+
if (hastRootPosition) hast.position = hastRootPosition;
|
|
2030
|
+
if (prevHast.data !== void 0) hast.data = prevHast.data;
|
|
2031
|
+
return { mdast, hast };
|
|
2020
2032
|
}
|
|
2021
2033
|
|
|
2022
2034
|
// src/components/incrementalParse/advanceIncrementalParse.ts
|
|
@@ -2138,6 +2150,38 @@ function normalizeForMatch(s) {
|
|
|
2138
2150
|
return normalizeIdentifier3(s);
|
|
2139
2151
|
}
|
|
2140
2152
|
|
|
2153
|
+
// src/components/blankLineScanner.ts
|
|
2154
|
+
function createBlankLineScanner() {
|
|
2155
|
+
let end = 0;
|
|
2156
|
+
let newline = false;
|
|
2157
|
+
let cr = false;
|
|
2158
|
+
return (source, from = 0) => {
|
|
2159
|
+
if (from === 0) {
|
|
2160
|
+
end = 0;
|
|
2161
|
+
newline = false;
|
|
2162
|
+
cr = false;
|
|
2163
|
+
}
|
|
2164
|
+
for (let i = from; i < source.length; i++) {
|
|
2165
|
+
const c = source[i];
|
|
2166
|
+
if (c === "\n") {
|
|
2167
|
+
if (newline) {
|
|
2168
|
+
end = i + 1;
|
|
2169
|
+
newline = false;
|
|
2170
|
+
} else newline = true;
|
|
2171
|
+
cr = false;
|
|
2172
|
+
} else if (newline) {
|
|
2173
|
+
if ((c === " " || c === " ") && !cr) continue;
|
|
2174
|
+
if (c === "\r" && !cr) cr = true;
|
|
2175
|
+
else {
|
|
2176
|
+
newline = false;
|
|
2177
|
+
cr = false;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return end;
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2141
2185
|
// src/components/collectDefLabels.ts
|
|
2142
2186
|
var SCANNER_BOUNDARY_PROFILE = { defListEnabled: false, mathFlow: false, referenceTaint: false };
|
|
2143
2187
|
function buildProcessor() {
|
|
@@ -2169,19 +2213,12 @@ var setsEqual = (a, b) => {
|
|
|
2169
2213
|
for (const v of a) if (!b.has(v)) return false;
|
|
2170
2214
|
return true;
|
|
2171
2215
|
};
|
|
2172
|
-
var BLANK_LINE_RE = /\r?\n[ \t]*\r?\n/g;
|
|
2173
|
-
function lastRegionStart(source) {
|
|
2174
|
-
BLANK_LINE_RE.lastIndex = 0;
|
|
2175
|
-
let start = 0;
|
|
2176
|
-
for (let m = BLANK_LINE_RE.exec(source); m !== null; m = BLANK_LINE_RE.exec(source)) {
|
|
2177
|
-
start = m.index + m[0].length;
|
|
2178
|
-
}
|
|
2179
|
-
return start;
|
|
2180
|
-
}
|
|
2181
2216
|
var DEF_LINE_START_RE = /^[ \t>*+\d.)-]*\[(?:[^\]\\]|\\[\s\S])*\]:/m;
|
|
2182
2217
|
function createDefLabelScanner(parse = collectDefLabels) {
|
|
2183
2218
|
let prevSource = null;
|
|
2184
2219
|
let prevLabels = null;
|
|
2220
|
+
const scanBlankLines = createBlankLineScanner();
|
|
2221
|
+
let regionStart = 0;
|
|
2185
2222
|
let frozenEnd = 0;
|
|
2186
2223
|
let frozenFootnotes = /* @__PURE__ */ new Set();
|
|
2187
2224
|
let frozenLinks = /* @__PURE__ */ new Set();
|
|
@@ -2194,13 +2231,16 @@ function createDefLabelScanner(parse = collectDefLabels) {
|
|
|
2194
2231
|
};
|
|
2195
2232
|
return {
|
|
2196
2233
|
scan(source) {
|
|
2234
|
+
if (source === prevSource && prevLabels !== null) return prevLabels;
|
|
2235
|
+
const previousRegionStart = regionStart;
|
|
2236
|
+
const appended = prevSource !== null && source.startsWith(prevSource);
|
|
2237
|
+
regionStart = scanBlankLines(source, appended ? prevSource.length : 0);
|
|
2197
2238
|
let isAppend = false;
|
|
2198
2239
|
if (prevSource !== null && prevLabels !== null) {
|
|
2199
2240
|
if (source === prevSource) return prevLabels;
|
|
2200
2241
|
if (source.startsWith(prevSource)) {
|
|
2201
2242
|
isAppend = true;
|
|
2202
|
-
const
|
|
2203
|
-
const region = prevSource.slice(regionStart) + source.slice(prevSource.length);
|
|
2243
|
+
const region = source.slice(previousRegionStart);
|
|
2204
2244
|
if (!DEF_LINE_START_RE.test(region)) {
|
|
2205
2245
|
prevSource = source;
|
|
2206
2246
|
return prevLabels;
|
|
@@ -2433,8 +2473,115 @@ function* extractContributions(mdast, options = {}) {
|
|
|
2433
2473
|
for (const c of out) yield c;
|
|
2434
2474
|
}
|
|
2435
2475
|
|
|
2476
|
+
// src/components/registryIndex.ts
|
|
2477
|
+
function buildRegistryIndex(registry) {
|
|
2478
|
+
const index = {
|
|
2479
|
+
footnotes: /* @__PURE__ */ new Map(),
|
|
2480
|
+
links: /* @__PURE__ */ new Map(),
|
|
2481
|
+
numbers: /* @__PURE__ */ new Map(),
|
|
2482
|
+
counts: /* @__PURE__ */ new Map(),
|
|
2483
|
+
occurrences: /* @__PURE__ */ new Map(),
|
|
2484
|
+
labelOccurrences: /* @__PURE__ */ new Map()
|
|
2485
|
+
};
|
|
2486
|
+
for (const sym of registry.chunkOrder) {
|
|
2487
|
+
const data = registry.chunkData.get(sym);
|
|
2488
|
+
if (!data) continue;
|
|
2489
|
+
for (const label of data.defs.keys()) if (!index.footnotes.has(label)) index.footnotes.set(label, sym);
|
|
2490
|
+
for (const label of data.linkDefs.keys()) if (!index.links.has(label)) index.links.set(label, sym);
|
|
2491
|
+
const local = /* @__PURE__ */ new Map();
|
|
2492
|
+
index.occurrences.set(sym, local);
|
|
2493
|
+
for (const ref of data.refs) {
|
|
2494
|
+
if (ref.kind !== "footnote") continue;
|
|
2495
|
+
const label = ref.label;
|
|
2496
|
+
if (!index.numbers.has(label)) index.numbers.set(label, index.numbers.size + 1);
|
|
2497
|
+
const total = (index.counts.get(label) ?? 0) + 1;
|
|
2498
|
+
index.counts.set(label, total);
|
|
2499
|
+
const prior = local.get(label);
|
|
2500
|
+
if (prior) prior.count++;
|
|
2501
|
+
else {
|
|
2502
|
+
const range = { start: total, count: 1 };
|
|
2503
|
+
local.set(label, range);
|
|
2504
|
+
let byChunk = index.labelOccurrences.get(label);
|
|
2505
|
+
if (!byChunk) index.labelOccurrences.set(label, byChunk = /* @__PURE__ */ new Map());
|
|
2506
|
+
byChunk.set(sym, range);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
return index;
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
// src/components/registrySubscriptions.ts
|
|
2514
|
+
function equal(a, b) {
|
|
2515
|
+
if (a.owner !== b.owner || a.url !== b.url || a.title !== b.title || a.number !== b.number || a.count !== b.count)
|
|
2516
|
+
return false;
|
|
2517
|
+
if (a.occurrences?.size !== b.occurrences?.size) return false;
|
|
2518
|
+
if (a.occurrences) {
|
|
2519
|
+
for (const [chunk, range] of a.occurrences) {
|
|
2520
|
+
const next = b.occurrences?.get(chunk);
|
|
2521
|
+
if (!next || next.start !== range.start || next.count !== range.count) return false;
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
return true;
|
|
2525
|
+
}
|
|
2526
|
+
function createRegistrySubscriptions(read) {
|
|
2527
|
+
const groups = { link: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() };
|
|
2528
|
+
const snapshot = (kind, label, { registry, index }) => {
|
|
2529
|
+
if (kind === "link") {
|
|
2530
|
+
const owner = index.links.get(label);
|
|
2531
|
+
const def = owner ? registry.chunkData.get(owner)?.linkDefs.get(label) : void 0;
|
|
2532
|
+
return { owner, url: def?.url, title: def?.title };
|
|
2533
|
+
}
|
|
2534
|
+
return {
|
|
2535
|
+
owner: index.footnotes.get(label),
|
|
2536
|
+
number: index.numbers.get(label),
|
|
2537
|
+
count: index.counts.get(label),
|
|
2538
|
+
occurrences: index.labelOccurrences.get(label)
|
|
2539
|
+
};
|
|
2540
|
+
};
|
|
2541
|
+
return {
|
|
2542
|
+
subscribe(kind, rawLabel, cb) {
|
|
2543
|
+
const label = normalizeId(rawLabel);
|
|
2544
|
+
const map = groups[kind];
|
|
2545
|
+
let group = map.get(label);
|
|
2546
|
+
if (!group) {
|
|
2547
|
+
group = { snapshot: snapshot(kind, label, read()), listeners: /* @__PURE__ */ new Set() };
|
|
2548
|
+
map.set(label, group);
|
|
2549
|
+
}
|
|
2550
|
+
const listener = () => cb();
|
|
2551
|
+
group.listeners.add(listener);
|
|
2552
|
+
return () => {
|
|
2553
|
+
group.listeners.delete(listener);
|
|
2554
|
+
if (group.listeners.size === 0 && map.get(label) === group) map.delete(label);
|
|
2555
|
+
};
|
|
2556
|
+
},
|
|
2557
|
+
collect() {
|
|
2558
|
+
if (groups.link.size === 0 && groups.footnote.size === 0) return [];
|
|
2559
|
+
const state = read();
|
|
2560
|
+
const callbacks = [];
|
|
2561
|
+
for (const kind of ["link", "footnote"]) {
|
|
2562
|
+
for (const [label, group] of groups[kind]) {
|
|
2563
|
+
const next = snapshot(kind, label, state);
|
|
2564
|
+
if (!equal(group.snapshot, next)) callbacks.push(...group.listeners);
|
|
2565
|
+
group.snapshot = next;
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
return callbacks;
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2436
2573
|
// src/components/documentRegistry.ts
|
|
2437
2574
|
function createRegistry(onEmpty) {
|
|
2575
|
+
let index;
|
|
2576
|
+
let indexedVersion = -1;
|
|
2577
|
+
const getIndex = () => {
|
|
2578
|
+
if (!index || indexedVersion !== reg.version) {
|
|
2579
|
+
index = buildRegistryIndex(reg);
|
|
2580
|
+
indexedVersion = reg.version;
|
|
2581
|
+
}
|
|
2582
|
+
return index;
|
|
2583
|
+
};
|
|
2584
|
+
const labels = createRegistrySubscriptions(() => ({ registry: reg, index: getIndex() }));
|
|
2438
2585
|
const reg = {
|
|
2439
2586
|
chunkOrder: [],
|
|
2440
2587
|
chunkData: /* @__PURE__ */ new Map(),
|
|
@@ -2585,73 +2732,29 @@ function createRegistry(onEmpty) {
|
|
|
2585
2732
|
this._subscribers.delete(cb);
|
|
2586
2733
|
};
|
|
2587
2734
|
},
|
|
2735
|
+
subscribeLabel(kind, label, cb) {
|
|
2736
|
+
return labels.subscribe(kind, label, cb);
|
|
2737
|
+
},
|
|
2588
2738
|
canonicalFootnoteFor(label) {
|
|
2589
|
-
|
|
2590
|
-
for (const sym of this.chunkOrder) {
|
|
2591
|
-
const data = this.chunkData.get(sym);
|
|
2592
|
-
if (data?.defs.has(id)) return sym;
|
|
2593
|
-
}
|
|
2594
|
-
return null;
|
|
2739
|
+
return getIndex().footnotes.get(normalizeId(label)) ?? null;
|
|
2595
2740
|
},
|
|
2596
2741
|
canonicalLinkFor(label) {
|
|
2597
|
-
|
|
2598
|
-
for (const sym of this.chunkOrder) {
|
|
2599
|
-
const data = this.chunkData.get(sym);
|
|
2600
|
-
if (data?.linkDefs.has(id)) return sym;
|
|
2601
|
-
}
|
|
2602
|
-
return null;
|
|
2742
|
+
return getIndex().links.get(normalizeId(label)) ?? null;
|
|
2603
2743
|
},
|
|
2604
2744
|
globalNumber(label) {
|
|
2605
|
-
|
|
2606
|
-
let n = 0;
|
|
2607
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2608
|
-
for (const sym of this.chunkOrder) {
|
|
2609
|
-
const data = this.chunkData.get(sym);
|
|
2610
|
-
if (!data) continue;
|
|
2611
|
-
for (const ref of data.refs) {
|
|
2612
|
-
if (ref.kind !== "footnote") continue;
|
|
2613
|
-
if (!seen.has(ref.label)) {
|
|
2614
|
-
seen.add(ref.label);
|
|
2615
|
-
n++;
|
|
2616
|
-
if (ref.label === id) return n;
|
|
2617
|
-
}
|
|
2618
|
-
}
|
|
2619
|
-
}
|
|
2620
|
-
return null;
|
|
2745
|
+
return getIndex().numbers.get(normalizeId(label)) ?? null;
|
|
2621
2746
|
},
|
|
2622
2747
|
resolveLinkDef(label) {
|
|
2623
|
-
const
|
|
2624
|
-
|
|
2625
|
-
return this.chunkData.get(sym)?.linkDefs.get(
|
|
2748
|
+
const id = normalizeId(label);
|
|
2749
|
+
const sym = getIndex().links.get(id);
|
|
2750
|
+
return sym ? this.chunkData.get(sym)?.linkDefs.get(id) ?? null : null;
|
|
2626
2751
|
},
|
|
2627
2752
|
getRefsForLabel(label) {
|
|
2628
|
-
|
|
2629
|
-
let n = 0;
|
|
2630
|
-
for (const sym of this.chunkOrder) {
|
|
2631
|
-
const data = this.chunkData.get(sym);
|
|
2632
|
-
if (!data) continue;
|
|
2633
|
-
for (const ref of data.refs) {
|
|
2634
|
-
if (ref.kind === "footnote" && ref.label === id) n++;
|
|
2635
|
-
}
|
|
2636
|
-
}
|
|
2637
|
-
return n;
|
|
2753
|
+
return getIndex().counts.get(normalizeId(label)) ?? 0;
|
|
2638
2754
|
},
|
|
2639
2755
|
globalOccurrenceForRef(chunkSym, label, localOccurrence) {
|
|
2640
|
-
const
|
|
2641
|
-
|
|
2642
|
-
for (const sym of this.chunkOrder) {
|
|
2643
|
-
const data = this.chunkData.get(sym);
|
|
2644
|
-
if (!data) continue;
|
|
2645
|
-
let localCount = 0;
|
|
2646
|
-
for (const ref of data.refs) {
|
|
2647
|
-
if (ref.kind !== "footnote") continue;
|
|
2648
|
-
if (ref.label !== id) continue;
|
|
2649
|
-
localCount++;
|
|
2650
|
-
global2++;
|
|
2651
|
-
if (sym === chunkSym && localCount === localOccurrence) return global2;
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
return null;
|
|
2756
|
+
const range = getIndex().occurrences.get(chunkSym)?.get(normalizeId(label));
|
|
2757
|
+
return range && Number.isInteger(localOccurrence) && localOccurrence > 0 && localOccurrence <= range.count ? range.start + localOccurrence - 1 : null;
|
|
2655
2758
|
},
|
|
2656
2759
|
_notify() {
|
|
2657
2760
|
this.version++;
|
|
@@ -2659,7 +2762,9 @@ function createRegistry(onEmpty) {
|
|
|
2659
2762
|
this._notifyScheduled = true;
|
|
2660
2763
|
queueMicrotask(() => {
|
|
2661
2764
|
this._notifyScheduled = false;
|
|
2765
|
+
const labelCallbacks = labels.collect();
|
|
2662
2766
|
for (const cb of [...this._subscribers]) cb();
|
|
2767
|
+
for (const cb of labelCallbacks) cb();
|
|
2663
2768
|
});
|
|
2664
2769
|
}
|
|
2665
2770
|
};
|
|
@@ -2716,7 +2821,7 @@ var ENGINE_PLACEHOLDER_TAGS = /* @__PURE__ */ new Set([
|
|
|
2716
2821
|
"cross-chunk-image"
|
|
2717
2822
|
]);
|
|
2718
2823
|
var ENGINE_PROVENANCE_PROPERTY = "engineProvenance";
|
|
2719
|
-
function walk(parent, provenance) {
|
|
2824
|
+
function walk(parent, provenance, ancestors) {
|
|
2720
2825
|
const children = parent.children;
|
|
2721
2826
|
let i = 0;
|
|
2722
2827
|
while (i < children.length) {
|
|
@@ -2727,21 +2832,32 @@ function walk(parent, provenance) {
|
|
|
2727
2832
|
const genuine = provenance !== "" && typeof stamped === "string" && stamped === provenance;
|
|
2728
2833
|
if (genuine) {
|
|
2729
2834
|
delete props[ENGINE_PROVENANCE_PROPERTY];
|
|
2730
|
-
|
|
2835
|
+
if (ancestors && (node.tagName === "cross-chunk-link" || node.tagName === "cross-chunk-image")) {
|
|
2836
|
+
(node.data ??= {}).referenceAncestors = ancestors.slice();
|
|
2837
|
+
}
|
|
2838
|
+
ancestors?.push(
|
|
2839
|
+
node.tagName === "cross-chunk-link" ? "a" : node.tagName === "cross-chunk-image" ? "img" : node.tagName
|
|
2840
|
+
);
|
|
2841
|
+
walk(node, provenance, ancestors);
|
|
2842
|
+
ancestors?.pop();
|
|
2731
2843
|
i += 1;
|
|
2732
2844
|
} else {
|
|
2733
2845
|
children.splice(i, 1, ...node.children);
|
|
2734
2846
|
}
|
|
2735
2847
|
continue;
|
|
2736
2848
|
}
|
|
2737
|
-
if (node.type === "element")
|
|
2849
|
+
if (node.type === "element") {
|
|
2850
|
+
ancestors?.push(node.tagName);
|
|
2851
|
+
walk(node, provenance, ancestors);
|
|
2852
|
+
ancestors?.pop();
|
|
2853
|
+
}
|
|
2738
2854
|
i += 1;
|
|
2739
2855
|
}
|
|
2740
2856
|
}
|
|
2741
2857
|
function rehypeVerifyEngineTags(options) {
|
|
2742
2858
|
const provenance = options?.provenance ?? "";
|
|
2743
2859
|
return function transformer(tree) {
|
|
2744
|
-
walk(tree, provenance);
|
|
2860
|
+
walk(tree, provenance, options?.referenceAncestors ? [] : void 0);
|
|
2745
2861
|
};
|
|
2746
2862
|
}
|
|
2747
2863
|
|
|
@@ -2762,16 +2878,18 @@ import remarkRemoveComments from "remark-remove-comments";
|
|
|
2762
2878
|
// src/components/rehypeRebaseHashLinks.ts
|
|
2763
2879
|
import { visit as visit5 } from "unist-util-visit";
|
|
2764
2880
|
var DEFAULT_PREFIX = "user-content-";
|
|
2881
|
+
function rebaseHashHref(href, prefix) {
|
|
2882
|
+
const hashPrefix = "#" + prefix;
|
|
2883
|
+
return href.startsWith("#") && !href.startsWith(hashPrefix) ? hashPrefix + href.slice(1) : href;
|
|
2884
|
+
}
|
|
2765
2885
|
var rehypeRebaseHashLinks = (options) => {
|
|
2766
2886
|
const prefix = options?.prefix ?? DEFAULT_PREFIX;
|
|
2767
|
-
const hashPrefix = "#" + prefix;
|
|
2768
2887
|
return (tree) => {
|
|
2769
2888
|
visit5(tree, "element", (node) => {
|
|
2770
2889
|
if (node.tagName !== "a") return;
|
|
2771
2890
|
const href = node.properties?.href;
|
|
2772
2891
|
if (typeof href !== "string" || !href.startsWith("#")) return;
|
|
2773
|
-
|
|
2774
|
-
node.properties.href = hashPrefix + href.slice(1);
|
|
2892
|
+
node.properties.href = rebaseHashHref(href, prefix);
|
|
2775
2893
|
});
|
|
2776
2894
|
};
|
|
2777
2895
|
};
|
|
@@ -2857,7 +2975,15 @@ function buildCoreRehypePlugins(sanitizeSchema2, clobberPrefix, options) {
|
|
|
2857
2975
|
[rehypeRaw, { passThrough: [] }],
|
|
2858
2976
|
// Unwrap forged engine placeholders BEFORE sanitize admits their tag
|
|
2859
2977
|
// names. Only when the caller holds a credential (see the option's doc).
|
|
2860
|
-
...options ? [
|
|
2978
|
+
...options ? [
|
|
2979
|
+
[
|
|
2980
|
+
rehypeVerifyEngineTags,
|
|
2981
|
+
{
|
|
2982
|
+
provenance: options.provenance,
|
|
2983
|
+
...sanitizeSchema2.ancestors?.a || sanitizeSchema2.ancestors?.img ? { referenceAncestors: true } : {}
|
|
2984
|
+
}
|
|
2985
|
+
]
|
|
2986
|
+
] : [],
|
|
2861
2987
|
// Sanitize HTML while allowing <mark> (highlight), KaTeX class names,
|
|
2862
2988
|
// and any extra protocols the caller permitted via the `sanitizeSchema`
|
|
2863
2989
|
// prop. Override `clobberPrefix` with the instance-scoped value — the
|
|
@@ -2931,11 +3057,9 @@ function buildCrossChunkHandlers() {
|
|
|
2931
3057
|
type: "element",
|
|
2932
3058
|
tagName: "cross-chunk-link",
|
|
2933
3059
|
properties: {
|
|
2934
|
-
//
|
|
2935
|
-
//
|
|
2936
|
-
|
|
2937
|
-
// which also preserves source case. Registry lookups normalize
|
|
2938
|
-
// internally, so cross-chunk case-insensitive matching still works.
|
|
3060
|
+
// Display labels decode escapes; registry identifiers must retain
|
|
3061
|
+
// those bytes. Never use the display label as the lookup key.
|
|
3062
|
+
identifier: node.identifier,
|
|
2939
3063
|
label: node.label ?? node.identifier,
|
|
2940
3064
|
referenceType: node.referenceType,
|
|
2941
3065
|
documentId: s.options.documentId,
|
|
@@ -2954,6 +3078,7 @@ function buildCrossChunkHandlers() {
|
|
|
2954
3078
|
type: "element",
|
|
2955
3079
|
tagName: "cross-chunk-image",
|
|
2956
3080
|
properties: {
|
|
3081
|
+
identifier: node.identifier,
|
|
2957
3082
|
label: node.label ?? node.identifier,
|
|
2958
3083
|
referenceType: node.referenceType,
|
|
2959
3084
|
alt: node.alt ?? "",
|
|
@@ -4216,8 +4341,8 @@ var sanitizeSchema = deepFreeze(
|
|
|
4216
4341
|
attributes: {
|
|
4217
4342
|
...defaultSchema.attributes,
|
|
4218
4343
|
code: mergeClassNameAllowlist(defaultSchema.attributes?.code, ["math-inline", "math-display"]),
|
|
4219
|
-
"cross-chunk-link": ["label", "referenceType", "documentId", "localUrl", "localTitle"],
|
|
4220
|
-
"cross-chunk-image": ["label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
|
|
4344
|
+
"cross-chunk-link": ["identifier", "label", "referenceType", "documentId", "localUrl", "localTitle"],
|
|
4345
|
+
"cross-chunk-image": ["identifier", "label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
|
|
4221
4346
|
"footnote-sup": ["label", "localOccurrence", "localNumber", "documentId"]
|
|
4222
4347
|
},
|
|
4223
4348
|
strip: [.../* @__PURE__ */ new Set([...defaultSchema.strip || [], ...STRIPPED_TAGS])]
|
|
@@ -4253,6 +4378,49 @@ function sanitizeCrossChunkUrl(rawUrl, key, tagName, urlTransform, schema) {
|
|
|
4253
4378
|
return String(transformed);
|
|
4254
4379
|
}
|
|
4255
4380
|
|
|
4381
|
+
// src/components/resolveCrossChunkReference.ts
|
|
4382
|
+
import rehypeSanitize2 from "rehype-sanitize";
|
|
4383
|
+
import { normalizeUri as normalizeUri3 } from "micromark-util-sanitize-uri";
|
|
4384
|
+
function resolveCrossChunkReference(input, schema, urlTransform, clobberPrefix) {
|
|
4385
|
+
const key = input.tagName === "a" ? "href" : "src";
|
|
4386
|
+
const element = {
|
|
4387
|
+
type: "element",
|
|
4388
|
+
tagName: input.tagName,
|
|
4389
|
+
properties: {
|
|
4390
|
+
[key]: normalizeUri3(input.url),
|
|
4391
|
+
...input.tagName === "img" ? { alt: input.alt ?? "" } : {},
|
|
4392
|
+
...input.title !== void 0 ? { title: input.title } : {}
|
|
4393
|
+
},
|
|
4394
|
+
children: input.tagName === "a" ? [{ type: "text", value: "__reference_children__" }] : []
|
|
4395
|
+
};
|
|
4396
|
+
const requiredAncestors = schema.ancestors?.[input.tagName];
|
|
4397
|
+
const recordedAncestors = input.node?.data?.referenceAncestors;
|
|
4398
|
+
let finalSchema = schema;
|
|
4399
|
+
if (requiredAncestors && Array.isArray(recordedAncestors) && requiredAncestors.some((tag) => recordedAncestors.includes(tag))) {
|
|
4400
|
+
const ancestors = { ...schema.ancestors };
|
|
4401
|
+
delete ancestors[input.tagName];
|
|
4402
|
+
finalSchema = { ...schema, ancestors };
|
|
4403
|
+
}
|
|
4404
|
+
const root2 = rehypeSanitize2({ ...finalSchema, clobberPrefix })({ type: "root", children: [element] });
|
|
4405
|
+
const node = root2.children[0];
|
|
4406
|
+
if (node?.type !== "element") return { element: null, keepChildren: node?.type === "text" };
|
|
4407
|
+
if (node.tagName === "a" && typeof node.properties.href === "string") {
|
|
4408
|
+
node.properties.href = rebaseHashHref(node.properties.href, clobberPrefix);
|
|
4409
|
+
}
|
|
4410
|
+
node.children = input.node?.children ?? [];
|
|
4411
|
+
if (input.node?.position) node.position = input.node.position;
|
|
4412
|
+
buildTransform({
|
|
4413
|
+
allowedElements: void 0,
|
|
4414
|
+
disallowedElements: void 0,
|
|
4415
|
+
allowElement: void 0,
|
|
4416
|
+
skipHtml: void 0,
|
|
4417
|
+
unwrapDisallowed: void 0,
|
|
4418
|
+
urlTransform
|
|
4419
|
+
})(node, 0, root2);
|
|
4420
|
+
node.children = [];
|
|
4421
|
+
return { element: node, keepChildren: false };
|
|
4422
|
+
}
|
|
4423
|
+
|
|
4256
4424
|
// src/plugins/defs.ts
|
|
4257
4425
|
function getEnginePluginInternals(plugin) {
|
|
4258
4426
|
const candidate = plugin;
|
|
@@ -4469,6 +4637,8 @@ var createSmoothStreamController = (options = {}) => {
|
|
|
4469
4637
|
let source = "";
|
|
4470
4638
|
let visibleEnd = 0;
|
|
4471
4639
|
let pending = [];
|
|
4640
|
+
let pendingHead = 0;
|
|
4641
|
+
const pendingCount = () => pending.length - pendingHead;
|
|
4472
4642
|
let tentativeEnd = 0;
|
|
4473
4643
|
let finished = false;
|
|
4474
4644
|
let seam;
|
|
@@ -4513,7 +4683,7 @@ var createSmoothStreamController = (options = {}) => {
|
|
|
4513
4683
|
cancelFrame = void 0;
|
|
4514
4684
|
};
|
|
4515
4685
|
const ensureScheduled = () => {
|
|
4516
|
-
if (disposed || cancelFrame ||
|
|
4686
|
+
if (disposed || cancelFrame || pendingCount() === 0) return;
|
|
4517
4687
|
lastTickAt = now();
|
|
4518
4688
|
credit = 0;
|
|
4519
4689
|
cancelFrame = schedule(tick);
|
|
@@ -4527,31 +4697,38 @@ var createSmoothStreamController = (options = {}) => {
|
|
|
4527
4697
|
const params = resolveParams();
|
|
4528
4698
|
let rate;
|
|
4529
4699
|
if (finished && drainDeadlineAt !== void 0) {
|
|
4530
|
-
rate = Math.max(params.minCharsPerSecond,
|
|
4700
|
+
rate = Math.max(params.minCharsPerSecond, pendingCount() * 1e3 / Math.max(1, drainDeadlineAt - t));
|
|
4531
4701
|
} else if (gapWindow.length > 0 && lastArrivalAt !== void 0) {
|
|
4532
4702
|
const gaps = gapWindow.map((s) => s.gap).sort((a, b) => a - b);
|
|
4533
4703
|
const intervalQ = gaps[Math.min(gaps.length - 1, Math.floor(gaps.length * INTERVAL_QUANTILE))];
|
|
4534
4704
|
const horizon = Math.max(16, Math.min(params.bufferFactor * intervalQ + HORIZON_PAD_MS, params.maxLagMs));
|
|
4535
4705
|
const deadline = Math.max(lastArrivalAt + horizon, t + DEADLINE_FLOOR_MS);
|
|
4536
|
-
rate = Math.max(params.minCharsPerSecond,
|
|
4706
|
+
rate = Math.max(params.minCharsPerSecond, pendingCount() * 1e3 / Math.max(1, deadline - t));
|
|
4537
4707
|
} else {
|
|
4538
|
-
rate = Math.max(params.minCharsPerSecond,
|
|
4708
|
+
rate = Math.max(params.minCharsPerSecond, pendingCount() * 1e3 / Math.max(1, params.correctionTauMs));
|
|
4539
4709
|
}
|
|
4540
4710
|
credit += rate * dt / 1e3;
|
|
4541
|
-
const reveal = Math.min(Math.floor(credit),
|
|
4711
|
+
const reveal = Math.min(Math.floor(credit), pendingCount());
|
|
4542
4712
|
if (reveal > 0) {
|
|
4543
|
-
visibleEnd = pending[reveal - 1];
|
|
4544
|
-
|
|
4545
|
-
|
|
4713
|
+
visibleEnd = pending[pendingHead + reveal - 1];
|
|
4714
|
+
pendingHead += reveal;
|
|
4715
|
+
if (pendingHead === pending.length) {
|
|
4716
|
+
pending = [];
|
|
4717
|
+
pendingHead = 0;
|
|
4718
|
+
} else if (pendingHead >= 1024 && pendingHead * 2 >= pending.length) {
|
|
4719
|
+
pending = pending.slice(pendingHead);
|
|
4720
|
+
pendingHead = 0;
|
|
4721
|
+
}
|
|
4722
|
+
credit = pendingCount() > 0 ? credit - reveal : 0;
|
|
4546
4723
|
notify();
|
|
4547
4724
|
}
|
|
4548
|
-
if (!disposed && !cancelFrame &&
|
|
4725
|
+
if (!disposed && !cancelFrame && pendingCount() > 0) cancelFrame = schedule(tick);
|
|
4549
4726
|
};
|
|
4550
4727
|
const resegmentTail = () => {
|
|
4551
|
-
if (seam !== void 0 && seam < source.length && pending[pending.length - 1] === seam) {
|
|
4728
|
+
if (pendingCount() > 0 && seam !== void 0 && seam < source.length && pending[pending.length - 1] === seam) {
|
|
4552
4729
|
pending.pop();
|
|
4553
4730
|
}
|
|
4554
|
-
const from =
|
|
4731
|
+
const from = pendingCount() > 0 ? pending[pending.length - 1] : visibleEnd;
|
|
4555
4732
|
let anchor = from;
|
|
4556
4733
|
if (seam !== void 0 && from <= seam) {
|
|
4557
4734
|
anchor = Math.max(0, from - RESUME_LOOKBACK);
|
|
@@ -4585,6 +4762,7 @@ var createSmoothStreamController = (options = {}) => {
|
|
|
4585
4762
|
visibleEnd = next.length;
|
|
4586
4763
|
tentativeEnd = next.length;
|
|
4587
4764
|
pending = [];
|
|
4765
|
+
pendingHead = 0;
|
|
4588
4766
|
seam = next.length;
|
|
4589
4767
|
credit = 0;
|
|
4590
4768
|
cancelScheduled();
|
|
@@ -4616,7 +4794,7 @@ var createSmoothStreamController = (options = {}) => {
|
|
|
4616
4794
|
if (finished) return;
|
|
4617
4795
|
finished = true;
|
|
4618
4796
|
lastArrivalAt = void 0;
|
|
4619
|
-
if (tentativeEnd > (
|
|
4797
|
+
if (tentativeEnd > (pendingCount() > 0 ? pending[pending.length - 1] : visibleEnd)) {
|
|
4620
4798
|
pending.push(tentativeEnd);
|
|
4621
4799
|
}
|
|
4622
4800
|
const params = resolveParams();
|
|
@@ -4642,10 +4820,11 @@ var createSmoothStreamController = (options = {}) => {
|
|
|
4642
4820
|
snap,
|
|
4643
4821
|
flush() {
|
|
4644
4822
|
disposed = false;
|
|
4645
|
-
const target = finished ? source.length :
|
|
4823
|
+
const target = finished ? source.length : pendingCount() > 0 ? pending[pending.length - 1] : visibleEnd;
|
|
4646
4824
|
if (target <= visibleEnd) return;
|
|
4647
4825
|
visibleEnd = target;
|
|
4648
4826
|
pending = [];
|
|
4827
|
+
pendingHead = 0;
|
|
4649
4828
|
credit = 0;
|
|
4650
4829
|
cancelScheduled();
|
|
4651
4830
|
notify();
|
|
@@ -5495,6 +5674,7 @@ export {
|
|
|
5495
5674
|
rehypeRebaseHashLinks_default as rehypeRebaseHashLinks,
|
|
5496
5675
|
rehypeVerifyEngineTags,
|
|
5497
5676
|
removeComments,
|
|
5677
|
+
resolveCrossChunkReference,
|
|
5498
5678
|
sanitizeCrossChunkUrl,
|
|
5499
5679
|
sanitizeSchema,
|
|
5500
5680
|
shortenDocumentId,
|