@stream-mdx/core 0.0.1 → 0.0.3

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +26 -37
  3. package/dist/code-highlighting.cjs +0 -1
  4. package/dist/code-highlighting.mjs +0 -1
  5. package/dist/index.cjs +87 -16
  6. package/dist/index.d.cts +1 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.mjs +86 -16
  9. package/dist/inline-parser.cjs +24 -16
  10. package/dist/inline-parser.d.cts +5 -0
  11. package/dist/inline-parser.d.ts +5 -0
  12. package/dist/inline-parser.mjs +24 -16
  13. package/dist/mixed-content.cjs +0 -1
  14. package/dist/mixed-content.mjs +0 -1
  15. package/dist/perf/backpressure.cjs +0 -1
  16. package/dist/perf/backpressure.mjs +0 -1
  17. package/dist/perf/patch-batching.cjs +0 -1
  18. package/dist/perf/patch-batching.mjs +0 -1
  19. package/dist/perf/patch-coalescing.cjs +0 -1
  20. package/dist/perf/patch-coalescing.mjs +0 -1
  21. package/dist/security.cjs +0 -1
  22. package/dist/security.mjs +0 -1
  23. package/dist/streaming/custom-matcher.cjs +0 -1
  24. package/dist/streaming/custom-matcher.mjs +0 -1
  25. package/dist/streaming/inline-streaming.cjs +88 -0
  26. package/dist/streaming/inline-streaming.d.cts +17 -0
  27. package/dist/streaming/inline-streaming.d.ts +17 -0
  28. package/dist/streaming/inline-streaming.mjs +63 -0
  29. package/dist/types.cjs +0 -1
  30. package/dist/types.d.cts +3 -0
  31. package/dist/types.d.ts +3 -0
  32. package/dist/types.mjs +0 -1
  33. package/dist/utils.cjs +0 -1
  34. package/dist/utils.mjs +0 -1
  35. package/dist/worker-html-sanitizer.cjs +0 -1
  36. package/dist/worker-html-sanitizer.mjs +0 -1
  37. package/package.json +9 -2
  38. package/dist/code-highlighting.cjs.map +0 -1
  39. package/dist/code-highlighting.mjs.map +0 -1
  40. package/dist/index.cjs.map +0 -1
  41. package/dist/index.mjs.map +0 -1
  42. package/dist/inline-parser.cjs.map +0 -1
  43. package/dist/inline-parser.mjs.map +0 -1
  44. package/dist/mixed-content.cjs.map +0 -1
  45. package/dist/mixed-content.mjs.map +0 -1
  46. package/dist/perf/backpressure.cjs.map +0 -1
  47. package/dist/perf/backpressure.mjs.map +0 -1
  48. package/dist/perf/patch-batching.cjs.map +0 -1
  49. package/dist/perf/patch-batching.mjs.map +0 -1
  50. package/dist/perf/patch-coalescing.cjs.map +0 -1
  51. package/dist/perf/patch-coalescing.mjs.map +0 -1
  52. package/dist/security.cjs.map +0 -1
  53. package/dist/security.mjs.map +0 -1
  54. package/dist/streaming/custom-matcher.cjs.map +0 -1
  55. package/dist/streaming/custom-matcher.mjs.map +0 -1
  56. package/dist/types.cjs.map +0 -1
  57. package/dist/types.mjs.map +0 -1
  58. package/dist/utils.cjs.map +0 -1
  59. package/dist/utils.mjs.map +0 -1
  60. package/dist/worker-html-sanitizer.cjs.map +0 -1
  61. package/dist/worker-html-sanitizer.mjs.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # @stream-mdx/core
2
+
3
+ ## 0.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 47d1374: Add opt-in streaming format anticipation and an optional Mermaid diagram addon for ` ```mermaid ` code blocks.
8
+ - 7c79f09: Port the docs demo page to match the ql-homepage streaming UI, and fix several streaming parser/rendering edge cases (hard line breaks and display-math handling) while keeping the hosted worker bundle self-contained for static hosting.
9
+
10
+ ## 0.0.2
11
+
12
+ ### Patch Changes
13
+
14
+ - 9e94660: Docs and release-quality improvements: ship package READMEs/CHANGELOGs, add pack+install smoke tests, expose MDX parity helper entrypoints, and add a deployable docs site workflow.
15
+
16
+ ## 0.0.1
17
+
18
+ ### Patch Changes
19
+
20
+ - Release maintenance: CI/build fixes, missing runtime deps (e.g. `rehype-katex`), and improved docs/README wiring for the `stream-mdx` package page.
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # `@stream-mdx/core`
2
2
 
