@ai-matrx/content-ir 0.16.1 → 0.16.2

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/source.d.cts CHANGED
@@ -421,20 +421,11 @@ declare function parseFenceOpener(line: string): {
421
421
  declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
422
422
 
423
423
  /**
424
- * `$$` pairing — the core's rule for which `$$` delimiters are real math.
425
- *
426
- * Ported from `@ai-matrx/kit/delimiter-guard` (`guardMathDelimiters`), which
427
- * every math-capable renderer runs before remark-math. Its decisions:
428
- * - `$$` tokens outside code (``` / ~~~ fences, `inline code`) pair in
429
- * document order, open → close;
430
- * - a pair whose inside reads as prose or carries markdown structure is NOT
431
- * math: the renderer neutralizes its opener and the closer is retried as
432
- * the next opener;
433
- * - an unpaired `$$` is inert — it renders as literal text.
434
- * So the tokenizer protects exactly the pairs the renderer shows as math, and
435
- * a lone `$$` (a stray closer, or an opener that never closed) never locks
436
- * anything. Linear time: one regex pass per code shape, one sweep.
424
+ * `$$...$$`, `$$…$$`, `$$ · $$`: a PLACEHOLDER — prose describing the syntax,
425
+ * never a formula. The pair is consumed whole as literal text (neither `$$`
426
+ * may open the next span).
437
427
  */
428
+ declare function isMathPlaceholder(inner: string): boolean;
438
429
  /**
439
430
  * The guard's `looksLikeMath`. `flow` = the opener is alone on its line: a
440
431
  * flow block may span blank lines (like a fence); a `$$` with text beside it
@@ -453,4 +444,4 @@ declare function looksLikeDisplayMath(inner: string, flow?: boolean): boolean;
453
444
  declare function pendingDisplayMathOpener(text: string): number;
454
445
  declare function pairDisplayMath(text: string): Map<number, number>;
455
446
 
456
- export { type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
447
+ export { type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
package/dist/source.d.ts CHANGED
@@ -421,20 +421,11 @@ declare function parseFenceOpener(line: string): {
421
421
  declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
422
422
 
423
423
  /**
424
- * `$$` pairing — the core's rule for which `$$` delimiters are real math.
425
- *
426
- * Ported from `@ai-matrx/kit/delimiter-guard` (`guardMathDelimiters`), which
427
- * every math-capable renderer runs before remark-math. Its decisions:
428
- * - `$$` tokens outside code (``` / ~~~ fences, `inline code`) pair in
429
- * document order, open → close;
430
- * - a pair whose inside reads as prose or carries markdown structure is NOT
431
- * math: the renderer neutralizes its opener and the closer is retried as
432
- * the next opener;
433
- * - an unpaired `$$` is inert — it renders as literal text.
434
- * So the tokenizer protects exactly the pairs the renderer shows as math, and
435
- * a lone `$$` (a stray closer, or an opener that never closed) never locks
436
- * anything. Linear time: one regex pass per code shape, one sweep.
424
+ * `$$...$$`, `$$…$$`, `$$ · $$`: a PLACEHOLDER — prose describing the syntax,
425
+ * never a formula. The pair is consumed whole as literal text (neither `$$`
426
+ * may open the next span).
437
427
  */
428
+ declare function isMathPlaceholder(inner: string): boolean;
438
429
  /**
439
430
  * The guard's `looksLikeMath`. `flow` = the opener is alone on its line: a
440
431
  * flow block may span blank lines (like a fence); a `$$` with text beside it
@@ -453,4 +444,4 @@ declare function looksLikeDisplayMath(inner: string, flow?: boolean): boolean;
453
444
  declare function pendingDisplayMathOpener(text: string): number;
454
445
  declare function pairDisplayMath(text: string): Map<number, number>;
455
446
 
456
- export { type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
447
+ export { type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
package/dist/source.js CHANGED
@@ -319,6 +319,9 @@ var STRUCTURAL_MARKDOWN = /\]\(|https?:\/\/|\*\*|(?:^|\n)[ \t]{0,3}#{1,6}[ \t]|(
319
319
  var LATEX_COMMAND = /\\[a-zA-Z]/;
320
320
  var PROSE_WORD = /[A-Za-z]{3,}/g;
321
321
  var PROSE_WORD_LIMIT = 6;
322
+ function isMathPlaceholder(inner) {
323
+ return /^[\s.…·⋯_-]*$/.test(inner) && /[.…·⋯]/.test(inner);
324
+ }
322
325
  function opensFlowBlock(text, open) {
323
326
  for (let k = open - 1; k >= 0 && text[k] !== "\n"; k--) if (text[k] !== " " && text[k] !== " ") return false;
324
327
  for (let k = open + 2; k < text.length && text[k] !== "\n"; k++) if (text[k] !== " " && text[k] !== " " && text[k] !== "\r") return false;
@@ -337,13 +340,84 @@ function looksLikeDisplayMath(inner, flow = false) {
337
340
  }
338
341
  function codeRanges(text) {
339
342
  const ranges = [];
340
- for (const re of [/```[\s\S]*?(?:```|$)/g, /~~~[\s\S]*?(?:~~~|$)/g, /`[^`\n]*`/g]) {
341
- let m;
342
- while ((m = re.exec(text)) !== null) {
343
- ranges.push([m.index, m.index + m[0].length]);
344
- if (m[0].length === 0) re.lastIndex++;
343
+ const n = text.length;
344
+ let fence = null;
345
+ let para = -1;
346
+ const spans = (from, to) => {
347
+ const runs = [];
348
+ for (let k = from; k < to; ) {
349
+ if (text.charCodeAt(k) !== 96) {
350
+ k++;
351
+ continue;
352
+ }
353
+ let len = 1;
354
+ while (k + len < to && text.charCodeAt(k + len) === 96) len++;
355
+ runs.push([k, len]);
356
+ k += len;
357
+ }
358
+ const nextSame = new Array(runs.length).fill(-1);
359
+ const last = /* @__PURE__ */ new Map();
360
+ for (let r = runs.length - 1; r >= 0; r--) {
361
+ const len = runs[r][1];
362
+ nextSame[r] = last.get(len) ?? -1;
363
+ last.set(len, r);
364
+ }
365
+ for (let r = 0; r < runs.length; ) {
366
+ const j = nextSame[r];
367
+ if (j === -1) {
368
+ r++;
369
+ continue;
370
+ }
371
+ const [s0] = runs[r];
372
+ const [s1, l1] = runs[j];
373
+ ranges.push([s0, s1 + l1]);
374
+ r = j + 1;
345
375
  }
346
- }
376
+ };
377
+ let pos = 0;
378
+ while (pos <= n) {
379
+ const nl = text.indexOf("\n", pos);
380
+ const lineEnd = nl === -1 ? n : nl;
381
+ const line = text.slice(pos, lineEnd);
382
+ let indent = 0;
383
+ while (indent < line.length && line[indent] === " ") indent++;
384
+ const body = line.slice(indent);
385
+ if (fence) {
386
+ const trimmed = trimFenceLine(line);
387
+ let closes = false;
388
+ if (fence.char === "`") {
389
+ const kind = classifyInnerFenceLine(trimmed, fence.len, fence.nests, fence.depth);
390
+ if (kind === "open-nested") fence.depth++;
391
+ else if (kind === "close-nested") fence.depth--;
392
+ else if (kind === "close-outer") closes = indent <= 3;
393
+ } else {
394
+ let t = 0;
395
+ while (t < trimmed.length && trimmed[t] === "~") t++;
396
+ closes = indent <= 3 && t >= fence.len && trimFenceLine(trimmed.slice(t)) === "";
397
+ }
398
+ if (closes) {
399
+ ranges.push([fence.start, lineEnd]);
400
+ fence = null;
401
+ }
402
+ } else {
403
+ const opener = indent <= 3 ? /^(`{3,}|~{3,})(.*)$/.exec(body) : null;
404
+ const info = opener ? opener[2] : "";
405
+ if (opener && !(opener[1][0] === "`" && info.includes("`"))) {
406
+ if (para !== -1) spans(para, pos);
407
+ para = -1;
408
+ const char = opener[1][0];
409
+ const parsed = char === "`" ? parseFenceOpener(line) : null;
410
+ fence = { char, len: opener[1].length, start: pos, nests: fenceNestsInnerFences(parsed?.lang), depth: 0 };
411
+ } else if (body.trim() === "") {
412
+ if (para !== -1) spans(para, pos);
413
+ para = -1;
414
+ } else if (para === -1) para = pos;
415
+ }
416
+ if (nl === -1) break;
417
+ pos = nl + 1;
418
+ }
419
+ if (fence) ranges.push([fence.start, n]);
420
+ else if (para !== -1) spans(para, n);
347
421
  return ranges.sort((a, b) => a[0] - b[0]);
