@ai-matrx/content-ir 0.15.0 → 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 +45 -0
- package/dist/index.cjs +114 -9
- 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 +114 -10
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +114 -9
- package/dist/source.cjs.map +1 -1
- package/dist/source.d.cts +26 -3
- package/dist/source.d.ts +26 -3
- package/dist/source.js +114 -10
- package/dist/source.js.map +1 -1
- package/package.json +1 -1
package/dist/source.cjs
CHANGED
|
@@ -321,15 +321,20 @@ var STRUCTURAL_MARKDOWN = /\]\(|https?:\/\/|\*\*|(?:^|\n)[ \t]{0,3}#{1,6}[ \t]|(
|
|
|
321
321
|
var LATEX_COMMAND = /\\[a-zA-Z]/;
|
|
322
322
|
var PROSE_WORD = /[A-Za-z]{3,}/g;
|
|
323
323
|
var PROSE_WORD_LIMIT = 6;
|
|
324
|
-
function
|
|
324
|
+
function opensFlowBlock(text, open) {
|
|
325
|
+
for (let k = open - 1; k >= 0 && text[k] !== "\n"; k--) if (text[k] !== " " && text[k] !== " ") return false;
|
|
326
|
+
for (let k = open + 2; k < text.length && text[k] !== "\n"; k++) if (text[k] !== " " && text[k] !== " " && text[k] !== "\r") return false;
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
function looksLikeDisplayMath(inner, flow = false) {
|
|
325
330
|
const s = inner.trim();
|
|
326
331
|
if (!s) return false;
|
|
327
332
|
if (STRUCTURAL_MARKDOWN.test(s)) return false;
|
|
328
333
|
if (s.length > MAX_MATH_SPAN) return false;
|
|
334
|
+
if (!flow && /\n[ \t]*\n/.test(inner)) return false;
|
|
329
335
|
if (LATEX_COMMAND.test(s)) {
|
|
330
336
|
return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT * 3;
|
|
331
337
|
}
|
|
332
|
-
if (/\n[ \t]*\n/.test(s)) return false;
|
|
333
338
|
return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT;
|
|
334
339
|
}
|
|
335
340
|
function codeRanges(text) {
|
|
@@ -343,6 +348,50 @@ function codeRanges(text) {
|
|
|
343
348
|
}
|
|
344
349
|
return ranges.sort((a, b) => a[0] - b[0]);
|
|
345
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
|
+
}
|
|
346
395
|
function pairDisplayMath(text) {
|
|
347
396
|
const pairs = /* @__PURE__ */ new Map();
|
|
348
397
|
if (!text.includes("$$")) return pairs;
|
|
@@ -363,7 +412,7 @@ function pairDisplayMath(text) {
|
|
|
363
412
|
const open = tokens[j];
|
|
364
413
|
const close = tokens[j + 1];
|
|
365
414
|
if (close === void 0) break;
|
|
366
|
-
if (looksLikeDisplayMath(text.slice(open + 2, close))) {
|
|
415
|
+
if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
|
|
367
416
|
pairs.set(open, close);
|
|
368
417
|
j += 2;
|
|
369
418
|
continue;
|
|
@@ -691,11 +740,15 @@ function isSplitterTreeLine(line) {
|
|
|
691
740
|
}
|
|
692
741
|
var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
|
|
693
742
|
var Tokenizer = class {
|
|
694
|
-
constructor(text, streaming = false) {
|
|
743
|
+
constructor(text, streaming = false, meter = void 0) {
|
|
695
744
|
this.text = text;
|
|
696
745
|
this.streaming = streaming;
|
|
746
|
+
this.meter = meter;
|
|
697
747
|
this.n = text.length;
|
|
748
|
+
this.tick(text.length);
|
|
698
749
|
this.mathPairs = pairDisplayMath(text);
|
|
750
|
+
this.provisionalFrom = streaming ? pendingDisplayMathOpener(text) : -1;
|
|
751
|
+
if (this.provisionalFrom === -1) this.provisionalFrom = Number.POSITIVE_INFINITY;
|
|
699
752
|
let start = 0;
|
|
700
753
|
for (let i = 0; i < text.length; i++) {
|
|
701
754
|
if (text.charCodeAt(i) === 10) {
|
|
@@ -706,13 +759,15 @@ var Tokenizer = class {
|
|
|
706
759
|
}
|
|
707
760
|
}
|
|
708
761
|
if (start < text.length || text.length === 0) {
|
|
762
|
+
this.pendingCR = streaming && text.length > start && text.charCodeAt(text.length - 1) === 13;
|
|
709
763
|
this.lineStarts.push(start);
|
|
710
|
-
this.contentEnds.push(text.length);
|
|
764
|
+
this.contentEnds.push(this.pendingCR ? text.length - 1 : text.length);
|
|
711
765
|
this.lineEnds.push(text.length);
|
|
712
766
|
}
|
|
713
767
|
}
|
|
714
768
|
text;
|
|
715
769
|
streaming;
|
|
770
|
+
meter;
|
|
716
771
|
n;
|
|
717
772
|
lineStarts = [];
|
|
718
773
|
contentEnds = [];
|
|
@@ -727,6 +782,23 @@ var Tokenizer = class {
|
|
|
727
782
|
/** `$$` opener → closer for the pairs the core renders as math. */
|
|
728
783
|
mathPairs;
|
|
729
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
|
+
}
|
|
730
802
|
/**
|
|
731
803
|
* `text.indexOf(needle, from)` in O(log k): the first query for a needle
|
|
732
804
|
* indexes all of its occurrences once, so repeated searches for a closer
|
|
@@ -750,9 +822,21 @@ var Tokenizer = class {
|
|
|
750
822
|
}
|
|
751
823
|
return lo < list.length ? list[lo] : -1;
|
|
752
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
|
+
}
|
|
753
837
|
/** Streaming only: the final line, still waiting for its terminator. */
|
|
754
838
|
isOpenTail(k) {
|
|
755
|
-
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);
|
|
756
840
|
}
|
|
757
841
|
get lineCount() {
|
|
758
842
|
return this.lineStarts.length;
|
|
@@ -777,6 +861,7 @@ var Tokenizer = class {
|
|
|
777
861
|
return this.text.slice(this.lineStarts[li], this.contentEnds[li]);
|
|
778
862
|
}
|
|
779
863
|
run() {
|
|
864
|
+
if (this.streaming) this.markOpenJsonTail();
|
|
780
865
|
let pos = 0;
|
|
781
866
|
while (pos < this.n) {
|
|
782
867
|
const li = this.lineOf(pos);
|
|
@@ -785,6 +870,10 @@ var Tokenizer = class {
|
|
|
785
870
|
pos = this.gap(pos, li);
|
|
786
871
|
continue;
|
|
787
872
|
}
|
|
873
|
+
if (pos >= this.provisionalFrom) {
|
|
874
|
+
this.push({ kind: "prose", start: pos, end: this.n, island: null, inlines: [] });
|
|
875
|
+
break;
|
|
876
|
+
}
|
|
788
877
|
const island = this.detectBlock(pos, li, true);
|
|
789
878
|
if (island) {
|
|
790
879
|
this.push({ kind: "island", start: island.start, end: island.end, island, inlines: [] });
|
|
@@ -988,6 +1077,7 @@ var Tokenizer = class {
|
|
|
988
1077
|
continue;
|
|
989
1078
|
}
|
|
990
1079
|
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
1080
|
+
if (this.isOpenTail(k)) break;
|
|
991
1081
|
last = k;
|
|
992
1082
|
}
|
|
993
1083
|
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
@@ -1149,6 +1239,7 @@ var Tokenizer = class {
|
|
|
1149
1239
|
const li = this.lineOf(tp);
|
|
1150
1240
|
const ce = this.contentEnds[li];
|
|
1151
1241
|
const tag = readXmlTag(this.text, tp, this.finder);
|
|
1242
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
1152
1243
|
let openEnd;
|
|
1153
1244
|
if (tag && !tag.isClosing) {
|
|
1154
1245
|
if (tag.isSelfClosing) {
|
|
@@ -1233,7 +1324,7 @@ var Tokenizer = class {
|
|
|
1233
1324
|
return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
|
|
1234
1325
|
}
|
|
1235
1326
|
const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
1236
|
-
const typeSeven = atParaStart && t.trimEnd() === tag.raw;
|
|
1327
|
+
const typeSeven = atParaStart && t.trimEnd() === tag.raw && !this.isOpenTail(li);
|
|
1237
1328
|
if (!typeSix && !typeSeven) return null;
|
|
1238
1329
|
let end = this.contentEnds[li];
|
|
1239
1330
|
for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
|
|
@@ -1325,6 +1416,10 @@ var Tokenizer = class {
|
|
|
1325
1416
|
let breakLine = -1;
|
|
1326
1417
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
1327
1418
|
if (this.lineIsBlank(k)) break;
|
|
1419
|
+
if (this.lineStarts[k] >= this.provisionalFrom) {
|
|
1420
|
+
end = this.n;
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1328
1423
|
if (this.detectBlock(this.lineStarts[k], k, false)) {
|
|
1329
1424
|
breakLine = k;
|
|
1330
1425
|
break;
|
|
@@ -1390,6 +1485,7 @@ var Tokenizer = class {
|
|
|
1390
1485
|
scanInline(ps, pe) {
|
|
1391
1486
|
const text = this.text;
|
|
1392
1487
|
const inlines = [];
|
|
1488
|
+
this.tick(pe - ps);
|
|
1393
1489
|
const hasKind = text.slice(ps, pe).includes("__kind");
|
|
1394
1490
|
let kindBudget = 4 * (pe - ps) + 65536;
|
|
1395
1491
|
const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
|
|
@@ -1400,6 +1496,7 @@ var Tokenizer = class {
|
|
|
1400
1496
|
let runs = null;
|
|
1401
1497
|
const codeSpanClose = (n, from) => {
|
|
1402
1498
|
if (!runs) {
|
|
1499
|
+
this.tick(pe - ps);
|
|
1403
1500
|
runs = /* @__PURE__ */ new Map();
|
|
1404
1501
|
for (let k = ps; k < pe; ) {
|
|
1405
1502
|
if (text.charCodeAt(k) !== 96) {
|
|
@@ -1426,7 +1523,8 @@ var Tokenizer = class {
|
|
|
1426
1523
|
return at !== void 0 && at + n <= pe ? at : -1;
|
|
1427
1524
|
};
|
|
1428
1525
|
let i = ps;
|
|
1429
|
-
|
|
1526
|
+
const scanEnd = Math.min(pe, this.provisionalFrom);
|
|
1527
|
+
while (i < scanEnd) {
|
|
1430
1528
|
const ch = text[i];
|
|
1431
1529
|
if (ch === "\\") {
|
|
1432
1530
|
const nextCh = text[i + 1];
|
|
@@ -1444,6 +1542,9 @@ var Tokenizer = class {
|
|
|
1444
1542
|
if (ch === "`") {
|
|
1445
1543
|
const n = backtickRunLength(text, i);
|
|
1446
1544
|
const close = codeSpanClose(n, i + n);
|
|
1545
|
+
if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
|
|
1546
|
+
return { inlines, breakIsland: null, orphan: false };
|
|
1547
|
+
}
|
|
1447
1548
|
i = close === -1 ? i + n : close + n;
|
|
1448
1549
|
continue;
|
|
1449
1550
|
}
|
|
@@ -1460,6 +1561,7 @@ var Tokenizer = class {
|
|
|
1460
1561
|
continue;
|
|
1461
1562
|
}
|
|
1462
1563
|
const end = singleDollarMathEnd(text, i, pe);
|
|
1564
|
+
this.tick(end > 0 ? end - i : Math.min(403, pe - i));
|
|
1463
1565
|
if (end > 0 && !(this.streaming && end === this.n)) {
|
|
1464
1566
|
inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
|
|
1465
1567
|
i = end;
|
|
@@ -1487,6 +1589,7 @@ var Tokenizer = class {
|
|
|
1487
1589
|
const limit = Math.min(pe, i + 65536);
|
|
1488
1590
|
const end = matchingJsonObjectEnd(text, i, limit);
|
|
1489
1591
|
kindBudget -= (end ?? limit) - i;
|
|
1592
|
+
this.tick((end ?? limit) - i);
|
|
1490
1593
|
if (end !== null) {
|
|
1491
1594
|
const kind = declaredKind(text.slice(i, end));
|
|
1492
1595
|
if (kind) {
|
|
@@ -1548,6 +1651,7 @@ var Tokenizer = class {
|
|
|
1548
1651
|
continue;
|
|
1549
1652
|
}
|
|
1550
1653
|
const tag = readXmlTag(text, i, this.finder);
|
|
1654
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
1551
1655
|
if (tag && i + tag.raw.length <= pe) {
|
|
1552
1656
|
const name = tag.tagName;
|
|
1553
1657
|
const tagEnd = i + tag.raw.length;
|
|
@@ -1596,7 +1700,7 @@ var Tokenizer = class {
|
|
|
1596
1700
|
}
|
|
1597
1701
|
};
|
|
1598
1702
|
function tokenizeSource(text, options = {}) {
|
|
1599
|
-
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
1703
|
+
const raw = new Tokenizer(text, options.streaming ?? false, options.meter).run();
|
|
1600
1704
|
const cp = buildCodePointIndex(text);
|
|
1601
1705
|
const inline = (island) => ({
|
|
1602
1706
|
islandType: island.type,
|
|
@@ -1970,6 +2074,7 @@ exports.mapPosition = mapPosition;
|
|
|
1970
2074
|
exports.mapRange = mapRange;
|
|
1971
2075
|
exports.pairDisplayMath = pairDisplayMath;
|
|
1972
2076
|
exports.parseFenceOpener = parseFenceOpener;
|
|
2077
|
+
exports.pendingDisplayMathOpener = pendingDisplayMathOpener;
|
|
1973
2078
|
exports.readXmlTag = readXmlTag;
|
|
1974
2079
|
exports.singleDollarMathEnd = singleDollarMathEnd;
|
|
1975
2080
|
exports.spliceSave = spliceSave;
|