@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 +40 -5
- package/dist/index.js +110 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +3 -1
- package/src/transformer/BlockTransformer.ts +90 -10
- package/src/transformer/index.ts +1 -0
- package/src/transformer/types.ts +3 -2
- package/src/transformer/utils.ts +124 -18
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
|
-
* - '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
package/src/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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(
|
|
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 {
|
package/src/transformer/index.ts
CHANGED
package/src/transformer/types.ts
CHANGED
|
@@ -29,9 +29,10 @@ export interface DisplayBlock<T = unknown> extends SourceBlock<T> {
|
|
|
29
29
|
/**
|
|
30
30
|
* 动画效果类型
|
|
31
31
|
* - 'none': 无动画效果
|
|
32
|
-
* - '
|
|
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 插件
|
package/src/transformer/utils.ts
CHANGED
|
@@ -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:
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|