348
422
  }
349
423
  function pendingDisplayMathOpener(text) {
@@ -366,6 +440,10 @@ function pendingDisplayMathOpener(text) {
366
440
  const open = tokens[j];
367
441
  const close = tokens[j + 1];
368
442
  if (close === void 0) break;
443
+ if (isMathPlaceholder(text.slice(open + 2, close))) {
444
+ j += 2;
445
+ continue;
446
+ }
369
447
  if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
370
448
  paired.add(open);
371
449
  paired.add(close);
@@ -410,6 +488,10 @@ function pairDisplayMath(text) {
410
488
  const open = tokens[j];
411
489
  const close = tokens[j + 1];
412
490
  if (close === void 0) break;
491
+ if (isMathPlaceholder(text.slice(open + 2, close))) {
492
+ j += 2;
493
+ continue;
494
+ }
413
495
  if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
414
496
  pairs.set(open, close);
415
497
  j += 2;
@@ -747,6 +829,19 @@ var Tokenizer = class {
747
829
  this.mathPairs = pairDisplayMath(text);
748
830
  this.provisionalFrom = streaming ? pendingDisplayMathOpener(text) : -1;
749
831
  if (this.provisionalFrom === -1) this.provisionalFrom = Number.POSITIVE_INFINITY;
832
+ if (streaming && text.includes("$$")) {
833
+ for (const pad of ["`", "``", "```", "~~~"]) {
834
+ const alt = pairDisplayMath(text + pad);
835
+ for (const [open, close] of this.mathPairs) {
836
+ if (alt.get(open) !== close) this.provisionalFrom = Math.min(this.provisionalFrom, open);
837
+ }
838
+ for (const [open, close] of alt) {
839
+ if (close < text.length && this.mathPairs.get(open) !== close) {
840
+ this.provisionalFrom = Math.min(this.provisionalFrom, open);
841
+ }
842
+ }
843
+ }
844
+ }
750
845
  let start = 0;
751
846
  for (let i = 0; i < text.length; i++) {
752
847
  if (text.charCodeAt(i) === 10) {
@@ -787,13 +882,17 @@ var Tokenizer = class {
787
882
  /**
788
883
  * Streaming: an open last line that begins with `{` is undecided — each new
789
884
  * byte can balance or unbalance its braces and flip the whole line between
790
- * prose and a JSON island — so it is provisional until it ends (G5).
885
+ * prose and a JSON island — and so is a line that is exactly one allowed
886
+ * HTML tag so far; both are provisional until they end (G5).
791
887
  */
792
888
  markOpenJsonTail() {
793
889
  const last = this.lineStarts.length - 1;
794
890
  if (!this.isOpenTail(last)) return;
795
891
  const start = this.lineStarts[last];
796
- if (this.lineText(last).trimStart().startsWith("{")) {
892
+ const t = this.lineText(last).trim();
893
+ const oneTag = t.startsWith("<") ? readXmlTag(t, 0) : null;
894
+ const loneTag = !!oneTag && oneTag.raw === t && ALLOWED_RAW_HTML_TAGS.has(oneTag.tagName.toLowerCase());
895
+ if (t.startsWith("{") || loneTag) {
797
896
  this.provisionalFrom = Math.min(this.provisionalFrom, start);
798
897
  }
799
898
  }
@@ -1087,10 +1186,16 @@ var Tokenizer = class {
1087
1186
  continue;
1088
1187
  }
1089
1188
  if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
1090
- if (this.isOpenTail(k)) break;
1189
+ if (this.isOpenTail(k)) return this.heldFootnote(p, open[1]);
1091
1190
  last = k;
1092
1191
  }
1093
- return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
1192
+ const end = this.contentEnds[last];
1193
+ if (this.paragraphMayGrow(end)) return this.heldFootnote(p, open[1]);
1194
+ return this.island("footnote_def", p, end, true, { id: open[1] });
1195
+ }
1196
+ /** A footnote whose continuation is still arriving: open to the end of the text. */
1197
+ heldFootnote(p, id) {
1198
+ return this.island("footnote_def", p, this.n, false, { id });
1094
1199
  }
1095
1200
  /**
1096
1201
  * Backtick fence — the renderer splitter's close rules: JSON-string aware for
@@ -1334,7 +1439,12 @@ var Tokenizer = class {
1334
1439
  return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
1335
1440
  }
1336
1441
  const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
1337
- const typeSeven = atParaStart && t.trimEnd() === tag.raw && !this.isOpenTail(li);
1442
+ const loneTag = atParaStart && t.trimEnd() === tag.raw;
1443
+ if (loneTag && this.isOpenTail(li)) {
1444
+ this.provisionalFrom = Math.min(this.provisionalFrom, p);
1445
+ return null;
1446
+ }
1447
+ const typeSeven = loneTag;
1338
1448
  if (!typeSix && !typeSeven) return null;
1339
1449
  let end = this.contentEnds[li];
1340
1450
  for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
@@ -1426,10 +1536,6 @@ var Tokenizer = class {
1426
1536
  let breakLine = -1;
1427
1537
  for (let k = li + 1; k < this.lineCount; k++) {
1428
1538
  if (this.lineIsBlank(k)) break;
1429
- if (this.lineStarts[k] >= this.provisionalFrom) {
1430
- end = this.n;
1431
- break;
1432
- }
1433
1539
  if (this.detectBlock(this.lineStarts[k], k, false)) {
1434
1540
  breakLine = k;
1435
1541
  break;
@@ -1572,7 +1678,11 @@ var Tokenizer = class {
1572
1678
  }
1573
1679
  const end = singleDollarMathEnd(text, i, pe);
1574
1680
  this.tick(end > 0 ? end - i : Math.min(403, pe - i));
1575
- if (end > 0 && !(this.streaming && end === this.n)) {
1681
+ if (end > 0 && this.streaming && end === this.n) {
1682
+ this.provisionalFrom = Math.min(this.provisionalFrom, i);
1683
+ return { inlines, breakIsland: null, orphan: false };
1684
+ }
1685
+ if (end > 0) {
1576
1686
  inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
1577
1687
  i = end;
1578
1688
  continue;
@@ -2063,6 +2173,6 @@ function mapRange(changes, start, end, unit = "utf16") {
2063
2173
  return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
2064
2174
  }
2065
2175
 
2066
- export { CALLOUT_NAMES, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
2176
+ export { CALLOUT_NAMES, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
2067
2177
  //# sourceMappingURL=source.js.map
2068
2178
  //# sourceMappingURL=source.js.map