@stream-mdx/worker 0.0.3 → 0.1.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @stream-mdx/worker
2
2
 
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 294e557: Release StreamMDX 0.1.0 across all published packages.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [294e557]
12
+ - @stream-mdx/core@0.1.0
13
+ - @stream-mdx/plugins@0.1.0
14
+
3
15
  ## 0.0.3
4
16
 
5
17
  ### Patch Changes
@@ -30993,6 +30993,12 @@ var {
30993
30993
  createHighlighter
30994
30994
  );
30995
30995
 
30996
+ // ../../node_modules/rehype-parse/index.js
30997
+ var rehype_parse_exports = {};
30998
+ __export(rehype_parse_exports, {
30999
+ default: () => rehypeParse
31000
+ });
31001
+
30996
31002
  // ../../node_modules/devlop/lib/default.js
30997
31003
  function ok() {
30998
31004
  }
@@ -41377,6 +41383,12 @@ function rehypeSanitize(options) {
41377
41383
  };
41378
41384
  }
41379
41385
 
41386
+ // ../../node_modules/rehype-stringify/index.js
41387
+ var rehype_stringify_exports = {};
41388
+ __export(rehype_stringify_exports, {
41389
+ default: () => rehypeStringify
41390
+ });
41391
+
41380
41392
  // ../../node_modules/rehype-stringify/lib/index.js
41381
41393
  function rehypeStringify(options) {
41382
41394
  const self2 = this;
@@ -43371,6 +43383,36 @@ function filterAllowedAttributes(attrs) {
43371
43383
  }
43372
43384
  return filtered;
43373
43385
  }
43386
+ function ensureGlobal(pattern) {
43387
+ if (pattern.global) return pattern;
43388
+ const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
43389
+ return new RegExp(pattern.source, flags);
43390
+ }
43391
+ function findLastMatch(pattern, value) {
43392
+ const re2 = ensureGlobal(pattern);
43393
+ let match = null;
43394
+ let next2;
43395
+ while ((next2 = re2.exec(value)) !== null) {
43396
+ match = next2;
43397
+ }
43398
+ return match;
43399
+ }
43400
+ function findMatchAfter(pattern, value, startIndex) {
43401
+ const re2 = ensureGlobal(pattern);
43402
+ re2.lastIndex = Math.max(0, startIndex);
43403
+ return re2.exec(value);
43404
+ }
43405
+ function isSamePattern(a, b) {
43406
+ return a.source === b.source && a.flags === b.flags;
43407
+ }
43408
+ function countMatches(pattern, value) {
43409
+ const re2 = ensureGlobal(pattern);
43410
+ let count = 0;
43411
+ while (re2.exec(value)) {
43412
+ count += 1;
43413
+ }
43414
+ return count;
43415
+ }
43374
43416
  var InlineParser = class {
43375
43417
  constructor(options = {}) {
43376
43418
  this.plugins = [];
@@ -43418,6 +43460,42 @@ var InlineParser = class {
43418
43460
  }
43419
43461
  return result;
43420
43462
  }
43463
+ /**
43464
+ * Streaming regex anticipation helper. Returns an append string if a plugin
43465
+ * declares an incomplete match at the end of the buffer.
43466
+ */
43467
+ getRegexAnticipationAppend(content4) {
43468
+ if (!content4 || this.plugins.length === 0) {
43469
+ return null;
43470
+ }
43471
+ for (const plugin of this.plugins) {
43472
+ if (!("re" in plugin)) continue;
43473
+ const regexPlugin = plugin;
43474
+ const anticipation = regexPlugin.anticipation;
43475
+ if (!anticipation) continue;
43476
+ const maxScanChars = Number.isFinite(anticipation.maxScanChars ?? Number.NaN) ? Math.max(1, anticipation.maxScanChars ?? 0) : 240;
43477
+ const scan = content4.slice(Math.max(0, content4.length - maxScanChars));
43478
+ if (regexPlugin.fastCheck && !regexPlugin.fastCheck(scan)) {
43479
+ continue;
43480
+ }
43481
+ const lastStart = findLastMatch(anticipation.start, scan);
43482
+ if (!lastStart) continue;
43483
+ if (isSamePattern(anticipation.start, anticipation.end)) {
43484
+ const occurrences = countMatches(anticipation.start, scan);
43485
+ if (occurrences % 2 === 0) {
43486
+ continue;
43487
+ }
43488
+ } else {
43489
+ const startIndex = lastStart.index + lastStart[0].length;
43490
+ const hasEnd = Boolean(findMatchAfter(anticipation.end, scan, startIndex));
43491
+ if (hasEnd) continue;
43492
+ }
43493
+ const appendValue = typeof anticipation.append === "function" ? anticipation.append(lastStart, content4) : anticipation.append;
43494
+ if (!appendValue) continue;
43495
+ return appendValue;
43496
+ }
43497
+ return null;
43498
+ }
43421
43499
  /**
43422
43500
  * Clear the memoization cache
43423
43501
  */
@@ -43546,9 +43624,16 @@ var InlineParser = class {
43546
43624
  this.registerPlugin({
43547
43625
  id: "citations",
43548
43626
  priority: 10,
43549
- re: /\[\^([^\]]+)\]|@cite\{([^}]+)\}/g,
43550
- toNode: (match) => ({ kind: "citation", id: match[1] || match[2] }),
43551
- fastCheck: (text12) => text12.indexOf("@") !== -1 || text12.indexOf("[^") !== -1
43627
+ re: /\[\^([^\]\n]+)\]|@cite\{([^}\n]+)\}|\{cite:([^}\n]+)\}/g,
43628
+ toNode: (match) => ({ kind: "citation", id: match[1] || match[2] || match[3] }),
43629
+ fastCheck: (text12) => text12.indexOf("@cite") !== -1 || text12.indexOf("[^") !== -1 || text12.indexOf("{cite:") !== -1,
43630
+ anticipation: {
43631
+ start: /@cite\{|\{cite:/g,
43632
+ end: /\}/g,
43633
+ full: /@cite\{[^}\n]+?\}|\{cite:[^}\n]+?\}/g,
43634
+ append: "}",
43635
+ maxScanChars: 120
43636
+ }
43552
43637
  });
