@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.0 — 2026-09-25
|
|
4
|
+
|
|
5
|
+
**`/source` — a deterministic attack suite, and streaming that only ever
|
|
6
|
+
grows** (verify-RC-B3 § Re-verification (0.15.0): G3, G4, G5). The verifier's
|
|
7
|
+
planted mutations M1–M6 plus M7 (the trailing-`$` streaming guard removed)
|
|
8
|
+
and M8 (the footnote open-tail rule removed) each turn
|
|
9
|
+
`__tests__/source-attack.test.ts` red ON ITS OWN; unmutated code is green.
|
|
10
|
+
|
|
11
|
+
- **G3 — work, not wall-clock.** `tokenizeSource(text, { meter })` (diagnostic)
|
|
12
|
+
counts every character the tokenizer's own loops visit; the attack suite adds
|
|
13
|
+
native string / regex work (indexOf / includes / lastIndexOf spans, trim,
|
|
14
|
+
split, replace, regex exec / test to where they stop) under a V8 cost model,
|
|
15
|
+
and asserts work at 4× input stays under 6× — deterministic on any host. One
|
|
16
|
+
generous wall-clock smoke bound remains (1 MB mixed in < 20 s). The meter
|
|
17
|
+
immediately caught two real quadratics, both fixed: the new pending-`$$`
|
|
18
|
+
scan (206 s at 1 MB of `$$\n`, now linear) — and it replaced a timing
|
|
19
|
+
check that flaked 3 of 12 runs under load.
|
|
20
|
+
- **G4** — a streamed `$x$` that the next byte turns into currency (`$x$5`)
|
|
21
|
+
never settles as math first; guarded by a message in the suite.
|
|
22
|
+
- **G5 — trailing islands only grow.** The suite asserts that a line-grown
|
|
23
|
+
island (tree, callout, footnote, HTML block, directive) keeps its start and
|
|
24
|
+
type and never shrinks, at every next prefix, over random documents. Fixed
|
|
25
|
+
classes it found: a footnote absorbing an unterminated line that becomes
|
|
26
|
+
the next note (`[^n]: short\n[`); a one-tag HTML line still arriving; a
|
|
27
|
+
trailing lone CR (the first half of CRLF) counted as content; text after an
|
|
28
|
+
unclosed backtick run while its paragraph can still grow; an open last line
|
|
29
|
+
starting with `{`; and anything after a `$$` that could still find its
|
|
30
|
+
partner (`pendingDisplayMathOpener` — the earliest pairable unpaired token).
|
|
31
|
+
In streaming mode all of these are provisional prose until decided.
|
|
32
|
+
- Distinct-document counting: the structure attack counts the distinct
|
|
33
|
+
documents it tokenized (mulberry32) and requires ≥ 95% of its rounds.
|
|
34
|
+
|
|
35
|
+
**Consumer action:** none for stored text. Streaming callers see fewer
|
|
36
|
+
islands near the tail until the text decides them.
|
|
37
|
+
|
|
38
|
+
## 0.15.1
|
|
39
|
+
|
|
40
|
+
- **Fixed (`/source` `pairDisplayMath`):** a stray `$$` in prose paired with
|
|
41
|
+
the next paragraph's formula when a LaTeX command sat between them. A `$$`
|
|
42
|
+
with text beside it never crosses a blank line (TeX's rule), checked on the
|
|
43
|
+
untrimmed span; a `$$` alone on its line still opens a flow block that may
|
|
44
|
+
span blank lines. `looksLikeDisplayMath(inner, flow?)` gains the `flow`
|
|
45
|
+
flag. Same rule as `@ai-matrx/kit` `delimiter-guard` (one math dialect).
|
|
46
|
+
- Consumer action: none — refresh to latest.
|
|
47
|
+
|
|
3
48
|
## 0.14.3
|
|
4
49
|
|
|
5
50
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
package/dist/index.cjs
CHANGED
|
@@ -5294,15 +5294,20 @@ var STRUCTURAL_MARKDOWN = /\]\(|https?:\/\/|\*\*|(?:^|\n)[ \t]{0,3}#{1,6}[ \t]|(
|
|
|
5294
5294
|
var LATEX_COMMAND = /\\[a-zA-Z]/;
|
|
5295
5295
|
var PROSE_WORD = /[A-Za-z]{3,}/g;
|
|
5296
5296
|
var PROSE_WORD_LIMIT = 6;
|
|
5297
|
-
function
|
|
5297
|
+
function opensFlowBlock(text, open) {
|
|
5298
|
+
for (let k = open - 1; k >= 0 && text[k] !== "\n"; k--) if (text[k] !== " " && text[k] !== " ") return false;
|
|
5299
|
+
for (let k = open + 2; k < text.length && text[k] !== "\n"; k++) if (text[k] !== " " && text[k] !== " " && text[k] !== "\r") return false;
|
|
5300
|
+
return true;
|
|
5301
|
+
}
|
|
5302
|
+
function looksLikeDisplayMath(inner, flow = false) {
|
|
5298
5303
|
const s = inner.trim();
|
|
5299
5304
|
if (!s) return false;
|
|
5300
5305
|
if (STRUCTURAL_MARKDOWN.test(s)) return false;
|
|
5301
5306
|
if (s.length > MAX_MATH_SPAN) return false;
|
|
5307
|
+
if (!flow && /\n[ \t]*\n/.test(inner)) return false;
|
|
5302
5308
|
if (LATEX_COMMAND.test(s)) {
|
|
5303
5309
|
return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT * 3;
|
|
5304
5310
|
}
|
|
5305
|
-
if (/\n[ \t]*\n/.test(s)) return false;
|
|
5306
5311
|
return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT;
|
|
5307
5312
|
}
|
|
5308
5313
|
function codeRanges(text) {
|
|
@@ -5316,6 +5321,50 @@ function codeRanges(text) {
|
|
|
5316
5321
|
}
|
|
5317
5322
|
return ranges.sort((a, b) => a[0] - b[0]);
|
|
5318
5323
|
}
|
|
5324
|
+
function pendingDisplayMathOpener(text) {
|
|
5325
|
+
if (!text.includes("$$")) return -1;
|
|
5326
|
+
const ranges = codeRanges(text);
|
|
5327
|
+
const tokens = [];
|
|
5328
|
+
let r = 0;
|
|
5329
|
+
let maxEnd = -1;
|
|
5330
|
+
for (let i = text.indexOf("$$"); i !== -1 && i < text.length - 1; i = text.indexOf("$$", i)) {
|
|
5331
|
+
while (r < ranges.length && ranges[r][0] <= i) {
|
|
5332
|
+
maxEnd = Math.max(maxEnd, ranges[r][1]);
|
|
5333
|
+
r++;
|
|
5334
|
+
}
|
|
5335
|
+
if (maxEnd <= i) tokens.push(i);
|
|
5336
|
+
i += 2;
|
|
5337
|
+
}
|
|
5338
|
+
const paired = /* @__PURE__ */ new Set();
|
|
5339
|
+
let j = 0;
|
|
5340
|
+
while (j < tokens.length) {
|
|
5341
|
+
const open = tokens[j];
|
|
5342
|
+
const close = tokens[j + 1];
|
|
5343
|
+
if (close === void 0) break;
|
|
5344
|
+
if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
|
|
5345
|
+
paired.add(open);
|
|
5346
|
+
paired.add(close);
|
|
5347
|
+
j += 2;
|
|
5348
|
+
continue;
|
|
5349
|
+
}
|
|
5350
|
+
j += 1;
|
|
5351
|
+
}
|
|
5352
|
+
let trail = 0;
|
|
5353
|
+
while (trail < text.length && /\s/.test(text[text.length - 1 - trail])) trail++;
|
|
5354
|
+
for (const token of tokens) {
|
|
5355
|
+
if (paired.has(token)) continue;
|
|
5356
|
+
let lead = 0;
|
|
5357
|
+
while (lead <= MAX_MATH_SPAN && /\s/.test(text[token + 2 + lead] ?? "x")) lead++;
|
|
5358
|
+
if (text.length - (token + 2) - lead - trail > MAX_MATH_SPAN) continue;
|
|
5359
|
+
const inner = text.slice(token + 2);
|
|
5360
|
+
const s = inner.trim();
|
|
5361
|
+
if (STRUCTURAL_MARKDOWN.test(s) || s.length > MAX_MATH_SPAN) continue;
|
|
5362
|
+
if (!opensFlowBlock(text, token) && /\n[ \t]*\n/.test(inner)) continue;
|
|
5363
|
+
if ((s.match(PROSE_WORD) ?? []).length >= PROSE_WORD_LIMIT * 3) continue;
|
|
5364
|
+
return token;
|
|
5365
|
+
}
|
|
5366
|
+
return -1;
|
|
5367
|
+
}
|
|
5319
5368
|
function pairDisplayMath(text) {
|
|
5320
5369
|
const pairs = /* @__PURE__ */ new Map();
|
|
5321
5370
|
if (!text.includes("$$")) return pairs;
|
|
@@ -5336,7 +5385,7 @@ function pairDisplayMath(text) {
|
|
|
5336
5385
|
const open = tokens[j];
|
|
5337
5386
|
const close = tokens[j + 1];
|
|
5338
5387
|
if (close === void 0) break;
|
|
5339
|
-
if (looksLikeDisplayMath(text.slice(open + 2, close))) {
|
|
5388
|
+
if (looksLikeDisplayMath(text.slice(open + 2, close), opensFlowBlock(text, open))) {
|
|
5340
5389
|
pairs.set(open, close);
|
|
5341
5390
|
j += 2;
|
|
5342
5391
|
continue;
|
|
@@ -5664,11 +5713,15 @@ function isSplitterTreeLine(line) {
|
|
|
5664
5713
|
}
|
|
5665
5714
|
var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
|
|
5666
5715
|
var Tokenizer = class {
|
|
5667
|
-
constructor(text, streaming = false) {
|
|
5716
|
+
constructor(text, streaming = false, meter = void 0) {
|
|
5668
5717
|
this.text = text;
|
|
5669
5718
|
this.streaming = streaming;
|
|
5719
|
+
this.meter = meter;
|
|
5670
5720
|
this.n = text.length;
|
|
5721
|
+
this.tick(text.length);
|
|
5671
5722
|
this.mathPairs = pairDisplayMath(text);
|
|
5723
|
+
this.provisionalFrom = streaming ? pendingDisplayMathOpener(text) : -1;
|
|
5724
|
+
if (this.provisionalFrom === -1) this.provisionalFrom = Number.POSITIVE_INFINITY;
|
|
5672
5725
|
let start = 0;
|
|
5673
5726
|
for (let i = 0; i < text.length; i++) {
|
|
5674
5727
|
if (text.charCodeAt(i) === 10) {
|
|
@@ -5679,13 +5732,15 @@ var Tokenizer = class {
|
|
|
5679
5732
|
}
|
|
5680
5733
|
}
|
|
5681
5734
|
if (start < text.length || text.length === 0) {
|
|
5735
|
+
this.pendingCR = streaming && text.length > start && text.charCodeAt(text.length - 1) === 13;
|
|
5682
5736
|
this.lineStarts.push(start);
|
|
5683
|
-
this.contentEnds.push(text.length);
|
|
5737
|
+
this.contentEnds.push(this.pendingCR ? text.length - 1 : text.length);
|
|
5684
5738
|
this.lineEnds.push(text.length);
|
|
5685
5739
|
}
|
|
5686
5740
|
}
|
|
5687
5741
|
text;
|
|
5688
5742
|
streaming;
|
|
5743
|
+
meter;
|
|
5689
5744
|
n;
|
|
5690
5745
|
lineStarts = [];
|
|
5691
5746
|
contentEnds = [];
|
|
@@ -5700,6 +5755,23 @@ var Tokenizer = class {
|
|
|
5700
5755
|
/** `$$` opener → closer for the pairs the core renders as math. */
|
|
5701
5756
|
mathPairs;
|
|
5702
5757
|
finder = (needle, from) => this.next(needle, from);
|
|
5758
|
+
/** Streaming: where provisional text starts (a pending `$$`), or +∞. */
|
|
5759
|
+
provisionalFrom = Number.POSITIVE_INFINITY;
|
|
5760
|
+
/** Streaming: the text ends in a lone CR whose LF has not arrived yet. */
|
|
5761
|
+
pendingCR = false;
|
|
5762
|
+
/**
|
|
5763
|
+
* Streaming: an open last line that begins with `{` is undecided — each new
|
|
5764
|
+
* byte can balance or unbalance its braces and flip the whole line between
|
|
5765
|
+
* prose and a JSON island — so it is provisional until it ends (G5).
|
|
5766
|
+
*/
|
|
5767
|
+
markOpenJsonTail() {
|
|
5768
|
+
const last = this.lineStarts.length - 1;
|
|
5769
|
+
if (!this.isOpenTail(last)) return;
|
|
5770
|
+
const start = this.lineStarts[last];
|
|
5771
|
+
if (this.lineText(last).trimStart().startsWith("{")) {
|
|
5772
|
+
this.provisionalFrom = Math.min(this.provisionalFrom, start);
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5703
5775
|
/**
|
|
5704
5776
|
* `text.indexOf(needle, from)` in O(log k): the first query for a needle
|
|
5705
5777
|
* indexes all of its occurrences once, so repeated searches for a closer
|
|
@@ -5723,9 +5795,21 @@ var Tokenizer = class {
|
|
|
5723
5795
|
}
|
|
5724
5796
|
return lo < list.length ? list[lo] : -1;
|
|
5725
5797
|
}
|
|
5798
|
+
/** Charge `n` visited characters to the diagnostic meter (complexity tests). */
|
|
5799
|
+
tick(n) {
|
|
5800
|
+
if (this.meter) this.meter.work += n;
|
|
5801
|
+
}
|
|
5802
|
+
/** Streaming only: a paragraph ending at `pe` may still be continued by a line not yet arrived. */
|
|
5803
|
+
paragraphMayGrow(pe) {
|
|
5804
|
+
if (!this.streaming) return false;
|
|
5805
|
+
const rest = this.n - pe;
|
|
5806
|
+
if (rest === 0) return true;
|
|
5807
|
+
const tail = this.text.slice(pe);
|
|
5808
|
+
return tail === "\n" || tail === "\r\n" || tail === "\r";
|
|
5809
|
+
}
|
|
5726
5810
|
/** Streaming only: the final line, still waiting for its terminator. */
|
|
5727
5811
|
isOpenTail(k) {
|
|
5728
|
-
return this.streaming && k === this.lineStarts.length - 1 && this.lineEnds[k] === this.contentEnds[k];
|
|
5812
|
+
return this.streaming && k === this.lineStarts.length - 1 && (this.lineEnds[k] === this.contentEnds[k] || this.pendingCR);
|
|
5729
5813
|
}
|
|
5730
5814
|
get lineCount() {
|
|
5731
5815
|
return this.lineStarts.length;
|
|
@@ -5750,6 +5834,7 @@ var Tokenizer = class {
|
|
|
5750
5834
|
return this.text.slice(this.lineStarts[li], this.contentEnds[li]);
|
|
5751
5835
|
}
|
|
5752
5836
|
run() {
|
|
5837
|
+
if (this.streaming) this.markOpenJsonTail();
|
|
5753
5838
|
let pos = 0;
|
|
5754
5839
|
while (pos < this.n) {
|
|
5755
5840
|
const li = this.lineOf(pos);
|
|
@@ -5758,6 +5843,10 @@ var Tokenizer = class {
|
|
|
5758
5843
|
pos = this.gap(pos, li);
|
|
5759
5844
|
continue;
|
|
5760
5845
|
}
|
|
5846
|
+
if (pos >= this.provisionalFrom) {
|
|
5847
|
+
this.push({ kind: "prose", start: pos, end: this.n, island: null, inlines: [] });
|
|
5848
|
+
break;
|
|
5849
|
+
}
|
|
5761
5850
|
const island = this.detectBlock(pos, li, true);
|
|
5762
5851
|
if (island) {
|
|
5763
5852
|
this.push({ kind: "island", start: island.start, end: island.end, island, inlines: [] });
|
|
@@ -5961,6 +6050,7 @@ var Tokenizer = class {
|
|
|
5961
6050
|
continue;
|
|
5962
6051
|
}
|
|
5963
6052
|
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
6053
|
+
if (this.isOpenTail(k)) break;
|
|
5964
6054
|
last = k;
|
|
5965
6055
|
}
|
|
5966
6056
|
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
@@ -6122,6 +6212,7 @@ var Tokenizer = class {
|
|
|
6122
6212
|
const li = this.lineOf(tp);
|
|
6123
6213
|
const ce = this.contentEnds[li];
|
|
6124
6214
|
const tag = readXmlTag(this.text, tp, this.finder);
|
|
6215
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
6125
6216
|
let openEnd;
|
|
6126
6217
|
if (tag && !tag.isClosing) {
|
|
6127
6218
|
if (tag.isSelfClosing) {
|
|
@@ -6206,7 +6297,7 @@ var Tokenizer = class {
|
|
|
6206
6297
|
return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
|
|
6207
6298
|
}
|
|
6208
6299
|
const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
6209
|
-
const typeSeven = atParaStart && t.trimEnd() === tag.raw;
|
|
6300
|
+
const typeSeven = atParaStart && t.trimEnd() === tag.raw && !this.isOpenTail(li);
|
|
6210
6301
|
if (!typeSix && !typeSeven) return null;
|
|
6211
6302
|
let end = this.contentEnds[li];
|
|
6212
6303
|
for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
|
|
@@ -6298,6 +6389,10 @@ var Tokenizer = class {
|
|
|
6298
6389
|
let breakLine = -1;
|
|
6299
6390
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
6300
6391
|
if (this.lineIsBlank(k)) break;
|
|
6392
|
+
if (this.lineStarts[k] >= this.provisionalFrom) {
|
|
6393
|
+
end = this.n;
|
|
6394
|
+
break;
|
|
6395
|
+
}
|
|
6301
6396
|
if (this.detectBlock(this.lineStarts[k], k, false)) {
|
|
6302
6397
|
breakLine = k;
|
|
6303
6398
|
break;
|
|
@@ -6363,6 +6458,7 @@ var Tokenizer = class {
|
|
|
6363
6458
|
scanInline(ps, pe) {
|
|
6364
6459
|
const text = this.text;
|
|
6365
6460
|
const inlines = [];
|
|
6461
|
+
this.tick(pe - ps);
|
|
6366
6462
|
const hasKind = text.slice(ps, pe).includes("__kind");
|
|
6367
6463
|
let kindBudget = 4 * (pe - ps) + 65536;
|
|
6368
6464
|
const stop = (island, orphan = false) => ({ inlines, breakIsland: island, orphan });
|
|
@@ -6373,6 +6469,7 @@ var Tokenizer = class {
|
|
|
6373
6469
|
let runs = null;
|
|
6374
6470
|
const codeSpanClose = (n, from) => {
|
|
6375
6471
|
if (!runs) {
|
|
6472
|
+
this.tick(pe - ps);
|
|
6376
6473
|
runs = /* @__PURE__ */ new Map();
|
|
6377
6474
|
for (let k = ps; k < pe; ) {
|
|
6378
6475
|
if (text.charCodeAt(k) !== 96) {
|
|
@@ -6399,7 +6496,8 @@ var Tokenizer = class {
|
|
|
6399
6496
|
return at !== void 0 && at + n <= pe ? at : -1;
|
|
6400
6497
|
};
|
|
6401
6498
|
let i = ps;
|
|
6402
|
-
|
|
6499
|
+
const scanEnd = Math.min(pe, this.provisionalFrom);
|
|
6500
|
+
while (i < scanEnd) {
|
|
6403
6501
|
const ch = text[i];
|
|
6404
6502
|
if (ch === "\\") {
|
|
6405
6503
|
const nextCh = text[i + 1];
|
|
@@ -6417,6 +6515,9 @@ var Tokenizer = class {
|
|
|
6417
6515
|
if (ch === "`") {
|
|
6418
6516
|
const n = backtickRunLength(text, i);
|
|
6419
6517
|
const close = codeSpanClose(n, i + n);
|
|
6518
|
+
if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
|
|
6519
|
+
return { inlines, breakIsland: null, orphan: false };
|
|
6520
|
+
}
|
|
6420
6521
|
i = close === -1 ? i + n : close + n;
|
|
6421
6522
|
continue;
|
|
6422
6523
|
}
|
|
@@ -6433,6 +6534,7 @@ var Tokenizer = class {
|
|
|
6433
6534
|
continue;
|
|
6434
6535
|
}
|
|
6435
6536
|
const end = singleDollarMathEnd(text, i, pe);
|
|
6537
|
+
this.tick(end > 0 ? end - i : Math.min(403, pe - i));
|
|
6436
6538
|
if (end > 0 && !(this.streaming && end === this.n)) {
|
|
6437
6539
|
inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
|
|
6438
6540
|
i = end;
|
|
@@ -6460,6 +6562,7 @@ var Tokenizer = class {
|
|
|
6460
6562
|
const limit = Math.min(pe, i + 65536);
|
|
6461
6563
|
const end = matchingJsonObjectEnd(text, i, limit);
|
|
6462
6564
|
kindBudget -= (end ?? limit) - i;
|
|
6565
|
+
this.tick((end ?? limit) - i);
|
|
6463
6566
|
if (end !== null) {
|
|
6464
6567
|
const kind = declaredKind(text.slice(i, end));
|
|
6465
6568
|
if (kind) {
|
|
@@ -6521,6 +6624,7 @@ var Tokenizer = class {
|
|
|
6521
6624
|
continue;
|
|
6522
6625
|
}
|
|
6523
6626
|
const tag = readXmlTag(text, i, this.finder);
|
|
6627
|
+
this.tick(tag ? tag.raw.length : 1);
|
|
6524
6628
|
if (tag && i + tag.raw.length <= pe) {
|
|
6525
6629
|
const name = tag.tagName;
|
|
6526
6630
|
const tagEnd = i + tag.raw.length;
|
|
@@ -6569,7 +6673,7 @@ var Tokenizer = class {
|
|
|
6569
6673
|
}
|
|
6570
6674
|
};
|
|
6571
6675
|
function tokenizeSource(text, options = {}) {
|
|
6572
|
-
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
6676
|
+
const raw = new Tokenizer(text, options.streaming ?? false, options.meter).run();
|
|
6573
6677
|
const cp = buildCodePointIndex(text);
|
|
6574
6678
|
const inline = (island) => ({
|
|
6575
6679
|
islandType: island.type,
|
|
@@ -7032,6 +7136,7 @@ exports.openParseSession = openParseSession;
|
|
|
7032
7136
|
exports.pairDisplayMath = pairDisplayMath;
|
|
7033
7137
|
exports.parseDirectiveSlug = parseDirectiveSlug;
|
|
7034
7138
|
exports.parseFenceOpener = parseFenceOpener;
|
|
7139
|
+
exports.pendingDisplayMathOpener = pendingDisplayMathOpener;
|
|
7035
7140
|
exports.readEnvelope = readEnvelope;
|
|
7036
7141
|
exports.readNodeOutcomeValue = readNodeOutcomeValue;
|
|
7037
7142
|
exports.readObjectKind = readObjectKind;
|