@incremark/core 0.0.5 → 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/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { P as ParserOptions, I as IncrementalUpdate, a as ParsedBlock, b as ParserState } from './index-i_qABRHQ.js';
2
2
  export { c as BlockContext, B as BlockStatus, e as BlockTypeInfo, C as ContainerConfig, d as ContainerMatch, r as createInitialContext, o as detectContainer, p as detectContainerEnd, g as detectFenceEnd, f as detectFenceStart, q as isBlockBoundary, l as isBlockquoteStart, i as isEmptyLine, h as isHeading, m as isHtmlBlock, k as isListItemStart, n as isTableDelimiter, j as isThematicBreak, u as updateContext } from './index-i_qABRHQ.js';
3
- import { Root, RootContent } from 'mdast';
3
+ import { Root, RootContent, Text } from 'mdast';
4
4
  export { Root, RootContent } from 'mdast';
5
5
  export { calculateLineOffset, generateId, joinLines, resetIdCounter, splitLines } from './utils/index.js';
6
6
  import 'micromark-util-types';
@@ -119,9 +119,10 @@ interface DisplayBlock<T = unknown> extends SourceBlock<T> {
119
119
  /**
120
120
  * 动画效果类型
121
121
  * - 'none': 无动画效果
122
- * - 'typing': 打字机光标效果(需配合 CSS)
122
+ * - 'fade-in': 新增字符渐入效果
123
+ * - 'typing': 打字机光标效果
123
124
  */
124
- type AnimationEffect = 'none' | 'typing';
125
+ type AnimationEffect = 'none' | 'fade-in' | 'typing';
125
126
  /**
126
127
  * Transformer 插件
127
128
  */
@@ -228,6 +229,7 @@ declare class BlockTransformer<T = unknown> {
228
229
  private lastTickTime;
229
230
  private isRunning;
230
231
  private isPaused;
232
+ private chunks;
231
233
  private visibilityHandler;
232
234
  constructor(options?: TransformerOptions);
233
235
  /**
@@ -298,6 +300,10 @@ declare class BlockTransformer<T = unknown> {
298
300
  private scheduleNextFrame;
299
301
  private animationFrame;
300
302
  private tick;
303
+ /**
304
+ * 从 AST 节点中提取指定范围的文本
305
+ */
306
+ private extractText;
301
307
  private getStep;
302
308
  private processNext;
303
309
  private cancelRaf;
@@ -312,18 +318,47 @@ declare class BlockTransformer<T = unknown> {
312
318
  */
313
319
  declare function createBlockTransformer<T = unknown>(options?: TransformerOptions): BlockTransformer<T>;
314
320
 
321
+ /**
322
+ * 文本块片段(用于渐入动画)
323
+ */
324
+ interface TextChunk {
325
+ /** 文本内容 */
326
+ text: string;
327
+ /** 创建时间戳 */
328
+ createdAt: number;
329
+ }
330
+ /**
331
+ * 扩展的文本节点(支持 chunks)
332
+ */
333
+ interface TextNodeWithChunks extends Text {
334
+ /** 稳定部分的长度(不需要动画) */
335
+ stableLength?: number;
336
+ /** 临时的文本片段,用于渐入动画 */
337
+ chunks?: TextChunk[];
338
+ }
315
339
  /**
316
340
  * 计算 AST 节点的总字符数
317
341
  */
318
342
  declare function countChars(node: RootContent): number;
343
+ /**
344
+ * 累积的 chunks 信息
345
+ */
346
+ interface AccumulatedChunks {
347
+ /** 已经稳定显示的字符数(不需要动画) */
348
+ stableChars: number;
349
+ /** 累积的 chunk 列表 */
350
+ chunks: TextChunk[];
351
+ }
319
352
  /**
320
353
  * 截断 AST 节点,只保留前 maxChars 个字符
354
+ * 支持 chunks(用于渐入动画)
321
355
  *
322
356
  * @param node 原始节点
323
357
  * @param maxChars 最大字符数
358
+ * @param accumulatedChunks 累积的 chunks 信息(用于渐入动画)
324
359
  * @returns 截断后的节点,如果 maxChars <= 0 返回 null
325
360
  */
326
- declare function sliceAst(node: RootContent, maxChars: number): RootContent | null;
361
+ declare function sliceAst(node: RootContent, maxChars: number, accumulatedChunks?: AccumulatedChunks): RootContent | null;
327
362
  /**
328
363
  * 深拷贝 AST 节点
329
364
  */
@@ -381,4 +416,4 @@ declare const allPlugins: TransformerPlugin[];
381
416
  */
382
417
  declare function createPlugin(name: string, matcher: (node: RootContent) => boolean, options?: Partial<Omit<TransformerPlugin, 'name' | 'match'>>): TransformerPlugin;
383
418
 
384
- export { type AnimationEffect, BlockTransformer, type DisplayBlock, IncremarkParser, IncrementalUpdate, ParsedBlock, ParserOptions, ParserState, type SourceBlock, type TransformerOptions, type TransformerPlugin, type TransformerState, allPlugins, cloneNode, codeBlockPlugin, countChars, createBlockTransformer, createIncremarkParser, createPlugin, defaultPlugins, imagePlugin, mathPlugin, mermaidPlugin, sliceAst, thematicBreakPlugin };
419
+ export { type AnimationEffect, BlockTransformer, type DisplayBlock, IncremarkParser, IncrementalUpdate, ParsedBlock, ParserOptions, ParserState, type SourceBlock, type TextChunk, type TextNodeWithChunks, type TransformerOptions, type TransformerPlugin, type TransformerState, allPlugins, cloneNode, codeBlockPlugin, countChars, createBlockTransformer, createIncremarkParser, createPlugin, defaultPlugins, imagePlugin, mathPlugin, mermaidPlugin, sliceAst, thematicBreakPlugin };
package/dist/index.js CHANGED
@@ -537,16 +537,63 @@ function countChars(node) {
537
537
  traverse(node);
538
538
  return count;
539
539
  }
540
- function sliceAst(node, maxChars) {
540
+ function sliceAst(node, maxChars, accumulatedChunks) {
541
541
  if (maxChars <= 0) return null;
542
542
  let remaining = maxChars;
543
+ let charIndex = 0;
544
+ const chunkRanges = [];
545
+ if (accumulatedChunks && accumulatedChunks.chunks.length > 0) {
546
+ let chunkStart = accumulatedChunks.stableChars;
547
+ for (const chunk of accumulatedChunks.chunks) {
548
+ chunkRanges.push({
549
+ start: chunkStart,
550
+ end: chunkStart + chunk.text.length,
551
+ chunk
552
+ });
553
+ chunkStart += chunk.text.length;
554
+ }
555
+ }
543
556
  function process(n) {
544
557
  if (remaining <= 0) return null;
545
558
  if (n.value && typeof n.value === "string") {
546
559
  const take = Math.min(n.value.length, remaining);
547
560
  remaining -= take;
548
561
  if (take === 0) return null;
549
- return { ...n, value: n.value.slice(0, take) };
562
+ const slicedValue = n.value.slice(0, take);
563
+ const nodeStart = charIndex;
564
+ const nodeEnd = charIndex + take;
565
+ charIndex += take;
566
+ const result = {
567
+ ...n,
568
+ value: slicedValue
569
+ };
570
+ if (chunkRanges.length > 0 && accumulatedChunks) {
571
+ const nodeChunks = [];
572
+ let firstChunkLocalStart = take;
573
+ for (const range of chunkRanges) {
574
+ const overlapStart = Math.max(range.start, nodeStart);
575
+ const overlapEnd = Math.min(range.end, nodeEnd);
576
+ if (overlapStart < overlapEnd) {
577
+ const localStart = overlapStart - nodeStart;
578
+ const localEnd = overlapEnd - nodeStart;
579
+ const chunkText = slicedValue.slice(localStart, localEnd);
580
+ if (chunkText.length > 0) {
581
+ if (nodeChunks.length === 0) {
582
+ firstChunkLocalStart = localStart;
583
+ }
584
+ nodeChunks.push({
585
+ text: chunkText,
586
+ createdAt: range.chunk.createdAt
587
+ });
588
+ }
589
+ }
590
+ }
591
+ if (nodeChunks.length > 0) {
592
+ result.stableLength = firstChunkLocalStart;
593
+ result.chunks = nodeChunks;
594
+ }
595
+ }
596
+ return result;
550
597
  }
551
598
  if (n.children && Array.isArray(n.children)) {
552
599
  const newChildren = [];
@@ -563,6 +610,7 @@ function sliceAst(node, maxChars) {
563
610
  return { ...n, children: newChildren };
564
611
  }
565
612
  remaining -= 1;
613
+ charIndex += 1;
566
614
  return { ...n };
567
615
  }
568
616
  return process(node);
@@ -579,6 +627,8 @@ var BlockTransformer = class {
579
627
  lastTickTime = 0;
580
628
  isRunning = false;
581
629
  isPaused = false;
630
+ chunks = [];
631
+ // 累积的 chunks(用于 fade-in 动画)
582
632
  visibilityHandler = null;
583
633
  constructor(options = {}) {
584
634
  this.options = {
@@ -614,10 +664,14 @@ var BlockTransformer = class {
614
664
  if (this.state.currentBlock) {
615
665
  const updated = blocks.find((b) => b.id === this.state.currentBlock.id);
616
666
  if (updated && updated.node !== this.state.currentBlock.node) {
667
+ const oldTotal = this.countChars(this.state.currentBlock.node);
668
+ const newTotal = this.countChars(updated.node);
669
+ if (newTotal < oldTotal || newTotal < this.state.currentProgress) {
670
+ this.state.currentProgress = Math.min(this.state.currentProgress, newTotal);
671
+ }
617
672
  this.state.currentBlock = updated;
618
673
  if (!this.rafId && !this.isPaused) {
619
- const total = this.countChars(updated.node);
620
- if (this.state.currentProgress < total) {
674
+ if (this.state.currentProgress < newTotal) {
621
675
  this.startIfNeeded();
622
676
  }
623
677
  }
@@ -653,6 +707,7 @@ var BlockTransformer = class {
653
707
  currentProgress: 0,
654
708
  pendingBlocks: []
655
709
  };
710
+ this.chunks = [];
656
711
  this.emit();
657
712
  }
658
713
  /**
@@ -666,6 +721,7 @@ var BlockTransformer = class {
666
721
  currentProgress: 0,
667
722
  pendingBlocks: []
668
723
  };
724
+ this.chunks = [];
669
725
  this.emit();
670
726
  }
671
727
  /**
@@ -699,7 +755,12 @@ var BlockTransformer = class {
699
755
  }
700
756
  if (this.state.currentBlock) {
701
757
  const total = this.countChars(this.state.currentBlock.node);
702
- const displayNode = this.sliceNode(this.state.currentBlock.node, this.state.currentProgress);
758
+ const accumulatedChunks = this.options.effect === "fade-in" && this.chunks.length > 0 ? { stableChars: 0, chunks: this.chunks } : void 0;
759
+ const displayNode = this.sliceNode(
760
+ this.state.currentBlock.node,
761
+ this.state.currentProgress,
762
+ accumulatedChunks
763
+ );
703
764
  result.push({
704
765
  ...this.state.currentBlock,
705
766
  displayNode: displayNode || { type: "paragraph", children: [] },
@@ -834,16 +895,56 @@ var BlockTransformer = class {
834
895
  }
835
896
  const total = this.countChars(block.node);
836
897
  const step = this.getStep();
837
- this.state.currentProgress = Math.min(this.state.currentProgress + step, total);
898
+ const prevProgress = this.state.currentProgress;
899
+ this.state.currentProgress = Math.min(prevProgress + step, total);
900
+ if (this.options.effect === "fade-in" && this.state.currentProgress > prevProgress) {
901
+ const newText = this.extractText(block.node, prevProgress, this.state.currentProgress);
902
+ if (newText.length > 0) {
903
+ this.chunks.push({
904
+ text: newText,
905
+ createdAt: Date.now()
906
+ });
907
+ }
908
+ }
838
909
  this.emit();
839
910
  if (this.state.currentProgress >= total) {
840
911
  this.notifyComplete(block.node);
841
912
  this.state.completedBlocks.push(block);
842
913
  this.state.currentBlock = null;
843
914
  this.state.currentProgress = 0;
915
+ this.chunks = [];
844
916
  this.processNext();
845
917
  }
846
918
  }
919
+ /**
920
+ * 从 AST 节点中提取指定范围的文本
921
+ */
922
+ extractText(node, start, end) {
923
+ let result = "";
924
+ let charIndex = 0;
925
+ function traverse(n) {
926
+ if (charIndex >= end) return false;
927
+ if (n.value && typeof n.value === "string") {
928
+ const nodeStart = charIndex;
929
+ const nodeEnd = charIndex + n.value.length;
930
+ charIndex = nodeEnd;
931
+ const overlapStart = Math.max(start, nodeStart);
932
+ const overlapEnd = Math.min(end, nodeEnd);
933
+ if (overlapStart < overlapEnd) {
934
+ result += n.value.slice(overlapStart - nodeStart, overlapEnd - nodeStart);
935
+ }
936
+ return charIndex < end;
937
+ }
938
+ if (n.children && Array.isArray(n.children)) {
939
+ for (const child of n.children) {
940
+ if (!traverse(child)) return false;
941
+ }
942
+ }
943
+ return true;
944
+ }
945
+ traverse(node);
946
+ return result;
947
+ }
847
948
  getStep() {
848
949
  const { charsPerTick } = this.options;
849
950
  if (typeof charsPerTick === "number") {
@@ -856,6 +957,7 @@ var BlockTransformer = class {
856
957
  if (this.state.pendingBlocks.length > 0) {
857
958
  this.state.currentBlock = this.state.pendingBlocks.shift();
858
959
  this.state.currentProgress = 0;
960
+ this.chunks = [];
859
961
  this.emit();
860
962
  } else {
861
963
  this.isRunning = false;
@@ -887,7 +989,7 @@ var BlockTransformer = class {
887
989
  }
888
990
  return countChars(node);
889
991
  }
890
- sliceNode(node, chars) {
992
+ sliceNode(node, chars, accumulatedChunks) {
891
993
  for (const plugin of this.options.plugins) {
892
994
  if (plugin.match?.(node) && plugin.sliceNode) {
893
995
  const total = this.countChars(node);
@@ -895,7 +997,7 @@ var BlockTransformer = class {
895
997
  if (result !== null) return result;
896
998
  }
897
999
  }
898
- return sliceAst(node, chars);
1000
+ return sliceAst(node, chars, accumulatedChunks);
899
1001
  }
900
1002
  notifyComplete(node) {
901
1003
  for (const plugin of this.options.plugins) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/detector/index.ts","../src/parser/IncremarkParser.ts","../src/utils/index.ts","../src/transformer/utils.ts","../src/transformer/BlockTransformer.ts","../src/transformer/plugins.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 块类型检测与边界判断\n *\n * Markdown 块级元素的识别规则\n */\n\nimport type { BlockContext, ContainerConfig, ContainerMatch } from '../types'\n\n// ============ 代码块检测 ============\n\n/**\n * 检测行是否是代码块 fence 开始\n */\nexport function detectFenceStart(line: string): { char: string; length: number } | null {\n const match = line.match(/^(\\s*)((`{3,})|(~{3,}))/)\n if (match) {\n const fence = match[2]\n const char = fence[0]\n return { char, length: fence.length }\n }\n return null\n}\n\n/**\n * 检测行是否是代码块 fence 结束\n */\nexport function detectFenceEnd(line: string, context: BlockContext): boolean {\n if (!context.inFencedCode || !context.fenceChar || !context.fenceLength) {\n return false\n }\n\n const pattern = new RegExp(`^\\\\s{0,3}${context.fenceChar}{${context.fenceLength},}\\\\s*$`)\n return pattern.test(line)\n}\n\n// ============ 行类型检测 ============\n\n/**\n * 检测是否是空行或仅包含空白字符\n */\nexport function isEmptyLine(line: string): boolean {\n return /^\\s*$/.test(line)\n}\n\n/**\n * 检测是否是标题行\n */\nexport function isHeading(line: string): boolean {\n return /^#{1,6}\\s/.test(line)\n}\n\n/**\n * 检测是否是 thematic break(水平线)\n */\nexport function isThematicBreak(line: string): boolean {\n return /^(\\*{3,}|-{3,}|_{3,})\\s*$/.test(line.trim())\n}\n\n/**\n * 检测是否是列表项开始\n */\nexport function isListItemStart(line: string): { ordered: boolean; indent: number } | null {\n // 无序列表: - * +\n const unordered = line.match(/^(\\s*)([-*+])\\s/)\n if (unordered) {\n return { ordered: false, indent: unordered[1].length }\n }\n\n // 有序列表: 1. 2) 等\n const ordered = line.match(/^(\\s*)(\\d{1,9})[.)]\\s/)\n if (ordered) {\n return { ordered: true, indent: ordered[1].length }\n }\n\n return null\n}\n\n/**\n * 检测是否是引用块开始\n */\nexport function isBlockquoteStart(line: string): boolean {\n return /^\\s{0,3}>/.test(line)\n}\n\n/**\n * 检测是否是 HTML 块\n */\nexport function isHtmlBlock(line: string): boolean {\n return (\n /^\\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\\?|!\\[CDATA\\[)/i.test(line) ||\n /^\\s{0,3}<\\/?[a-zA-Z][a-zA-Z0-9-]*(\\s|>|$)/.test(line)\n )\n}\n\n/**\n * 检测表格分隔行\n */\nexport function isTableDelimiter(line: string): boolean {\n return /^\\|?\\s*:?-{3,}:?\\s*(\\|\\s*:?-{3,}:?\\s*)*\\|?$/.test(line.trim())\n}\n\n// ============ 容器检测 ============\n\n/**\n * 检测容器开始或结束\n *\n * 支持格式:\n * - ::: name 开始\n * - ::: name attr 开始(带属性)\n * - ::: 结束\n * - :::::: name 开始(更长的标记,用于嵌套)\n */\nexport function detectContainer(line: string, config?: ContainerConfig): ContainerMatch | null {\n const marker = config?.marker || ':'\n const minLength = config?.minMarkerLength || 3\n\n const escapedMarker = marker.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const pattern = new RegExp(\n `^(\\\\s*)(${escapedMarker}{${minLength},})(?:\\\\s+(\\\\w[\\\\w-]*))?(?:\\\\s+(.*))?\\\\s*$`\n )\n\n const match = line.match(pattern)\n if (!match) {\n return null\n }\n\n const markerLength = match[2].length\n const name = match[3] || ''\n const isEnd = !name && !match[4]\n\n if (!isEnd && config?.allowedNames && config.allowedNames.length > 0) {\n if (!config.allowedNames.includes(name)) {\n return null\n }\n }\n\n return { name, markerLength, isEnd }\n}\n\n/**\n * 检测容器结束\n */\nexport function detectContainerEnd(\n line: string,\n context: BlockContext,\n config?: ContainerConfig\n): boolean {\n if (!context.inContainer || !context.containerMarkerLength) {\n return false\n }\n\n const result = detectContainer(line, config)\n if (!result) {\n return false\n }\n\n return result.isEnd && result.markerLength >= context.containerMarkerLength\n}\n\n// ============ 边界检测 ============\n\n/**\n * 判断两行之间是否构成块边界\n */\nexport function isBlockBoundary(\n prevLine: string,\n currentLine: string,\n context: BlockContext\n): boolean {\n if (context.inFencedCode) {\n return detectFenceEnd(currentLine, context)\n }\n\n if (isEmptyLine(prevLine) && !isEmptyLine(currentLine)) {\n return true\n }\n\n if (isHeading(currentLine) && !isEmptyLine(prevLine)) {\n return true\n }\n\n if (isThematicBreak(currentLine)) {\n return true\n }\n\n if (detectFenceStart(currentLine)) {\n return true\n }\n\n return false\n}\n\n// ============ 上下文管理 ============\n\n/**\n * 创建初始上下文\n */\nexport function createInitialContext(): BlockContext {\n return {\n inFencedCode: false,\n listDepth: 0,\n blockquoteDepth: 0,\n inContainer: false,\n containerDepth: 0\n }\n}\n\n/**\n * 更新上下文(处理一行后)\n */\nexport function updateContext(\n line: string,\n context: BlockContext,\n containerConfig?: ContainerConfig | boolean\n): BlockContext {\n const newContext = { ...context }\n\n const containerCfg =\n containerConfig === true ? {} : containerConfig === false ? undefined : containerConfig\n\n // 代码块优先级最高\n if (context.inFencedCode) {\n if (detectFenceEnd(line, context)) {\n newContext.inFencedCode = false\n newContext.fenceChar = undefined\n newContext.fenceLength = undefined\n }\n return newContext\n }\n\n const fence = detectFenceStart(line)\n if (fence) {\n newContext.inFencedCode = true\n newContext.fenceChar = fence.char\n newContext.fenceLength = fence.length\n return newContext\n }\n\n // 容器处理\n if (containerCfg !== undefined) {\n if (context.inContainer) {\n if (detectContainerEnd(line, context, containerCfg)) {\n newContext.containerDepth = context.containerDepth - 1\n if (newContext.containerDepth === 0) {\n newContext.inContainer = false\n newContext.containerMarkerLength = undefined\n newContext.containerName = undefined\n }\n return newContext\n }\n\n const nested = detectContainer(line, containerCfg)\n if (nested && !nested.isEnd) {\n newContext.containerDepth = context.containerDepth + 1\n return newContext\n }\n } else {\n const container = detectContainer(line, containerCfg)\n if (container && !container.isEnd) {\n newContext.inContainer = true\n newContext.containerMarkerLength = container.markerLength\n newContext.containerName = container.name\n newContext.containerDepth = 1\n return newContext\n }\n }\n }\n\n return newContext\n}\n\n","/**\n * 增量 Markdown 解析器\n *\n * 设计思路:\n * 1. 维护一个文本缓冲区,接收流式输入\n * 2. 识别\"稳定边界\"(如空行、标题等),将已完成的块标记为 completed\n * 3. 对于正在接收的块,每次重新解析,但只解析该块的内容\n * 4. 复杂嵌套节点(如列表、引用)作为整体处理,直到确认完成\n */\n\nimport { fromMarkdown } from 'mdast-util-from-markdown'\nimport { gfmFromMarkdown } from 'mdast-util-gfm'\nimport { gfm } from 'micromark-extension-gfm'\nimport type { Extension as MicromarkExtension } from 'micromark-util-types'\nimport type { Extension as MdastExtension } from 'mdast-util-from-markdown'\n\nimport type {\n Root,\n RootContent,\n ParsedBlock,\n IncrementalUpdate,\n ParserOptions,\n BlockStatus,\n BlockContext,\n ContainerConfig\n} from '../types'\n\nimport {\n createInitialContext,\n updateContext,\n isEmptyLine,\n detectFenceStart,\n isHeading,\n isThematicBreak,\n isBlockquoteStart,\n isListItemStart,\n detectContainer\n} from '../detector'\n\n// ============ 解析器类 ============\n\nexport class IncremarkParser {\n private buffer = ''\n private lines: string[] = []\n /** 行偏移量前缀和:lineOffsets[i] = 第i行起始位置的偏移量 */\n private lineOffsets: number[] = [0]\n private completedBlocks: ParsedBlock[] = []\n private pendingStartLine = 0\n private blockIdCounter = 0\n private context: BlockContext\n private options: ParserOptions\n /** 缓存的容器配置,避免重复计算 */\n private cachedContainerConfig: ContainerConfig | undefined | null = null\n /** 上次 append 返回的 pending blocks,用于 getAst 复用 */\n private lastPendingBlocks: ParsedBlock[] = []\n\n constructor(options: ParserOptions = {}) {\n this.options = {\n gfm: true,\n ...options\n }\n this.context = createInitialContext()\n // 初始化容器配置缓存\n this.cachedContainerConfig = this.computeContainerConfig()\n }\n\n private generateBlockId(): string {\n return `block-${++this.blockIdCounter}`\n }\n\n private computeContainerConfig(): ContainerConfig | undefined {\n const containers = this.options.containers\n if (!containers) return undefined\n return containers === true ? {} : containers\n }\n\n private getContainerConfig(): ContainerConfig | undefined {\n return this.cachedContainerConfig ?? undefined\n }\n\n private parse(text: string): Root {\n const extensions: MicromarkExtension[] = []\n const mdastExtensions: MdastExtension[] = []\n\n if (this.options.gfm) {\n extensions.push(gfm())\n mdastExtensions.push(...gfmFromMarkdown())\n }\n\n // 如果用户传入了自定义扩展,添加它们\n if (this.options.extensions) {\n extensions.push(...this.options.extensions)\n }\n if (this.options.mdastExtensions) {\n mdastExtensions.push(...this.options.mdastExtensions)\n }\n\n return fromMarkdown(text, { extensions, mdastExtensions })\n }\n\n /**\n * 增量更新 lines 和 lineOffsets\n * 只处理新增的内容,避免全量 split\n */\n private updateLines(): void {\n const prevLineCount = this.lines.length\n\n if (prevLineCount === 0) {\n // 首次输入,直接 split\n this.lines = this.buffer.split('\\n')\n this.lineOffsets = [0]\n for (let i = 0; i < this.lines.length; i++) {\n this.lineOffsets.push(this.lineOffsets[i] + this.lines[i].length + 1)\n }\n return\n }\n\n // 找到最后一个不完整的行(可能被新 chunk 续上)\n const lastLineStart = this.lineOffsets[prevLineCount - 1]\n const textFromLastLine = this.buffer.slice(lastLineStart)\n\n // 重新 split 最后一行及之后的内容\n const newLines = textFromLastLine.split('\\n')\n\n // 替换最后一行并追加新行\n this.lines.length = prevLineCount - 1\n this.lineOffsets.length = prevLineCount\n\n for (let i = 0; i < newLines.length; i++) {\n this.lines.push(newLines[i])\n const prevOffset = this.lineOffsets[this.lineOffsets.length - 1]\n this.lineOffsets.push(prevOffset + newLines[i].length + 1)\n }\n }\n\n /**\n * O(1) 获取行偏移量\n */\n private getLineOffset(lineIndex: number): number {\n return this.lineOffsets[lineIndex] ?? 0\n }\n\n /**\n * 查找稳定边界\n * 返回稳定边界行号和该行对应的上下文(用于后续更新,避免重复计算)\n */\n private findStableBoundary(): { line: number; contextAtLine: BlockContext } {\n let stableLine = -1\n let stableContext: BlockContext = this.context\n let tempContext = { ...this.context }\n const containerConfig = this.getContainerConfig()\n\n for (let i = this.pendingStartLine; i < this.lines.length; i++) {\n const line = this.lines[i]\n const wasInFencedCode = tempContext.inFencedCode\n const wasInContainer = tempContext.inContainer\n const wasContainerDepth = tempContext.containerDepth\n\n tempContext = updateContext(line, tempContext, containerConfig)\n\n if (wasInFencedCode && !tempContext.inFencedCode) {\n if (i < this.lines.length - 1) {\n stableLine = i\n stableContext = { ...tempContext }\n }\n continue\n }\n\n if (tempContext.inFencedCode) {\n continue\n }\n\n if (wasInContainer && wasContainerDepth === 1 && !tempContext.inContainer) {\n if (i < this.lines.length - 1) {\n stableLine = i\n stableContext = { ...tempContext }\n }\n continue\n }\n\n if (tempContext.inContainer) {\n continue\n }\n\n const stablePoint = this.checkStability(i, containerConfig)\n if (stablePoint >= 0) {\n stableLine = stablePoint\n stableContext = { ...tempContext }\n }\n }\n\n return { line: stableLine, contextAtLine: stableContext }\n }\n\n private checkStability(\n lineIndex: number,\n containerConfig: ContainerConfig | undefined\n ): number {\n // 第一行永远不稳定\n if (lineIndex === 0) {\n return -1\n }\n\n const line = this.lines[lineIndex]\n const prevLine = this.lines[lineIndex - 1]\n\n // 前一行是独立块(标题、分割线),该块已完成\n if (isHeading(prevLine) || isThematicBreak(prevLine)) {\n return lineIndex - 1\n }\n\n // 最后一行不稳定(可能还有更多内容)\n if (lineIndex >= this.lines.length - 1) {\n return -1\n }\n\n // 前一行非空时,如果当前行是新块开始,则前一块已完成\n if (!isEmptyLine(prevLine)) {\n // 新标题开始\n if (isHeading(line)) {\n return lineIndex - 1\n }\n\n // 新代码块开始\n if (detectFenceStart(line)) {\n return lineIndex - 1\n }\n\n // 新引用块开始(排除连续引用)\n if (isBlockquoteStart(line) && !isBlockquoteStart(prevLine)) {\n return lineIndex - 1\n }\n\n // 新列表开始(排除连续列表项)\n if (isListItemStart(line) && !isListItemStart(prevLine)) {\n return lineIndex - 1\n }\n\n // 新容器开始\n if (containerConfig !== undefined) {\n const container = detectContainer(line, containerConfig)\n if (container && !container.isEnd) {\n const prevContainer = detectContainer(prevLine, containerConfig)\n if (!prevContainer || prevContainer.isEnd) {\n return lineIndex - 1\n }\n }\n }\n }\n\n // 空行标志段落结束\n if (isEmptyLine(line) && !isEmptyLine(prevLine)) {\n return lineIndex\n }\n\n return -1\n }\n\n private nodesToBlocks(\n nodes: RootContent[],\n startOffset: number,\n rawText: string,\n status: BlockStatus\n ): ParsedBlock[] {\n const blocks: ParsedBlock[] = []\n let currentOffset = startOffset\n\n for (const node of nodes) {\n const nodeStart = node.position?.start?.offset ?? currentOffset\n const nodeEnd = node.position?.end?.offset ?? currentOffset + 1\n const nodeText = rawText.substring(nodeStart - startOffset, nodeEnd - startOffset)\n\n blocks.push({\n id: this.generateBlockId(),\n status,\n node,\n startOffset: nodeStart,\n endOffset: nodeEnd,\n rawText: nodeText\n })\n\n currentOffset = nodeEnd\n }\n\n return blocks\n }\n\n /**\n * 追加新的 chunk 并返回增量更新\n */\n append(chunk: string): IncrementalUpdate {\n this.buffer += chunk\n this.updateLines()\n\n const { line: stableBoundary, contextAtLine } = this.findStableBoundary()\n\n const update: IncrementalUpdate = {\n completed: [],\n updated: [],\n pending: [],\n ast: { type: 'root', children: [] }\n }\n\n if (stableBoundary >= this.pendingStartLine && stableBoundary >= 0) {\n const stableText = this.lines.slice(this.pendingStartLine, stableBoundary + 1).join('\\n')\n const stableOffset = this.getLineOffset(this.pendingStartLine)\n\n const ast = this.parse(stableText)\n const newBlocks = this.nodesToBlocks(ast.children, stableOffset, stableText, 'completed')\n\n this.completedBlocks.push(...newBlocks)\n update.completed = newBlocks\n\n // 直接使用 findStableBoundary 计算好的上下文,避免重复遍历\n this.context = contextAtLine\n this.pendingStartLine = stableBoundary + 1\n }\n\n if (this.pendingStartLine < this.lines.length) {\n const pendingText = this.lines.slice(this.pendingStartLine).join('\\n')\n\n if (pendingText.trim()) {\n const pendingOffset = this.getLineOffset(this.pendingStartLine)\n const ast = this.parse(pendingText)\n\n update.pending = this.nodesToBlocks(ast.children, pendingOffset, pendingText, 'pending')\n }\n }\n\n // 缓存 pending blocks 供 getAst 使用\n this.lastPendingBlocks = update.pending\n\n update.ast = {\n type: 'root',\n children: [...this.completedBlocks.map((b) => b.node), ...update.pending.map((b) => b.node)]\n }\n\n // 触发状态变化回调\n this.emitChange(update.pending)\n\n return update\n }\n\n /**\n * 触发状态变化回调\n */\n private emitChange(pendingBlocks: ParsedBlock[] = []): void {\n if (this.options.onChange) {\n this.options.onChange({\n completedBlocks: this.completedBlocks,\n pendingBlocks,\n markdown: this.buffer,\n ast: {\n type: 'root',\n children: [\n ...this.completedBlocks.map((b) => b.node),\n ...pendingBlocks.map((b) => b.node)\n ]\n }\n })\n }\n }\n\n /**\n * 标记解析完成,处理剩余内容\n * 也可用于强制中断时(如用户点击停止),将 pending 内容标记为 completed\n */\n finalize(): IncrementalUpdate {\n const update: IncrementalUpdate = {\n completed: [],\n updated: [],\n pending: [],\n ast: { type: 'root', children: [] }\n }\n\n if (this.pendingStartLine < this.lines.length) {\n const remainingText = this.lines.slice(this.pendingStartLine).join('\\n')\n\n if (remainingText.trim()) {\n const remainingOffset = this.getLineOffset(this.pendingStartLine)\n const ast = this.parse(remainingText)\n\n const finalBlocks = this.nodesToBlocks(\n ast.children,\n remainingOffset,\n remainingText,\n 'completed'\n )\n\n this.completedBlocks.push(...finalBlocks)\n update.completed = finalBlocks\n }\n }\n\n // 清空 pending 缓存\n this.lastPendingBlocks = []\n this.pendingStartLine = this.lines.length\n\n update.ast = {\n type: 'root',\n children: this.completedBlocks.map((b) => b.node)\n }\n\n // 触发状态变化回调\n this.emitChange([])\n\n return update\n }\n\n /**\n * 强制中断解析,将所有待处理内容标记为完成\n * 语义上等同于 finalize(),但名称更清晰\n */\n abort(): IncrementalUpdate {\n return this.finalize()\n }\n\n /**\n * 获取当前完整的 AST\n * 复用上次 append 的 pending 结果,避免重复解析\n */\n getAst(): Root {\n return {\n type: 'root',\n children: [\n ...this.completedBlocks.map((b) => b.node),\n ...this.lastPendingBlocks.map((b) => b.node)\n ]\n }\n }\n\n /**\n * 获取所有已完成的块\n */\n getCompletedBlocks(): ParsedBlock[] {\n return [...this.completedBlocks]\n }\n\n /**\n * 获取当前缓冲区内容\n */\n getBuffer(): string {\n return this.buffer\n }\n\n /**\n * 设置状态变化回调(用于 DevTools 等)\n */\n setOnChange(callback: ((state: import('../types').ParserState) => void) | undefined): void {\n this.options.onChange = callback\n }\n\n /**\n * 重置解析器状态\n */\n reset(): void {\n this.buffer = ''\n this.lines = []\n this.lineOffsets = [0]\n this.completedBlocks = []\n this.pendingStartLine = 0\n this.blockIdCounter = 0\n this.context = createInitialContext()\n this.lastPendingBlocks = []\n\n // 触发状态变化回调\n this.emitChange([])\n }\n\n /**\n * 一次性渲染完整 Markdown(reset + append + finalize)\n * @param content 完整的 Markdown 内容\n * @returns 解析结果\n */\n render(content: string): IncrementalUpdate {\n this.reset()\n this.append(content)\n return this.finalize()\n }\n}\n\n/**\n * 创建 Incremark 解析器实例\n */\nexport function createIncremarkParser(options?: ParserOptions): IncremarkParser {\n return new IncremarkParser(options)\n}\n","/**\n * 工具函数\n */\n\n/**\n * 生成唯一 ID\n */\nlet idCounter = 0\nexport function generateId(prefix = 'block'): string {\n return `${prefix}-${++idCounter}`\n}\n\n/**\n * 重置 ID 计数器(用于测试)\n */\nexport function resetIdCounter(): void {\n idCounter = 0\n}\n\n/**\n * 计算行的偏移量\n */\nexport function calculateLineOffset(lines: string[], lineIndex: number): number {\n let offset = 0\n for (let i = 0; i < lineIndex && i < lines.length; i++) {\n offset += lines[i].length + 1 // +1 for newline\n }\n return offset\n}\n\n/**\n * 将文本按行分割\n */\nexport function splitLines(text: string): string[] {\n return text.split('\\n')\n}\n\n/**\n * 合并行为文本\n */\nexport function joinLines(lines: string[], start: number, end: number): string {\n return lines.slice(start, end + 1).join('\\n')\n}\n\n","import type { RootContent } from 'mdast'\n\n/**\n * 计算 AST 节点的总字符数\n */\nexport function countChars(node: RootContent): number {\n let count = 0\n\n function traverse(n: any): void {\n // 文本类节点\n if (n.value && typeof n.value === 'string') {\n count += n.value.length\n return\n }\n\n // 容器节点,递归处理子节点\n if (n.children && Array.isArray(n.children)) {\n for (const child of n.children) {\n traverse(child)\n }\n }\n }\n\n traverse(node)\n return count\n}\n\n/**\n * 截断 AST 节点,只保留前 maxChars 个字符\n * \n * @param node 原始节点\n * @param maxChars 最大字符数\n * @returns 截断后的节点,如果 maxChars <= 0 返回 null\n */\nexport function sliceAst(node: RootContent, maxChars: number): RootContent | null {\n if (maxChars <= 0) return null\n\n let remaining = maxChars\n\n function process(n: any): any {\n if (remaining <= 0) return null\n\n // 文本类节点:截断 value\n if (n.value && typeof n.value === 'string') {\n const take = Math.min(n.value.length, remaining)\n remaining -= take\n if (take === 0) return null\n return { ...n, value: n.value.slice(0, take) }\n }\n\n // 容器节点:递归处理 children\n if (n.children && Array.isArray(n.children)) {\n const newChildren: any[] = []\n for (const child of n.children) {\n if (remaining <= 0) break\n const processed = process(child)\n if (processed) {\n newChildren.push(processed)\n }\n }\n // 如果没有 children 了,根据节点类型决定是否保留\n if (newChildren.length === 0) {\n // 对于某些容器节点,即使没有内容也应该保留结构\n // 例如 list 节点如果没有 children 就不应该渲染\n return null\n }\n return { ...n, children: newChildren }\n }\n\n // 其他节点(如 thematicBreak, image):整体处理\n // 算作 1 个字符的消耗\n remaining -= 1\n return { ...n }\n }\n\n return process(node)\n}\n\n/**\n * 深拷贝 AST 节点\n */\nexport function cloneNode<T extends RootContent>(node: T): T {\n return JSON.parse(JSON.stringify(node))\n}\n\n","import type { RootContent } from 'mdast'\nimport type {\n SourceBlock,\n DisplayBlock,\n TransformerOptions,\n TransformerState,\n TransformerPlugin,\n AnimationEffect\n} from './types'\nimport { countChars as defaultCountChars, sliceAst as defaultSliceAst } from './utils'\n\n/**\n * Block Transformer\n *\n * 用于控制 blocks 的逐步显示(打字机效果)\n * 作为解析器和渲染器之间的中间层\n *\n * 特性:\n * - 使用 requestAnimationFrame 实现流畅动画\n * - 支持随机步长,模拟真实打字效果\n * - 支持 typing 动画效果\n * - 页面不可见时自动暂停,节省资源\n * - 插件系统支持自定义节点处理\n *\n * @example\n * ```typescript\n * const transformer = new BlockTransformer({\n * charsPerTick: [1, 3], // 随机 1-3 个字符\n * tickInterval: 30,\n * effect: 'typing',\n * onChange: (displayBlocks) => {\n * // 更新 UI\n * }\n * })\n *\n * // 推入新 blocks\n * transformer.push(blocks)\n *\n * // 获取当前显示状态\n * const displayBlocks = transformer.getDisplayBlocks()\n * ```\n */\nexport class BlockTransformer<T = unknown> {\n private state: TransformerState<T>\n private options: {\n charsPerTick: number | [number, number]\n tickInterval: number\n effect: AnimationEffect\n plugins: TransformerPlugin[]\n onChange: (displayBlocks: DisplayBlock<T>[]) => void\n pauseOnHidden: boolean\n }\n private rafId: number | null = null\n private lastTickTime = 0\n private isRunning = false\n private isPaused = false\n private visibilityHandler: (() => void) | null = null\n\n constructor(options: TransformerOptions = {}) {\n this.options = {\n charsPerTick: options.charsPerTick ?? 1,\n tickInterval: options.tickInterval ?? 20,\n effect: options.effect ?? 'none',\n plugins: options.plugins ?? [],\n onChange: options.onChange ?? (() => {}),\n pauseOnHidden: options.pauseOnHidden ?? true\n }\n\n this.state = {\n completedBlocks: [],\n currentBlock: null,\n currentProgress: 0,\n pendingBlocks: []\n }\n\n // 设置页面可见性监听\n if (this.options.pauseOnHidden && typeof document !== 'undefined') {\n this.setupVisibilityHandler()\n }\n }\n\n /**\n * 推入新的 blocks\n * 会自动过滤已存在的 blocks\n */\n push(blocks: SourceBlock<T>[]): void {\n const existingIds = this.getAllBlockIds()\n\n // 找出新增的 blocks\n const newBlocks = blocks.filter((b) => !existingIds.has(b.id))\n\n if (newBlocks.length > 0) {\n this.state.pendingBlocks.push(...newBlocks)\n this.startIfNeeded()\n }\n\n // 如果当前正在显示的 block 内容更新了(pending block 变化)\n if (this.state.currentBlock) {\n const updated = blocks.find((b) => b.id === this.state.currentBlock!.id)\n if (updated && updated.node !== this.state.currentBlock.node) {\n // 内容增加了,更新引用\n this.state.currentBlock = updated\n // 如果之前暂停了(因为到达末尾),重新开始\n if (!this.rafId && !this.isPaused) {\n const total = this.countChars(updated.node)\n if (this.state.currentProgress < total) {\n this.startIfNeeded()\n }\n }\n }\n }\n }\n\n /**\n * 更新指定 block(用于 pending block 内容增加时)\n */\n update(block: SourceBlock<T>): void {\n if (this.state.currentBlock?.id === block.id) {\n const oldTotal = this.countChars(this.state.currentBlock.node)\n const newTotal = this.countChars(block.node)\n\n this.state.currentBlock = block\n\n // 如果内容增加了且之前暂停了,继续\n if (newTotal > oldTotal && !this.rafId && !this.isPaused && this.state.currentProgress >= oldTotal) {\n this.startIfNeeded()\n }\n }\n }\n\n /**\n * 跳过所有动画,直接显示全部内容\n */\n skip(): void {\n this.stop()\n\n const allBlocks = [\n ...this.state.completedBlocks,\n ...(this.state.currentBlock ? [this.state.currentBlock] : []),\n ...this.state.pendingBlocks\n ]\n\n this.state = {\n completedBlocks: allBlocks,\n currentBlock: null,\n currentProgress: 0,\n pendingBlocks: []\n }\n\n this.emit()\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.stop()\n this.state = {\n completedBlocks: [],\n currentBlock: null,\n currentProgress: 0,\n pendingBlocks: []\n }\n this.emit()\n }\n\n /**\n * 暂停动画\n */\n pause(): void {\n this.isPaused = true\n this.cancelRaf()\n }\n\n /**\n * 恢复动画\n */\n resume(): void {\n if (this.isPaused) {\n this.isPaused = false\n this.startIfNeeded()\n }\n }\n\n /**\n * 获取用于渲染的 display blocks\n */\n getDisplayBlocks(): DisplayBlock<T>[] {\n const result: DisplayBlock<T>[] = []\n\n // 已完成的 blocks\n for (const block of this.state.completedBlocks) {\n result.push({\n ...block,\n displayNode: block.node,\n progress: 1,\n isDisplayComplete: true\n })\n }\n\n // 当前正在显示的 block\n if (this.state.currentBlock) {\n const total = this.countChars(this.state.currentBlock.node)\n const displayNode = this.sliceNode(this.state.currentBlock.node, this.state.currentProgress)\n\n result.push({\n ...this.state.currentBlock,\n displayNode: displayNode || { type: 'paragraph', children: [] },\n progress: total > 0 ? this.state.currentProgress / total : 1,\n isDisplayComplete: false\n })\n }\n\n return result\n }\n\n /**\n * 是否正在处理中\n */\n isProcessing(): boolean {\n return this.isRunning || this.state.currentBlock !== null || this.state.pendingBlocks.length > 0\n }\n\n /**\n * 是否已暂停\n */\n isPausedState(): boolean {\n return this.isPaused\n }\n\n /**\n * 获取内部状态(用于调试)\n */\n getState(): Readonly<TransformerState<T>> {\n return { ...this.state }\n }\n\n /**\n * 动态更新配置\n */\n setOptions(options: Partial<Pick<TransformerOptions, 'charsPerTick' | 'tickInterval' | 'effect' | 'pauseOnHidden'>>): void {\n if (options.charsPerTick !== undefined) {\n this.options.charsPerTick = options.charsPerTick\n }\n if (options.tickInterval !== undefined) {\n this.options.tickInterval = options.tickInterval\n }\n if (options.effect !== undefined) {\n this.options.effect = options.effect\n }\n if (options.pauseOnHidden !== undefined) {\n this.options.pauseOnHidden = options.pauseOnHidden\n if (options.pauseOnHidden && typeof document !== 'undefined') {\n this.setupVisibilityHandler()\n } else {\n this.removeVisibilityHandler()\n }\n }\n }\n\n /**\n * 获取当前配置\n */\n getOptions(): { \n charsPerTick: number | [number, number]\n tickInterval: number\n effect: AnimationEffect\n } {\n return {\n charsPerTick: this.options.charsPerTick,\n tickInterval: this.options.tickInterval,\n effect: this.options.effect\n }\n }\n\n /**\n * 获取当前动画效果\n */\n getEffect(): AnimationEffect {\n return this.options.effect\n }\n\n /**\n * 销毁,清理资源\n */\n destroy(): void {\n this.stop()\n this.removeVisibilityHandler()\n }\n\n // ============ 私有方法 ============\n\n private getAllBlockIds(): Set<string> {\n return new Set([\n ...this.state.completedBlocks.map((b) => b.id),\n this.state.currentBlock?.id,\n ...this.state.pendingBlocks.map((b) => b.id)\n ].filter((id): id is string => id !== undefined))\n }\n\n private setupVisibilityHandler(): void {\n if (this.visibilityHandler) return\n\n this.visibilityHandler = () => {\n if (document.hidden) {\n this.pause()\n } else {\n this.resume()\n }\n }\n\n document.addEventListener('visibilitychange', this.visibilityHandler)\n }\n\n private removeVisibilityHandler(): void {\n if (this.visibilityHandler) {\n document.removeEventListener('visibilitychange', this.visibilityHandler)\n this.visibilityHandler = null\n }\n }\n\n private startIfNeeded(): void {\n if (this.rafId || this.isPaused) return\n\n if (!this.state.currentBlock && this.state.pendingBlocks.length > 0) {\n this.state.currentBlock = this.state.pendingBlocks.shift()!\n this.state.currentProgress = 0\n }\n\n if (this.state.currentBlock) {\n this.isRunning = true\n this.lastTickTime = 0\n this.scheduleNextFrame()\n }\n }\n\n private scheduleNextFrame(): void {\n this.rafId = requestAnimationFrame((time) => this.animationFrame(time))\n }\n\n private animationFrame(time: number): void {\n this.rafId = null\n\n // 计算是否应该执行 tick\n if (this.lastTickTime === 0) {\n this.lastTickTime = time\n }\n\n const elapsed = time - this.lastTickTime\n\n if (elapsed >= this.options.tickInterval) {\n this.lastTickTime = time\n this.tick()\n }\n\n // 如果还在运行,继续调度\n if (this.isRunning && !this.isPaused) {\n this.scheduleNextFrame()\n }\n }\n\n private tick(): void {\n const block = this.state.currentBlock\n if (!block) {\n this.processNext()\n return\n }\n\n const total = this.countChars(block.node)\n const step = this.getStep()\n \n this.state.currentProgress = Math.min(this.state.currentProgress + step, total)\n\n this.emit()\n\n if (this.state.currentProgress >= total) {\n // 当前 block 完成\n this.notifyComplete(block.node)\n this.state.completedBlocks.push(block)\n this.state.currentBlock = null\n this.state.currentProgress = 0\n this.processNext()\n }\n }\n\n private getStep(): number {\n const { charsPerTick } = this.options\n if (typeof charsPerTick === 'number') {\n return charsPerTick\n }\n // 随机步长\n const [min, max] = charsPerTick\n return Math.floor(Math.random() * (max - min + 1)) + min\n }\n\n private processNext(): void {\n if (this.state.pendingBlocks.length > 0) {\n this.state.currentBlock = this.state.pendingBlocks.shift()!\n this.state.currentProgress = 0\n this.emit()\n // 继续运行(rAF 已经在调度中)\n } else {\n this.isRunning = false\n this.cancelRaf()\n this.emit()\n }\n }\n\n private cancelRaf(): void {\n if (this.rafId) {\n cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n }\n\n private stop(): void {\n this.cancelRaf()\n this.isRunning = false\n this.isPaused = false\n }\n\n private emit(): void {\n this.options.onChange(this.getDisplayBlocks())\n }\n\n // ============ 插件调用 ============\n\n private countChars(node: RootContent): number {\n // 先找匹配的插件\n for (const plugin of this.options.plugins) {\n if (plugin.match?.(node) && plugin.countChars) {\n const result = plugin.countChars(node)\n if (result !== undefined) return result\n }\n }\n // 默认计算\n return defaultCountChars(node)\n }\n\n private sliceNode(node: RootContent, chars: number): RootContent | null {\n // 先找匹配的插件\n for (const plugin of this.options.plugins) {\n if (plugin.match?.(node) && plugin.sliceNode) {\n const total = this.countChars(node)\n const result = plugin.sliceNode(node, chars, total)\n if (result !== null) return result\n }\n }\n // 默认截断\n return defaultSliceAst(node, chars)\n }\n\n private notifyComplete(node: RootContent): void {\n for (const plugin of this.options.plugins) {\n if (plugin.match?.(node) && plugin.onComplete) {\n plugin.onComplete(node)\n }\n }\n }\n}\n\n/**\n * 创建 BlockTransformer 实例的工厂函数\n */\nexport function createBlockTransformer<T = unknown>(\n options?: TransformerOptions\n): BlockTransformer<T> {\n return new BlockTransformer<T>(options)\n}\n\n\n\n","import type { RootContent, Code } from 'mdast'\nimport type { TransformerPlugin } from './types'\n\n/**\n * 代码块插件:整体出现,不逐字符显示\n * \n * 注意:默认不启用,代码块默认参与打字机效果\n * 如需整体显示代码块,可手动添加此插件\n */\nexport const codeBlockPlugin: TransformerPlugin = {\n name: 'code-block',\n match: (node: RootContent) => node.type === 'code',\n countChars: () => 1, // 算作 1 个字符,整体出现\n sliceNode: (node, displayedChars, totalChars) => {\n // 要么全部显示,要么不显示\n return displayedChars >= totalChars ? node : null\n }\n}\n\n/**\n * Mermaid 图表插件:整体出现\n * \n * 注意:默认不启用,mermaid 默认参与打字机效果\n * 如需整体显示 mermaid,可手动添加此插件\n */\nexport const mermaidPlugin: TransformerPlugin = {\n name: 'mermaid',\n match: (node: RootContent) => {\n if (node.type !== 'code') return false\n const codeNode = node as Code\n return codeNode.lang === 'mermaid'\n },\n countChars: () => 1,\n sliceNode: (node, displayedChars) => (displayedChars > 0 ? node : null)\n}\n\n/**\n * 图片插件:立即显示(不参与打字机效果)\n * 图片没有文本内容,应立即显示\n */\nexport const imagePlugin: TransformerPlugin = {\n name: 'image',\n match: (node: RootContent) => node.type === 'image',\n countChars: () => 0 // 0 字符,立即显示\n}\n\n/**\n * 数学公式插件:整体出现\n * \n * 注意:默认不启用,数学公式默认参与打字机效果\n * 如需整体显示公式,可手动添加此插件\n */\nexport const mathPlugin: TransformerPlugin = {\n name: 'math',\n match: (node: RootContent) => {\n const type = node.type as string\n return type === 'math' || type === 'inlineMath'\n },\n countChars: () => 1,\n sliceNode: (node, displayedChars) => (displayedChars > 0 ? node : null)\n}\n\n/**\n * 分割线插件:立即显示\n * 分隔线没有文本内容,应立即显示\n */\nexport const thematicBreakPlugin: TransformerPlugin = {\n name: 'thematic-break',\n match: (node: RootContent) => node.type === 'thematicBreak',\n countChars: () => 0\n}\n\n/**\n * 默认插件集合\n * \n * 只包含确实需要特殊处理的节点:\n * - 图片:无文本内容,立即显示\n * - 分隔线:无文本内容,立即显示\n * \n * 代码块、mermaid、数学公式默认参与打字机效果\n * 如需整体显示,可手动添加对应插件\n */\nexport const defaultPlugins: TransformerPlugin[] = [\n imagePlugin,\n thematicBreakPlugin\n]\n\n/**\n * 完整插件集合(所有特殊节点整体显示)\n * 包含代码块、mermaid、数学公式等的整体显示\n */\nexport const allPlugins: TransformerPlugin[] = [\n mermaidPlugin, // mermaid 优先于普通 code block\n codeBlockPlugin,\n imagePlugin,\n mathPlugin,\n thematicBreakPlugin\n]\n\n/**\n * 创建自定义插件的辅助函数\n */\nexport function createPlugin(\n name: string,\n matcher: (node: RootContent) => boolean,\n options: Partial<Omit<TransformerPlugin, 'name' | 'match'>> = {}\n): TransformerPlugin {\n return {\n name,\n match: matcher,\n ...options\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/detector/index.ts","../src/parser/IncremarkParser.ts","../src/utils/index.ts","../src/transformer/utils.ts","../src/transformer/BlockTransformer.ts","../src/transformer/plugins.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 块类型检测与边界判断\n *\n * Markdown 块级元素的识别规则\n */\n\nimport type { BlockContext, ContainerConfig, ContainerMatch } from '../types'\n\n// ============ 代码块检测 ============\n\n/**\n * 检测行是否是代码块 fence 开始\n */\nexport function detectFenceStart(line: string): { char: string; length: number } | null {\n const match = line.match(/^(\\s*)((`{3,})|(~{3,}))/)\n if (match) {\n const fence = match[2]\n const char = fence[0]\n return { char, length: fence.length }\n }\n return null\n}\n\n/**\n * 检测行是否是代码块 fence 结束\n */\nexport function detectFenceEnd(line: string, context: BlockContext): boolean {\n if (!context.inFencedCode || !context.fenceChar || !context.fenceLength) {\n return false\n }\n\n const pattern = new RegExp(`^\\\\s{0,3}${context.fenceChar}{${context.fenceLength},}\\\\s*$`)\n return pattern.test(line)\n}\n\n// ============ 行类型检测 ============\n\n/**\n * 检测是否是空行或仅包含空白字符\n */\nexport function isEmptyLine(line: string): boolean {\n return /^\\s*$/.test(line)\n}\n\n/**\n * 检测是否是标题行\n */\nexport function isHeading(line: string): boolean {\n return /^#{1,6}\\s/.test(line)\n}\n\n/**\n * 检测是否是 thematic break(水平线)\n */\nexport function isThematicBreak(line: string): boolean {\n return /^(\\*{3,}|-{3,}|_{3,})\\s*$/.test(line.trim())\n}\n\n/**\n * 检测是否是列表项开始\n */\nexport function isListItemStart(line: string): { ordered: boolean; indent: number } | null {\n // 无序列表: - * +\n const unordered = line.match(/^(\\s*)([-*+])\\s/)\n if (unordered) {\n return { ordered: false, indent: unordered[1].length }\n }\n\n // 有序列表: 1. 2) 等\n const ordered = line.match(/^(\\s*)(\\d{1,9})[.)]\\s/)\n if (ordered) {\n return { ordered: true, indent: ordered[1].length }\n }\n\n return null\n}\n\n/**\n * 检测是否是引用块开始\n */\nexport function isBlockquoteStart(line: string): boolean {\n return /^\\s{0,3}>/.test(line)\n}\n\n/**\n * 检测是否是 HTML 块\n */\nexport function isHtmlBlock(line: string): boolean {\n return (\n /^\\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\\?|!\\[CDATA\\[)/i.test(line) ||\n /^\\s{0,3}<\\/?[a-zA-Z][a-zA-Z0-9-]*(\\s|>|$)/.test(line)\n )\n}\n\n/**\n * 检测表格分隔行\n */\nexport function isTableDelimiter(line: string): boolean {\n return /^\\|?\\s*:?-{3,}:?\\s*(\\|\\s*:?-{3,}:?\\s*)*\\|?$/.test(line.trim())\n}\n\n// ============ 容器检测 ============\n\n/**\n * 检测容器开始或结束\n *\n * 支持格式:\n * - ::: name 开始\n * - ::: name attr 开始(带属性)\n * - ::: 结束\n * - :::::: name 开始(更长的标记,用于嵌套)\n */\nexport function detectContainer(line: string, config?: ContainerConfig): ContainerMatch | null {\n const marker = config?.marker || ':'\n const minLength = config?.minMarkerLength || 3\n\n const escapedMarker = marker.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const pattern = new RegExp(\n `^(\\\\s*)(${escapedMarker}{${minLength},})(?:\\\\s+(\\\\w[\\\\w-]*))?(?:\\\\s+(.*))?\\\\s*$`\n )\n\n const match = line.match(pattern)\n if (!match) {\n return null\n }\n\n const markerLength = match[2].length\n const name = match[3] || ''\n const isEnd = !name && !match[4]\n\n if (!isEnd && config?.allowedNames && config.allowedNames.length > 0) {\n if (!config.allowedNames.includes(name)) {\n return null\n }\n }\n\n return { name, markerLength, isEnd }\n}\n\n/**\n * 检测容器结束\n */\nexport function detectContainerEnd(\n line: string,\n context: BlockContext,\n config?: ContainerConfig\n): boolean {\n if (!context.inContainer || !context.containerMarkerLength) {\n return false\n }\n\n const result = detectContainer(line, config)\n if (!result) {\n return false\n }\n\n return result.isEnd && result.markerLength >= context.containerMarkerLength\n}\n\n// ============ 边界检测 ============\n\n/**\n * 判断两行之间是否构成块边界\n */\nexport function isBlockBoundary(\n prevLine: string,\n currentLine: string,\n context: BlockContext\n): boolean {\n if (context.inFencedCode) {\n return detectFenceEnd(currentLine, context)\n }\n\n if (isEmptyLine(prevLine) && !isEmptyLine(currentLine)) {\n return true\n }\n\n if (isHeading(currentLine) && !isEmptyLine(prevLine)) {\n return true\n }\n\n if (isThematicBreak(currentLine)) {\n return true\n }\n\n if (detectFenceStart(currentLine)) {\n return true\n }\n\n return false\n}\n\n// ============ 上下文管理 ============\n\n/**\n * 创建初始上下文\n */\nexport function createInitialContext(): BlockContext {\n return {\n inFencedCode: false,\n listDepth: 0,\n blockquoteDepth: 0,\n inContainer: false,\n containerDepth: 0\n }\n}\n\n/**\n * 更新上下文(处理一行后)\n */\nexport function updateContext(\n line: string,\n context: BlockContext,\n containerConfig?: ContainerConfig | boolean\n): BlockContext {\n const newContext = { ...context }\n\n const containerCfg =\n containerConfig === true ? {} : containerConfig === false ? undefined : containerConfig\n\n // 代码块优先级最高\n if (context.inFencedCode) {\n if (detectFenceEnd(line, context)) {\n newContext.inFencedCode = false\n newContext.fenceChar = undefined\n newContext.fenceLength = undefined\n }\n return newContext\n }\n\n const fence = detectFenceStart(line)\n if (fence) {\n newContext.inFencedCode = true\n newContext.fenceChar = fence.char\n newContext.fenceLength = fence.length\n return newContext\n }\n\n // 容器处理\n if (containerCfg !== undefined) {\n if (context.inContainer) {\n if (detectContainerEnd(line, context, containerCfg)) {\n newContext.containerDepth = context.containerDepth - 1\n if (newContext.containerDepth === 0) {\n newContext.inContainer = false\n newContext.containerMarkerLength = undefined\n newContext.containerName = undefined\n }\n return newContext\n }\n\n const nested = detectContainer(line, containerCfg)\n if (nested && !nested.isEnd) {\n newContext.containerDepth = context.containerDepth + 1\n return newContext\n }\n } else {\n const container = detectContainer(line, containerCfg)\n if (container && !container.isEnd) {\n newContext.inContainer = true\n newContext.containerMarkerLength = container.markerLength\n newContext.containerName = container.name\n newContext.containerDepth = 1\n return newContext\n }\n }\n }\n\n return newContext\n}\n\n","/**\n * 增量 Markdown 解析器\n *\n * 设计思路:\n * 1. 维护一个文本缓冲区,接收流式输入\n * 2. 识别\"稳定边界\"(如空行、标题等),将已完成的块标记为 completed\n * 3. 对于正在接收的块,每次重新解析,但只解析该块的内容\n * 4. 复杂嵌套节点(如列表、引用)作为整体处理,直到确认完成\n */\n\nimport { fromMarkdown } from 'mdast-util-from-markdown'\nimport { gfmFromMarkdown } from 'mdast-util-gfm'\nimport { gfm } from 'micromark-extension-gfm'\nimport type { Extension as MicromarkExtension } from 'micromark-util-types'\nimport type { Extension as MdastExtension } from 'mdast-util-from-markdown'\n\nimport type {\n Root,\n RootContent,\n ParsedBlock,\n IncrementalUpdate,\n ParserOptions,\n BlockStatus,\n BlockContext,\n ContainerConfig\n} from '../types'\n\nimport {\n createInitialContext,\n updateContext,\n isEmptyLine,\n detectFenceStart,\n isHeading,\n isThematicBreak,\n isBlockquoteStart,\n isListItemStart,\n detectContainer\n} from '../detector'\n\n// ============ 解析器类 ============\n\nexport class IncremarkParser {\n private buffer = ''\n private lines: string[] = []\n /** 行偏移量前缀和:lineOffsets[i] = 第i行起始位置的偏移量 */\n private lineOffsets: number[] = [0]\n private completedBlocks: ParsedBlock[] = []\n private pendingStartLine = 0\n private blockIdCounter = 0\n private context: BlockContext\n private options: ParserOptions\n /** 缓存的容器配置,避免重复计算 */\n private cachedContainerConfig: ContainerConfig | undefined | null = null\n /** 上次 append 返回的 pending blocks,用于 getAst 复用 */\n private lastPendingBlocks: ParsedBlock[] = []\n\n constructor(options: ParserOptions = {}) {\n this.options = {\n gfm: true,\n ...options\n }\n this.context = createInitialContext()\n // 初始化容器配置缓存\n this.cachedContainerConfig = this.computeContainerConfig()\n }\n\n private generateBlockId(): string {\n return `block-${++this.blockIdCounter}`\n }\n\n private computeContainerConfig(): ContainerConfig | undefined {\n const containers = this.options.containers\n if (!containers) return undefined\n return containers === true ? {} : containers\n }\n\n private getContainerConfig(): ContainerConfig | undefined {\n return this.cachedContainerConfig ?? undefined\n }\n\n private parse(text: string): Root {\n const extensions: MicromarkExtension[] = []\n const mdastExtensions: MdastExtension[] = []\n\n if (this.options.gfm) {\n extensions.push(gfm())\n mdastExtensions.push(...gfmFromMarkdown())\n }\n\n // 如果用户传入了自定义扩展,添加它们\n if (this.options.extensions) {\n extensions.push(...this.options.extensions)\n }\n if (this.options.mdastExtensions) {\n mdastExtensions.push(...this.options.mdastExtensions)\n }\n\n return fromMarkdown(text, { extensions, mdastExtensions })\n }\n\n /**\n * 增量更新 lines 和 lineOffsets\n * 只处理新增的内容,避免全量 split\n */\n private updateLines(): void {\n const prevLineCount = this.lines.length\n\n if (prevLineCount === 0) {\n // 首次输入,直接 split\n this.lines = this.buffer.split('\\n')\n this.lineOffsets = [0]\n for (let i = 0; i < this.lines.length; i++) {\n this.lineOffsets.push(this.lineOffsets[i] + this.lines[i].length + 1)\n }\n return\n }\n\n // 找到最后一个不完整的行(可能被新 chunk 续上)\n const lastLineStart = this.lineOffsets[prevLineCount - 1]\n const textFromLastLine = this.buffer.slice(lastLineStart)\n\n // 重新 split 最后一行及之后的内容\n const newLines = textFromLastLine.split('\\n')\n\n // 替换最后一行并追加新行\n this.lines.length = prevLineCount - 1\n this.lineOffsets.length = prevLineCount\n\n for (let i = 0; i < newLines.length; i++) {\n this.lines.push(newLines[i])\n const prevOffset = this.lineOffsets[this.lineOffsets.length - 1]\n this.lineOffsets.push(prevOffset + newLines[i].length + 1)\n }\n }\n\n /**\n * O(1) 获取行偏移量\n */\n private getLineOffset(lineIndex: number): number {\n return this.lineOffsets[lineIndex] ?? 0\n }\n\n /**\n * 查找稳定边界\n * 返回稳定边界行号和该行对应的上下文(用于后续更新,避免重复计算)\n */\n private findStableBoundary(): { line: number; contextAtLine: BlockContext } {\n let stableLine = -1\n let stableContext: BlockContext = this.context\n let tempContext = { ...this.context }\n const containerConfig = this.getContainerConfig()\n\n for (let i = this.pendingStartLine; i < this.lines.length; i++) {\n const line = this.lines[i]\n const wasInFencedCode = tempContext.inFencedCode\n const wasInContainer = tempContext.inContainer\n const wasContainerDepth = tempContext.containerDepth\n\n tempContext = updateContext(line, tempContext, containerConfig)\n\n if (wasInFencedCode && !tempContext.inFencedCode) {\n if (i < this.lines.length - 1) {\n stableLine = i\n stableContext = { ...tempContext }\n }\n continue\n }\n\n if (tempContext.inFencedCode) {\n continue\n }\n\n if (wasInContainer && wasContainerDepth === 1 && !tempContext.inContainer) {\n if (i < this.lines.length - 1) {\n stableLine = i\n stableContext = { ...tempContext }\n }\n continue\n }\n\n if (tempContext.inContainer) {\n continue\n }\n\n const stablePoint = this.checkStability(i, containerConfig)\n if (stablePoint >= 0) {\n stableLine = stablePoint\n stableContext = { ...tempContext }\n }\n }\n\n return { line: stableLine, contextAtLine: stableContext }\n }\n\n private checkStability(\n lineIndex: number,\n containerConfig: ContainerConfig | undefined\n ): number {\n // 第一行永远不稳定\n if (lineIndex === 0) {\n return -1\n }\n\n const line = this.lines[lineIndex]\n const prevLine = this.lines[lineIndex - 1]\n\n // 前一行是独立块(标题、分割线),该块已完成\n if (isHeading(prevLine) || isThematicBreak(prevLine)) {\n return lineIndex - 1\n }\n\n // 最后一行不稳定(可能还有更多内容)\n if (lineIndex >= this.lines.length - 1) {\n return -1\n }\n\n // 前一行非空时,如果当前行是新块开始,则前一块已完成\n if (!isEmptyLine(prevLine)) {\n // 新标题开始\n if (isHeading(line)) {\n return lineIndex - 1\n }\n\n // 新代码块开始\n if (detectFenceStart(line)) {\n return lineIndex - 1\n }\n\n // 新引用块开始(排除连续引用)\n if (isBlockquoteStart(line) && !isBlockquoteStart(prevLine)) {\n return lineIndex - 1\n }\n\n // 新列表开始(排除连续列表项)\n if (isListItemStart(line) && !isListItemStart(prevLine)) {\n return lineIndex - 1\n }\n\n // 新容器开始\n if (containerConfig !== undefined) {\n const container = detectContainer(line, containerConfig)\n if (container && !container.isEnd) {\n const prevContainer = detectContainer(prevLine, containerConfig)\n if (!prevContainer || prevContainer.isEnd) {\n return lineIndex - 1\n }\n }\n }\n }\n\n // 空行标志段落结束\n if (isEmptyLine(line) && !isEmptyLine(prevLine)) {\n return lineIndex\n }\n\n return -1\n }\n\n private nodesToBlocks(\n nodes: RootContent[],\n startOffset: number,\n rawText: string,\n status: BlockStatus\n ): ParsedBlock[] {\n const blocks: ParsedBlock[] = []\n let currentOffset = startOffset\n\n for (const node of nodes) {\n const nodeStart = node.position?.start?.offset ?? currentOffset\n const nodeEnd = node.position?.end?.offset ?? currentOffset + 1\n const nodeText = rawText.substring(nodeStart - startOffset, nodeEnd - startOffset)\n\n blocks.push({\n id: this.generateBlockId(),\n status,\n node,\n startOffset: nodeStart,\n endOffset: nodeEnd,\n rawText: nodeText\n })\n\n currentOffset = nodeEnd\n }\n\n return blocks\n }\n\n /**\n * 追加新的 chunk 并返回增量更新\n */\n append(chunk: string): IncrementalUpdate {\n this.buffer += chunk\n this.updateLines()\n\n const { line: stableBoundary, contextAtLine } = this.findStableBoundary()\n\n const update: IncrementalUpdate = {\n completed: [],\n updated: [],\n pending: [],\n ast: { type: 'root', children: [] }\n }\n\n if (stableBoundary >= this.pendingStartLine && stableBoundary >= 0) {\n const stableText = this.lines.slice(this.pendingStartLine, stableBoundary + 1).join('\\n')\n const stableOffset = this.getLineOffset(this.pendingStartLine)\n\n const ast = this.parse(stableText)\n const newBlocks = this.nodesToBlocks(ast.children, stableOffset, stableText, 'completed')\n\n this.completedBlocks.push(...newBlocks)\n update.completed = newBlocks\n\n // 直接使用 findStableBoundary 计算好的上下文,避免重复遍历\n this.context = contextAtLine\n this.pendingStartLine = stableBoundary + 1\n }\n\n if (this.pendingStartLine < this.lines.length) {\n const pendingText = this.lines.slice(this.pendingStartLine).join('\\n')\n\n if (pendingText.trim()) {\n const pendingOffset = this.getLineOffset(this.pendingStartLine)\n const ast = this.parse(pendingText)\n\n update.pending = this.nodesToBlocks(ast.children, pendingOffset, pendingText, 'pending')\n }\n }\n\n // 缓存 pending blocks 供 getAst 使用\n this.lastPendingBlocks = update.pending\n\n update.ast = {\n type: 'root',\n children: [...this.completedBlocks.map((b) => b.node), ...update.pending.map((b) => b.node)]\n }\n\n // 触发状态变化回调\n this.emitChange(update.pending)\n\n return update\n }\n\n /**\n * 触发状态变化回调\n */\n private emitChange(pendingBlocks: ParsedBlock[] = []): void {\n if (this.options.onChange) {\n this.options.onChange({\n completedBlocks: this.completedBlocks,\n pendingBlocks,\n markdown: this.buffer,\n ast: {\n type: 'root',\n children: [\n ...this.completedBlocks.map((b) => b.node),\n ...pendingBlocks.map((b) => b.node)\n ]\n }\n })\n }\n }\n\n /**\n * 标记解析完成,处理剩余内容\n * 也可用于强制中断时(如用户点击停止),将 pending 内容标记为 completed\n */\n finalize(): IncrementalUpdate {\n const update: IncrementalUpdate = {\n completed: [],\n updated: [],\n pending: [],\n ast: { type: 'root', children: [] }\n }\n\n if (this.pendingStartLine < this.lines.length) {\n const remainingText = this.lines.slice(this.pendingStartLine).join('\\n')\n\n if (remainingText.trim()) {\n const remainingOffset = this.getLineOffset(this.pendingStartLine)\n const ast = this.parse(remainingText)\n\n const finalBlocks = this.nodesToBlocks(\n ast.children,\n remainingOffset,\n remainingText,\n 'completed'\n )\n\n this.completedBlocks.push(...finalBlocks)\n update.completed = finalBlocks\n }\n }\n\n // 清空 pending 缓存\n this.lastPendingBlocks = []\n this.pendingStartLine = this.lines.length\n\n update.ast = {\n type: 'root',\n children: this.completedBlocks.map((b) => b.node)\n }\n\n // 触发状态变化回调\n this.emitChange([])\n\n return update\n }\n\n /**\n * 强制中断解析,将所有待处理内容标记为完成\n * 语义上等同于 finalize(),但名称更清晰\n */\n abort(): IncrementalUpdate {\n return this.finalize()\n }\n\n /**\n * 获取当前完整的 AST\n * 复用上次 append 的 pending 结果,避免重复解析\n */\n getAst(): Root {\n return {\n type: 'root',\n children: [\n ...this.completedBlocks.map((b) => b.node),\n ...this.lastPendingBlocks.map((b) => b.node)\n ]\n }\n }\n\n /**\n * 获取所有已完成的块\n */\n getCompletedBlocks(): ParsedBlock[] {\n return [...this.completedBlocks]\n }\n\n /**\n * 获取当前缓冲区内容\n */\n getBuffer(): string {\n return this.buffer\n }\n\n /**\n * 设置状态变化回调(用于 DevTools 等)\n */\n setOnChange(callback: ((state: import('../types').ParserState) => void) | undefined): void {\n this.options.onChange = callback\n }\n\n /**\n * 重置解析器状态\n */\n reset(): void {\n this.buffer = ''\n this.lines = []\n this.lineOffsets = [0]\n this.completedBlocks = []\n this.pendingStartLine = 0\n this.blockIdCounter = 0\n this.context = createInitialContext()\n this.lastPendingBlocks = []\n\n // 触发状态变化回调\n this.emitChange([])\n }\n\n /**\n * 一次性渲染完整 Markdown(reset + append + finalize)\n * @param content 完整的 Markdown 内容\n * @returns 解析结果\n */\n render(content: string): IncrementalUpdate {\n this.reset()\n this.append(content)\n return this.finalize()\n }\n}\n\n/**\n * 创建 Incremark 解析器实例\n */\nexport function createIncremarkParser(options?: ParserOptions): IncremarkParser {\n return new IncremarkParser(options)\n}\n","/**\n * 工具函数\n */\n\n/**\n * 生成唯一 ID\n */\nlet idCounter = 0\nexport function generateId(prefix = 'block'): string {\n return `${prefix}-${++idCounter}`\n}\n\n/**\n * 重置 ID 计数器(用于测试)\n */\nexport function resetIdCounter(): void {\n idCounter = 0\n}\n\n/**\n * 计算行的偏移量\n */\nexport function calculateLineOffset(lines: string[], lineIndex: number): number {\n let offset = 0\n for (let i = 0; i < lineIndex && i < lines.length; i++) {\n offset += lines[i].length + 1 // +1 for newline\n }\n return offset\n}\n\n/**\n * 将文本按行分割\n */\nexport function splitLines(text: string): string[] {\n return text.split('\\n')\n}\n\n/**\n * 合并行为文本\n */\nexport function joinLines(lines: string[], start: number, end: number): string {\n return lines.slice(start, end + 1).join('\\n')\n}\n\n","import type { RootContent, Text, Parent } from 'mdast'\n\n/**\n * 文本块片段(用于渐入动画)\n */\nexport interface TextChunk {\n /** 文本内容 */\n text: string\n /** 创建时间戳 */\n createdAt: number\n}\n\n/**\n * 扩展的文本节点(支持 chunks)\n */\nexport interface TextNodeWithChunks extends Text {\n /** 稳定部分的长度(不需要动画) */\n stableLength?: number\n /** 临时的文本片段,用于渐入动画 */\n chunks?: TextChunk[]\n}\n\n/**\n * AST 节点的通用类型(文本节点或容器节点)\n */\ninterface AstNode {\n type: string\n value?: string\n children?: AstNode[]\n}\n\n/**\n * 计算 AST 节点的总字符数\n */\nexport function countChars(node: RootContent): number {\n let count = 0\n\n function traverse(n: AstNode): void {\n if (n.value && typeof n.value === 'string') {\n count += n.value.length\n return\n }\n if (n.children && Array.isArray(n.children)) {\n for (const child of n.children) {\n traverse(child)\n }\n }\n }\n\n traverse(node as AstNode)\n return count\n}\n\n/**\n * 累积的 chunks 信息\n */\nexport interface AccumulatedChunks {\n /** 已经稳定显示的字符数(不需要动画) */\n stableChars: number\n /** 累积的 chunk 列表 */\n chunks: TextChunk[]\n}\n\n/** chunk 范围信息 */\ninterface ChunkRange {\n start: number\n end: number\n chunk: TextChunk\n}\n\n/**\n * 截断 AST 节点,只保留前 maxChars 个字符\n * 支持 chunks(用于渐入动画)\n * \n * @param node 原始节点\n * @param maxChars 最大字符数\n * @param accumulatedChunks 累积的 chunks 信息(用于渐入动画)\n * @returns 截断后的节点,如果 maxChars <= 0 返回 null\n */\nexport function sliceAst(\n node: RootContent, \n maxChars: number,\n accumulatedChunks?: AccumulatedChunks\n): RootContent | null {\n if (maxChars <= 0) return null\n\n let remaining = maxChars\n let charIndex = 0\n \n // 计算 chunks 在文本中的范围\n const chunkRanges: ChunkRange[] = []\n if (accumulatedChunks && accumulatedChunks.chunks.length > 0) {\n let chunkStart = accumulatedChunks.stableChars\n for (const chunk of accumulatedChunks.chunks) {\n chunkRanges.push({\n start: chunkStart,\n end: chunkStart + chunk.text.length,\n chunk\n })\n chunkStart += chunk.text.length\n }\n }\n\n function process(n: AstNode): AstNode | null {\n if (remaining <= 0) return null\n\n // 文本类节点:截断 value,可能添加 chunks\n if (n.value && typeof n.value === 'string') {\n const take = Math.min(n.value.length, remaining)\n remaining -= take\n if (take === 0) return null\n\n const slicedValue = n.value.slice(0, take)\n const nodeStart = charIndex\n const nodeEnd = charIndex + take\n charIndex += take\n \n const result: AstNode & { stableLength?: number; chunks?: TextChunk[] } = { \n ...n, \n value: slicedValue \n }\n \n // 检查是否有 chunks 落在这个节点范围内\n if (chunkRanges.length > 0 && accumulatedChunks) {\n const nodeChunks: TextChunk[] = []\n let firstChunkLocalStart = take // 第一个 chunk 在节点中的起始位置\n \n for (const range of chunkRanges) {\n // 计算 chunk 与当前节点的交集\n const overlapStart = Math.max(range.start, nodeStart)\n const overlapEnd = Math.min(range.end, nodeEnd)\n \n if (overlapStart < overlapEnd) {\n // 有交集,提取对应的文本\n const localStart = overlapStart - nodeStart\n const localEnd = overlapEnd - nodeStart\n const chunkText = slicedValue.slice(localStart, localEnd)\n \n if (chunkText.length > 0) {\n // 记录第一个 chunk 的起始位置\n if (nodeChunks.length === 0) {\n firstChunkLocalStart = localStart\n }\n nodeChunks.push({\n text: chunkText,\n createdAt: range.chunk.createdAt\n })\n }\n }\n }\n \n if (nodeChunks.length > 0) {\n result.stableLength = firstChunkLocalStart\n result.chunks = nodeChunks\n }\n }\n \n return result\n }\n\n // 容器节点:递归处理 children\n if (n.children && Array.isArray(n.children)) {\n const newChildren: AstNode[] = []\n for (const child of n.children) {\n if (remaining <= 0) break\n const processed = process(child)\n if (processed) {\n newChildren.push(processed)\n }\n }\n if (newChildren.length === 0) {\n return null\n }\n return { ...n, children: newChildren }\n }\n\n // 其他节点(如 thematicBreak, image)\n remaining -= 1\n charIndex += 1\n return { ...n }\n }\n\n return process(node as AstNode) as RootContent | null\n}\n\n/**\n * 深拷贝 AST 节点\n */\nexport function cloneNode<T extends RootContent>(node: T): T {\n return JSON.parse(JSON.stringify(node))\n}\n","import type { RootContent } from 'mdast'\nimport type {\n SourceBlock,\n DisplayBlock,\n TransformerOptions,\n TransformerState,\n TransformerPlugin,\n AnimationEffect\n} from './types'\nimport { countChars as defaultCountChars, sliceAst as defaultSliceAst, type TextChunk, type AccumulatedChunks } from './utils'\n\n/**\n * Block Transformer\n *\n * 用于控制 blocks 的逐步显示(打字机效果)\n * 作为解析器和渲染器之间的中间层\n *\n * 特性:\n * - 使用 requestAnimationFrame 实现流畅动画\n * - 支持随机步长,模拟真实打字效果\n * - 支持 typing 动画效果\n * - 页面不可见时自动暂停,节省资源\n * - 插件系统支持自定义节点处理\n *\n * @example\n * ```typescript\n * const transformer = new BlockTransformer({\n * charsPerTick: [1, 3], // 随机 1-3 个字符\n * tickInterval: 30,\n * effect: 'typing',\n * onChange: (displayBlocks) => {\n * // 更新 UI\n * }\n * })\n *\n * // 推入新 blocks\n * transformer.push(blocks)\n *\n * // 获取当前显示状态\n * const displayBlocks = transformer.getDisplayBlocks()\n * ```\n */\nexport class BlockTransformer<T = unknown> {\n private state: TransformerState<T>\n private options: {\n charsPerTick: number | [number, number]\n tickInterval: number\n effect: AnimationEffect\n plugins: TransformerPlugin[]\n onChange: (displayBlocks: DisplayBlock<T>[]) => void\n pauseOnHidden: boolean\n }\n private rafId: number | null = null\n private lastTickTime = 0\n private isRunning = false\n private isPaused = false\n private chunks: TextChunk[] = [] // 累积的 chunks(用于 fade-in 动画)\n private visibilityHandler: (() => void) | null = null\n\n constructor(options: TransformerOptions = {}) {\n this.options = {\n charsPerTick: options.charsPerTick ?? 1,\n tickInterval: options.tickInterval ?? 20,\n effect: options.effect ?? 'none',\n plugins: options.plugins ?? [],\n onChange: options.onChange ?? (() => {}),\n pauseOnHidden: options.pauseOnHidden ?? true\n }\n\n this.state = {\n completedBlocks: [],\n currentBlock: null,\n currentProgress: 0,\n pendingBlocks: []\n }\n\n // 设置页面可见性监听\n if (this.options.pauseOnHidden && typeof document !== 'undefined') {\n this.setupVisibilityHandler()\n }\n }\n\n /**\n * 推入新的 blocks\n * 会自动过滤已存在的 blocks\n */\n push(blocks: SourceBlock<T>[]): void {\n const existingIds = this.getAllBlockIds()\n\n // 找出新增的 blocks\n const newBlocks = blocks.filter((b) => !existingIds.has(b.id))\n\n if (newBlocks.length > 0) {\n this.state.pendingBlocks.push(...newBlocks)\n this.startIfNeeded()\n }\n\n // 如果当前正在显示的 block 内容更新了(pending block 变化)\n if (this.state.currentBlock) {\n const updated = blocks.find((b) => b.id === this.state.currentBlock!.id)\n if (updated && updated.node !== this.state.currentBlock.node) {\n const oldTotal = this.countChars(this.state.currentBlock.node)\n const newTotal = this.countChars(updated.node)\n \n // 如果字符数减少了(AST 结构变化,如 **xxx 变成 **xxx**)\n // 重新计算进度,保持相对位置\n if (newTotal < oldTotal || newTotal < this.state.currentProgress) {\n this.state.currentProgress = Math.min(this.state.currentProgress, newTotal)\n }\n \n // 内容更新,更新引用\n this.state.currentBlock = updated\n // 如果之前暂停了(因为到达末尾),重新开始\n if (!this.rafId && !this.isPaused) {\n if (this.state.currentProgress < newTotal) {\n this.startIfNeeded()\n }\n }\n }\n }\n }\n\n /**\n * 更新指定 block(用于 pending block 内容增加时)\n */\n update(block: SourceBlock<T>): void {\n if (this.state.currentBlock?.id === block.id) {\n const oldTotal = this.countChars(this.state.currentBlock.node)\n const newTotal = this.countChars(block.node)\n\n this.state.currentBlock = block\n\n // 如果内容增加了且之前暂停了,继续\n if (newTotal > oldTotal && !this.rafId && !this.isPaused && this.state.currentProgress >= oldTotal) {\n this.startIfNeeded()\n }\n }\n }\n\n /**\n * 跳过所有动画,直接显示全部内容\n */\n skip(): void {\n this.stop()\n\n const allBlocks = [\n ...this.state.completedBlocks,\n ...(this.state.currentBlock ? [this.state.currentBlock] : []),\n ...this.state.pendingBlocks\n ]\n\n this.state = {\n completedBlocks: allBlocks,\n currentBlock: null,\n currentProgress: 0,\n pendingBlocks: []\n }\n this.chunks = []\n\n this.emit()\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.stop()\n this.state = {\n completedBlocks: [],\n currentBlock: null,\n currentProgress: 0,\n pendingBlocks: []\n }\n this.chunks = []\n this.emit()\n }\n\n /**\n * 暂停动画\n */\n pause(): void {\n this.isPaused = true\n this.cancelRaf()\n }\n\n /**\n * 恢复动画\n */\n resume(): void {\n if (this.isPaused) {\n this.isPaused = false\n this.startIfNeeded()\n }\n }\n\n /**\n * 获取用于渲染的 display blocks\n */\n getDisplayBlocks(): DisplayBlock<T>[] {\n const result: DisplayBlock<T>[] = []\n\n // 已完成的 blocks\n for (const block of this.state.completedBlocks) {\n result.push({\n ...block,\n displayNode: block.node,\n progress: 1,\n isDisplayComplete: true\n })\n }\n\n // 当前正在显示的 block\n if (this.state.currentBlock) {\n const total = this.countChars(this.state.currentBlock.node)\n // fade-in 效果:传入累积的 chunks\n const accumulatedChunks: AccumulatedChunks | undefined = \n this.options.effect === 'fade-in' && this.chunks.length > 0\n ? { stableChars: 0, chunks: this.chunks }\n : undefined\n \n const displayNode = this.sliceNode(\n this.state.currentBlock.node, \n this.state.currentProgress,\n accumulatedChunks\n )\n\n result.push({\n ...this.state.currentBlock,\n displayNode: displayNode || { type: 'paragraph', children: [] },\n progress: total > 0 ? this.state.currentProgress / total : 1,\n isDisplayComplete: false\n })\n }\n\n return result\n }\n\n /**\n * 是否正在处理中\n */\n isProcessing(): boolean {\n return this.isRunning || this.state.currentBlock !== null || this.state.pendingBlocks.length > 0\n }\n\n /**\n * 是否已暂停\n */\n isPausedState(): boolean {\n return this.isPaused\n }\n\n /**\n * 获取内部状态(用于调试)\n */\n getState(): Readonly<TransformerState<T>> {\n return { ...this.state }\n }\n\n /**\n * 动态更新配置\n */\n setOptions(options: Partial<Pick<TransformerOptions, 'charsPerTick' | 'tickInterval' | 'effect' | 'pauseOnHidden'>>): void {\n if (options.charsPerTick !== undefined) {\n this.options.charsPerTick = options.charsPerTick\n }\n if (options.tickInterval !== undefined) {\n this.options.tickInterval = options.tickInterval\n }\n if (options.effect !== undefined) {\n this.options.effect = options.effect\n }\n if (options.pauseOnHidden !== undefined) {\n this.options.pauseOnHidden = options.pauseOnHidden\n if (options.pauseOnHidden && typeof document !== 'undefined') {\n this.setupVisibilityHandler()\n } else {\n this.removeVisibilityHandler()\n }\n }\n }\n\n /**\n * 获取当前配置\n */\n getOptions(): { \n charsPerTick: number | [number, number]\n tickInterval: number\n effect: AnimationEffect\n } {\n return {\n charsPerTick: this.options.charsPerTick,\n tickInterval: this.options.tickInterval,\n effect: this.options.effect\n }\n }\n\n /**\n * 获取当前动画效果\n */\n getEffect(): AnimationEffect {\n return this.options.effect\n }\n\n /**\n * 销毁,清理资源\n */\n destroy(): void {\n this.stop()\n this.removeVisibilityHandler()\n }\n\n // ============ 私有方法 ============\n\n private getAllBlockIds(): Set<string> {\n return new Set([\n ...this.state.completedBlocks.map((b) => b.id),\n this.state.currentBlock?.id,\n ...this.state.pendingBlocks.map((b) => b.id)\n ].filter((id): id is string => id !== undefined))\n }\n\n private setupVisibilityHandler(): void {\n if (this.visibilityHandler) return\n\n this.visibilityHandler = () => {\n if (document.hidden) {\n this.pause()\n } else {\n this.resume()\n }\n }\n\n document.addEventListener('visibilitychange', this.visibilityHandler)\n }\n\n private removeVisibilityHandler(): void {\n if (this.visibilityHandler) {\n document.removeEventListener('visibilitychange', this.visibilityHandler)\n this.visibilityHandler = null\n }\n }\n\n private startIfNeeded(): void {\n if (this.rafId || this.isPaused) return\n\n if (!this.state.currentBlock && this.state.pendingBlocks.length > 0) {\n this.state.currentBlock = this.state.pendingBlocks.shift()!\n this.state.currentProgress = 0\n }\n\n if (this.state.currentBlock) {\n this.isRunning = true\n this.lastTickTime = 0\n this.scheduleNextFrame()\n }\n }\n\n private scheduleNextFrame(): void {\n this.rafId = requestAnimationFrame((time) => this.animationFrame(time))\n }\n\n private animationFrame(time: number): void {\n this.rafId = null\n\n // 计算是否应该执行 tick\n if (this.lastTickTime === 0) {\n this.lastTickTime = time\n }\n\n const elapsed = time - this.lastTickTime\n\n if (elapsed >= this.options.tickInterval) {\n this.lastTickTime = time\n this.tick()\n }\n\n // 如果还在运行,继续调度\n if (this.isRunning && !this.isPaused) {\n this.scheduleNextFrame()\n }\n }\n\n private tick(): void {\n const block = this.state.currentBlock\n if (!block) {\n this.processNext()\n return\n }\n\n const total = this.countChars(block.node)\n const step = this.getStep()\n const prevProgress = this.state.currentProgress\n \n this.state.currentProgress = Math.min(prevProgress + step, total)\n\n // 如果是 fade-in 效果,添加新的 chunk\n if (this.options.effect === 'fade-in' && this.state.currentProgress > prevProgress) {\n // 从 block.node 中提取新增的字符\n const newText = this.extractText(block.node, prevProgress, this.state.currentProgress)\n if (newText.length > 0) {\n this.chunks.push({\n text: newText,\n createdAt: Date.now()\n })\n }\n }\n\n this.emit()\n\n if (this.state.currentProgress >= total) {\n // 当前 block 完成,清空 chunks\n this.notifyComplete(block.node)\n this.state.completedBlocks.push(block)\n this.state.currentBlock = null\n this.state.currentProgress = 0\n this.chunks = []\n this.processNext()\n }\n }\n\n /**\n * 从 AST 节点中提取指定范围的文本\n */\n private extractText(node: RootContent, start: number, end: number): string {\n let result = ''\n let charIndex = 0\n\n interface AstNode {\n type: string\n value?: string\n children?: AstNode[]\n }\n\n function traverse(n: AstNode): boolean {\n if (charIndex >= end) return false\n\n if (n.value && typeof n.value === 'string') {\n const nodeStart = charIndex\n const nodeEnd = charIndex + n.value.length\n charIndex = nodeEnd\n\n // 计算交集\n const overlapStart = Math.max(start, nodeStart)\n const overlapEnd = Math.min(end, nodeEnd)\n\n if (overlapStart < overlapEnd) {\n result += n.value.slice(overlapStart - nodeStart, overlapEnd - nodeStart)\n }\n return charIndex < end\n }\n\n if (n.children && Array.isArray(n.children)) {\n for (const child of n.children) {\n if (!traverse(child)) return false\n }\n }\n\n return true\n }\n\n traverse(node as AstNode)\n return result\n }\n\n private getStep(): number {\n const { charsPerTick } = this.options\n if (typeof charsPerTick === 'number') {\n return charsPerTick\n }\n // 随机步长\n const [min, max] = charsPerTick\n return Math.floor(Math.random() * (max - min + 1)) + min\n }\n\n private processNext(): void {\n if (this.state.pendingBlocks.length > 0) {\n this.state.currentBlock = this.state.pendingBlocks.shift()!\n this.state.currentProgress = 0\n this.chunks = []\n this.emit()\n // 继续运行(rAF 已经在调度中)\n } else {\n this.isRunning = false\n this.cancelRaf()\n this.emit()\n }\n }\n\n private cancelRaf(): void {\n if (this.rafId) {\n cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n }\n\n private stop(): void {\n this.cancelRaf()\n this.isRunning = false\n this.isPaused = false\n }\n\n private emit(): void {\n this.options.onChange(this.getDisplayBlocks())\n }\n\n // ============ 插件调用 ============\n\n private countChars(node: RootContent): number {\n // 先找匹配的插件\n for (const plugin of this.options.plugins) {\n if (plugin.match?.(node) && plugin.countChars) {\n const result = plugin.countChars(node)\n if (result !== undefined) return result\n }\n }\n // 默认计算\n return defaultCountChars(node)\n }\n\n private sliceNode(node: RootContent, chars: number, accumulatedChunks?: AccumulatedChunks): RootContent | null {\n // 先找匹配的插件\n for (const plugin of this.options.plugins) {\n if (plugin.match?.(node) && plugin.sliceNode) {\n const total = this.countChars(node)\n const result = plugin.sliceNode(node, chars, total)\n if (result !== null) return result\n }\n }\n // 默认截断,传入累积的 chunks\n return defaultSliceAst(node, chars, accumulatedChunks)\n }\n\n private notifyComplete(node: RootContent): void {\n for (const plugin of this.options.plugins) {\n if (plugin.match?.(node) && plugin.onComplete) {\n plugin.onComplete(node)\n }\n }\n }\n}\n\n/**\n * 创建 BlockTransformer 实例的工厂函数\n */\nexport function createBlockTransformer<T = unknown>(\n options?: TransformerOptions\n): BlockTransformer<T> {\n return new BlockTransformer<T>(options)\n}\n\n\n\n","import type { RootContent, Code } from 'mdast'\nimport type { TransformerPlugin } from './types'\n\n/**\n * 代码块插件:整体出现,不逐字符显示\n * \n * 注意:默认不启用,代码块默认参与打字机效果\n * 如需整体显示代码块,可手动添加此插件\n */\nexport const codeBlockPlugin: TransformerPlugin = {\n name: 'code-block',\n match: (node: RootContent) => node.type === 'code',\n countChars: () => 1, // 算作 1 个字符,整体出现\n sliceNode: (node, displayedChars, totalChars) => {\n // 要么全部显示,要么不显示\n return displayedChars >= totalChars ? node : null\n }\n}\n\n/**\n * Mermaid 图表插件:整体出现\n * \n * 注意:默认不启用,mermaid 默认参与打字机效果\n * 如需整体显示 mermaid,可手动添加此插件\n */\nexport const mermaidPlugin: TransformerPlugin = {\n name: 'mermaid',\n match: (node: RootContent) => {\n if (node.type !== 'code') return false\n const codeNode = node as Code\n return codeNode.lang === 'mermaid'\n },\n countChars: () => 1,\n sliceNode: (node, displayedChars) => (displayedChars > 0 ? node : null)\n}\n\n/**\n * 图片插件:立即显示(不参与打字机效果)\n * 图片没有文本内容,应立即显示\n */\nexport const imagePlugin: TransformerPlugin = {\n name: 'image',\n match: (node: RootContent) => node.type === 'image',\n countChars: () => 0 // 0 字符,立即显示\n}\n\n/**\n * 数学公式插件:整体出现\n * \n * 注意:默认不启用,数学公式默认参与打字机效果\n * 如需整体显示公式,可手动添加此插件\n */\nexport const mathPlugin: TransformerPlugin = {\n name: 'math',\n match: (node: RootContent) => {\n const type = node.type as string\n return type === 'math' || type === 'inlineMath'\n },\n countChars: () => 1,\n sliceNode: (node, displayedChars) => (displayedChars > 0 ? node : null)\n}\n\n/**\n * 分割线插件:立即显示\n * 分隔线没有文本内容,应立即显示\n */\nexport const thematicBreakPlugin: TransformerPlugin = {\n name: 'thematic-break',\n match: (node: RootContent) => node.type === 'thematicBreak',\n countChars: () => 0\n}\n\n/**\n * 默认插件集合\n * \n * 只包含确实需要特殊处理的节点:\n * - 图片:无文本内容,立即显示\n * - 分隔线:无文本内容,立即显示\n * \n * 代码块、mermaid、数学公式默认参与打字机效果\n * 如需整体显示,可手动添加对应插件\n */\nexport const defaultPlugins: TransformerPlugin[] = [\n imagePlugin,\n thematicBreakPlugin\n]\n\n/**\n * 完整插件集合(所有特殊节点整体显示)\n * 包含代码块、mermaid、数学公式等的整体显示\n */\nexport const allPlugins: TransformerPlugin[] = [\n mermaidPlugin, // mermaid 优先于普通 code block\n codeBlockPlugin,\n imagePlugin,\n mathPlugin,\n thematicBreakPlugin\n]\n\n/**\n * 创建自定义插件的辅助函数\n */\nexport function createPlugin(\n name: string,\n matcher: (node: RootContent) => boolean,\n options: Partial<Omit<TransformerPlugin, 'name' | 'match'>> = {}\n): TransformerPlugin {\n return {\n name,\n match: matcher,\n ...options\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@incremark/core",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "增量式 Markdown 解析器核心库",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -76,7 +76,9 @@ export type {
76
76
  TransformerPlugin,
77
77
  TransformerOptions,
78
78
  TransformerState,
79
- AnimationEffect
79
+ AnimationEffect,
80
+ TextChunk,
81
+ TextNodeWithChunks
80
82
  } from './transformer'
81
83
 
82
84
  /**
@@ -7,7 +7,7 @@ import type {
7
7
  TransformerPlugin,
8
8
  AnimationEffect
9
9
  } from './types'
10
- import { countChars as defaultCountChars, sliceAst as defaultSliceAst } from './utils'
10
+ import { countChars as defaultCountChars, sliceAst as defaultSliceAst, type TextChunk, type AccumulatedChunks } from './utils'
11
11
 
12
12
  /**
13
13
  * Block Transformer
@@ -54,6 +54,7 @@ export class BlockTransformer<T = unknown> {
54
54
  private lastTickTime = 0
55
55
  private isRunning = false
56
56
  private isPaused = false
57
+ private chunks: TextChunk[] = [] // 累积的 chunks(用于 fade-in 动画)
57
58
  private visibilityHandler: (() => void) | null = null
58
59
 
59
60
  constructor(options: TransformerOptions = {}) {
@@ -98,12 +99,20 @@ export class BlockTransformer<T = unknown> {
98
99
  if (this.state.currentBlock) {
99
100
  const updated = blocks.find((b) => b.id === this.state.currentBlock!.id)
100
101
  if (updated && updated.node !== this.state.currentBlock.node) {
101
- // 内容增加了,更新引用
102
+ const oldTotal = this.countChars(this.state.currentBlock.node)
103
+ const newTotal = this.countChars(updated.node)
104
+
105
+ // 如果字符数减少了(AST 结构变化,如 **xxx 变成 **xxx**)
106
+ // 重新计算进度,保持相对位置
107
+ if (newTotal < oldTotal || newTotal < this.state.currentProgress) {
108
+ this.state.currentProgress = Math.min(this.state.currentProgress, newTotal)
109
+ }
110
+
111
+ // 内容更新,更新引用
102
112
  this.state.currentBlock = updated
103
113
  // 如果之前暂停了(因为到达末尾),重新开始
104
114
  if (!this.rafId && !this.isPaused) {
105
- const total = this.countChars(updated.node)
106
- if (this.state.currentProgress < total) {
115
+ if (this.state.currentProgress < newTotal) {
107
116
  this.startIfNeeded()
108
117
  }
109
118
  }
@@ -146,6 +155,7 @@ export class BlockTransformer<T = unknown> {
146
155
  currentProgress: 0,
147
156
  pendingBlocks: []
148
157
  }
158
+ this.chunks = []
149
159
 
150
160
  this.emit()
151
161
  }
@@ -161,6 +171,7 @@ export class BlockTransformer<T = unknown> {
161
171
  currentProgress: 0,
162
172
  pendingBlocks: []
163
173
  }
174
+ this.chunks = []
164
175
  this.emit()
165
176
  }
166
177
 
@@ -201,7 +212,17 @@ export class BlockTransformer<T = unknown> {
201
212
  // 当前正在显示的 block
202
213
  if (this.state.currentBlock) {
203
214
  const total = this.countChars(this.state.currentBlock.node)
204
- const displayNode = this.sliceNode(this.state.currentBlock.node, this.state.currentProgress)
215
+ // fade-in 效果:传入累积的 chunks
216
+ const accumulatedChunks: AccumulatedChunks | undefined =
217
+ this.options.effect === 'fade-in' && this.chunks.length > 0
218
+ ? { stableChars: 0, chunks: this.chunks }
219
+ : undefined
220
+
221
+ const displayNode = this.sliceNode(
222
+ this.state.currentBlock.node,
223
+ this.state.currentProgress,
224
+ accumulatedChunks
225
+ )
205
226
 
206
227
  result.push({
207
228
  ...this.state.currentBlock,
@@ -368,21 +389,79 @@ export class BlockTransformer<T = unknown> {
368
389
 
369
390
  const total = this.countChars(block.node)
370
391
  const step = this.getStep()
392
+ const prevProgress = this.state.currentProgress
371
393
 
372
- this.state.currentProgress = Math.min(this.state.currentProgress + step, total)
394
+ this.state.currentProgress = Math.min(prevProgress + step, total)
395
+
396
+ // 如果是 fade-in 效果,添加新的 chunk
397
+ if (this.options.effect === 'fade-in' && this.state.currentProgress > prevProgress) {
398
+ // 从 block.node 中提取新增的字符
399
+ const newText = this.extractText(block.node, prevProgress, this.state.currentProgress)
400
+ if (newText.length > 0) {
401
+ this.chunks.push({
402
+ text: newText,
403
+ createdAt: Date.now()
404
+ })
405
+ }
406
+ }
373
407
 
374
408
  this.emit()
375
409
 
376
410
  if (this.state.currentProgress >= total) {
377
- // 当前 block 完成
411
+ // 当前 block 完成,清空 chunks
378
412
  this.notifyComplete(block.node)
379
413
  this.state.completedBlocks.push(block)
380
414
  this.state.currentBlock = null
381
415
  this.state.currentProgress = 0
416
+ this.chunks = []
382
417
  this.processNext()
383
418
  }
384
419
  }
385
420
 
421
+ /**
422
+ * 从 AST 节点中提取指定范围的文本
423
+ */
424
+ private extractText(node: RootContent, start: number, end: number): string {
425
+ let result = ''
426
+ let charIndex = 0
427
+
428
+ interface AstNode {
429
+ type: string
430
+ value?: string
431
+ children?: AstNode[]
432
+ }
433
+
434
+ function traverse(n: AstNode): boolean {
435
+ if (charIndex >= end) return false
436
+
437
+ if (n.value && typeof n.value === 'string') {
438
+ const nodeStart = charIndex
439
+ const nodeEnd = charIndex + n.value.length
440
+ charIndex = nodeEnd
441
+
442
+ // 计算交集
443
+ const overlapStart = Math.max(start, nodeStart)
444
+ const overlapEnd = Math.min(end, nodeEnd)
445
+
446
+ if (overlapStart < overlapEnd) {
447
+ result += n.value.slice(overlapStart - nodeStart, overlapEnd - nodeStart)
448
+ }
449
+ return charIndex < end
450
+ }
451
+
452
+ if (n.children && Array.isArray(n.children)) {
453
+ for (const child of n.children) {
454
+ if (!traverse(child)) return false
455
+ }
456
+ }
457
+
458
+ return true
459
+ }
460
+
461
+ traverse(node as AstNode)
462
+ return result
463
+ }
464
+
386
465
  private getStep(): number {
387
466
  const { charsPerTick } = this.options
388
467
  if (typeof charsPerTick === 'number') {
@@ -397,6 +476,7 @@ export class BlockTransformer<T = unknown> {
397
476
  if (this.state.pendingBlocks.length > 0) {
398
477
  this.state.currentBlock = this.state.pendingBlocks.shift()!
399
478
  this.state.currentProgress = 0
479
+ this.chunks = []
400
480
  this.emit()
401
481
  // 继续运行(rAF 已经在调度中)
402
482
  } else {
@@ -437,7 +517,7 @@ export class BlockTransformer<T = unknown> {
437
517
  return defaultCountChars(node)
438
518
  }
439
519
 
440
- private sliceNode(node: RootContent, chars: number): RootContent | null {
520
+ private sliceNode(node: RootContent, chars: number, accumulatedChunks?: AccumulatedChunks): RootContent | null {
441
521
  // 先找匹配的插件
442
522
  for (const plugin of this.options.plugins) {
443
523
  if (plugin.match?.(node) && plugin.sliceNode) {
@@ -446,8 +526,8 @@ export class BlockTransformer<T = unknown> {
446
526
  if (result !== null) return result
447
527
  }
448
528
  }
449
- // 默认截断
450
- return defaultSliceAst(node, chars)
529
+ // 默认截断,传入累积的 chunks
530
+ return defaultSliceAst(node, chars, accumulatedChunks)
451
531
  }
452
532
 
453
533
  private notifyComplete(node: RootContent): void {
@@ -20,6 +20,7 @@ export type {
20
20
 
21
21
  // 工具函数
22
22
  export { countChars, sliceAst, cloneNode } from './utils'
23
+ export type { TextChunk, TextNodeWithChunks, AccumulatedChunks } from './utils'
23
24
 
24
25
  // 内置插件
25
26
  export {
@@ -29,9 +29,10 @@ export interface DisplayBlock<T = unknown> extends SourceBlock<T> {
29
29
  /**
30
30
  * 动画效果类型
31
31
  * - 'none': 无动画效果
32
- * - 'typing': 打字机光标效果(需配合 CSS)
32
+ * - 'fade-in': 新增字符渐入效果
33
+ * - 'typing': 打字机光标效果
33
34
  */
34
- export type AnimationEffect = 'none' | 'typing'
35
+ export type AnimationEffect = 'none' | 'fade-in' | 'typing'
35
36
 
36
37
  /**
37
38
  * Transformer 插件
@@ -1,4 +1,33 @@
1
- import type { RootContent } from 'mdast'
1
+ import type { RootContent, Text, Parent } from 'mdast'
2
+
3
+ /**
4
+ * 文本块片段(用于渐入动画)
5
+ */
6
+ export interface TextChunk {
7
+ /** 文本内容 */
8
+ text: string
9
+ /** 创建时间戳 */
10
+ createdAt: number
11
+ }
12
+
13
+ /**
14
+ * 扩展的文本节点(支持 chunks)
15
+ */
16
+ export interface TextNodeWithChunks extends Text {
17
+ /** 稳定部分的长度(不需要动画) */
18
+ stableLength?: number
19
+ /** 临时的文本片段,用于渐入动画 */
20
+ chunks?: TextChunk[]
21
+ }
22
+
23
+ /**
24
+ * AST 节点的通用类型(文本节点或容器节点)
25
+ */
26
+ interface AstNode {
27
+ type: string
28
+ value?: string
29
+ children?: AstNode[]
30
+ }
2
31
 
3
32
  /**
4
33
  * 计算 AST 节点的总字符数
@@ -6,14 +35,11 @@ import type { RootContent } from 'mdast'
6
35
  export function countChars(node: RootContent): number {
7
36
  let count = 0
8
37
 
9
- function traverse(n: any): void {
10
- // 文本类节点
38
+ function traverse(n: AstNode): void {
11
39
  if (n.value && typeof n.value === 'string') {
12
40
  count += n.value.length
13
41
  return
14
42
  }
15
-
16
- // 容器节点,递归处理子节点
17
43
  if (n.children && Array.isArray(n.children)) {
18
44
  for (const child of n.children) {
19
45
  traverse(child)
@@ -21,36 +47,120 @@ export function countChars(node: RootContent): number {
21
47
  }
22
48
  }
23
49
 
24
- traverse(node)
50
+ traverse(node as AstNode)
25
51
  return count
26
52
  }
27
53
 
54
+ /**
55
+ * 累积的 chunks 信息
56
+ */
57
+ export interface AccumulatedChunks {
58
+ /** 已经稳定显示的字符数(不需要动画) */
59
+ stableChars: number
60
+ /** 累积的 chunk 列表 */
61
+ chunks: TextChunk[]
62
+ }
63
+
64
+ /** chunk 范围信息 */
65
+ interface ChunkRange {
66
+ start: number
67
+ end: number
68
+ chunk: TextChunk
69
+ }
70
+
28
71
  /**
29
72
  * 截断 AST 节点,只保留前 maxChars 个字符
73
+ * 支持 chunks(用于渐入动画)
30
74
  *
31
75
  * @param node 原始节点
32
76
  * @param maxChars 最大字符数
77
+ * @param accumulatedChunks 累积的 chunks 信息(用于渐入动画)
33
78
  * @returns 截断后的节点,如果 maxChars <= 0 返回 null
34
79
  */
35
- export function sliceAst(node: RootContent, maxChars: number): RootContent | null {
80
+ export function sliceAst(
81
+ node: RootContent,
82
+ maxChars: number,
83
+ accumulatedChunks?: AccumulatedChunks
84
+ ): RootContent | null {
36
85
  if (maxChars <= 0) return null
37
86
 
38
87
  let remaining = maxChars
88
+ let charIndex = 0
89
+
90
+ // 计算 chunks 在文本中的范围
91
+ const chunkRanges: ChunkRange[] = []
92
+ if (accumulatedChunks && accumulatedChunks.chunks.length > 0) {
93
+ let chunkStart = accumulatedChunks.stableChars
94
+ for (const chunk of accumulatedChunks.chunks) {
95
+ chunkRanges.push({
96
+ start: chunkStart,
97
+ end: chunkStart + chunk.text.length,
98
+ chunk
99
+ })
100
+ chunkStart += chunk.text.length
101
+ }
102
+ }
39
103
 
40
- function process(n: any): any {
104
+ function process(n: AstNode): AstNode | null {
41
105
  if (remaining <= 0) return null
42
106
 
43
- // 文本类节点:截断 value
107
+ // 文本类节点:截断 value,可能添加 chunks
44
108
  if (n.value && typeof n.value === 'string') {
45
109
  const take = Math.min(n.value.length, remaining)
46
110
  remaining -= take
47
111
  if (take === 0) return null
48
- return { ...n, value: n.value.slice(0, take) }
112
+
113
+ const slicedValue = n.value.slice(0, take)
114
+ const nodeStart = charIndex
115
+ const nodeEnd = charIndex + take
116
+ charIndex += take
117
+
118
+ const result: AstNode & { stableLength?: number; chunks?: TextChunk[] } = {
119
+ ...n,
120
+ value: slicedValue
121
+ }
122
+
123
+ // 检查是否有 chunks 落在这个节点范围内
124
+ if (chunkRanges.length > 0 && accumulatedChunks) {
125
+ const nodeChunks: TextChunk[] = []
126
+ let firstChunkLocalStart = take // 第一个 chunk 在节点中的起始位置
127
+
128
+ for (const range of chunkRanges) {
129
+ // 计算 chunk 与当前节点的交集
130
+ const overlapStart = Math.max(range.start, nodeStart)
131
+ const overlapEnd = Math.min(range.end, nodeEnd)
132
+
133
+ if (overlapStart < overlapEnd) {
134
+ // 有交集,提取对应的文本
135
+ const localStart = overlapStart - nodeStart
136
+ const localEnd = overlapEnd - nodeStart
137
+ const chunkText = slicedValue.slice(localStart, localEnd)
138
+
139
+ if (chunkText.length > 0) {
140
+ // 记录第一个 chunk 的起始位置
141
+ if (nodeChunks.length === 0) {
142
+ firstChunkLocalStart = localStart
143
+ }
144
+ nodeChunks.push({
145
+ text: chunkText,
146
+ createdAt: range.chunk.createdAt
147
+ })
148
+ }
149
+ }
150
+ }
151
+
152
+ if (nodeChunks.length > 0) {
153
+ result.stableLength = firstChunkLocalStart
154
+ result.chunks = nodeChunks
155
+ }
156
+ }
157
+
158
+ return result
49
159
  }
50
160
 
51
161
  // 容器节点:递归处理 children
52
162
  if (n.children && Array.isArray(n.children)) {
53
- const newChildren: any[] = []
163
+ const newChildren: AstNode[] = []
54
164
  for (const child of n.children) {
55
165
  if (remaining <= 0) break
56
166
  const processed = process(child)
@@ -58,22 +168,19 @@ export function sliceAst(node: RootContent, maxChars: number): RootContent | nul
58
168
  newChildren.push(processed)
59
169
  }
60
170
  }
61
- // 如果没有 children 了,根据节点类型决定是否保留
62
171
  if (newChildren.length === 0) {
63
- // 对于某些容器节点,即使没有内容也应该保留结构
64
- // 例如 list 节点如果没有 children 就不应该渲染
65
172
  return null
66
173
  }
67
174
  return { ...n, children: newChildren }
68
175
  }
69
176
 
70
- // 其他节点(如 thematicBreak, image):整体处理
71
- // 算作 1 个字符的消耗
177
+ // 其他节点(如 thematicBreak, image
72
178
  remaining -= 1
179
+ charIndex += 1
73
180
  return { ...n }
74
181
  }
75
182
 
76
- return process(node)
183
+ return process(node as AstNode) as RootContent | null
77
184
  }
78
185
 
79
186
  /**
@@ -82,4 +189,3 @@ export function sliceAst(node: RootContent, maxChars: number): RootContent | nul
82
189
  export function cloneNode<T extends RootContent>(node: T): T {
83
190
  return JSON.parse(JSON.stringify(node))
84
191
  }
85
-