3
- Pure TypeScript primitives shared across the streaming renderer stack. This package intentionally contains **no DOM/React code**; everything exported is structured-clone-safe so it can cross `postMessage` boundaries without serialization hacks.
3
+ Core types + utilities shared across the StreamMDX stack.
4
+
5
+ This package is intentionally React-free. It contains structured-clone-safe types and helpers used by both the worker and the renderer.
6
+
7
+ Most consumers should install `stream-mdx` and follow the main docs. Use `@stream-mdx/core` directly if you’re building tooling or customizing lower-level behavior.
4
8
 
5
9
  ## Install
6
10
 
@@ -8,47 +12,32 @@ Pure TypeScript primitives shared across the streaming renderer stack. This pack
8
12
  npm install @stream-mdx/core
9
13
  ```
10
14
 
11
- ## Exports
15
+ ## Entry points
12
16
 
13
- | Module | Description |
14
- | --- | --- |
15
- | `types` | `Block`, `InlineNode`, `Patch`, `PatchBatch`, `RendererMetrics`, worker message unions. |
16
- | `block-snapshot` | Helpers for cloning/mutating block trees in the worker. |
17
- | `code-highlighting` | Shiki token utilities (`CodeLine`, `flattenHighlights`). |
18
- | `mixed-content` | Inline HTML/Multi-block parsing helpers. |
19
- | `inline-parser` | Incremental inline AST parser (Lezer wrappers). |
20
- | `security` | Sanitization schema + trusted-types friendly helpers. |
21
- | `utils` | Tree traversal, node ID generation, list depth normalization. |
22
- | `perf/backpressure` | Back-pressure defaults + smoothing functions shared by worker/renderer. |
23
- | `worker-html-sanitizer` | Preconfigured DOMPurify-like sanitization for worker context. |
17
+ - `@stream-mdx/core` (root)
18
+ - `@stream-mdx/core/types`
19
+ - `@stream-mdx/core/utils`
20
+ - `@stream-mdx/core/code-highlighting`
21
+ - `@stream-mdx/core/inline-parser`
22
+ - `@stream-mdx/core/mixed-content`
23
+ - `@stream-mdx/core/worker-html-sanitizer`
24
+ - `@stream-mdx/core/security`
25
+ - `@stream-mdx/core/perf/backpressure`
26
+ - `@stream-mdx/core/perf/patch-batching`
27
+ - `@stream-mdx/core/perf/patch-coalescing`
28
+ - `@stream-mdx/core/streaming/custom-matcher`
24
29
 
25
- See `packages/markdown-v2-core/src/index.ts` for the canonical export list.
26
-
27
- ## Usage
30
+ ## Example
28
31
 
29
32
  ```ts
30
- import type { Patch } from "@stream-mdx/core";
31
- import { applyPatchBatch } from "@stream-mdx/core/block-snapshot";
32
-
33
- export function replay(patches: Patch[]) {
34
- const snapshot = createInitialSnapshot();
35
- for (const patch of patches) {
36
- applyPatchBatch(snapshot, [patch]);
37
- }
38
- return snapshot;
33
+ import { DEFAULT_BACKPRESSURE_CONFIG } from "@stream-mdx/core/perf/backpressure";
34
+
35
+ export function makeConfig(overrides?: Partial<typeof DEFAULT_BACKPRESSURE_CONFIG>) {
36
+ return { ...DEFAULT_BACKPRESSURE_CONFIG, ...overrides };
39
37
  }
40
38
  ```
41
39
 
42
- The worker bundle (`@stream-mdx/worker`) consumes these helpers to build `Patch` batches, and the renderer uses the same types for its store/scheduler.
43
-
44
- > For end-to-end math/MDX registration steps (worker + renderer), see [`docs/STREAMING_MARKDOWN_PLUGINS_COOKBOOK.md#5-math--mdx-workerrenderer-registration`](../../docs/STREAMING_MARKDOWN_PLUGINS_COOKBOOK.md#5-math--mdx-workerrenderer-registration).
45
-
46
- ## Security notes
47
-
48
- - Sanitization helpers assume you pass trusted markdown inputs or run the worker in an isolated thread. If you enable raw HTML rendering, ensure you serve KaTeX/MDX assets from trusted origins and set CSP headers accordingly.
49
- - `worker-html-sanitizer` exports a minimal schema. Override/augment it if you need to allow additional tags/attributes (e.g., custom `data-*` props).
50
-
51
- ## Roadmap
40
+ ## Docs
52
41
 
53
- - Document semver guarantees once `1.0.0` ships.
54
- - Publish detailed inline docs for every exported type (linkable from `docs/PUBLIC_API.md`).
42
+ - API reference: `docs/PUBLIC_API.md`
43
+ - Security model: `docs/SECURITY_MODEL.md`
@@ -217,4 +217,3 @@ function filterAllowedAttributes(attrs) {
217
217
  extractHighlightedLines,
218
218
  stripCodeFence
219
219
  });
