@ai-matrx/content-ir 0.15.1 → 0.16.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/CHANGELOG.md +49 -0
- package/dist/index.cjs +120 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +120 -9
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +120 -8
- package/dist/source.cjs.map +1 -1
- package/dist/source.d.cts +19 -1
- package/dist/source.d.ts +19 -1
- package/dist/source.js +120 -9
- package/dist/source.js.map +1 -1
- package/package.json +1 -1
package/dist/source.cjs
CHANGED
|
@@ -348,6 +348,50 @@ function codeRanges(text) {
|
|
|
348
348
|
}
|
|
349
349
|
return ranges.sort((a, b) => a[0] - b[0]);
|
|
350
350
|
}
|
|
351
|
+
function pendingDisplayMathOpener(text) {
|
|
352
|
+
if (!text.includes("$$")) return -1;
|
|
353
|
+
const ranges = codeRanges(text);
|
|
354
|
+
const tokens = [];
|
|
355
|
+
let r = 0;
|
|
356
|
+
let maxEnd = -1;
|
|
357
|
+
for (let i = text.indexOf("$$"); i !== -1 && i < text.length - 1; i = text.indexOf("$$", i)) {
|
|
358
|
+
while (r < ranges.length && ranges[r][0] <= i) {
|
|
359
|
+
maxEnd = Math.max(maxEnd, ranges[r][1]);
|
|
360
|
+
r++;
|
|
361
|
+
}
|
|
362
|
+
if (maxEnd <= i) tokens.push(i);
|
|
363
|
+
i += 2;
|
|
364
|
+
}
|
|
365
|
+
const paired = /* @__PURE__ */ new Set();
|
|
366
|
+
let j = 0;
|
|
367
|
+
while (j < tokens.length) {
|
|
368
|
+
const open = tokens[j];
|
|
369
|
+
const close = tokens[j + 1];
|
|
370
|
+
if (close === void 0) break;
|
|
371
|
+
if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
|
|
372
|
+
paired.add(open);
|
|
373
|
+
paired.add(close);
|
|
374
|
+
j += 2;
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
j += 1;
|
|
378
|
+
}
|
|
379
|
+
let trail = 0;
|
|
380
|
+
while (trail < text.length && /\s/.test(text[text.length - 1 - trail])) trail++;
|
|
381
|
+
for (const token of tokens) {
|
|
382
|
+
if (paired.has(token)) continue;
|
|
383
|
+
let lead = 0;
|
|
384
|
+
while (lead <= MAX_MATH_SPAN && /\s/.test(text[token + 2 + lead] ?? "x")) lead++;
|
|
385
|
+
if (text.length - (token + 2) - lead - trail > MAX_MATH_SPAN) continue;
|
|
386
|
+
const inner = text.slice(token + 2);
|
|
387
|
+
const s = inner.trim();
|
|
388
|
+
if (STRUCTURAL_MARKDOWN.test(s) || s.length > MAX_MATH_SPAN) continue;
|
|
389
|
+
if (!opensFlowBlock(text, token) && /\n[ \t]*\n/.test(inner)) continue;
|
|
390
|
+
if ((s.match(PROSE_WORD) ?? []).length >= PROSE_WORD_LIMIT * 3) continue;
|
|
391
|
+
return token;
|
|
392
|
+
}
|
|
393
|
+
return -1;
|
|
394
|
+
}
|
|
351
395
|
function pairDisplayMath(text) {
|
|
352
396
|
const pairs = /* @__PURE__ */ new Map();
|
|
353
397
|
if (!text.includes("$$")) return pairs;
|
|
@@ -696,11 +740,15 @@ function isSplitterTreeLine(line) {
|
|
|
696
740
|
}
|
|
697
741
|
var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
|
|
698
742
|
var Tokenizer = class {
|
|
699
|
-
constructor(text, streaming = false) {
|
|
743
|
+
constructor(text, streaming = false, meter = void 0) {
|
|
700
744
|
this.text = text;
|
|
701
745
|
this.streaming = streaming;
|
|
746
|
+
this.meter = meter;
|
|
702
747
|
this.n = text.length;
|
|
748
|
+
this.tick(text.length);
|
|
703
749
|
this.mathPairs = pairDisplayMath(text);
|
|
750
|
+
this.provisionalFrom = streaming ? pendingDisplayMathOpener(text) : -1;
|
|
751
|
+
if (this.provisionalFrom === -1) this.provisionalFrom = Number.POSITIVE_INFINITY;
|
|
704
752
|
let start = 0;
|
|
705
753
|
for (let i = 0; i < text.length; i++) {
|
|
706
754
|
if (text.charCodeAt(i) === 10) {
|
|
@@ -711,13 +759,15 @@ var Tokenizer = class {
|
|
|
711
759
|
}
|
|
712
760
|
}
|
|
713
761
|
if (start < text.length || text.length === 0) {
|
|
762
|
+
this.pendingCR = streaming && text.length > start && text.charCodeAt(text.length - 1) === 13;
|
|
714
763
|
this.lineStarts.push(start);
|
|
715
|
-
this.contentEnds.push(text.length);
|
|
764
|
+
this.contentEnds.push(this.pendingCR ? text.length - 1 : text.length);
|
|
716
765
|
this.lineEnds.push(text.length);
|
|
717
766
|
}
|
|
718
767
|
}
|
|
719
768
|
text;
|
|
720
769
|
streaming;
|
|
770
|
+
meter;
|
|
721
771
|
n;
|
|
722
772
|
lineStarts = [];
|
|
723
773
|
contentEnds = [];
|
|
@@ -732,6 +782,23 @@ var Tokenizer = class {
|
|
|
732
782
|
/** `$$` opener → closer for the pairs the core renders as math. */
|
|
733
783
|
mathPairs;
|
|
734
784
|
finder = (needle, from) => this.next(needle, from);
|
|
785
|
+
/** Streaming: where provisional text starts (a pending `$$`), or +∞. */
|
|
786
|
+
provisionalFrom = Number.POSITIVE_INFINITY;
|
|
787
|
+
/** Streaming: the text ends in a lone CR whose LF has not arrived yet. */
|
|
788
|
+
pendingCR = false;
|
|
789
|
+
/**
|
|
790
|
+
* Streaming: an open last line that begins with `{` is undecided — each new
|
|
791
|
+
* byte can balance or unbalance its braces and flip the whole line between
|
|
792
|
+
* prose and a JSON island — so it is provisional until it ends (G5).
|
|
793
|
+
*/
|
|
794
|
+
markOpenJsonTail() {
|
|
795
|
+
const last = this.lineStarts.length - 1;
|
|
796
|
+
if (!this.isOpenTail(last)) return;
|
|
797
|
+
const start = this.lineStarts[last];
|
|
798
|
+
if (this.lineText(last).trimStart().startsWith("{")) {
|
|
799
|
+
this.provisionalFrom = Math.min(this.provisionalFrom, start);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
735
802
|
/**
|
|
736
803
|
* `text.indexOf(needle, from)` in O(log k): the first query for a needle
|
|
737
804
|
* indexes all of its occurrences once, so repeated searches for a closer
|
|
@@ -755,9 +822,21 @@ var Tokenizer = class {
|
|
|
755
822
|
}
|
|
756
823
|
return lo < list.length ? list[lo] : -1;
|
|
757
824
|
}
|
|
825
|
+
/** Charge `n` visited characters to the diagnostic meter (complexity tests). */
|
|
826
|
+
tick(n) {
|
|
827
|
+
if (this.meter) this.meter.work += n;
|
|
828
|
+
}
|
|
829
|
+
/** Streaming only: a paragraph ending at `pe` may still be continued by a line not yet arrived. */
|
|
830
|
+
paragraphMayGrow(pe) {
|
|
831
|
+
if (!this.streaming) return false;
|
|
832
|
+
const rest = this.n - pe;
|
|
833
|
+
if (rest === 0) return true;
|
|
834
|
+
const tail = this.text.slice(pe);
|
|
835
|
+
return tail === "\n" || tail === "\r\n" || tail === "\r";
|
|
836
|
+
}
|
|
758
837
|
/** Streaming only: the final line, still waiting for its terminator. */
|
|
759
838
|
isOpenTail(k) {
|
|
760
|
-
return this.streaming && k === this.lineStarts.length - 1 && this.lineEnds[k] === this.contentEnds[k];
|
|
839
|
+
return this.streaming && k === this.lineStarts.length - 1 && (this.lineEnds[k] === this.contentEnds[k] || this.pendingCR);
|
|
761
840
|
}
|
|
762
841
|
get lineCount() {
|
|
763
842
|
return this.lineStarts.length;
|
|
@@ -782,6 +861,7 @@ var Tokenizer = class {
|
|
|
782
861
|
return this.text.slice(this.lineStarts[li], this.contentEnds[li]);
|
|
783
862
|
}
|
|
784
863
|
run() {
|
|
864
|
+
if (this.streaming) this.markOpenJsonTail();
|
|
785
865
|
let pos = 0;
|
|
786
866
|
while (pos < this.n) {
|
|
787
867
|
const li = this.lineOf(pos);
|
|
@@ -790,6 +870,10 @@ var Tokenizer = class {
|
|
|
790
870
|
pos = this.gap(pos, li);
|
|
791
871
|
continue;
|
|
792
872
|
}
|
|
873
|
+
if (pos >= this.provisionalFrom) {
|
|
874
|
+
this.push({ kind: "prose", start: pos, end: this.n, island: null, inlines: [] });
|
|
875
|
+
break;
|
|
876
|
+
}
|
|
793
877
|
const island = this.detectBlock(pos, li, true);
|
|
794
878
|
if (island) {
|
|
795
879
|
this.push({ kind: "island", start: island.start, end: island.end, island, inlines: [] });
|
|
@@ -840,7 +924,8 @@ var Tokenizer = class {
|
|
|
840
924
|
const fm = this.frontMatter(li, t);
|
|
841
925
|
if (fm) return fm;
|
|
842
926
|
}
|
|
843
|
-
|
|
927
|
+
const listNested = indent > 0 && this.inListContinuation(li);
|
|
928
|
+
if (indent <= 3 && !listNested && t.startsWith("::")) {
|
|
844
929
|
const directive = this.directive(p, li, t);
|
|
845
930
|
if (directive) return directive;
|
|
846
931
|
}
|
|
@@ -848,7 +933,7 @@ var Tokenizer = class {
|
|
|
848
933
|
const admonition = this.mkdocsAdmonition(p, li, t);
|
|
849
934
|
if (admonition) return admonition;
|
|
850
935
|
}
|
|
851
|
-
if (indent <= 3 && t.startsWith(">")) {
|
|
936
|
+
if (indent <= 3 && !listNested && t.startsWith(">")) {
|
|
852
937
|
const callout = this.callout(p, li, t);
|
|
853
938
|
if (callout) return callout;
|
|
854
939
|
}
|
|
@@ -889,6 +974,17 @@ var Tokenizer = class {
|
|
|
889
974
|
}
|
|
890
975
|
return null;
|
|
891
976
|
}
|
|
977
|
+
/** True when line `li` continues a list item (the nearest non-blank line above is a list item or indented text under one). */
|
|
978
|
+
inListContinuation(li) {
|
|
979
|
+
for (let k = li - 1; k >= 0; k--) {
|
|
980
|
+
const line = this.lineText(k);
|
|
981
|
+
if (!NOT_WHITESPACE.test(line)) continue;
|
|
982
|
+
if (/^[ \t]*(?:[-*+]|\d{1,9}[.)])[ \t]/.test(line)) return true;
|
|
983
|
+
if (/^[ \t]/.test(line)) continue;
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
892
988
|
island(type, start, end, complete, meta = {}) {
|
|
893
989
|
return { type, start, end, complete, meta };
|
|
894
990
|
}
|
|
@@ -993,6 +1089,7 @@ var Tokenizer = class {
|
|
|
993
1089
|
continue;
|
|
994
1090
|
}
|
|
995
1091
|
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
1092
|
+
if (this.isOpenTail(k)) break;
|
|
996
1093
|
last = k;
|
|
997
1094
|
}
|
|
998
1095
|
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
@@ -1154,6 +1251,7 @@ var Tokenizer = class {
|
|
|
1154
1251
|
const li = this.lineOf(tp);
|
|
1155
1252
|
const ce = this.contentEnds[li];
|
|
1156
1253
|
const tag = readXmlTag(this.text, tp, this.finder);
|
|
1254
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
1157
1255
|
let openEnd;
|
|
1158
1256
|
if (tag && !tag.isClosing) {
|
|
1159
1257
|
if (tag.isSelfClosing) {
|
|
@@ -1238,7 +1336,7 @@ var Tokenizer = class {
|
|
|
1238
1336
|
return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
|
|
1239
1337
|
}
|
|
1240
1338
|
const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
1241
|
-
const typeSeven = atParaStart && t.trimEnd() === tag.raw;
|
|
1339
|
+
const typeSeven = atParaStart && t.trimEnd() === tag.raw && !this.isOpenTail(li);
|
|
1242
1340
|
if (!typeSix && !typeSeven) return null;
|
|
1243
1341
|
let end = this.contentEnds[li];
|
|
1244
1342
|
for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
|
|
@@ -1330,6 +1428,10 @@ var Tokenizer = class {
|
|
|
1330
1428
|
let breakLine = -1;
|
|
1331
1429
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
1332
1430
|
if (this.lineIsBlank(k)) break;
|
|
1431
|
+
if (this.lineStarts[k] >= this.provisionalFrom) {
|
|
1432
|
+
end = this.n;
|
|
1433
|
+
break;
|
|
1434
|
+
}
|
|
1333
1435
|
if (this.detectBlock(this.lineStarts[k], k, false)) {
|
|
1334
1436
|
breakLine = k;
|
|
1335
1437
|
break;
|
|
@@ -1395,6 +1497,7 @@ var Tokenizer = class {
|
|
|
1395
1497
|
scanInline(ps, pe) {
|
|
1396
1498
|
const text = this.text;
|
|
1397
1499
|
const inlines = [];
|
|
1500
|
+
this.tick(pe - ps);
|
|
1398
1501
|
const hasKind = text.slice(ps, pe).includes("__kind");
|
|
1399
1502
|
let kindBudget = 4 * (pe - ps) + 65536;
|
|
1400
1503
|
const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
|
|
@@ -1405,6 +1508,7 @@ var Tokenizer = class {
|
|
|
1405
1508
|
let runs = null;
|
|
1406
1509
|
const codeSpanClose = (n, from) => {
|
|
1407
1510
|
if (!runs) {
|
|
1511
|
+
this.tick(pe - ps);
|
|
1408
1512
|
runs = /* @__PURE__ */ new Map();
|
|
1409
1513
|
for (let k = ps; k < pe; ) {
|
|
1410
1514
|
if (text.charCodeAt(k) !== 96) {
|
|
@@ -1431,7 +1535,8 @@ var Tokenizer = class {
|
|
|
1431
1535
|
return at !== void 0 && at + n <= pe ? at : -1;
|
|
1432
1536
|
};
|
|
1433
1537
|
let i = ps;
|
|
1434
|
-
|
|
1538
|
+
const scanEnd = Math.min(pe, this.provisionalFrom);
|
|
1539
|
+
while (i < scanEnd) {
|
|
1435
1540
|
const ch = text[i];
|
|
1436
1541
|
if (ch === "\\") {
|
|
1437
1542
|
const nextCh = text[i + 1];
|
|
@@ -1449,6 +1554,9 @@ var Tokenizer = class {
|
|
|
1449
1554
|
if (ch === "`") {
|
|
1450
1555
|
const n = backtickRunLength(text, i);
|
|
1451
1556
|
const close = codeSpanClose(n, i + n);
|
|
1557
|
+
if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
|
|
1558
|
+
return { inlines, breakIsland: null, orphan: false };
|
|
1559
|
+
}
|
|
1452
1560
|
i = close === -1 ? i + n : close + n;
|
|
1453
1561
|
continue;
|
|
1454
1562
|
}
|
|
@@ -1465,6 +1573,7 @@ var Tokenizer = class {
|
|
|
1465
1573
|
continue;
|
|
1466
1574
|
}
|
|
1467
1575
|
const end = singleDollarMathEnd(text, i, pe);
|
|
1576
|
+
this.tick(end > 0 ? end - i : Math.min(403, pe - i));
|
|
1468
1577
|
if (end > 0 && !(this.streaming && end === this.n)) {
|
|
1469
1578
|
inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
|
|
1470
1579
|
i = end;
|
|
@@ -1492,6 +1601,7 @@ var Tokenizer = class {
|
|
|
1492
1601
|
const limit = Math.min(pe, i + 65536);
|
|
1493
1602
|
const end = matchingJsonObjectEnd(text, i, limit);
|
|
1494
1603
|
kindBudget -= (end ?? limit) - i;
|
|
1604
|
+
this.tick((end ?? limit) - i);
|
|
1495
1605
|
if (end !== null) {
|
|
1496
1606
|
const kind = declaredKind(text.slice(i, end));
|
|
1497
1607
|
if (kind) {
|
|
@@ -1553,6 +1663,7 @@ var Tokenizer = class {
|
|
|
1553
1663
|
continue;
|
|
1554
1664
|
}
|
|
1555
1665
|
const tag = readXmlTag(text, i, this.finder);
|
|
1666
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
1556
1667
|
if (tag && i + tag.raw.length <= pe) {
|
|
1557
1668
|
const name = tag.tagName;
|
|
1558
1669
|
const tagEnd = i + tag.raw.length;
|
|
@@ -1601,7 +1712,7 @@ var Tokenizer = class {
|
|
|
1601
1712
|
}
|
|
1602
1713
|
};
|
|
1603
1714
|
function tokenizeSource(text, options = {}) {
|
|
1604
|
-
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
1715
|
+
const raw = new Tokenizer(text, options.streaming ?? false, options.meter).run();
|
|
1605
1716
|
const cp = buildCodePointIndex(text);
|
|
1606
1717
|
const inline = (island) => ({
|
|
1607
1718
|
islandType: island.type,
|
|
@@ -1975,6 +2086,7 @@ exports.mapPosition = mapPosition;
|
|
|
1975
2086
|
exports.mapRange = mapRange;
|
|
1976
2087
|
exports.pairDisplayMath = pairDisplayMath;
|
|
1977
2088
|
exports.parseFenceOpener = parseFenceOpener;
|
|
2089
|
+
exports.pendingDisplayMathOpener = pendingDisplayMathOpener;
|
|
1978
2090
|
exports.readXmlTag = readXmlTag;
|
|
1979
2091
|
exports.singleDollarMathEnd = singleDollarMathEnd;
|
|
1980
2092
|
exports.spliceSave = spliceSave;
|