@stream-mdx/worker 0.2.0 → 0.3.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.
@@ -82165,6 +82165,9 @@ var mdxCompileMode = "server";
82165
82165
  var formatAnticipationConfig = normalizeFormatAnticipation(false);
82166
82166
  var codeHighlightingMode = "final";
82167
82167
  var highlightOutputMode = "html";
82168
+ var emitHighlightTokens = true;
82169
+ var emitDiffBlocks = false;
82170
+ var liveTokenizationEnabled = true;
82168
82171
  var enableMath = true;
82169
82172
  var mdxComponentAllowlist = null;
82170
82173
  var WORKER_MDX_CACHE = /* @__PURE__ */ new Map();
@@ -82604,7 +82607,10 @@ async function initialize(initialContent = "", prewarmLangs = [], docPlugins, md
82604
82607
  math: docPlugins?.math ?? true,
82605
82608
  formatAnticipation: docPlugins?.formatAnticipation ?? false,
82606
82609
  codeHighlighting: docPlugins?.codeHighlighting,
82607
- liveCodeHighlighting: docPlugins?.liveCodeHighlighting ?? false
82610
+ liveCodeHighlighting: docPlugins?.liveCodeHighlighting ?? false,
82611
+ liveTokenization: docPlugins?.liveTokenization ?? true,
82612
+ emitHighlightTokens: docPlugins?.emitHighlightTokens ?? true,
82613
+ emitDiffBlocks: docPlugins?.emitDiffBlocks ?? false
82608
82614
  };
82609
82615
  enableMath = enable.math;
82610
82616
  formatAnticipationConfig = normalizeFormatAnticipation(enable.formatAnticipation);
@@ -82618,6 +82624,9 @@ async function initialize(initialContent = "", prewarmLangs = [], docPlugins, md
82618
82624
  } else {
82619
82625
  highlightOutputMode = "html";
82620
82626
  }
82627
+ emitHighlightTokens = enable.emitHighlightTokens;
82628
+ emitDiffBlocks = enable.emitDiffBlocks;
82629
+ liveTokenizationEnabled = enable.liveTokenization;
82621
82630
  if (docPlugins?.lazyTokenization) {
82622
82631
  lazyTokenizationEnabled = docPlugins.lazyTokenization.enabled ?? true;
82623
82632
  const desiredThreshold = docPlugins.lazyTokenization.thresholdLines ?? DEFAULT_LAZY_TOKENIZATION_THRESHOLD;
@@ -83302,6 +83311,154 @@ function parseUnifiedDiffLine(line, cursor) {
83302
83311
  }
83303
83312
  return { text: line, kind: "meta", prefix: "", content: line, oldNo: null, newNo: null };
83304
83313
  }
