@ai-matrx/content-ir 0.14.3 → 0.15.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/dist/source.d.cts CHANGED
@@ -390,6 +390,24 @@ type InnerFenceLine =
390
390
  declare const FENCE_WHITESPACE = " \t\n\r\f\v";
391
391
  /** Strip {@link FENCE_WHITESPACE} (and nothing else) from both ends of a line. */
392
392
  declare function trimFenceLine(line: string): string;
393
+ /**
394
+ * The whitespace around a fence OPENER and inside its info string. The
395
+ * renderer finds openers with JavaScript's `String#trim()` and splits the info
396
+ * string on `/\s/`; this set IS that definition, written out so the Python
397
+ * twin can match it exactly — ECMAScript WhiteSpace + LineTerminator. It
398
+ * differs from Python's `str.split()` on U+0085 and U+001C–U+001F (not JS
399
+ * whitespace) and U+FEFF (JS whitespace) — verify-RC-B3 residual R4′.
400
+ */
401
+ declare const FENCE_OPENER_WHITESPACE = "\t\n\v\f\r \u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF";
402
+ /**
403
+ * Parse a backtick fence OPENER line the way the renderer does: trim the line,
404
+ * count the backtick run (3+), trim the rest, and take the first
405
+ * whitespace-separated word as the language. null when the line opens nothing.
406
+ */
407
+ declare function parseFenceOpener(line: string): {
408
+ ticks: number;
409
+ lang: string;
410
+ } | null;
393
411
  declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
394
412
 
395
413
  /**
@@ -407,9 +425,14 @@ declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nest
407
425
  * a lone `$$` (a stray closer, or an opener that never closed) never locks
408
426
  * anything. Linear time: one regex pass per code shape, one sweep.
409
427
  */
410
- /** The guard's `looksLikeMath`, verbatim. */
411
- declare function looksLikeDisplayMath(inner: string): boolean;
428
+ /**
429
+ * The guard's `looksLikeMath`. `flow` = the opener is alone on its line: a
430
+ * flow block may span blank lines (like a fence); a `$$` with text beside it
431
+ * never crosses one — TeX's rule, and what keeps a stray prose `$$` from
432
+ * pairing with the next paragraph's formula.
433
+ */
434
+ declare function looksLikeDisplayMath(inner: string, flow?: boolean): boolean;
412
435
  /** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
413
436
  declare function pairDisplayMath(text: string): Map<number, number>;
414
437
 
415
- export { type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type DisturbedIsland, 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, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
438
+ 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, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
package/dist/source.d.ts CHANGED
@@ -390,6 +390,24 @@ type InnerFenceLine =
390
390
  declare const FENCE_WHITESPACE = " \t\n\r\f\v";
391
391
  /** Strip {@link FENCE_WHITESPACE} (and nothing else) from both ends of a line. */
392
392
  declare function trimFenceLine(line: string): string;
393
+ /**
394
+ * The whitespace around a fence OPENER and inside its info string. The
395
+ * renderer finds openers with JavaScript's `String#trim()` and splits the info
396
+ * string on `/\s/`; this set IS that definition, written out so the Python
397
+ * twin can match it exactly — ECMAScript WhiteSpace + LineTerminator. It
398
+ * differs from Python's `str.split()` on U+0085 and U+001C–U+001F (not JS
399
+ * whitespace) and U+FEFF (JS whitespace) — verify-RC-B3 residual R4′.
400
+ */
401
+ declare const FENCE_OPENER_WHITESPACE = "\t\n\v\f\r \u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF";
402
+ /**
403
+ * Parse a backtick fence OPENER line the way the renderer does: trim the line,
404
+ * count the backtick run (3+), trim the rest, and take the first
405
+ * whitespace-separated word as the language. null when the line opens nothing.
406
+ */
407
+ declare function parseFenceOpener(line: string): {
408
+ ticks: number;
409
+ lang: string;
410
+ } | null;
393
411
  declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
394
412
 
395
413
  /**
@@ -407,9 +425,14 @@ declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nest
407
425
  * a lone `$$` (a stray closer, or an opener that never closed) never locks
408
426
  * anything. Linear time: one regex pass per code shape, one sweep.
409
427
  */