43553
43638
  this.registerPlugin({
43554
43639
  id: "mentions",
@@ -43612,9 +43697,23 @@ function splitTextByRegexWithPrecedence(text12, regex3, toNode3) {
43612
43697
  }
43613
43698
  return result;
43614
43699
  }
43615
- var { defaultSchema: defaultSchema2 } = rehype_sanitize_exports;
43700
+ var rehypeSanitizeModule = rehype_sanitize_exports;
43701
+ var defaultSchema2 = rehypeSanitizeModule.defaultSchema;
43702
+ var resolvePlugin = (mod) => {
43703
+ if (typeof mod === "function") return mod;
43704
+ if (mod && typeof mod.default === "function") {
43705
+ return mod.default;
43706
+ }
43707
+ if (mod && typeof mod.default?.default === "function") {
43708
+ return mod.default?.default;
43709
+ }
43710
+ return mod;
43711
+ };
43712
+ var rehypeParsePlugin = resolvePlugin(rehype_parse_exports);
43713
+ var rehypeSanitizePlugin = resolvePlugin(rehypeSanitizeModule);
43714
+ var rehypeStringifyPlugin = resolvePlugin(rehype_stringify_exports);
43616
43715
  var SANITIZED_SCHEMA = createSchema();
43617
- var sanitizeProcessor = unified().use(rehypeParse, { fragment: true }).use(rehypeSanitize, SANITIZED_SCHEMA).use(rehypeStringify).freeze();
43716
+ var sanitizeProcessor = unified().use(rehypeParsePlugin, { fragment: true }).use(rehypeSanitizePlugin, SANITIZED_SCHEMA).use(rehypeStringifyPlugin).freeze();
43618
43717
  function sanitizeHtmlInWorker(html9) {
43619
43718
  if (!html9) return "";
43620
43719
  try {
@@ -43728,9 +43827,27 @@ function mergeAttributes(existing, additions) {
43728
43827
  }
43729
43828
  return next2;
43730
43829
  }
43731
- function extractMixedContentSegments(raw2, baseOffset, parseInline) {
43830
+ var DEFAULT_INLINE_HTML_AUTOCLOSE_TAGS = /* @__PURE__ */ new Set([
43831
+ "span",
43832
+ "em",
43833
+ "strong",
43834
+ "code",
43835
+ "kbd",
43836
+ "del",
43837
+ "s",
43838
+ "mark",
43839
+ "sub",
43840
+ "sup",
43841
+ "i",
43842
+ "b",
43843
+ "u",
43844
+ "small",
43845
+ "abbr",
43846
+ "a"
43847
+ ]);
43848
+ function extractMixedContentSegments(raw2, baseOffset, parseInline, options) {
43732
43849
  if (!raw2) return [];
43733
- const initial = splitByTagSegments(raw2, baseOffset, parseInline);
43850
+ const initial = splitByTagSegments(raw2, baseOffset, parseInline, options);
43734
43851
  const expanded = [];
43735
43852
  for (const segment of initial) {
43736
43853
  if (segment.kind === "text") {
@@ -43741,22 +43858,58 @@ function extractMixedContentSegments(raw2, baseOffset, parseInline) {
43741
43858
  }
43742
43859
  return mergeAdjacentTextSegments(expanded, parseInline);
43743
43860
  }
43744
- function splitByTagSegments(source, baseOffset, parseInline) {
43861
+ function splitByTagSegments(source, baseOffset, parseInline, options) {
43745
43862
  const segments = [];
43746
43863
  const lowerSource = source.toLowerCase();
43747
43864
  const tagPattern = /<([A-Za-z][\w:-]*)([^<>]*?)\/?>/g;
43748
43865
  let cursor = 0;
43749
43866
  let match = tagPattern.exec(source);
43750
43867
  const baseIsFinite = typeof baseOffset === "number" && Number.isFinite(baseOffset);
43868
+ const htmlAllowTags = normalizeHtmlAllowlist(options?.html?.allowTags);
43869
+ const htmlAutoClose = options?.html?.autoClose === true;
43870
+ const htmlMaxNewlines = normalizeNewlineLimit(options?.html?.maxNewlines);
43871
+ const mdxAutoClose = options?.mdx?.autoClose === true;
43872
+ const mdxMaxNewlines = normalizeNewlineLimit(options?.mdx?.maxNewlines);
43873
+ const mdxAllowlist = normalizeComponentAllowlist(options?.mdx?.componentAllowlist);
43751
43874
  while (match !== null) {
43752
43875
  const start2 = match.index;
43753
43876
  const tagName = match[1];
43754
43877
  const matchText = match[0];
43755
- const isSelfClosing = matchText.endsWith("/>") || isVoidHtmlTag(tagName);
43878
+ const tagNameLower = tagName.toLowerCase();
43879
+ const isSelfClosing = matchText.endsWith("/>") || isVoidHtmlTag(tagNameLower);
43880
+ const mdxCandidate = isLikelyMdxComponent(tagName);
43881
+ const mdxAllowed = mdxCandidate && (!mdxAllowlist || mdxAllowlist.has(tagName));
43882
+ if (mdxCandidate && mdxAllowlist && !mdxAllowed) {
43883
+ tagPattern.lastIndex = start2 + 1;
43884
+ match = tagPattern.exec(source);
43885
+ continue;
43886
+ }
43756
43887
  let end = tagPattern.lastIndex;
43757
- if (!isSelfClosing && !isLikelyMdxComponent(tagName)) {
43888
+ if (!isSelfClosing && !mdxAllowed) {
43758
43889
  const closingIndex = findClosingHtmlTag(lowerSource, tagName.toLowerCase(), end);
43759
43890
  if (closingIndex === -1) {
43891
+ if (htmlAutoClose && htmlAllowTags.has(tagNameLower)) {
43892
+ const tail = source.slice(end);
43893
+ const newlineCount = countNewlines(tail, htmlMaxNewlines + 1);
43894
+ if (newlineCount <= htmlMaxNewlines) {
43895
+ if (start2 > cursor) {
43896
+ const absoluteFrom = baseIsFinite ? baseOffset + cursor : void 0;
43897
+ const absoluteTo = baseIsFinite ? baseOffset + start2 : void 0;
43898
+ pushTextSegment(segments, source.slice(cursor, start2), absoluteFrom, absoluteTo, parseInline);
43899
+ }
43900
+ const rawSegment2 = source.slice(start2);
43901
+ const closedValue = `${rawSegment2}</${tagName}>`;
43902
+ const segment2 = {
43903
+ kind: "html",
43904
+ value: closedValue,
43905
+ range: createSegmentRange(baseOffset, start2, source.length),
43906
+ sanitized: sanitizeHtmlInWorker(closedValue)
43907
+ };
43908
+ segments.push(segment2);
43909
+ cursor = source.length;
43910
+ break;
43911
+ }
43912
+ }
43760
43913
  tagPattern.lastIndex = start2 + 1;
43761
43914
  match = tagPattern.exec(source);
43762
43915
  continue;
@@ -43768,8 +43921,8 @@ function splitByTagSegments(source, baseOffset, parseInline) {
43768
43921
  const absoluteTo = baseIsFinite ? baseOffset + start2 : void 0;
43769
43922
  pushTextSegment(segments, source.slice(cursor, start2), absoluteFrom, absoluteTo, parseInline);
43770
43923
  }
43771
- const rawSegment = source.slice(start2, end);
43772
- const kind = isLikelyMdxComponent(tagName) ? "mdx" : "html";
43924
+ let rawSegment = source.slice(start2, end);
43925
+ const kind = mdxAllowed ? "mdx" : "html";
43773
43926
  const segment = {
43774
43927
  kind,
43775
43928
  value: rawSegment,
@@ -43778,6 +43931,17 @@ function splitByTagSegments(source, baseOffset, parseInline) {
43778
43931
  if (kind === "html") {
43779
43932
  segment.sanitized = sanitizeHtmlInWorker(rawSegment);
43780
43933
  } else {
43934
+ const tail = source.slice(end);
43935
+ const newlineCount = countNewlines(tail, mdxMaxNewlines + 1);
43936
+ if (mdxAutoClose && newlineCount > mdxMaxNewlines) {
43937
+ tagPattern.lastIndex = start2 + 1;
43938
+ match = tagPattern.exec(source);
43939
+ continue;
43940
+ }
43941
+ if (mdxAutoClose && !rawSegment.endsWith("/>")) {
43942
+ rawSegment = selfCloseTag(rawSegment);
43943
+ segment.value = rawSegment;
43944
+ }
43781
43945
  segment.status = "pending";
43782
43946
  }
43783
43947
  segments.push(segment);
@@ -43902,6 +44066,48 @@ var VOID_HTML_TAGS = /* @__PURE__ */ new Set(["br", "hr", "img", "meta", "input"
43902
44066
  function isVoidHtmlTag(tagName) {
43903
44067
  return VOID_HTML_TAGS.has(tagName.toLowerCase());
43904
44068
  }
44069
+ function normalizeNewlineLimit(value) {
44070
+ if (!Number.isFinite(value ?? Number.NaN)) {
44071
+ return 2;
44072
+ }
44073
+ return Math.max(0, value ?? 0);
44074
+ }
44075
+ function normalizeHtmlAllowlist(value) {
44076
+ if (!value) return DEFAULT_INLINE_HTML_AUTOCLOSE_TAGS;
44077
+ const tags2 = /* @__PURE__ */ new Set();
44078
+ for (const tag of value) {
44079
+ if (tag) {
44080
+ tags2.add(tag.toLowerCase());
44081
+ }
44082
+ }
44083
+ return tags2.size > 0 ? tags2 : DEFAULT_INLINE_HTML_AUTOCLOSE_TAGS;
44084
+ }
44085
+ function normalizeComponentAllowlist(value) {
44086
+ if (!value) return null;
44087
+ const tags2 = /* @__PURE__ */ new Set();
44088
+ for (const tag of value) {
44089
+ if (tag) tags2.add(tag);
44090
+ }
44091
+ return tags2.size > 0 ? tags2 : null;
44092
+ }
44093
+ function countNewlines(value, limit) {
44094
+ let count = 0;
44095
+ for (let i = 0; i < value.length; i++) {
44096
+ if (value.charCodeAt(i) === 10) {
44097
+ count += 1;
44098
+ if (limit !== void 0 && count >= limit) {
44099
+ return count;
44100
+ }
44101
+ }
44102
+ }
44103
+ return count;
44104
+ }
44105
+ function selfCloseTag(rawTag) {
44106
+ if (rawTag.endsWith("/>")) return rawTag;
44107
+ const closeIndex = rawTag.lastIndexOf(">");
44108
+ if (closeIndex === -1) return rawTag;
44109
+ return `${rawTag.slice(0, closeIndex)}/>`;
44110
+ }
43905
44111
  function isLikelyMdxComponent(tagName) {
43906
44112
  const first = tagName.charAt(0);
43907
44113
  return first.toUpperCase() === first && first.toLowerCase() !== first;
@@ -44686,63 +44892,126 @@ function computeHeavyPatchBudget(credit, config = DEFAULT_BACKPRESSURE_CONFIG) {
44686
44892
  return Math.min(config.maxHeavyPatchBudget, budget);
44687
44893
  }
44688
44894
  var USE_LINEAR_COALESCING = typeof process === "undefined" ? true : process.env.V2_USE_LINEAR_COALESCING !== "false" && true;
44895
+ var DEFAULT_FORMAT_ANTICIPATION = {
44896
+ inline: false,
44897
+ mathInline: false,
44898
+ mathBlock: false,
44899
+ html: false,
44900
+ mdx: false,
44901
+ regex: false
44902
+ };
44903
+ function normalizeFormatAnticipation(input) {
44904
+ if (input === true) {
44905
+ return { ...DEFAULT_FORMAT_ANTICIPATION, inline: true };
44906
+ }
44907
+ if (!input) {
44908
+ return { ...DEFAULT_FORMAT_ANTICIPATION };
44909
+ }
44910
+ return {
44911
+ inline: input.inline ?? false,
44912
+ mathInline: input.mathInline ?? false,
44913
+ mathBlock: input.mathBlock ?? false,
44914
+ html: input.html ?? false,
44915
+ mdx: input.mdx ?? false,
44916
+ regex: input.regex ?? false
44917
+ };
44918
+ }
44689
44919
  function prepareInlineStreamingContent(content4, options) {
44690
- const enableAnticipation = Boolean(options?.formatAnticipation);
44691
44920
  const enableMath2 = options?.math !== false;
44692
- let dollarCount = 0;
44693
- let backtickCount = 0;
44694
- let starCount = 0;
44695
- let doubleStarCount = 0;
44696
- let tildePairCount = 0;
44921
+ const anticipation = normalizeFormatAnticipation(options?.formatAnticipation);
44922
+ const enableInlineAnticipation = anticipation.inline;
44923
+ const enableMathInlineAnticipation = anticipation.mathInline;
44924
+ const enableMathBlockAnticipation = anticipation.mathBlock;
44925
+ const stack = [];
44926
+ const toggleToken = (token2) => {
44927
+ const last = stack[stack.length - 1];
44928
+ if (last === token2) {
44929
+ stack.pop();
44930
+ } else {
44931
+ stack.push(token2);
44932
+ }
44933
+ };
44934
+ let mathDisplayOpen = false;
44935
+ let mathDisplayCrossedNewline = false;
44697
44936
  for (let i = 0; i < content4.length; i++) {
44698
44937
  const code4 = content4.charCodeAt(i);
44699
- if (code4 === 36) {
44700
- dollarCount += 1;
44938
+ if (code4 === 10 || code4 === 13) {
44939
+ if (mathDisplayOpen) {
44940
+ mathDisplayCrossedNewline = true;
44941
+ }
44701
44942
  continue;
44702
44943
  }
44703
44944
  if (code4 === 96) {
44704
- backtickCount += 1;
44945
+ toggleToken("code");
44946
+ continue;
44947
+ }
44948
+ if (code4 === 126 && i + 1 < content4.length && content4.charCodeAt(i + 1) === 126) {
44949
+ toggleToken("strike");
44950
+ i += 1;
44705
44951
  continue;
44706
44952
  }
44707
44953
  if (code4 === 42) {
44708
44954
  if (i + 1 < content4.length && content4.charCodeAt(i + 1) === 42) {
44709
- doubleStarCount += 1;
44710
- starCount += 2;
44955
+ toggleToken("strong");
44711
44956
  i += 1;
44712
44957
  } else {
44713
- starCount += 1;
44958
+ toggleToken("em");
44714
44959
  }
44715
44960
  continue;
44716
44961
  }
44717
- if (code4 === 126) {
44718
- if (i + 1 < content4.length && content4.charCodeAt(i + 1) === 126) {
44719
- tildePairCount += 1;
44962
+ if (enableMath2 && code4 === 36) {
44963
+ if (i + 1 < content4.length && content4.charCodeAt(i + 1) === 36) {
44964
+ toggleToken("math-display");
44965
+ if (mathDisplayOpen) {
44966
+ mathDisplayOpen = false;
44967
+ mathDisplayCrossedNewline = false;
44968
+ } else {
44969
+ mathDisplayOpen = true;
44970
+ mathDisplayCrossedNewline = false;
44971
+ }
44720
44972
  i += 1;
44973
+ } else {
44974
+ toggleToken("math-inline");
44721
44975
  }
44722
44976
  }
44723
44977
  }
44724
- const hasIncompleteMath = enableMath2 && dollarCount % 2 !== 0;
44725
- if (hasIncompleteMath) {
44726
- return { kind: "raw", status: "raw", reason: "incomplete-math" };
44727
- }
44728
- const hasIncompleteCode = backtickCount % 2 !== 0;
44729
- const hasIncompleteStrong = doubleStarCount % 2 !== 0;
44730
- const singleStarCount = starCount - doubleStarCount * 2;
44731
- const hasIncompleteEmphasis = singleStarCount % 2 !== 0;
44732
- const hasIncompleteStrike = tildePairCount % 2 !== 0;
44733
- const hasAnyIncomplete = hasIncompleteCode || hasIncompleteStrong || hasIncompleteEmphasis || hasIncompleteStrike;
44734
- if (!hasAnyIncomplete) {
44735
- return { kind: "parse", status: "complete", content: content4, appended: "" };
44978
+ const hasIncompleteFormatting = stack.some((token2) => token2 === "code" || token2 === "strike" || token2 === "strong" || token2 === "em");
44979
+ const hasIncompleteMathInline = stack.includes("math-inline");
44980
+ const hasIncompleteMathDisplay = stack.includes("math-display");
44981
+ const hasIncompleteMath = hasIncompleteMathInline || hasIncompleteMathDisplay;
44982
+ if (enableMath2 && hasIncompleteMath) {
44983
+ if (hasIncompleteMathInline && !enableMathInlineAnticipation) {
44984
+ return { kind: "raw", status: "raw", reason: "incomplete-math" };
44985
+ }
44986
+ if (hasIncompleteMathDisplay && (!enableMathBlockAnticipation || mathDisplayCrossedNewline)) {
44987
+ return { kind: "raw", status: "raw", reason: "incomplete-math" };
44988
+ }
44736
44989
  }
44737
- if (!enableAnticipation) {
44990
+ if (hasIncompleteFormatting && !enableInlineAnticipation) {
44738
44991
  return { kind: "raw", status: "raw", reason: "incomplete-formatting" };
44739
44992
  }
44740
- let appended = "";
44741
- if (hasIncompleteCode) appended += "`";
44742
- if (hasIncompleteStrike) appended += "~~";
44743
- if (hasIncompleteStrong && hasIncompleteEmphasis) appended += "***";
44744
- else if (hasIncompleteStrong) appended += "**";
44745
- else if (hasIncompleteEmphasis) appended += "*";
44993
+ if (!hasIncompleteFormatting && !hasIncompleteMath) {
44994
+ return { kind: "parse", status: "complete", content: content4, appended: "" };
44995
+ }
44996
+ const appendForToken = (token2) => {
44997
+ switch (token2) {
44998
+ case "code":
44999
+ return "`";
45000
+ case "strike":
45001
+ return "~~";
45002
+ case "strong":
45003
+ return "**";
45004
+ case "em":
45005
+ return "*";
45006
+ case "math-inline":
45007
+ return "$";
45008
+ case "math-display":
45009
+ return "$$";
45010
+ default:
45011
+ return "";
45012
+ }
45013
+ };
45014
+ const appended = stack.slice().reverse().map((token2) => appendForToken(token2)).join("");
44746
45015
  return { kind: "parse", status: "anticipated", content: content4 + appended, appended };
44747
45016
  }
44748
45017
 
@@ -81705,14 +81974,16 @@ var MAX_DEFERRED_FLUSH_PATCHES = 120;
81705
81974
  var CODE_HIGHLIGHT_CACHE = /* @__PURE__ */ new Map();
81706
81975
  var MAX_CODE_HIGHLIGHT_CACHE_ENTRIES = 200;
81707
81976
  var mdxCompileMode = "server";
81708
- var enableFormatAnticipation = false;
81977
+ var formatAnticipationConfig = normalizeFormatAnticipation(false);
81709
81978
  var enableLiveCodeHighlighting = false;
81710
81979
  var enableMath = true;
81980
+ var mdxComponentAllowlist = null;
81711
81981
  var WORKER_MDX_CACHE = /* @__PURE__ */ new Map();
81712
81982
  var WORKER_MDX_INFLIGHT = /* @__PURE__ */ new Map();
81713
81983
  var MAX_WORKER_MDX_CACHE_ENTRIES = 128;
81714
81984
  var loggedMdxSkipCount = 0;
81715
81985
  var MAX_MDX_SKIP_LOGS = 20;
81986
+ var MIXED_CONTENT_AUTOCLOSE_NEWLINES = 2;
81716
81987
  function isDebugEnabled(flag) {
81717
81988
  try {
81718
81989
  if (typeof process !== "undefined" && process.env) {
@@ -81731,6 +82002,8 @@ function isDebugEnabled(flag) {
81731
82002
  }
81732
82003
  var DEBUG_MDX = isDebugEnabled("mdx");
81733
82004
  var sharedTextEncoder = typeof TextEncoder !== "undefined" ? new TextEncoder() : null;
82005
+ var shouldTrackInlineStatus = () => formatAnticipationConfig.inline || formatAnticipationConfig.mathInline || formatAnticipationConfig.mathBlock;
82006
+ var shouldAllowMixedStreaming = () => formatAnticipationConfig.html || formatAnticipationConfig.mdx;
81734
82007
  function now() {
81735
82008
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
81736
82009
  }
@@ -81998,13 +82271,23 @@ function mapToHighlightRecord(map3) {
81998
82271
  return result;
81999
82272
  }
82000
82273
  function parseInlineStreaming(content4) {
82001
- const prepared = prepareInlineStreamingContent(content4, { formatAnticipation: enableFormatAnticipation, math: enableMath });
82274
+ const prepared = prepareInlineStreamingContent(content4, { formatAnticipation: formatAnticipationConfig, math: enableMath });
82002
82275
  if (prepared.kind === "raw") {
82003
82276
  return { inline: [{ kind: "text", text: content4 }], status: prepared.status };
82004
82277
  }
82278
+ let preparedContent = prepared.content;
82279
+ let appended = prepared.appended;
82280
+ if (formatAnticipationConfig.regex) {
82281
+ const regexAppend = inlineParser.getRegexAnticipationAppend(content4);
82282
+ if (regexAppend) {
82283
+ preparedContent += regexAppend;
82284
+ appended += regexAppend;
82285
+ }
82286
+ }
82287
+ const status = appended.length > 0 ? "anticipated" : prepared.status;
82005
82288
  return {
82006
- inline: inlineParser.parse(prepared.content, { cache: false }),
82007
- status: prepared.status
82289
+ inline: inlineParser.parse(preparedContent, { cache: false }),
82290
+ status
82008
82291
  };
82009
82292
  }
82010
82293
  async function initialize(initialContent = "", prewarmLangs = [], docPlugins, mdxOptions) {
@@ -82032,8 +82315,13 @@ async function initialize(initialContent = "", prewarmLangs = [], docPlugins, md
82032
82315
  liveCodeHighlighting: docPlugins?.liveCodeHighlighting ?? false
82033
82316
  };
82034
82317
  enableMath = enable.math;
82035
- enableFormatAnticipation = enable.formatAnticipation;
82318
+ formatAnticipationConfig = normalizeFormatAnticipation(enable.formatAnticipation);
82036
82319
  enableLiveCodeHighlighting = enable.liveCodeHighlighting;
82320
+ if (Array.isArray(docPlugins?.mdxComponentNames) && docPlugins?.mdxComponentNames.length > 0) {
82321
+ mdxComponentAllowlist = new Set(docPlugins.mdxComponentNames);
82322
+ } else {
82323
+ mdxComponentAllowlist = null;
82324
+ }
82037
82325
  inlineParser = new InlineParser({ enableMath });
82038
82326
  documentPluginState.inlineParser = inlineParser;
82039
82327
  if (enable.footnotes) registerFootnotesPlugin();
@@ -82221,13 +82509,13 @@ async function enrichBlock(block) {
82221
82509
  if (block.isFinalized) {
82222
82510
  block.payload.raw = normalizedHeading;
82223
82511
  block.payload.inline = inlineParser.parse(normalizedHeading);
82224
- if (enableFormatAnticipation && block.payload.meta) {
82512
+ if (shouldTrackInlineStatus() && block.payload.meta) {
82225
82513
  block.payload.meta.inlineStatus = void 0;
82226
82514
  }
82227
82515
  } else {
82228
82516
  const parsed = parseInlineStreaming(normalizedHeading);
82229
82517
  block.payload.inline = parsed.inline;
82230
- if (enableFormatAnticipation && block.payload.meta) {
82518
+ if (shouldTrackInlineStatus() && block.payload.meta) {
82231
82519
  block.payload.meta.inlineStatus = parsed.status;
82232
82520
  }
82233
82521
  }
@@ -82238,7 +82526,11 @@ async function enrichBlock(block) {
82238
82526
  block.payload.raw = normalized;
82239
82527
  const streamingParsed = !block.isFinalized ? parseInlineStreaming(normalized) : null;
82240
82528
  const inlineParse = block.isFinalized ? (value) => inlineParser.parse(value) : (value) => parseInlineStreaming(value).inline;
82241
- const segments = extractMixedContentSegments(normalized, void 0, inlineParse);
82529
+ const mixedOptions = !block.isFinalized && shouldAllowMixedStreaming() ? {
82530
+ html: formatAnticipationConfig.html ? { autoClose: true, maxNewlines: MIXED_CONTENT_AUTOCLOSE_NEWLINES } : void 0,
82531
+ mdx: formatAnticipationConfig.mdx ? { autoClose: true, maxNewlines: MIXED_CONTENT_AUTOCLOSE_NEWLINES, componentAllowlist: mdxComponentAllowlist ?? void 0 } : void 0
82532
+ } : void 0;
82533
+ const segments = extractMixedContentSegments(normalized, void 0, inlineParse, mixedOptions);
82242
82534
  const currentMeta = block.payload.meta ?? {};
82243
82535
  const nextMeta = {
82244
82536
  ...currentMeta,
@@ -82249,7 +82541,7 @@ async function enrichBlock(block) {
82249
82541
  } else {
82250
82542
  nextMeta.mixedSegments = void 0;
82251
82543
  }
82252
- if (enableFormatAnticipation) {
82544
+ if (shouldTrackInlineStatus()) {
82253
82545
  nextMeta.inlineStatus = block.isFinalized ? void 0 : streamingParsed?.status;
82254
82546
  }
82255
82547
  if (Object.keys(nextMeta).length > 0) {
@@ -82272,7 +82564,8 @@ async function enrichBlock(block) {
82272
82564
  const currentMeta = block.payload.meta ?? {};
82273
82565
  const nextMeta = { ...currentMeta };
82274
82566
  let metaChanged = false;
82275
- if (enableFormatAnticipation) {
82567
+ const allowMixedStreaming = shouldAllowMixedStreaming();
82568
+ if (shouldTrackInlineStatus()) {
82276
82569
  const desired = block.isFinalized ? void 0 : streamingParsed?.status;
82277
82570
  if (desired !== void 0) {
82278
82571
  if (!Object.prototype.hasOwnProperty.call(nextMeta, "inlineStatus") || nextMeta.inlineStatus !== desired) {
@@ -82298,17 +82591,36 @@ async function enrichBlock(block) {
82298
82591
  const shouldExtractSegments = typeof rawParagraph === "string" && (rawParagraph.includes("<") || rawParagraph.includes("{"));
82299
82592
  if (shouldExtractSegments) {
82300
82593
  const baseOffset = typeof block.payload.range?.from === "number" ? block.payload.range.from : void 0;
82301
- const segments = extractMixedContentSegments(rawParagraph, baseOffset, (value) => inlineParse(value));
82594
+ const mixedOptions = !block.isFinalized && shouldAllowMixedStreaming() ? {
82595
+ html: formatAnticipationConfig.html ? { autoClose: true, maxNewlines: MIXED_CONTENT_AUTOCLOSE_NEWLINES } : void 0,
82596
+ mdx: formatAnticipationConfig.mdx ? { autoClose: true, maxNewlines: MIXED_CONTENT_AUTOCLOSE_NEWLINES, componentAllowlist: mdxComponentAllowlist ?? void 0 } : void 0
82597
+ } : void 0;
82598
+ const segments = extractMixedContentSegments(rawParagraph, baseOffset, (value) => inlineParse(value), mixedOptions);
82302
82599
  if (segments.length > 0) {
82303
82600
  nextMeta.mixedSegments = segments;
82304
82601
  metaChanged = true;
82602
+ if (allowMixedStreaming) {
82603
+ nextMeta.allowMixedStreaming = true;
82604
+ metaChanged = true;
82605
+ } else if (Object.prototype.hasOwnProperty.call(nextMeta, "allowMixedStreaming")) {
82606
+ nextMeta.allowMixedStreaming = void 0;
82607
+ metaChanged = true;
82608
+ }
82305
82609
  } else if (Object.prototype.hasOwnProperty.call(nextMeta, "mixedSegments")) {
82306
82610
  nextMeta.mixedSegments = void 0;
82307
82611
  metaChanged = true;
82612
+ if (Object.prototype.hasOwnProperty.call(nextMeta, "allowMixedStreaming")) {
82613
+ nextMeta.allowMixedStreaming = void 0;
82614
+ metaChanged = true;
82615
+ }
82308
82616
  }
82309
82617
  } else if (Object.prototype.hasOwnProperty.call(nextMeta, "mixedSegments")) {
82310
82618
  nextMeta.mixedSegments = void 0;
82311
82619
  metaChanged = true;
82620
+ if (Object.prototype.hasOwnProperty.call(nextMeta, "allowMixedStreaming")) {
82621
+ nextMeta.allowMixedStreaming = void 0;
82622
+ metaChanged = true;
82623
+ }
82312
82624
  }
82313
82625
  if (metaChanged) {
82314
82626
  if (Object.keys(nextMeta).length > 0) {
@@ -83414,6 +83726,19 @@ async function finalizeAllBlocks() {
83414
83726
  dispatchPatchBatch(finalizeSetProps, metricsCollector);
83415
83727
  }
83416
83728
  }
83729
+ if (deferredPatchQueue.length > 0) {
83730
+ const previousCredits = workerCredits;
83731
+ workerCredits = 1;
83732
+ const maxIterations = Math.ceil(deferredPatchQueue.length / MAX_DEFERRED_FLUSH_PATCHES) + 8;
83733
+ for (let i = 0; i < maxIterations && deferredPatchQueue.length > 0; i++) {
83734
+ const before = deferredPatchQueue.length;
83735
+ flushDeferredPatches();
83736
+ if (deferredPatchQueue.length >= before) {
83737
+ break;
83738
+ }
83739
+ }
83740
+ workerCredits = previousCredits;
83741
+ }
83417
83742
  if (getActiveMetricsCollector() === metricsCollector) {
83418
83743
  setActiveMetricsCollector(null);
83419
83744
  }
@@ -1,4 +1,4 @@
1
- import { WorkerOut } from '@stream-mdx/core';
1
+ import { WorkerOut, FormatAnticipationConfig } from '@stream-mdx/core';
2
2
 
3
3
  type DefaultWorkerMode = "auto" | "hosted" | "blob";
4
4
  interface CreateDefaultWorkerOptions {
@@ -54,8 +54,9 @@ declare class MarkdownWorkerClient {
54
54
  tables?: boolean;
55
55
  callouts?: boolean;
56
56
  math?: boolean;
57
- formatAnticipation?: boolean;
57
+ formatAnticipation?: FormatAnticipationConfig;
58
58
  liveCodeHighlighting?: boolean;
59
+ mdxComponentNames?: string[];
59
60
  }, mdxOptions?: {
60
61
  compileMode?: "server" | "worker";
61
62
  }): void;
@@ -1,4 +1,4 @@
1
- import { WorkerOut } from '@stream-mdx/core';
1
+ import { WorkerOut, FormatAnticipationConfig } from '@stream-mdx/core';
2
2
 
3
3
  type DefaultWorkerMode = "auto" | "hosted" | "blob";
4
4
  interface CreateDefaultWorkerOptions {
@@ -54,8 +54,9 @@ declare class MarkdownWorkerClient {
54
54
  tables?: boolean;
55
55
  callouts?: boolean;
56
56
  math?: boolean;
57
- formatAnticipation?: boolean;
57
+ formatAnticipation?: FormatAnticipationConfig;
58
58
  liveCodeHighlighting?: boolean;
59
+ mdxComponentNames?: string[];
59
60
  }, mdxOptions?: {
60
61
  compileMode?: "server" | "worker";
61
62
  }): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-mdx/worker",
3
- "version": "0.0.3",
3
+ "version": "0.1.0",
4
4
  "description": "Worker client utilities and shared worker helpers for the Streaming Markdown V2 pipeline",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -55,7 +55,7 @@
55
55
  "scripts": {
56
56
  "build": "tsup",
57
57
  "build:hosted": "tsup --config tsup.hosted-worker.config.ts",
58
- "test": "tsx __tests__/*.test.ts",
58
+ "test": "tsx ../../scripts/run-tests.ts __tests__",
59
59
  "clean": "rm -rf dist",
60
60
  "prepack": "npm run build && npm run build:hosted"
61
61
  },
@@ -63,8 +63,8 @@
63
63
  "@lezer/common": "^1.2.3",
64
64
  "@lezer/lr": "^1.4.2",
65
65
  "@lezer/markdown": "^1.3.0",
66
- "@stream-mdx/core": "0.0.3",
67
- "@stream-mdx/plugins": "0.0.3",
66
+ "@stream-mdx/core": "0.1.0",
67
+ "@stream-mdx/plugins": "0.1.0",
68
68
  "@mdx-js/mdx": "^3.1.0",
69
69
  "@shikijs/engine-javascript": "^1.29.2",
70
70
  "@shikijs/engine-oniguruma": "^1.29.2",