83314
+ function normalizeDiffPath(value) {
83315
+ if (!value) return null;
83316
+ let path3 = value.trim();
83317
+ if (!path3 || path3 === "/dev/null") return null;
83318
+ if (path3.startsWith('"') && path3.endsWith('"') || path3.startsWith("'") && path3.endsWith("'")) {
83319
+ path3 = path3.slice(1, -1);
83320
+ }
83321
+ if (path3.startsWith("a/") || path3.startsWith("b/")) {
83322
+ path3 = path3.slice(2);
83323
+ }
83324
+ return path3 || null;
83325
+ }
83326
+ function extractDiffFilePath(line) {
83327
+ if (line.startsWith("diff --git")) {
83328
+ const match = line.match(/^diff --git\\s+(\\S+)\\s+(\\S+)/);
83329
+ if (match) {
83330
+ return normalizeDiffPath(match[2] ?? match[1] ?? null);
83331
+ }
83332
+ }
83333
+ if (line.startsWith("+++ ") || line.startsWith("--- ")) {
83334
+ const path3 = normalizeDiffPath(line.slice(4));
83335
+ return path3;
83336
+ }
83337
+ if (line.startsWith("rename to ")) {
83338
+ return normalizeDiffPath(line.slice("rename to ".length));
83339
+ }
83340
+ return null;
83341
+ }
83342
+ function looksLikeUnifiedDiff(lines) {
83343
+ if (lines.length === 0) return false;
83344
+ for (const line of lines) {
83345
+ if (line.startsWith("diff --git") || line.startsWith("@@") || line.startsWith("+++ ") || line.startsWith("--- ")) {
83346
+ return true;
83347
+ }
83348
+ }
83349
+ return false;
83350
+ }
83351
+ function guessLanguageFromPath(filePath) {
83352
+ if (!filePath) return null;
83353
+ const parts = filePath.split(/[\\\\/]/);
83354
+ const file = parts[parts.length - 1] ?? "";
83355
+ const idx = file.lastIndexOf(".");
83356
+ if (idx <= 0 || idx >= file.length - 1) return null;
83357
+ const ext = file.slice(idx + 1);
83358
+ return normalizeLang(ext);
83359
+ }
83360
+ function guessLanguageFromDiffLines(lines) {
83361
+ for (const line of lines) {
83362
+ const filePath = extractDiffFilePath(line);
83363
+ if (filePath) {
83364
+ const guessed = guessLanguageFromPath(filePath);
83365
+ if (guessed) return guessed;
83366
+ }
83367
+ }
83368
+ return null;
83369
+ }
83370
+ function toDiffLineKind(kind) {
83371
+ if (kind === "remove") return "del";
83372
+ return kind;
83373
+ }
83374
+ function toThemedLine(tokenLine, theme) {
83375
+ if (!tokenLine) return null;
83376
+ return tokenLine.spans.map((span) => {
83377
+ const style2 = span.s ?? span.v?.[theme];
83378
+ const color3 = typeof style2?.fg === "string" ? style2.fg : null;
83379
+ const fontStyle = typeof style2?.fs === "number" ? style2.fs : null;
83380
+ return {
83381
+ content: span.t,
83382
+ color: color3,
83383
+ fontStyle
83384
+ };
83385
+ });
83386
+ }
83387
+ function stripPrefixFromThemedLine(tokens, prefix) {
83388
+ if (!tokens || !prefix) return tokens;
83389
+ if (tokens.length === 0) return tokens;
83390
+ const first = tokens[0];
83391
+ if (first.content === prefix) {
83392
+ return tokens.slice(1);
83393
+ }
83394
+ if (first.content.startsWith(prefix)) {
83395
+ const trimmed = first.content.slice(prefix.length);
83396
+ const next2 = trimmed ? [{ ...first, content: trimmed }, ...tokens.slice(1)] : tokens.slice(1);
83397
+ return next2;
83398
+ }
83399
+ return tokens;
83400
+ }
83401
+ function buildDiffBlocksFromLines(lines, rawLines, tokenLines, defaultLanguage) {
83402
+ const blocks2 = [];
83403
+ let current2 = null;
83404
+ let currentRaw = [];
83405
+ let additions = 0;
83406
+ let deletions = 0;
83407
+ const finalize = () => {
83408
+ if (!current2) return;
83409
+ current2.additions = additions;
83410
+ current2.deletions = deletions;
83411
+ if (currentRaw.length > 0) {
83412
+ current2.unified = currentRaw.join("\n");
83413
+ }
83414
+ blocks2.push(current2);
83415
+ current2 = null;
83416
+ currentRaw = [];
83417
+ additions = 0;
83418
+ deletions = 0;
83419
+ };
83420
+ for (let i = 0; i < lines.length; i++) {
83421
+ const line = lines[i];
83422
+ const raw2 = rawLines[i] ?? line.text;
83423
+ const filePath = extractDiffFilePath(raw2);
83424
+ if (raw2.startsWith("diff --git")) {
83425
+ finalize();
83426
+ }
83427
+ if (!current2) {
83428
+ current2 = {
83429
+ kind: "diff",
83430
+ filePath: filePath ?? null,
83431
+ language: filePath ? guessLanguageFromPath(filePath) ?? defaultLanguage : defaultLanguage,
83432
+ lines: [],
83433
+ additions: null,
83434
+ deletions: null,
83435
+ unified: null
83436
+ };
83437
+ } else if (filePath && !current2.filePath) {
83438
+ current2.filePath = filePath;
83439
+ if (!current2.language) {
83440
+ current2.language = guessLanguageFromPath(filePath) ?? defaultLanguage;
83441
+ }
83442
+ }
83443
+ if (line.kind === "add") additions += 1;
83444
+ if (line.kind === "remove") deletions += 1;
83445
+ let themed = tokenLines ? toThemedLine(tokenLines[i] ?? null, "dark") : null;
83446
+ if (line.kind === "add" || line.kind === "remove" || line.kind === "context") {
83447
+ themed = stripPrefixFromThemedLine(themed, line.prefix);
83448
+ }
83449
+ const entry = {
83450
+ kind: toDiffLineKind(line.kind),
83451
+ oldNo: line.oldNo ?? null,
83452
+ newNo: line.newNo ?? null,
83453
+ raw: raw2,
83454
+ tokens: themed ?? null
83455
+ };
83456
+ current2.lines.push(entry);
83457
+ currentRaw.push(raw2);
83458
+ }
83459
+ finalize();
83460
+ return blocks2;
83461
+ }
83305
83462
  function tokenizeDiffRun(lines, language, grammarState) {
83306
83463
  if (!highlighter) {
83307
83464
  return { tokens: [], nextGrammarState: grammarState };
@@ -83559,17 +83716,24 @@ async function handleLazyTokenizationRequest(request) {
83559
83716
  const raw2 = block.payload.raw ?? "";
83560
83717
  const { code: code4, info, hadFence } = stripCodeFence(raw2);
83561
83718
  const { lang: lang236, meta: meta2 } = parseCodeFenceInfo(info);
83562
- const diffInfo = detectDiffLanguage(lang236, meta2);
83563
- const requestedLanguage = diffInfo.isDiff ? diffInfo.diffLang : lang236 || "text";
83564
- const tokenLanguage = diffInfo.isDiff ? diffInfo.baseLang ?? "text" : requestedLanguage;
83565
83719
  const codeBody = hadFence ? code4 : dedentIndentedCode(raw2);
83566
83720
  const codeLines = extractCodeLines(raw2);
83721
+ let diffInfo = detectDiffLanguage(lang236, meta2);
83722
+ if (!diffInfo.isDiff && emitDiffBlocks && looksLikeUnifiedDiff(codeLines)) {
83723
+ diffInfo = {
83724
+ isDiff: true,
83725
+ diffLang: "diff",
83726
+ baseLang: guessLanguageFromDiffLines(codeLines)
83727
+ };
83728
+ }
83729
+ const requestedLanguage = diffInfo.isDiff ? diffInfo.diffLang : lang236 || "text";
83730
+ const tokenLanguage = diffInfo.isDiff ? diffInfo.baseLang ?? "text" : requestedLanguage;
83567
83731
  const hasHighlightableContent = codeBody.trim().length > 0;
83568
83732
  if (!shouldLazyTokenizeBlock(codeLines.length, Boolean(highlighter), hasHighlightableContent)) {
83569
83733
  return;
83570
83734
  }
83571
83735
  const wantsHtml = highlightOutputMode === "html" || highlightOutputMode === "both";
83572
- const wantsTokens = highlightOutputMode === "tokens" || highlightOutputMode === "both";
83736
+ const wantsTokens = (highlightOutputMode === "tokens" || highlightOutputMode === "both") && emitHighlightTokens;
83573
83737
  const diffEnabled = diffInfo.isDiff && wantsTokens;
83574
83738
  if (!wantsHtml && !wantsTokens) return;
83575
83739
  const { startLine, endLine } = clampLazyRange(request.startLine, request.endLine, codeLines.length);
@@ -83697,6 +83861,13 @@ async function handleLazyTokenizationRequest(request) {
83697
83861
  if ("oldNo" in nextMeta) delete nextMeta.oldNo;
83698
83862
  if ("newNo" in nextMeta) delete nextMeta.newNo;
83699
83863
  }
83864
+ if (emitDiffBlocks && diffInfo.isDiff) {
83865
+ const cursor = { oldLine: null, newLine: null };
83866
+ const diffLines = codeLines.map((line) => parseUnifiedDiffLine(line, cursor));
83867
+ nextMeta.diffBlocks = buildDiffBlocksFromLines(diffLines, codeLines, wantsTokens ? state.tokenLines : null, diffInfo.baseLang ?? null);
83868
+ } else if ("diffBlocks" in nextMeta) {
83869
+ delete nextMeta.diffBlocks;
83870
+ }
83700
83871
  updated.payload.meta = nextMeta;
83701
83872
  blocks[index2] = updated;
83702
83873
  const nextSnapshot = await blockToNodeSnapshot(updated);
@@ -83717,18 +83888,26 @@ async function enrichCodeBlock(block) {
83717
83888
  const raw2 = block.payload.raw ?? "";
83718
83889
  const { code: code4, info, hadFence } = stripCodeFence(raw2);
83719
83890
  const { lang: lang236, meta: meta2 } = parseCodeFenceInfo(info);
83720
- const diffInfo = detectDiffLanguage(lang236, meta2);
83721
- const requestedLanguage = diffInfo.isDiff ? diffInfo.diffLang : lang236 || "text";
83722
- const tokenLanguage = diffInfo.isDiff ? diffInfo.baseLang ?? "text" : requestedLanguage;
83891
+ let diffInfo = detectDiffLanguage(lang236, meta2);
83723
83892
  const codeBody = hadFence ? code4 : dedentIndentedCode(raw2);
83724
83893
  const codeLines = extractCodeLines(raw2);
83894
+ if (!diffInfo.isDiff && emitDiffBlocks && looksLikeUnifiedDiff(codeLines)) {
83895
+ diffInfo = {
83896
+ isDiff: true,
83897
+ diffLang: "diff",
83898
+ baseLang: guessLanguageFromDiffLines(codeLines)
83899
+ };
83900
+ }
83901
+ const requestedLanguage = diffInfo.isDiff ? diffInfo.diffLang : lang236 || "text";
83902
+ const tokenLanguage = diffInfo.isDiff ? diffInfo.baseLang ?? "text" : requestedLanguage;
83725
83903
  const baseMeta = block.payload.meta ?? {};
83726
83904
  let resolvedLanguage = requestedLanguage;
83727
83905
  let resolvedTokenLanguage = tokenLanguage;
83728
83906
  const hasHighlighter = Boolean(highlighter);
83729
83907
  const hasHighlightableContent = codeBody.trim().length > 0;
83730
83908
  const wantsHtml = highlightOutputMode === "html" || highlightOutputMode === "both";
83731
- const wantsTokens = highlightOutputMode === "tokens" || highlightOutputMode === "both";
83909
+ const wantsTokens = (highlightOutputMode === "tokens" || highlightOutputMode === "both") && emitHighlightTokens;
83910
+ const wantsTokensNow = wantsTokens && (block.isFinalized || liveTokenizationEnabled);
83732
83911
  if (!block.isFinalized) {
83733
83912
  if (codeHighlightingMode === "final" || !hasHighlighter || !hasHighlightableContent) {
83734
83913
  resetIncrementalHighlightState(block.id);
@@ -83749,6 +83928,9 @@ async function enrichCodeBlock(block) {
83749
83928
  if ("newNo" in nextMeta2) {
83750
83929
  delete nextMeta2.newNo;
83751
83930
  }
83931
+ if ("diffBlocks" in nextMeta2) {
83932
+ delete nextMeta2.diffBlocks;
83933
+ }
83752
83934
  block.payload.meta = nextMeta2;
83753
83935
  return;
83754
83936
  }
@@ -83773,13 +83955,13 @@ async function enrichCodeBlock(block) {
83773
83955
  state.tokenLang = wantsTokens ? resolvedTokenLanguage : void 0;
83774
83956
  const appended = codeBody.slice(state.processedLength);
83775
83957
  const combined = state.pendingLine + appended;
83776
- const diffEnabled = diffInfo.isDiff && wantsTokens;
83958
+ const diffEnabled = diffInfo.isDiff && wantsTokensNow;
83777
83959
  if (combined.length > 0) {
83778
83960
  const parts = combined.split("\n");
83779
83961
  const completeLines = parts.slice(0, -1);
83780
83962
  const tail = parts.length > 0 ? parts[parts.length - 1] ?? "" : "";
83781
83963
  if (completeLines.length > 0) {
83782
- if (wantsHtml || wantsTokens && !diffEnabled) {
83964
+ if (wantsHtml || wantsTokensNow && !diffEnabled) {
83783
83965
  try {
83784
83966
  const sharedLanguage = wantsHtml ? resolvedLanguage : resolvedTokenLanguage;
83785
83967
  const tokens = highlighter?.codeToTokensWithThemes(completeLines.join("\n"), {
@@ -83791,7 +83973,7 @@ async function enrichCodeBlock(block) {
83791
83973
  const htmlLines = renderShikiLines(tokens);
83792
83974
  state.highlightedLines.push(...htmlLines);
83793
83975
  }
83794
- if (wantsTokens && !diffEnabled) {
83976
+ if (wantsTokensNow && !diffEnabled) {
83795
83977
  const tokenLines2 = renderTokenLines(tokens);
83796
83978
  state.tokenLines.push(...tokenLines2);
83797
83979
  }
@@ -83801,12 +83983,12 @@ async function enrichCodeBlock(block) {
83801
83983
  if (wantsHtml) {
83802
83984
  state.highlightedLines.push(...completeLines.map(() => null));
83803
83985
  }
83804
- if (wantsTokens && !diffEnabled) {
83986
+ if (wantsTokensNow && !diffEnabled) {
83805
83987
  state.tokenLines.push(...completeLines.map(() => null));
83806
83988
  }
83807
83989
  }
83808
83990
  }
83809
- if (wantsTokens && diffEnabled) {
83991
+ if (wantsTokensNow && diffEnabled) {
83810
83992
  const cursor = state.diffCursor ?? { oldLine: null, newLine: null };
83811
83993
  const diffLines = completeLines.map((line) => parseUnifiedDiffLine(line, cursor));
83812
83994
  state.diffCursor = cursor;
@@ -83837,7 +84019,7 @@ async function enrichCodeBlock(block) {
83837
84019
  } else if ("highlightedLines" in nextMeta2) {
83838
84020
  delete nextMeta2.highlightedLines;
83839
84021
  }
83840
- if (wantsTokens) {
84022
+ if (wantsTokensNow) {
83841
84023
  nextMeta2.tokenLines = state.tokenLines;
83842
84024
  if (diffEnabled) {
83843
84025
  nextMeta2.diffKind = state.diffKind;
@@ -83854,6 +84036,13 @@ async function enrichCodeBlock(block) {
83854
84036
  if ("oldNo" in nextMeta2) delete nextMeta2.oldNo;
83855
84037
  if ("newNo" in nextMeta2) delete nextMeta2.newNo;
83856
84038
  }
84039
+ if (emitDiffBlocks && diffInfo.isDiff && liveTokenizationEnabled) {
84040
+ const cursor = { oldLine: null, newLine: null };
84041
+ const diffLines = codeLines.map((line) => parseUnifiedDiffLine(line, cursor));
84042
+ nextMeta2.diffBlocks = buildDiffBlocksFromLines(diffLines, codeLines, wantsTokensNow ? state.tokenLines : null, diffInfo.baseLang ?? null);
84043
+ } else if ("diffBlocks" in nextMeta2) {
84044
+ delete nextMeta2.diffBlocks;
84045
+ }
83857
84046
  block.payload.meta = nextMeta2;
83858
84047
  const highlightDuration2 = performanceTimer.measure("highlight-code");
83859
84048
  metrics?.recordShiki(highlightDuration2);
@@ -83900,6 +84089,13 @@ async function enrichCodeBlock(block) {
83900
84089
  if ("oldNo" in nextMeta2) delete nextMeta2.oldNo;
83901
84090
  if ("newNo" in nextMeta2) delete nextMeta2.newNo;
83902
84091
  }
84092
+ if (emitDiffBlocks && diffInfo.isDiff) {
84093
+ const cursor = { oldLine: null, newLine: null };
84094
+ const diffLines = codeLines.map((line) => parseUnifiedDiffLine(line, cursor));
84095
+ nextMeta2.diffBlocks = buildDiffBlocksFromLines(diffLines, codeLines, wantsTokens ? state.tokenLines : null, diffInfo.baseLang ?? null);
84096
+ } else if ("diffBlocks" in nextMeta2) {
84097
+ delete nextMeta2.diffBlocks;
84098
+ }
83903
84099
  block.payload.highlightedHtml = void 0;
83904
84100
  block.payload.meta = nextMeta2;
83905
84101
  return;
@@ -84002,6 +84198,13 @@ async function enrichCodeBlock(block) {
84002
84198
  if ("oldNo" in nextMeta) delete nextMeta.oldNo;
84003
84199
  if ("newNo" in nextMeta) delete nextMeta.newNo;
84004
84200
  }
84201
+ if (emitDiffBlocks && diffInfo.isDiff) {
84202
+ const cursor = { oldLine: null, newLine: null };
84203
+ const diffLines = codeLines.map((line) => parseUnifiedDiffLine(line, cursor));
84204
+ nextMeta.diffBlocks = buildDiffBlocksFromLines(diffLines, codeLines, wantsTokens ? tokenLines ?? null : null, diffInfo.baseLang ?? null);
84205
+ } else if ("diffBlocks" in nextMeta) {
84206
+ delete nextMeta.diffBlocks;
84207
+ }
84005
84208
  block.payload.meta = nextMeta;
84006
84209
  const highlightDuration = performanceTimer.measure("highlight-code");
84007
84210
  metrics?.recordShiki(highlightDuration);
@@ -58,6 +58,9 @@ declare class MarkdownWorkerClient {
58
58
  codeHighlighting?: CodeHighlightingMode;
59
59
  outputMode?: CodeHighlightOutputMode;
60
60
  liveCodeHighlighting?: boolean;
61
+ liveTokenization?: boolean;
62
+ emitHighlightTokens?: boolean;
63
+ emitDiffBlocks?: boolean;
61
64
  mdxComponentNames?: string[];
62
65
  lazyTokenization?: {
63
66
  enabled?: boolean;
@@ -58,6 +58,9 @@ declare class MarkdownWorkerClient {
58
58
  codeHighlighting?: CodeHighlightingMode;
59
59
  outputMode?: CodeHighlightOutputMode;
60
60
  liveCodeHighlighting?: boolean;
61
+ liveTokenization?: boolean;
62
+ emitHighlightTokens?: boolean;
63
+ emitDiffBlocks?: boolean;
61
64
  mdxComponentNames?: string[];
62
65
  lazyTokenization?: {
63
66
  enabled?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-mdx/worker",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Worker client utilities and shared worker helpers for the Streaming Markdown V2 pipeline",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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.2.0",
67
- "@stream-mdx/plugins": "0.2.0",
66
+ "@stream-mdx/core": "0.3.0",
67
+ "@stream-mdx/plugins": "0.3.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",