220
- //# sourceMappingURL=code-highlighting.cjs.map
@@ -188,4 +188,3 @@ export {
188
188
  extractHighlightedLines,
189
189
  stripCodeFence
190
190
  };
191
- //# sourceMappingURL=code-highlighting.mjs.map
package/dist/index.cjs CHANGED
@@ -74,6 +74,7 @@ __export(index_exports, {
74
74
  normalizeBlockquoteText: () => normalizeBlockquoteText,
75
75
  normalizeLang: () => normalizeLang,
76
76
  parseCodeFenceInfo: () => parseCodeFenceInfo,
77
+ prepareInlineStreamingContent: () => prepareInlineStreamingContent,
77
78
  removeHeadingMarkers: () => removeHeadingMarkers,
78
79
  sanitizeCodeHTML: () => sanitizeCodeHTML,
79
80
  sanitizeHTML: () => sanitizeHTML,
@@ -294,7 +295,7 @@ var InlineParser = class {
294
295
  this.plugins = [];
295
296
  this.cache = /* @__PURE__ */ new Map();
296
297
  this.maxCacheEntries = Number.isFinite(options.maxCacheEntries ?? Number.NaN) ? Math.max(0, options.maxCacheEntries ?? 0) : 2e3;
297
- this.registerDefaultPlugins();
298
+ this.registerDefaultPlugins({ enableMath: options.enableMath !== false });
298
299
  }
299
300
  /**
300
301
  * Register a plugin with the parser
@@ -360,10 +361,27 @@ var InlineParser = class {
360
361
  * Register default plugins with proper precedence ordering
361
362
  * Lower priority numbers = higher precedence (run first)
362
363
  */
363
- registerDefaultPlugins() {
364
+ registerDefaultPlugins(options) {
365
+ if (options.enableMath) {
366
+ this.registerPlugin({
367
+ id: "math-display",
368
+ priority: 0,
369
+ re: /\$\$([\s\S]+?)\$\$/g,
370
+ toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
371
+ fastCheck: (text) => text.indexOf("$$") !== -1
372
+ });
373
+ this.registerPlugin({
374
+ id: "math-inline",
375
+ priority: 1,
376
+ re: /\$([^$\n]+?)\$/g,
377
+ // Non-greedy to prevent spanning multiple expressions
378
+ toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
379
+ fastCheck: (text) => text.indexOf("$") !== -1
380
+ });
381
+ }
364
382
  this.registerPlugin({
365
383
  id: "escaped-character",
366
- priority: 0,
384
+ priority: 2,
367
385
  re: /\\([\\`*_{}\[\]()#+\-.!>])/g,
368
386
  toNode: (match) => ({
369
387
  kind: "text",
@@ -372,19 +390,11 @@ var InlineParser = class {
372
390
  fastCheck: (text) => text.indexOf("\\") !== -1
373
391
  });
374
392
  this.registerPlugin({
375
- id: "math-display",
376
- priority: 1,
377
- re: /\$\$([^$]+?)\$\$/g,
378
- toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
379
- fastCheck: (text) => text.indexOf("$$") !== -1
380
- });
381
- this.registerPlugin({
382
- id: "math-inline",
393
+ id: "hard-break",
383
394
  priority: 2,
384
- re: /\$([^$\n]+?)\$/g,
385
- // Non-greedy to prevent spanning multiple expressions
386
- toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
387
- fastCheck: (text) => text.indexOf("$") !== -1
395
+ re: /\\\r?\n| {2,}\r?\n/g,
396
+ toNode: (_match) => ({ kind: "br" }),
397
+ fastCheck: (text) => text.indexOf("\n") !== -1 || text.indexOf("\r") !== -1
388
398
  });
389
399
  this.registerPlugin({
390
400
  id: "code-spans",
@@ -2799,6 +2809,67 @@ var CustomStreamingMatcher = class {
2799
2809
  return false;
2800
2810
  }
2801
2811
  };
2812
+
2813
+ // src/streaming/inline-streaming.ts
2814
+ function prepareInlineStreamingContent(content, options) {
2815
+ const enableAnticipation = Boolean(options?.formatAnticipation);
2816
+ const enableMath = options?.math !== false;
2817
+ let dollarCount = 0;
2818
+ let backtickCount = 0;
2819
+ let starCount = 0;
2820
+ let doubleStarCount = 0;
2821
+ let tildePairCount = 0;
2822
+ for (let i = 0; i < content.length; i++) {
2823
+ const code = content.charCodeAt(i);
2824
+ if (code === 36) {
2825
+ dollarCount += 1;
2826
+ continue;
2827
+ }
2828
+ if (code === 96) {
2829
+ backtickCount += 1;
2830
+ continue;
2831
+ }
2832
+ if (code === 42) {
2833
+ if (i + 1 < content.length && content.charCodeAt(i + 1) === 42) {
2834
+ doubleStarCount += 1;
2835
+ starCount += 2;
2836
+ i += 1;
2837
+ } else {
2838
+ starCount += 1;
2839
+ }
2840
+ continue;
2841
+ }
2842
+ if (code === 126) {
2843
+ if (i + 1 < content.length && content.charCodeAt(i + 1) === 126) {
2844
+ tildePairCount += 1;
2845
+ i += 1;
2846
+ }
2847
+ }
2848
+ }
2849
+ const hasIncompleteMath = enableMath && dollarCount % 2 !== 0;
2850
+ if (hasIncompleteMath) {
2851
+ return { kind: "raw", status: "raw", reason: "incomplete-math" };
2852
+ }
2853
+ const hasIncompleteCode = backtickCount % 2 !== 0;
2854
+ const hasIncompleteStrong = doubleStarCount % 2 !== 0;
2855
+ const singleStarCount = starCount - doubleStarCount * 2;
2856
+ const hasIncompleteEmphasis = singleStarCount % 2 !== 0;
2857
+ const hasIncompleteStrike = tildePairCount % 2 !== 0;
2858
+ const hasAnyIncomplete = hasIncompleteCode || hasIncompleteStrong || hasIncompleteEmphasis || hasIncompleteStrike;
2859
+ if (!hasAnyIncomplete) {
2860
+ return { kind: "parse", status: "complete", content, appended: "" };
2861
+ }
2862
+ if (!enableAnticipation) {
2863
+ return { kind: "raw", status: "raw", reason: "incomplete-formatting" };
2864
+ }
2865
+ let appended = "";
2866
+ if (hasIncompleteCode) appended += "`";
2867
+ if (hasIncompleteStrike) appended += "~~";
2868
+ if (hasIncompleteStrong && hasIncompleteEmphasis) appended += "***";
2869
+ else if (hasIncompleteStrong) appended += "**";
2870
+ else if (hasIncompleteEmphasis) appended += "*";
2871
+ return { kind: "parse", status: "anticipated", content: content + appended, appended };
2872
+ }
2802
2873
  // Annotate the CommonJS export names for ESM import in node:
2803
2874
  0 && (module.exports = {
2804
2875
  CSP_HEADERS,
@@ -2845,6 +2916,7 @@ var CustomStreamingMatcher = class {
2845
2916
  normalizeBlockquoteText,
2846
2917
  normalizeLang,
2847
2918
  parseCodeFenceInfo,
2919
+ prepareInlineStreamingContent,
2848
2920
  removeHeadingMarkers,
2849
2921
  sanitizeCodeHTML,
2850
2922
  sanitizeHTML,
@@ -2854,4 +2926,3 @@ var CustomStreamingMatcher = class {
2854
2926
  smoothCredit,
2855
2927
  stripCodeFence
2856
2928
  });
2857
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -9,6 +9,7 @@ export { sanitizeHtmlInWorker } from './worker-html-sanitizer.cjs';
9
9
  export { BackpressureConfig, DEFAULT_BACKPRESSURE_CONFIG, calculateRawCredit, calculateSmoothedCredit, clampCredit, computeHeavyPatchBudget, smoothCredit } from './perf/backpressure.cjs';
10
10
  export { CoalesceConfig, DEFAULT_COALESCE_CONFIG, coalescePatches, coalescePatchesLinear, coalescePatchesQuadratic, coalescePatchesWithMetrics } from './perf/patch-coalescing.cjs';
11
11
  export { CustomStreamingMatcher, MatchResult } from './streaming/custom-matcher.cjs';
12
+ export { InlineStreamingInlineStatus, InlineStreamingPrepareResult, prepareInlineStreamingContent } from './streaming/inline-streaming.cjs';
12
13
  import 'dompurify';
13
14
 
14
15
  declare function cloneBlock(block: Block): Block;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export { sanitizeHtmlInWorker } from './worker-html-sanitizer.js';
9
9
  export { BackpressureConfig, DEFAULT_BACKPRESSURE_CONFIG, calculateRawCredit, calculateSmoothedCredit, clampCredit, computeHeavyPatchBudget, smoothCredit } from './perf/backpressure.js';
10
10
  export { CoalesceConfig, DEFAULT_COALESCE_CONFIG, coalescePatches, coalescePatchesLinear, coalescePatchesQuadratic, coalescePatchesWithMetrics } from './perf/patch-coalescing.js';
11
11
  export { CustomStreamingMatcher, MatchResult } from './streaming/custom-matcher.js';
12
+ export { InlineStreamingInlineStatus, InlineStreamingPrepareResult, prepareInlineStreamingContent } from './streaming/inline-streaming.js';
12
13
  import 'dompurify';
13
14
 
14
15
  declare function cloneBlock(block: Block): Block;
package/dist/index.mjs CHANGED
@@ -207,7 +207,7 @@ var InlineParser = class {
207
207
  this.plugins = [];
208
208
  this.cache = /* @__PURE__ */ new Map();
209
209
  this.maxCacheEntries = Number.isFinite(options.maxCacheEntries ?? Number.NaN) ? Math.max(0, options.maxCacheEntries ?? 0) : 2e3;
210
- this.registerDefaultPlugins();
210
+ this.registerDefaultPlugins({ enableMath: options.enableMath !== false });
211
211
  }
212
212
  /**
213
213
  * Register a plugin with the parser
@@ -273,10 +273,27 @@ var InlineParser = class {
273
273
  * Register default plugins with proper precedence ordering
274
274
  * Lower priority numbers = higher precedence (run first)
275
275
  */
276
- registerDefaultPlugins() {
276
+ registerDefaultPlugins(options) {
277
+ if (options.enableMath) {
278
+ this.registerPlugin({
279
+ id: "math-display",
280
+ priority: 0,
281
+ re: /\$\$([\s\S]+?)\$\$/g,
282
+ toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
283
+ fastCheck: (text) => text.indexOf("$$") !== -1
284
+ });
285
+ this.registerPlugin({
286
+ id: "math-inline",
287
+ priority: 1,
288
+ re: /\$([^$\n]+?)\$/g,
289
+ // Non-greedy to prevent spanning multiple expressions
290
+ toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
291
+ fastCheck: (text) => text.indexOf("$") !== -1
292
+ });
293
+ }
277
294
  this.registerPlugin({
278
295
  id: "escaped-character",
279
- priority: 0,
296
+ priority: 2,
280
297
  re: /\\([\\`*_{}\[\]()#+\-.!>])/g,
281
298
  toNode: (match) => ({
282
299
  kind: "text",
@@ -285,19 +302,11 @@ var InlineParser = class {
285
302
  fastCheck: (text) => text.indexOf("\\") !== -1
286
303
  });
287
304
  this.registerPlugin({
288
- id: "math-display",
289
- priority: 1,
290
- re: /\$\$([^$]+?)\$\$/g,
291
- toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
292
- fastCheck: (text) => text.indexOf("$$") !== -1
293
- });
294
- this.registerPlugin({
295
- id: "math-inline",
305
+ id: "hard-break",
296
306
  priority: 2,
297
- re: /\$([^$\n]+?)\$/g,
298
- // Non-greedy to prevent spanning multiple expressions
299
- toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
300
- fastCheck: (text) => text.indexOf("$") !== -1
307
+ re: /\\\r?\n| {2,}\r?\n/g,
308
+ toNode: (_match) => ({ kind: "br" }),
309
+ fastCheck: (text) => text.indexOf("\n") !== -1 || text.indexOf("\r") !== -1
301
310
  });
302
311
  this.registerPlugin({
303
312
  id: "code-spans",
@@ -2712,6 +2721,67 @@ var CustomStreamingMatcher = class {
2712
2721
  return false;
2713
2722
  }
2714
2723
  };
2724
+
2725
+ // src/streaming/inline-streaming.ts
2726
+ function prepareInlineStreamingContent(content, options) {
2727
+ const enableAnticipation = Boolean(options?.formatAnticipation);
2728
+ const enableMath = options?.math !== false;
2729
+ let dollarCount = 0;
2730
+ let backtickCount = 0;
2731
+ let starCount = 0;
2732
+ let doubleStarCount = 0;
2733
+ let tildePairCount = 0;
2734
+ for (let i = 0; i < content.length; i++) {
2735
+ const code = content.charCodeAt(i);
2736
+ if (code === 36) {
2737
+ dollarCount += 1;
2738
+ continue;
2739
+ }
2740
+ if (code === 96) {
2741
+ backtickCount += 1;
2742
+ continue;
2743
+ }
2744
+ if (code === 42) {
2745
+ if (i + 1 < content.length && content.charCodeAt(i + 1) === 42) {
2746
+ doubleStarCount += 1;
2747
+ starCount += 2;
2748
+ i += 1;
2749
+ } else {
2750
+ starCount += 1;
2751
+ }
2752
+ continue;
2753
+ }
2754
+ if (code === 126) {
2755
+ if (i + 1 < content.length && content.charCodeAt(i + 1) === 126) {
2756
+ tildePairCount += 1;
2757
+ i += 1;
2758
+ }
2759
+ }
2760
+ }
2761
+ const hasIncompleteMath = enableMath && dollarCount % 2 !== 0;
2762
+ if (hasIncompleteMath) {
2763
+ return { kind: "raw", status: "raw", reason: "incomplete-math" };
2764
+ }
2765
+ const hasIncompleteCode = backtickCount % 2 !== 0;
2766
+ const hasIncompleteStrong = doubleStarCount % 2 !== 0;
2767
+ const singleStarCount = starCount - doubleStarCount * 2;
2768
+ const hasIncompleteEmphasis = singleStarCount % 2 !== 0;
2769
+ const hasIncompleteStrike = tildePairCount % 2 !== 0;
2770
+ const hasAnyIncomplete = hasIncompleteCode || hasIncompleteStrong || hasIncompleteEmphasis || hasIncompleteStrike;
2771
+ if (!hasAnyIncomplete) {
2772
+ return { kind: "parse", status: "complete", content, appended: "" };
2773
+ }
2774
+ if (!enableAnticipation) {
2775
+ return { kind: "raw", status: "raw", reason: "incomplete-formatting" };
2776
+ }
2777
+ let appended = "";
2778
+ if (hasIncompleteCode) appended += "`";
2779
+ if (hasIncompleteStrike) appended += "~~";
2780
+ if (hasIncompleteStrong && hasIncompleteEmphasis) appended += "***";
2781
+ else if (hasIncompleteStrong) appended += "**";
2782
+ else if (hasIncompleteEmphasis) appended += "*";
2783
+ return { kind: "parse", status: "anticipated", content: content + appended, appended };
2784
+ }
2715
2785
  export {
2716
2786
  CSP_HEADERS,
2717
2787
  CustomStreamingMatcher,
@@ -2757,6 +2827,7 @@ export {
2757
2827
  normalizeBlockquoteText,
2758
2828
  normalizeLang,
2759
2829
  parseCodeFenceInfo,
2830
+ prepareInlineStreamingContent,
2760
2831
  removeHeadingMarkers,
2761
2832
  sanitizeCodeHTML,
2762
2833
  sanitizeHTML,
@@ -2766,4 +2837,3 @@ export {
2766
2837
  smoothCredit,
2767
2838
  stripCodeFence
2768
2839
  };
2769
- //# sourceMappingURL=index.mjs.map
@@ -30,7 +30,7 @@ var InlineParser = class {
30
30
  this.plugins = [];
31
31
  this.cache = /* @__PURE__ */ new Map();
32
32
  this.maxCacheEntries = Number.isFinite(options.maxCacheEntries ?? Number.NaN) ? Math.max(0, options.maxCacheEntries ?? 0) : 2e3;
33
- this.registerDefaultPlugins();
33
+ this.registerDefaultPlugins({ enableMath: options.enableMath !== false });
34
34
  }
35
35
  /**
36
36
  * Register a plugin with the parser
@@ -96,10 +96,27 @@ var InlineParser = class {
96
96
  * Register default plugins with proper precedence ordering
97
97
  * Lower priority numbers = higher precedence (run first)
98
98
  */
99
- registerDefaultPlugins() {
99
+ registerDefaultPlugins(options) {
100
+ if (options.enableMath) {
101
+ this.registerPlugin({
102
+ id: "math-display",
103
+ priority: 0,
104
+ re: /\$\$([\s\S]+?)\$\$/g,
105
+ toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
106
+ fastCheck: (text) => text.indexOf("$$") !== -1
107
+ });
108
+ this.registerPlugin({
109
+ id: "math-inline",
110
+ priority: 1,
111
+ re: /\$([^$\n]+?)\$/g,
112
+ // Non-greedy to prevent spanning multiple expressions
113
+ toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
114
+ fastCheck: (text) => text.indexOf("$") !== -1
115
+ });
116
+ }
100
117
  this.registerPlugin({
101
118
  id: "escaped-character",
102
- priority: 0,
119
+ priority: 2,
103
120
  re: /\\([\\`*_{}\[\]()#+\-.!>])/g,
104
121
  toNode: (match) => ({
105
122
  kind: "text",
@@ -108,19 +125,11 @@ var InlineParser = class {
108
125
  fastCheck: (text) => text.indexOf("\\") !== -1
109
126
  });
110
127
  this.registerPlugin({
111
- id: "math-display",
112
- priority: 1,
113
- re: /\$\$([^$]+?)\$\$/g,
114
- toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
115
- fastCheck: (text) => text.indexOf("$$") !== -1
116
- });
117
- this.registerPlugin({
118
- id: "math-inline",
128
+ id: "hard-break",
119
129
  priority: 2,
120
- re: /\$([^$\n]+?)\$/g,
121
- // Non-greedy to prevent spanning multiple expressions
122
- toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
123
- fastCheck: (text) => text.indexOf("$") !== -1
130
+ re: /\\\r?\n| {2,}\r?\n/g,
131
+ toNode: (_match) => ({ kind: "br" }),
132
+ fastCheck: (text) => text.indexOf("\n") !== -1 || text.indexOf("\r") !== -1
124
133
  });
125
134
  this.registerPlugin({
126
135
  id: "code-spans",
@@ -293,4 +302,3 @@ function splitTextByRegexWithPrecedence(text, regex, toNode) {
293
302
  applyASTPlugin,
294
303
  applyRegexPlugin
295
304
  });
296
- //# sourceMappingURL=inline-parser.cjs.map
@@ -7,6 +7,11 @@ interface InlineParserOptions {
7
7
  * parsing many intermediate states.
8
8
  */
9
9
  maxCacheEntries?: number;
10
+ /**
11
+ * Enable parsing `$...$` and `$$...$$` math nodes.
12
+ * Defaults to `true`.
13
+ */
14
+ enableMath?: boolean;
10
15
  }
11
16
  interface InlineParseOptions {
12
17
  /**
@@ -7,6 +7,11 @@ interface InlineParserOptions {
7
7
  * parsing many intermediate states.
8
8
  */
9
9
  maxCacheEntries?: number;
10
+ /**
11
+ * Enable parsing `$...$` and `$$...$$` math nodes.
12
+ * Defaults to `true`.
13
+ */
14
+ enableMath?: boolean;
10
15
  }
11
16
  interface InlineParseOptions {
12
17
  /**
@@ -4,7 +4,7 @@ var InlineParser = class {
4
4
  this.plugins = [];
5
5
  this.cache = /* @__PURE__ */ new Map();
6
6
  this.maxCacheEntries = Number.isFinite(options.maxCacheEntries ?? Number.NaN) ? Math.max(0, options.maxCacheEntries ?? 0) : 2e3;
7
- this.registerDefaultPlugins();
7
+ this.registerDefaultPlugins({ enableMath: options.enableMath !== false });
8
8
  }
9
9
  /**
10
10
  * Register a plugin with the parser
@@ -70,10 +70,27 @@ var InlineParser = class {
70
70
  * Register default plugins with proper precedence ordering
71
71
  * Lower priority numbers = higher precedence (run first)
72
72
  */
73
- registerDefaultPlugins() {
73
+ registerDefaultPlugins(options) {
74
+ if (options.enableMath) {
75
+ this.registerPlugin({
76
+ id: "math-display",
77
+ priority: 0,
78
+ re: /\$\$([\s\S]+?)\$\$/g,
79
+ toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
80
+ fastCheck: (text) => text.indexOf("$$") !== -1
81
+ });
82
+ this.registerPlugin({
83
+ id: "math-inline",
84
+ priority: 1,
85
+ re: /\$([^$\n]+?)\$/g,
86
+ // Non-greedy to prevent spanning multiple expressions
87
+ toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
88
+ fastCheck: (text) => text.indexOf("$") !== -1
89
+ });
90
+ }
74
91
  this.registerPlugin({
75
92
  id: "escaped-character",
76
- priority: 0,
93
+ priority: 2,
77
94
  re: /\\([\\`*_{}\[\]()#+\-.!>])/g,
78
95
  toNode: (match) => ({
79
96
  kind: "text",
@@ -82,19 +99,11 @@ var InlineParser = class {
82
99
  fastCheck: (text) => text.indexOf("\\") !== -1
83
100
  });
84
101
  this.registerPlugin({
85
- id: "math-display",
86
- priority: 1,
87
- re: /\$\$([^$]+?)\$\$/g,
88
- toNode: (match) => ({ kind: "math-display", tex: match[1].trim() }),
89
- fastCheck: (text) => text.indexOf("$$") !== -1
90
- });
91
- this.registerPlugin({
92
- id: "math-inline",
102
+ id: "hard-break",
93
103
  priority: 2,
94
- re: /\$([^$\n]+?)\$/g,
95
- // Non-greedy to prevent spanning multiple expressions
96
- toNode: (match) => ({ kind: "math-inline", tex: match[1].trim() }),
97
- fastCheck: (text) => text.indexOf("$") !== -1
104
+ re: /\\\r?\n| {2,}\r?\n/g,
105
+ toNode: (_match) => ({ kind: "br" }),
106
+ fastCheck: (text) => text.indexOf("\n") !== -1 || text.indexOf("\r") !== -1
98
107
  });
99
108
  this.registerPlugin({
100
109
  id: "code-spans",
@@ -266,4 +275,3 @@ export {
266
275
  applyASTPlugin,
267
276
  applyRegexPlugin
268
277
  };
269
- //# sourceMappingURL=inline-parser.mjs.map
@@ -370,4 +370,3 @@ function findClosingHtmlTag(lowerSource, lowerTagName, startIndex) {
370
370
  findClosingHtmlTag,
371
371
  isLikelyMdxComponent
372
372
  });
373
- //# sourceMappingURL=mixed-content.cjs.map
@@ -331,4 +331,3 @@ export {
331
331
  findClosingHtmlTag,
332
332
  isLikelyMdxComponent
333
333
  };
334
- //# sourceMappingURL=mixed-content.mjs.map
@@ -101,4 +101,3 @@ function clamp01(value) {
101
101
  computeHeavyPatchBudget,
102
102
  smoothCredit
103
103
  });
104
- //# sourceMappingURL=backpressure.cjs.map
@@ -71,4 +71,3 @@ export {
71
71
  computeHeavyPatchBudget,
72
72
  smoothCredit
73
73
  };
74
- //# sourceMappingURL=backpressure.mjs.map
@@ -135,4 +135,3 @@ function splitPatchBatch(patches, maxLightChunk = DEFAULT_MAX_LIGHT_PATCHES_PER_
135
135
  isHeavyPatch,
136
136
  splitPatchBatch
137
137
  });
138
- //# sourceMappingURL=patch-batching.cjs.map
@@ -109,4 +109,3 @@ export {
109
109
  isHeavyPatch,
110
110
  splitPatchBatch
111
111
  };
112
- //# sourceMappingURL=patch-batching.mjs.map
@@ -427,4 +427,3 @@ function coalescePatchesQuadratic(patches, config = DEFAULT_COALESCE_CONFIG) {
427
427
  coalescePatchesQuadratic,
428
428
  coalescePatchesWithMetrics
429
429
  });
430
- //# sourceMappingURL=patch-coalescing.cjs.map
@@ -398,4 +398,3 @@ export {
398
398
  coalescePatchesQuadratic,
399
399
  coalescePatchesWithMetrics
400
400
  };
401
- //# sourceMappingURL=patch-coalescing.mjs.map
package/dist/security.cjs CHANGED
@@ -416,4 +416,3 @@ function initializeSecurity() {
416
416
  sanitizeMathHTML,
417
417
  sanitizeURL
418
418
  });
419
- //# sourceMappingURL=security.cjs.map
package/dist/security.mjs CHANGED
@@ -373,4 +373,3 @@ export {
373
373
  sanitizeMathHTML,
374
374
  sanitizeURL
375
375
  };
376
- //# sourceMappingURL=security.mjs.map
@@ -116,4 +116,3 @@ var CustomStreamingMatcher = class {
116
116
  0 && (module.exports = {
117
117
  CustomStreamingMatcher
118
118
  });
119
- //# sourceMappingURL=custom-matcher.cjs.map
@@ -91,4 +91,3 @@ var CustomStreamingMatcher = class {
91
91
  export {
92
92
  CustomStreamingMatcher
93
93
  };
94
- //# sourceMappingURL=custom-matcher.mjs.map