@ai-matrx/content-ir 0.18.4 → 0.18.5

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.5
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/content-ir-core/v0.18.4..npm/content-ir-core/v0.18.5 -- apps/shared/content-ir-core`).
7
+ No source changes intended and no consumer action required.
8
+
3
9
  ## 0.18.4
4
10
 
5
11
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -5296,6 +5296,7 @@ var FenceReader = class {
5296
5296
  function closeFence(src, open, opener) {
5297
5297
  const first = readFence(src, open, new FenceReader(opener));
5298
5298
  if (first.closed || !first.reader.sawNested || first.reader.nestedDepth <= 0) return { line: first.line, closed: first.closed };
5299
+ if (src.streaming) return { line: first.line, closed: false };
5299
5300
  const strict = readFence(src, open, new FenceReader(opener, { nesting: false }));
5300
5301
  return { line: strict.line, closed: strict.closed };
5301
5302
  }
@@ -5559,6 +5560,8 @@ function fenceLineKinds(text) {
5559
5560
  function pendingCodeSpanStart(text) {
5560
5561
  const n = text.length;
5561
5562
  if (n === 0 || /\n[ \t]*\n[ \t]*$/.test(text)) return -1;
5563
+ const lastLine = text.slice(text.lastIndexOf("\n") + 1);
5564
+ if (lastLine && /^(?: {0,3}>[ \t]?)*[ \t]*$/.test(lastLine)) return pendingCodeSpanStart(`${text}x`);
5562
5565
  const s = scan(text);
5563
5566
  const para = s.pendingPara;
5564
5567
  if (s.endsInFence || para === -1) return -1;
@@ -5705,13 +5708,26 @@ var MATH_SHAPE_CHARS = /^[A-Za-z0-9'\s(),.*\/-]+$/;
5705
5708
  function isSingleDollarMath(content, after) {
5706
5709
  if (!content || content.length > 400) return false;
5707
5710
  if (/^\s/.test(content) || /\s$/.test(content)) return false;
5708
- if (after !== void 0 && /[0-9]/.test(after)) return false;
5711
+ if (after !== void 0 && /^[0-9]/.test(after)) return false;
5712
+ if (isVariableChain(content, after)) return false;
5709
5713
  if (/(?:^|[^\\])%/.test(content)) return false;
5710
5714
  if (/^[)\]}"/]/.test(content) || /[(\[{":;,/]$/.test(content)) return false;
5711
- if (/^[0-9]/.test(content) && after !== void 0 && /[A-Za-z]/.test(after)) return false;
5715
+ if (/^[0-9]/.test(content) && after !== void 0 && /^[A-Za-z]/.test(after)) return false;
5712
5716
  if (isMathPlaceholder(content)) return false;
5713
5717
  return TEX_SIGNAL.test(content) || !readsAsProse(content);
5714
5718
  }
5719
+ var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
5720
+ var MATH_SUFFIX = /^(?:s|es|th|st|nd|rd)$/i;
5721
+ function isVariableChain(content, after) {
5722
+ if (/^\{[A-Za-z_][\w.]*\}$/.test(content)) return true;
5723
+ if (!after) return false;
5724
+ if (after[0] === "{") return IDENTIFIER.test(content);
5725
+ const run = /^[A-Za-z0-9_]+/.exec(after)?.[0];
5726
+ if (!run) return false;
5727
+ if (after.length === 1) return false;
5728
+ if (/^[A-Za-z_][A-Za-z0-9_]*[.@-]$/.test(content)) return true;
5729
+ return IDENTIFIER.test(content) && !MATH_SUFFIX.test(run);
5730
+ }
5715
5731
  var FUNCTION_NAMES = /* @__PURE__ */ new Set([
5716
5732
  "sin",
5717
5733
  "cos",
@@ -5755,6 +5771,12 @@ function isMathShape(content) {
5755
5771
  if (/[A-Za-z]'+[A-Za-z]/.test(content) || /(?:^|[\s(,])[A-Za-z]\.(?:[A-Za-z]\.|\s|$)/.test(content)) return false;
5756
5772
  return /[A-Za-z]'*\(|[A-Za-z]'|\b[A-Za-z]\s+[A-Za-z]\b|\([^)]*[A-Za-z][^)]*\)/.test(content);
5757
5773
  }
5774
+ var AFTER_WINDOW = 32;
5775
+ function singleDollarAfter(text, close) {
5776
+ const rest = text.slice(close + 1, close + 1 + AFTER_WINDOW);
5777
+ return rest.length < AFTER_WINDOW ? `${rest}
5778
+ ` : rest;
5779
+ }
5758
5780
  function singleDollarMathEnd(text, open, limit = text.length) {
5759
5781
  const bound = Math.min(limit, open + 403);
5760
5782
  let close = -1;
@@ -5772,7 +5794,7 @@ function singleDollarMathEnd(text, open, limit = text.length) {
5772
5794
  }
5773
5795
  if (close === -1 || text[close + 1] === "$") return -1;
5774
5796
  const content = text.slice(open + 1, close);
5775
- return isSingleDollarMath(content, text[close + 1]) ? close + 1 : -1;
5797
+ return isSingleDollarMath(content, singleDollarAfter(text, close)) ? close + 1 : -1;
5776
5798
  }
5777
5799
  var BRACKET_TEX_SIGNAL = /\\[A-Za-z]+|[\^{}=<>+]|_\{|(?:^|[^A-Za-z0-9])[A-Za-z]_[A-Za-z0-9](?![A-Za-z0-9])/;
5778
5800
  function isEscapedBracketMath(content, before) {
@@ -6143,18 +6165,14 @@ var Tokenizer = class {
6143
6165
  /**
6144
6166
  * Streaming: an open last line that begins with `{` is undecided — each new
6145
6167
  * byte can balance or unbalance its braces and flip the whole line between
6146
- * prose and a JSON island — and so is a line that is exactly one allowed
6147
- * HTML tag so far; both are provisional until they end (G5).
6168
+ * prose and a JSON island — so it is provisional until it ends (G5).
6169
+ * (A lone HTML tag on that line is held by {@link holdUndecidedTail}.)
6148
6170
  */
6149
6171
  markOpenJsonTail() {
6150
6172
  const last = this.lineStarts.length - 1;
6151
6173
  if (!this.isOpenTail(last)) return;
6152
- const start = this.lineStarts[last];
6153
- const t = this.lineText(last).trim();
6154
- const oneTag = t.startsWith("<") ? readXmlTag(t, 0) : null;
6155
- const loneTag = !!oneTag && oneTag.raw === t && ALLOWED_RAW_HTML_TAGS.has(oneTag.tagName.toLowerCase());
6156
- if (t.startsWith("{") || loneTag) {
6157
- this.provisionalFrom = Math.min(this.provisionalFrom, start);
6174
+ if (this.lineText(last).trim().startsWith("{")) {
6175
+ this.provisionalFrom = Math.min(this.provisionalFrom, this.lineStarts[last]);
6158
6176
  }
6159
6177
  }
6160
6178
  /**
@@ -6187,11 +6205,22 @@ var Tokenizer = class {
6187
6205
  /** Streaming only: a paragraph ending at `pe` may still be continued by a line not yet arrived. */
6188
6206
  paragraphMayGrow(pe) {
6189
6207
  if (!this.streaming) return false;
6208
+ if (this.undecidedBreaks.has(pe)) return true;
6190
6209
  const rest = this.n - pe;
6191
6210
  if (rest === 0) return true;
6192
6211
  const tail = this.text.slice(pe);
6193
- return tail === "\n" || tail === "\r\n" || tail === "\r";
6212
+ return /^(?:\r\n|\r|\n)[ \t]*$/.test(tail);
6213
+ }
6214
+ /**
6215
+ * Streaming: an open block that may still turn back into prose — a `$$`
6216
+ * pair whose closer is on the open last line (prose after it makes it
6217
+ * inline), or a JSON head whose braces have not balanced (it may never parse).
6218
+ */
6219
+ mayDissolve(block) {
6220
+ return this.streaming && !block.complete && (block.type === "math_block" || block.type === "json");
6194
6221
  }
6222
+ /** Streaming: paragraph ends where an undecided, dissolvable block cut them short. */
6223
+ undecidedBreaks = /* @__PURE__ */ new Set();
6195
6224
  /** Streaming only: the final line, still waiting for its terminator. */
6196
6225
  isOpenTail(k) {
6197
6226
  return this.streaming && k === this.lineStarts.length - 1 && (this.lineEnds[k] === this.contentEnds[k] || this.pendingCR);
@@ -6240,8 +6269,103 @@ var Tokenizer = class {
6240
6269
  }
6241
6270
  pos = this.paragraph(pos, li);
6242
6271
  }
6272
+ if (this.streaming) this.holdUndecidedTail();
6243
6273
  return this.blocks;
6244
6274
  }
6275
+ /**
6276
+ * Streaming: settle nothing the next bytes can still change (verify-RC-B3 F3).
6277
+ *
6278
+ * 1. A block island that ends on the open last line is undecided — the next
6279
+ * bytes on that line can re-read it or dissolve it (`<!--@a:k1-->` +
6280
+ * ` more` is an inline anchor, `<br>` + `x` is prose). It runs open to
6281
+ * the end of the text.
6282
+ * 2. A box-drawing tree still forming at the end of the text claims, as its
6283
+ * root label, the lines directly above its first connector (the
6284
+ * renderer's `findTreeBlockStart`), and the open last line itself may
6285
+ * become one of its connector lines — so inlines on those lines are held
6286
+ * back as prose until a blank line, a heading or a tree line decides.
6287
+ * This also holds everything a closer still able to arrive on the open
6288
+ * last line could change (`$x$` + `5` is currency, G4; `{{v}}` + `}`).
6289
+ */
6290
+ holdUndecidedTail() {
6291
+ const last = this.lineStarts.length - 1;
6292
+ if (last < 0) return;
6293
+ if (this.isOpenTail(last)) {
6294
+ const lineStart = this.lineStarts[last];
6295
+ for (const block2 of this.blocks) {
6296
+ if (block2.kind === "prose" && block2.end > lineStart) {
6297
+ block2.inlines = block2.inlines.filter((inline) => inline.end <= lineStart);
6298
+ }
6299
+ }
6300
+ let b = this.blocks.length - 1;
6301
+ while (b >= 0 && this.blocks[b].kind === "gap") b--;
6302
+ const block = this.blocks[b];
6303
+ if (block?.island?.complete && block.island.end > this.lineStarts[last]) {
6304
+ block.island.complete = false;
6305
+ block.island.end = this.n;
6306
+ block.end = this.n;
6307
+ this.blocks.length = b + 1;
6308
+ }
6309
+ }
6310
+ const from = this.treeRootHoldFrom();
6311
+ for (let b = this.blocks.length - 1; b >= 0; b--) {
6312
+ const block = this.blocks[b];
6313
+ if (block.end <= from) break;
6314
+ if (block.kind === "prose") block.inlines = block.inlines.filter((inline) => inline.end <= from);
6315
+ if (block.island) this.blocks[b] = { kind: "prose", start: block.start, end: block.end, island: null, inlines: [] };
6316
+ }
6317
+ }
6318
+ /**
6319
+ * Streaming: where a tree that may still form at the end of the text would
6320
+ * start claiming lines (`n` when none can). Only paragraph lines can be
6321
+ * claimed — a line that starts inside an island (a fence body, an XML
6322
+ * region…) is never a tree line nor a root label, so it stops the walk.
6323
+ */
6324
+ treeRootHoldFrom() {
6325
+ const claimable = (k2) => {
6326
+ for (; ; ) {
6327
+ const block = this.blockAt(this.lineStarts[k2]);
6328
+ if (!block || block.kind !== "island" || block.island?.fromParagraph === true) return true;
6329
+ const opened = this.lineOf(block.start);
6330
+ if (this.lineStarts[opened] === block.start || opened === k2) return false;
6331
+ k2 = opened;
6332
+ }
6333
+ };
6334
+ let k = this.lineCount - 1;
6335
+ let start = this.lineCount;
6336
+ if (k >= 0 && this.isOpenTail(k)) {
6337
+ if (!claimable(k)) return this.n;
6338
+ start = k;
6339
+ k--;
6340
+ }
6341
+ for (; k >= 0 && claimable(k); k--) {
6342
+ this.tick(1);
6343
+ if (this.lineIsBlank(k)) continue;
6344
+ if (!TREE_GLYPHS.test(this.lineText(k))) break;
6345
+ start = k;
6346
+ }
6347
+ let root = start;
6348
+ for (let j = start - 1; j >= 0 && claimable(j); j--) {
6349
+ const trimmed = this.lineText(j).trim();
6350
+ this.tick(trimmed.length + 1);
6351
+ if (!trimmed || isSplitterTreeLine(trimmed) || /^#{1,6}\s/.test(trimmed)) break;
6352
+ root = j;
6353
+ }
6354
+ return root < this.lineCount ? this.lineStarts[root] : this.n;
6355
+ }
6356
+ /** The block (so far) containing offset `pos`, or null. */
6357
+ blockAt(pos) {
6358
+ let lo = 0;
6359
+ let hi = this.blocks.length - 1;
6360
+ while (lo <= hi) {
6361
+ const mid = lo + hi >>> 1;
6362
+ const block = this.blocks[mid];
6363
+ if (pos < block.start) hi = mid - 1;
6364
+ else if (pos >= block.end) lo = mid + 1;
6365
+ else return block;
6366
+ }
6367
+ return null;
6368
+ }
6245
6369
  push(block) {
6246
6370
  if (block.end <= block.start) return;
6247
6371
  if (block.kind === "prose" && this.isBlank(block.start, block.end)) {
@@ -6445,7 +6569,10 @@ var Tokenizer = class {
6445
6569
  continue;
6446
6570
  }
6447
6571
  if (this.isOpenTail(k)) return this.heldFootnote(p, open[1]);
6448
- if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
6572
+ if (FOOTNOTE_DEF.test(line.trimStart())) break;
6573
+ const block = this.detectBlock(this.lineStarts[k], k, false);
6574
+ if (block && this.mayDissolve(block)) return this.heldFootnote(p, open[1]);
6575
+ if (block) break;
6449
6576
  last = k;
6450
6577
  }
6451
6578
  const end = this.contentEnds[last];
@@ -6461,7 +6588,8 @@ var Tokenizer = class {
6461
6588
  return {
6462
6589
  count: this.lineCount,
6463
6590
  line: (k) => this.lineText(k),
6464
- openTail: (k) => this.isOpenTail(k)
6591
+ openTail: (k) => this.isOpenTail(k),
6592
+ streaming: this.streaming
6465
6593
  };
6466
6594
  }
6467
6595
  /**
@@ -6521,6 +6649,10 @@ var Tokenizer = class {
6521
6649
  if (fenceOpenerOf(this.lineText(j))?.char === "~") continue;
6522
6650
  const inner = this.detectBlockUncached(start, j, false);
6523
6651
  if (!inner) continue;
6652
+ if (this.streaming && inner.end >= tildeEnd && this.paragraphMayGrow(inner.end)) {
6653
+ this.overflowComplete = false;
6654
+ return this.n;
6655
+ }
6524
6656
  if (inner.end > end) {
6525
6657
  end = inner.end;
6526
6658
  this.overflowComplete = inner.complete;
@@ -6649,12 +6781,7 @@ var Tokenizer = class {
6649
6781
  return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
6650
6782
  }
6651
6783
  const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
6652
- const loneTag = atParaStart && t.trimEnd() === tag.raw;
6653
- if (loneTag && this.isOpenTail(li)) {
6654
- this.provisionalFrom = Math.min(this.provisionalFrom, p);
6655
- return null;
6656
- }
6657
- const typeSeven = loneTag;
6784
+ const typeSeven = atParaStart && t.trimEnd() === tag.raw;
6658
6785
  if (!typeSix && !typeSeven) return null;
6659
6786
  let end = this.contentEnds[li];
6660
6787
  for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
@@ -6712,6 +6839,13 @@ var Tokenizer = class {
6712
6839
  }
6713
6840
  return null;
6714
6841
  }
6842
+ if (this.isOpenTail(lastLine)) {
6843
+ if (isRecognizedJsonHead(this.text.slice(tp, tp + 512))) {
6844
+ return this.island("json", p, this.n, false, jsonMeta(this.text.slice(tp)));
6845
+ }
6846
+ this.provisionalFrom = Math.min(this.provisionalFrom, p);
6847
+ return null;
6848
+ }
6715
6849
  if (net !== 0) return null;
6716
6850
  const end = this.contentEnds[lastLine];
6717
6851
  const content = this.text.slice(tp, end).trim();
@@ -6746,8 +6880,10 @@ var Tokenizer = class {
6746
6880
  let breakLine = -1;
6747
6881
  for (let k = li + 1; k < this.lineCount; k++) {
6748
6882
  if (this.lineIsBlank(k)) break;
6749
- if (this.detectBlock(this.lineStarts[k], k, false)) {
6883
+ const block = this.detectBlock(this.lineStarts[k], k, false);
6884
+ if (block) {
6750
6885
  breakLine = k;
6886
+ if (this.mayDissolve(block)) this.undecidedBreaks.add(end);
6751
6887
  break;
6752
6888
  }
6753
6889
  end = this.contentEnds[k];
@@ -6785,7 +6921,7 @@ var Tokenizer = class {
6785
6921
  this.push({ kind: "prose", start: pos, end, island: null, inlines: scan2.inlines });
6786
6922
  return end;
6787
6923
  }
6788
- const br = scan2.breakIsland;
6924
+ const br = { ...scan2.breakIsland, fromParagraph: true };
6789
6925
  if (scan2.orphan) {
6790
6926
  let start = pos;
6791
6927
  while (this.blocks.length) {
@@ -6808,6 +6944,15 @@ var Tokenizer = class {
6808
6944
  this.push({ kind: "island", start: br.start, end: br.end, island: br, inlines: [] });
6809
6945
  return br.end;
6810
6946
  }
6947
+ /**
6948
+ * An island that opens inside a paragraph and closes past its end becomes a
6949
+ * block. Streaming: while the paragraph may still grow over its closer, the
6950
+ * island may yet be inline — undecided, so it runs open to the end (F3).
6951
+ */
6952
+ spill(type, start, end, pe, meta) {
6953
+ if (this.paragraphMayGrow(pe)) return this.island(type, start, this.n, false, meta);
6954
+ return this.island(type, start, end, true, meta);
6955
+ }
6811
6956
  scanInline(ps, pe) {
6812
6957
  const text = this.text;
6813
6958
  const inlines = [];
@@ -6842,6 +6987,9 @@ var Tokenizer = class {
6842
6987
  i = close + 2;
6843
6988
  continue;
6844
6989
  }
6990
+ if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
6991
+ return { inlines, breakIsland: null, orphan: false };
6992
+ }
6845
6993
  }
6846
6994
  i += 2;
6847
6995
  continue;
@@ -6862,17 +7010,13 @@ var Tokenizer = class {
6862
7010
  i += 2;
6863
7011
  continue;
6864
7012
  }
6865
- if (close + 2 > pe) return stop(this.island("math_block", i, close + 2, true, { delimiter: "$$" }));
7013
+ if (close + 2 > pe) return stop(this.spill("math_block", i, close + 2, pe, { delimiter: "$$" }));
6866
7014
  inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: "$$" }));
6867
7015
  i = close + 2;
6868
7016
  continue;
6869
7017
  }
6870
7018
  const end = singleDollarMathEnd(text, i, pe);
6871
7019
  this.tick(end > 0 ? end - i : Math.min(403, pe - i));
6872
- if (end > 0 && this.streaming && end === this.n) {
6873
- this.provisionalFrom = Math.min(this.provisionalFrom, i);
6874
- return { inlines, breakIsland: null, orphan: false };
6875
- }
6876
7020
  if (end > 0) {
6877
7021
  inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
6878
7022
  i = end;
@@ -6950,7 +7094,7 @@ var Tokenizer = class {
6950
7094
  const anchor = end - i <= 64 ? PINNED_ANCHOR_RE.exec(text.slice(i, end)) : null;
6951
7095
  const type = anchor ? "anchor" : "html_comment";
6952
7096
  const meta = anchor ? { id: anchor[1] } : {};
6953
- if (end > pe) return stop(this.island(type, i, end, true, meta));
7097
+ if (end > pe) return stop(this.spill(type, i, end, pe, meta));
6954
7098
  inlines.push(this.island(type, i, end, true, meta));
6955
7099
  i = end;
6956
7100
  continue;
@@ -6979,7 +7123,7 @@ var Tokenizer = class {
6979
7123
  const blockType = isAttr ? "xml_attr" : "xml_region";
6980
7124
  if (close === -1) return stop(this.island(blockType, i, this.n, false, { tag: name }));
6981
7125
  const end = close + closer.length;
6982
- if (end > pe) return stop(this.island(blockType, i, end, true, { tag: name }));
7126
+ if (end > pe) return stop(this.spill(blockType, i, end, pe, { tag: name }));
6983
7127
  inlines.push(this.island("xml_inline", i, end, true, { tag: name }));
6984
7128
  i = end;
6985
7129
  continue;
@@ -7365,6 +7509,7 @@ function mapRange(changes, start, end, unit = "utf16") {
7365
7509
  }
7366
7510
 
7367
7511
  exports.ACTION_BY_CLASS = ACTION_BY_CLASS;
7512
+ exports.AFTER_WINDOW = AFTER_WINDOW;
7368
7513
  exports.BacktickRuns = BacktickRuns;
7369
7514
  exports.CALLOUT_NAMES = CALLOUT_NAMES;
7370
7515
  exports.CAPABILITY_BY_CLASS = CAPABILITY_BY_CLASS;
@@ -7508,6 +7653,7 @@ exports.scalarArrayItemType = scalarArrayItemType;
7508
7653
  exports.schemaLayoutMode = schemaLayoutMode;
7509
7654
  exports.schemaStructureDepth = schemaStructureDepth;
7510
7655
  exports.setJsonRootKeyLookup = setJsonRootKeyLookup;
7656
+ exports.singleDollarAfter = singleDollarAfter;
7511
7657
  exports.singleDollarMathEnd = singleDollarMathEnd;
7512
7658
  exports.spliceSave = spliceSave;
7513
7659
  exports.splitsSurrogatePair = splitsSurrogatePair;