@ai-matrx/content-ir 0.15.1 → 0.16.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/CHANGELOG.md +35 -0
- package/dist/index.cjs +106 -6
- 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 +106 -7
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +106 -6
- 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 +106 -7
- 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: [] });
|
|
@@ -993,6 +1077,7 @@ var Tokenizer = class {
|
|
|
993
1077
|
continue;
|
|
994
1078
|
}
|
|
995
1079
|
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
1080
|
+
if (this.isOpenTail(k)) break;
|
|
996
1081
|
last = k;
|
|
997
1082
|
}
|
|
998
1083
|
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
@@ -1154,6 +1239,7 @@ var Tokenizer = class {
|
|
|
1154
1239
|
const li = this.lineOf(tp);
|
|
1155
1240
|
const ce = this.contentEnds[li];
|
|
1156
1241
|
const tag = readXmlTag(this.text, tp, this.finder);
|
|
1242
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
1157
1243
|
let openEnd;
|
|
1158
1244
|
if (tag && !tag.isClosing) {
|
|
1159
1245
|
if (tag.isSelfClosing) {
|
|
@@ -1238,7 +1324,7 @@ var Tokenizer = class {
|
|
|
1238
1324
|
return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
|
|
1239
1325
|
}
|
|
1240
1326
|
const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
1241
|
-
const typeSeven = atParaStart && t.trimEnd() === tag.raw;
|
|
1327
|
+
const typeSeven = atParaStart && t.trimEnd() === tag.raw && !this.isOpenTail(li);
|
|
1242
1328
|
if (!typeSix && !typeSeven) return null;
|
|
1243
1329
|
let end = this.contentEnds[li];
|
|
1244
1330
|
for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
|
|
@@ -1330,6 +1416,10 @@ var Tokenizer = class {
|
|
|
1330
1416
|
let breakLine = -1;
|
|
1331
1417
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
1332
1418
|
if (this.lineIsBlank(k)) break;
|
|
1419
|
+
if (this.lineStarts[k] >= this.provisionalFrom) {
|
|
1420
|
+
end = this.n;
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1333
1423
|
if (this.detectBlock(this.lineStarts[k], k, false)) {
|
|
1334
1424
|
breakLine = k;
|
|
1335
1425
|
break;
|
|
@@ -1395,6 +1485,7 @@ var Tokenizer = class {
|
|
|
1395
1485
|
scanInline(ps, pe) {
|
|
1396
1486
|
const text = this.text;
|
|
1397
1487
|
const inlines = [];
|
|
1488
|
+
this.tick(pe - ps);
|
|
1398
1489
|
const hasKind = text.slice(ps, pe).includes("__kind");
|
|
1399
1490
|
let kindBudget = 4 * (pe - ps) + 65536;
|
|
1400
1491
|
const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
|
|
@@ -1405,6 +1496,7 @@ var Tokenizer = class {
|
|
|
1405
1496
|
let runs = null;
|
|
1406
1497
|
const codeSpanClose = (n, from) => {
|
|
1407
1498
|
if (!runs) {
|
|
1499
|
+
this.tick(pe - ps);
|
|
1408
1500
|
runs = /* @__PURE__ */ new Map();
|
|
1409
1501
|
for (let k = ps; k < pe; ) {
|
|
1410
1502
|
if (text.charCodeAt(k) !== 96) {
|
|
@@ -1431,7 +1523,8 @@ var Tokenizer = class {
|
|
|
1431
1523
|
return at !== void 0 && at + n <= pe ? at : -1;
|
|
1432
1524
|
};
|
|
1433
1525
|
let i = ps;
|
|
1434
|
-
|
|
1526
|
+
const scanEnd = Math.min(pe, this.provisionalFrom);
|
|
1527
|
+
while (i < scanEnd) {
|
|
1435
1528
|
const ch = text[i];
|
|
1436
1529
|
if (ch === "\\") {
|
|
1437
1530
|
const nextCh = text[i + 1];
|
|
@@ -1449,6 +1542,9 @@ var Tokenizer = class {
|
|
|
1449
1542
|
if (ch === "`") {
|
|
1450
1543
|
const n = backtickRunLength(text, i);
|
|
1451
1544
|
const close = codeSpanClose(n, i + n);
|
|
1545
|
+
if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
|
|
1546
|
+
return { inlines, breakIsland: null, orphan: false };
|
|
1547
|
+
}
|
|
1452
1548
|
i = close === -1 ? i + n : close + n;
|
|
1453
1549
|
continue;
|
|
1454
1550
|
}
|
|
@@ -1465,6 +1561,7 @@ var Tokenizer = class {
|
|
|
1465
1561
|
continue;
|
|
1466
1562
|
}
|
|
1467
1563
|
const end = singleDollarMathEnd(text, i, pe);
|
|
1564
|
+
this.tick(end > 0 ? end - i : Math.min(403, pe - i));
|
|
1468
1565
|
if (end > 0 && !(this.streaming && end === this.n)) {
|
|
1469
1566
|
inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
|
|
1470
1567
|
i = end;
|
|
@@ -1492,6 +1589,7 @@ var Tokenizer = class {
|
|
|
1492
1589
|
const limit = Math.min(pe, i + 65536);
|
|
1493
1590
|
const end = matchingJsonObjectEnd(text, i, limit);
|
|
1494
1591
|
kindBudget -= (end ?? limit) - i;
|
|
1592
|
+
this.tick((end ?? limit) - i);
|
|
1495
1593
|
if (end !== null) {
|
|
1496
1594
|
const kind = declaredKind(text.slice(i, end));
|
|
1497
1595
|
if (kind) {
|
|
@@ -1553,6 +1651,7 @@ var Tokenizer = class {
|
|
|
1553
1651
|
continue;
|
|
1554
1652
|
}
|
|
1555
1653
|
const tag = readXmlTag(text, i, this.finder);
|
|
1654
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
1556
1655
|
if (tag && i + tag.raw.length <= pe) {
|
|
1557
1656
|
const name = tag.tagName;
|
|
1558
1657
|
const tagEnd = i + tag.raw.length;
|
|
@@ -1601,7 +1700,7 @@ var Tokenizer = class {
|
|
|
1601
1700
|
}
|
|
1602
1701
|
};
|
|
1603
1702
|
function tokenizeSource(text, options = {}) {
|
|
1604
|
-
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
1703
|
+
const raw = new Tokenizer(text, options.streaming ?? false, options.meter).run();
|
|
1605
1704
|
const cp = buildCodePointIndex(text);
|
|
1606
1705
|
const inline = (island) => ({
|
|
1607
1706
|
islandType: island.type,
|
|
@@ -1975,6 +2074,7 @@ exports.mapPosition = mapPosition;
|
|
|
1975
2074
|
exports.mapRange = mapRange;
|
|
1976
2075
|
exports.pairDisplayMath = pairDisplayMath;
|
|
1977
2076
|
exports.parseFenceOpener = parseFenceOpener;
|
|
2077
|
+
exports.pendingDisplayMathOpener = pendingDisplayMathOpener;
|
|
1978
2078
|
exports.readXmlTag = readXmlTag;
|
|
1979
2079
|
exports.singleDollarMathEnd = singleDollarMathEnd;
|
|
1980
2080
|
exports.spliceSave = spliceSave;
|