410
- /** The guard's `looksLikeMath`, verbatim. */
411
- declare function looksLikeDisplayMath(inner: string): boolean;
428
+ /**
429
+ * The guard's `looksLikeMath`. `flow` = the opener is alone on its line: a
430
+ * flow block may span blank lines (like a fence); a `$$` with text beside it
431
+ * never crosses one — TeX's rule, and what keeps a stray prose `$$` from
432
+ * pairing with the next paragraph's formula.
433
+ */
434
+ declare function looksLikeDisplayMath(inner: string, flow?: boolean): boolean;
412
435
  /** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
413
436
  declare function pairDisplayMath(text: string): Map<number, number>;
414
437
 
415
- export { type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type DisturbedIsland, 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, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
438
+ 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, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
package/dist/source.js CHANGED
@@ -220,6 +220,24 @@ function trimFenceLine(line) {
220
220
  while (end > start && isFenceWhitespace(line[end - 1])) end--;
221
221
  return start === 0 && end === line.length ? line : line.slice(start, end);
222
222
  }
223
+ var FENCE_OPENER_WHITESPACE = " \n\v\f\r \xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF";
224
+ function isOpenerWhitespace(ch) {
225
+ return ch !== void 0 && ch !== "" && FENCE_OPENER_WHITESPACE.includes(ch);
226
+ }
227
+ function parseFenceOpener(line) {
228
+ let start = 0;
229
+ let end = line.length;
230
+ while (start < end && isOpenerWhitespace(line[start])) start++;
231
+ while (end > start && isOpenerWhitespace(line[end - 1])) end--;
232
+ let ticks = 0;
233
+ while (start + ticks < end && line[start + ticks] === "`") ticks++;
234
+ if (ticks < 3) return null;
235
+ let infoStart = start + ticks;
236
+ while (infoStart < end && isOpenerWhitespace(line[infoStart])) infoStart++;
237
+ let langEnd = infoStart;
238
+ while (langEnd < end && !isOpenerWhitespace(line[langEnd])) langEnd++;
239
+ return { ticks, lang: line.slice(infoStart, langEnd) };
240
+ }
223
241
  function classifyInnerFenceLine(trimmed, openTicks, nests, nestedDepth) {
224
242
  let ticks = 0;
225
243
  while (ticks < trimmed.length && trimmed[ticks] === "`") ticks++;
@@ -301,15 +319,20 @@ var STRUCTURAL_MARKDOWN = /\]\(|https?:\/\/|\*\*|(?:^|\n)[ \t]{0,3}#{1,6}[ \t]|(
301
319
  var LATEX_COMMAND = /\\[a-zA-Z]/;
302
320
  var PROSE_WORD = /[A-Za-z]{3,}/g;
303
321
  var PROSE_WORD_LIMIT = 6;
304
- function looksLikeDisplayMath(inner) {
322
+ function opensFlowBlock(text, open) {
323
+ for (let k = open - 1; k >= 0 && text[k] !== "\n"; k--) if (text[k] !== " " && text[k] !== " ") return false;
324
+ for (let k = open + 2; k < text.length && text[k] !== "\n"; k++) if (text[k] !== " " && text[k] !== " " && text[k] !== "\r") return false;
325
+ return true;
326
+ }
327
+ function looksLikeDisplayMath(inner, flow = false) {
305
328
  const s = inner.trim();
306
329
  if (!s) return false;
307
330
  if (STRUCTURAL_MARKDOWN.test(s)) return false;
308
331
  if (s.length > MAX_MATH_SPAN) return false;
332
+ if (!flow && /\n[ \t]*\n/.test(inner)) return false;
309
333
  if (LATEX_COMMAND.test(s)) {
310
334
  return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT * 3;
311
335
  }
312
- if (/\n[ \t]*\n/.test(s)) return false;
313
336
  return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT;
314
337
  }
315
338
  function codeRanges(text) {
@@ -343,7 +366,7 @@ function pairDisplayMath(text) {
343
366
  const open = tokens[j];
344
367
  const close = tokens[j + 1];
345
368
  if (close === void 0) break;
346
- if (looksLikeDisplayMath(text.slice(open + 2, close))) {
369
+ if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
347
370
  pairs.set(open, close);
348
371
  j += 2;
349
372
  continue;
@@ -980,8 +1003,7 @@ var Tokenizer = class {
980
1003
  */
981
1004
  backtickFence(p, li, t) {
982
1005
  const openTicks = backtickRunLength(t, 0);
983
- const info = t.slice(openTicks).trim();
984
- const lang = info.split(/\s/)[0] ?? "";
1006
+ const lang = parseFenceOpener(t)?.lang ?? "";
985
1007
  const isJson = lang === "json";
986
1008
  const normalized = normalizeFenceLanguage(lang);
987
1009
  const meta = { fence: "`", ticks: openTicks, lang };
@@ -1111,6 +1133,7 @@ var Tokenizer = class {
1111
1133
  const endLine = this.lineOf(close);
1112
1134
  const endCe = this.contentEnds[endLine];
1113
1135
  if (endLine !== li && !this.isBlank(end, endCe)) return null;
1136
+ if (this.isOpenTail(endLine)) return this.island("math_block", p, this.n, false, { delimiter: "$$" });
1114
1137
  return this.island("math_block", p, end, true, { delimiter: "$$" });
1115
1138
  }
1116
1139
  /** `<artifact …>`, `<decision …>`, … at the start of a line. */
@@ -1440,7 +1463,7 @@ var Tokenizer = class {
1440
1463
  continue;
1441
1464
  }
1442
1465
  const end = singleDollarMathEnd(text, i, pe);
1443
- if (end > 0) {
1466
+ if (end > 0 && !(this.streaming && end === this.n)) {
1444
1467
  inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
1445
1468
  i = end;
1446
1469
  continue;
@@ -1850,11 +1873,17 @@ function spliceSave(original, edits, options = {}) {
1850
1873
  else newIslandsByStart.set(island.start, [island.raw]);
1851
1874
  }
1852
1875
  const disturbed = [];
1876
+ const carried = (island) => sorted.some((edit) => !edit.island && island.start >= edit.start && island.end <= edit.end);
1877
+ const changedInside = [];
1853
1878
  for (const island of islands) {
1854
1879
  if (replacedIslands.has(`${island.start}:${island.end}`)) continue;
1855
1880
  const mappedStart = mapPosition(changes, island.start, { assoc: 1 }).pos;
1856
1881
  const candidates = newIslandsByStart.get(mappedStart);
1857
1882
  if (!candidates || !candidates.includes(island.raw)) {
1883
+ if (carried(island)) {
1884
+ changedInside.push(island);
1885
+ continue;
1886
+ }
1858
1887
  disturbed.push({
1859
1888
  islandType: island.islandType,
1860
1889
  inline: island.inline,
@@ -1864,6 +1893,14 @@ function spliceSave(original, edits, options = {}) {
1864
1893
  });
1865
1894
  }
1866
1895
  }
1896
+ if (changedInside.length > 0) {
1897
+ const first = changedInside[0];
1898
+ const name = first.meta.tag ?? first.meta.name ?? first.meta.lang ?? "";
1899
+ throw new SourceSpliceError(
1900
+ "island_edit",
1901
+ `the edit changes the protected ${first.islandType}${name ? ` (${String(name)})` : ""} island at [${first.start}, ${first.end}) \u2014 its bytes survive only as ordinary text${changedInside.length > 1 ? ` (and ${changedInside.length - 1} more)` : ""}; islands change only through islandEdit()`
1902
+ );
1903
+ }
1867
1904
  const integrity = {
1868
1905
  ok: bytesOutsideEditsIdentical && disturbed.length === 0,
1869
1906
  bytesOutsideEditsIdentical,
@@ -1915,6 +1952,6 @@ function mapRange(changes, start, end, unit = "utf16") {
1915
1952
  return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
1916
1953
  }
1917
1954
 
1918
- export { CALLOUT_NAMES, FENCE_WHITESPACE, NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
1955
+ 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, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
1919
1956
  //# sourceMappingURL=source.js.map
1920
1957
  //# sourceMappingURL=source.js.map