@incremark/core 0.2.5 → 0.2.6

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.
@@ -1,4 +1,4 @@
1
- export { r as createInitialContext, o as detectContainer, p as detectContainerEnd, g as detectFenceEnd, f as detectFenceStart, q as isBlockBoundary, l as isBlockquoteStart, i as isEmptyLine, T as isFootnoteContinuation, S as isFootnoteDefinitionStart, h as isHeading, m as isHtmlBlock, k as isListItemStart, n as isTableDelimiter, j as isThematicBreak, u as updateContext } from '../index-BfVDhalw.js';
1
+ export { r as createInitialContext, o as detectContainer, p as detectContainerEnd, g as detectFenceEnd, f as detectFenceStart, q as isBlockBoundary, l as isBlockquoteStart, i as isEmptyLine, T as isFootnoteContinuation, S as isFootnoteDefinitionStart, h as isHeading, m as isHtmlBlock, k as isListItemStart, n as isTableDelimiter, j as isThematicBreak, u as updateContext } from '../index-BMUkM7mT.js';
2
2
  import 'mdast';
3
3
  import 'micromark-util-types';
4
4
  import 'mdast-util-from-markdown';
@@ -3,14 +3,12 @@ var RE_FENCE_START = /^(\s*)((`{3,})|(~{3,}))/;
3
3
  var RE_EMPTY_LINE = /^\s*$/;
4
4
  var RE_HEADING = /^#{1,6}\s/;
5
5
  var RE_THEMATIC_BREAK = /^(\*{3,}|-{3,}|_{3,})\s*$/;
6
- var RE_UNORDERED_LIST = /^(\s*)([-*+])\s/;
7
- var RE_ORDERED_LIST = /^(\s*)(\d{1,9})[.)]\s/;
8
6
  var RE_BLOCKQUOTE = /^\s{0,3}>/;
9
7
  var RE_HTML_BLOCK_1 = /^\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\?|!\[CDATA\[)/i;
10
8
  var RE_HTML_BLOCK_2 = /^\s{0,3}<\/?[a-zA-Z][a-zA-Z0-9-]*(\s|>|$)/;
11
9
  var RE_TABLE_DELIMITER = /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)*\|?$/;
12
10
  var RE_ESCAPE_SPECIAL = /[.*+?^${}()|[\]\\]/g;
13
- var RE_FOOTNOTE_DEFINITION = /^\[\^[^\]]+\]:\s/;
11
+ var RE_FOOTNOTE_DEFINITION = /^\[\^([^\]]+)\]:\s/;
14
12
  var RE_FOOTNOTE_CONTINUATION = /^(?: |\t)/;
15
13
  var fenceEndPatternCache = /* @__PURE__ */ new Map();
16
14
  var containerPatternCache = /* @__PURE__ */ new Map();
@@ -45,13 +43,23 @@ function isThematicBreak(line) {
45
43
  return RE_THEMATIC_BREAK.test(line.trim());
46
44
  }
47
45
  function isListItemStart(line) {
48
- const unordered = line.match(RE_UNORDERED_LIST);
49
- if (unordered) {
50
- return { ordered: false, indent: unordered[1].length };
46
+ const hasListMarker = /^(\s*)([-*+]|\d{1,9}[.)])/.test(line);
47
+ if (!hasListMarker) {
48
+ return null;
51
49
  }
52
- const ordered = line.match(RE_ORDERED_LIST);
53
- if (ordered) {
54
- return { ordered: true, indent: ordered[1].length };
50
+ const match = line.match(/^(\s*)([-*+]|\d{1,9}[.)])(.*)/);
51
+ if (match) {
52
+ const indent = match[1].length;
53
+ const marker = match[2];
54
+ const rest = match[3];
55
+ if (rest.trim()) {
56
+ const isOrdered = /^\d{1,9}[.)]/.test(marker);
57
+ return { ordered: isOrdered, indent };
58
+ }
59
+ if (/^\s+$/.test(rest)) {
60
+ const isOrdered = /^\d{1,9}[.)]/.test(marker);
61
+ return { ordered: isOrdered, indent };
62
+ }
55
63
  }
56
64
  return null;
57
65
  }
@@ -131,7 +139,9 @@ function createInitialContext() {
131
139
  blockquoteDepth: 0,
132
140
  inContainer: false,
133
141
  containerDepth: 0,
134
- inList: false
142
+ inList: false,
143
+ inFootnote: false,
144
+ footnoteIdentifier: void 0
135
145
  };
136
146
  }
137
147
  function isListContinuation(line, listIndent) {
@@ -187,6 +197,17 @@ function updateContext(line, context, containerConfig) {
187
197
  }
188
198
  }
189
199
  }
200
+ if (context.inFootnote && isFootnoteDefinitionStart(line)) {
201
+ const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1];
202
+ newContext.footnoteIdentifier = identifier;
203
+ return newContext;
204
+ }
205
+ if (!context.inFootnote && isFootnoteDefinitionStart(line)) {
206
+ const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1];
207
+ newContext.inFootnote = true;
208
+ newContext.footnoteIdentifier = identifier;
209
+ return newContext;
210
+ }
190
211
  const listItem = isListItemStart(line);
191
212
  if (context.inList) {
192
213
  if (context.listMayEnd) {
@@ -235,6 +256,41 @@ function updateContext(line, context, containerConfig) {
235
256
  return newContext;
236
257
  }
237
258
  }
259
+ if (context.inFootnote) {
260
+ if (isEmptyLine(line)) {
261
+ return newContext;
262
+ } else if (isListItemStart(line)) {
263
+ const listItemInfo = isListItemStart(line);
264
+ if (listItemInfo.indent === 0) {
265
+ newContext.inFootnote = false;
266
+ newContext.footnoteIdentifier = void 0;
267
+ } else {
268
+ return newContext;
269
+ }
270
+ } else if (isHeading(line)) {
271
+ newContext.inFootnote = false;
272
+ newContext.footnoteIdentifier = void 0;
273
+ return newContext;
274
+ } else if (detectFenceStart(line)) {
275
+ newContext.inFootnote = false;
276
+ newContext.footnoteIdentifier = void 0;
277
+ return newContext;
278
+ } else if (isBlockquoteStart(line)) {
279
+ newContext.inFootnote = false;
280
+ newContext.footnoteIdentifier = void 0;
281
+ return newContext;
282
+ } else if (isFootnoteContinuation(line)) {
283
+ return newContext;
284
+ } else if (isFootnoteDefinitionStart(line)) {
285
+ const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1];
286
+ newContext.footnoteIdentifier = identifier;
287
+ return newContext;
288
+ } else {
289
+ newContext.inFootnote = false;
290
+ newContext.footnoteIdentifier = void 0;
291
+ return newContext;
292
+ }
293
+ }
238
294
  return newContext;
239
295
  }
240
296
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/detector/index.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\nconst RE_FENCE_START = /^(\\s*)((`{3,})|(~{3,}))/\nconst RE_EMPTY_LINE = /^\\s*$/\nconst RE_HEADING = /^#{1,6}\\s/\nconst RE_THEMATIC_BREAK = /^(\\*{3,}|-{3,}|_{3,})\\s*$/\nconst RE_UNORDERED_LIST = /^(\\s*)([-*+])\\s/\nconst RE_ORDERED_LIST = /^(\\s*)(\\d{1,9})[.)]\\s/\nconst RE_BLOCKQUOTE = /^\\s{0,3}>/\nconst RE_HTML_BLOCK_1 = /^\\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\\?|!\\[CDATA\\[)/i\nconst RE_HTML_BLOCK_2 = /^\\s{0,3}<\\/?[a-zA-Z][a-zA-Z0-9-]*(\\s|>|$)/\nconst RE_TABLE_DELIMITER = /^\\|?\\s*:?-{3,}:?\\s*(\\|\\s*:?-{3,}:?\\s*)*\\|?$/\nconst RE_ESCAPE_SPECIAL = /[.*+?^${}()|[\\]\\\\]/g\nconst RE_FOOTNOTE_DEFINITION = /^\\[\\^[^\\]]+\\]:\\s/\nconst RE_FOOTNOTE_CONTINUATION = /^(?: |\\t)/\n\n/** fence 结束模式缓存 */\nconst fenceEndPatternCache = new Map<string, RegExp>()\n\n/** 容器模式缓存 */\nconst containerPatternCache = new Map<string, RegExp>()\n\n// ============ 代码块检测 ============\n\n/**\n * 检测行是否是代码块 fence 开始\n */\nexport function detectFenceStart(line: string): { char: string; length: number } | null {\n const match = line.match(RE_FENCE_START)\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 // 使用缓存的正则表达式\n const cacheKey = `${context.fenceChar}-${context.fenceLength}`\n let pattern = fenceEndPatternCache.get(cacheKey)\n if (!pattern) {\n pattern = new RegExp(`^\\\\s{0,3}${context.fenceChar}{${context.fenceLength},}\\\\s*$`)\n fenceEndPatternCache.set(cacheKey, pattern)\n }\n return pattern.test(line)\n}\n\n// ============ 行类型检测 ============\n\n/**\n * 检测是否是空行或仅包含空白字符\n */\nexport function isEmptyLine(line: string): boolean {\n return RE_EMPTY_LINE.test(line)\n}\n\n/**\n * 检测是否是标题行\n */\nexport function isHeading(line: string): boolean {\n return RE_HEADING.test(line)\n}\n\n/**\n * 检测是否是 thematic break(水平线)\n */\nexport function isThematicBreak(line: string): boolean {\n return RE_THEMATIC_BREAK.test(line.trim())\n}\n\n/**\n * 检测是否是列表项开始\n */\nexport function isListItemStart(line: string): { ordered: boolean; indent: number } | null {\n // 无序列表: - * +\n const unordered = line.match(RE_UNORDERED_LIST)\n if (unordered) {\n return { ordered: false, indent: unordered[1].length }\n }\n\n // 有序列表: 1. 2) 等\n const ordered = line.match(RE_ORDERED_LIST)\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 RE_BLOCKQUOTE.test(line)\n}\n\n/**\n * 检测是否是 HTML 块\n */\nexport function isHtmlBlock(line: string): boolean {\n return RE_HTML_BLOCK_1.test(line) || RE_HTML_BLOCK_2.test(line)\n}\n\n/**\n * 检测表格分隔行\n */\nexport function isTableDelimiter(line: string): boolean {\n return RE_TABLE_DELIMITER.test(line.trim())\n}\n\n// ============ 脚注检测 ============\n\n/**\n * 检测是否是脚注定义的起始行\n * 格式: [^id]: content\n * \n * @example\n * isFootnoteDefinitionStart('[^1]: 脚注内容') // true\n * isFootnoteDefinitionStart('[^note]: 内容') // true\n * isFootnoteDefinitionStart(' 缩进内容') // false\n */\nexport function isFootnoteDefinitionStart(line: string): boolean {\n return RE_FOOTNOTE_DEFINITION.test(line)\n}\n\n/**\n * 检测是否是脚注定义的延续行(缩进行)\n * 至少4个空格或1个tab\n * \n * @example\n * isFootnoteContinuation(' 第二行') // true\n * isFootnoteContinuation('\\t第二行') // true\n * isFootnoteContinuation(' 两个空格') // false\n */\nexport function isFootnoteContinuation(line: string): boolean {\n return RE_FOOTNOTE_CONTINUATION.test(line)\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 // 使用缓存的正则表达式\n const cacheKey = `${marker}-${minLength}`\n let pattern = containerPatternCache.get(cacheKey)\n if (!pattern) {\n const escapedMarker = marker.replace(RE_ESCAPE_SPECIAL, '\\\\$&')\n // 支持两种格式:\n // 1. ::: name attr (有空格分隔)\n // 2. :::name{...} (directive 语法,无空格)\n pattern = new RegExp(\n `^(\\\\s*)(${escapedMarker}{${minLength},})(?:\\\\s*(\\\\w[\\\\w-]*))?(?:\\\\{[^}]*\\\\})?(?:\\\\s+(.*))?\\\\s*$`\n )\n containerPatternCache.set(cacheKey, pattern)\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 inList: false\n }\n}\n\n/**\n * 检测是否是列表项的延续内容(缩进内容或空行)\n * @param line 当前行\n * @param listIndent 列表的基础缩进\n */\nfunction isListContinuation(line: string, listIndent: number): boolean {\n // 空行可能是列表内部的段落分隔\n if (isEmptyLine(line)) {\n return true\n }\n\n // 检查是否有足够的缩进(列表内容至少需要缩进到列表标记之后)\n // 通常列表标记后至少需要 2 个字符的缩进(如 \"1. \" 或 \"- \")\n const contentIndent = line.match(/^(\\s*)/)?.[1].length ?? 0\n return contentIndent > listIndent\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 // 检查是否是容器结束\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 // 检查是否是嵌套容器开始\n const nested = detectContainer(line, containerCfg)\n if (nested && !nested.isEnd) {\n newContext.containerDepth = context.containerDepth + 1\n return newContext\n }\n\n // ⚠️ 关键:在容器内,无论是什么内容(空行、列表、段落等),都保持 inContainer = true\n // 只有容器结束标记才能改变容器状态\n // 这里不需要做任何操作,因为 newContext 已经复制了 context,inContainer 已经是 true\n return newContext\n } else {\n // 不在容器内,检查是否是容器开始\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 // 列表处理\n const listItem = isListItemStart(line)\n\n if (context.inList) {\n // 已经在列表中\n if (context.listMayEnd) {\n // 上一行是空行,需要确认列表是否结束\n if (listItem) {\n // 遇到新的列表项\n // 检查是否是同类型列表的延续\n if (listItem.ordered === context.listOrdered && listItem.indent === context.listIndent) {\n // 同类型同级别列表项,列表继续\n newContext.listMayEnd = false\n return newContext\n }\n // 不同类型或不同级别,列表结束,新列表开始\n newContext.inList = true\n newContext.listOrdered = listItem.ordered\n newContext.listIndent = listItem.indent\n newContext.listMayEnd = false\n return newContext\n } else if (isListContinuation(line, context.listIndent ?? 0)) {\n // 缩进内容或空行,列表继续\n newContext.listMayEnd = isEmptyLine(line)\n return newContext\n } else {\n // 非列表内容,列表结束\n newContext.inList = false\n newContext.listOrdered = undefined\n newContext.listIndent = undefined\n newContext.listMayEnd = false\n return newContext\n }\n } else {\n // 上一行不是空行\n if (listItem) {\n // 新列表项(可能是同级或嵌套)\n return newContext\n } else if (isEmptyLine(line)) {\n // 遇到空行,列表可能结束\n newContext.listMayEnd = true\n return newContext\n } else if (isListContinuation(line, context.listIndent ?? 0)) {\n // 缩进内容,列表继续\n return newContext\n } else {\n // 非缩进非列表内容,列表结束\n newContext.inList = false\n newContext.listOrdered = undefined\n newContext.listIndent = undefined\n newContext.listMayEnd = false\n return newContext\n }\n }\n } else {\n // 不在列表中\n if (listItem) {\n // 列表开始\n newContext.inList = true\n newContext.listOrdered = listItem.ordered\n newContext.listIndent = listItem.indent\n newContext.listMayEnd = false\n return newContext\n }\n }\n\n return newContext\n}\n\n"]}
1
+ {"version":3,"sources":["../../src/detector/index.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\nconst RE_FENCE_START = /^(\\s*)((`{3,})|(~{3,}))/\nconst RE_EMPTY_LINE = /^\\s*$/\nconst RE_HEADING = /^#{1,6}\\s/\nconst RE_THEMATIC_BREAK = /^(\\*{3,}|-{3,}|_{3,})\\s*$/\nconst RE_UNORDERED_LIST = /^(\\s*)([-*+])\\s/\nconst RE_ORDERED_LIST = /^(\\s*)(\\d{1,9})[.)]\\s/\nconst RE_BLOCKQUOTE = /^\\s{0,3}>/\nconst RE_HTML_BLOCK_1 = /^\\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\\?|!\\[CDATA\\[)/i\nconst RE_HTML_BLOCK_2 = /^\\s{0,3}<\\/?[a-zA-Z][a-zA-Z0-9-]*(\\s|>|$)/\nconst RE_TABLE_DELIMITER = /^\\|?\\s*:?-{3,}:?\\s*(\\|\\s*:?-{3,}:?\\s*)*\\|?$/\nconst RE_ESCAPE_SPECIAL = /[.*+?^${}()|[\\]\\\\]/g\nconst RE_FOOTNOTE_DEFINITION = /^\\[\\^([^\\]]+)\\]:\\s/\nconst RE_FOOTNOTE_CONTINUATION = /^(?: |\\t)/\n\n/** fence 结束模式缓存 */\nconst fenceEndPatternCache = new Map<string, RegExp>()\n\n/** 容器模式缓存 */\nconst containerPatternCache = new Map<string, RegExp>()\n\n// ============ 代码块检测 ============\n\n/**\n * 检测行是否是代码块 fence 开始\n */\nexport function detectFenceStart(line: string): { char: string; length: number } | null {\n const match = line.match(RE_FENCE_START)\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 // 使用缓存的正则表达式\n const cacheKey = `${context.fenceChar}-${context.fenceLength}`\n let pattern = fenceEndPatternCache.get(cacheKey)\n if (!pattern) {\n pattern = new RegExp(`^\\\\s{0,3}${context.fenceChar}{${context.fenceLength},}\\\\s*$`)\n fenceEndPatternCache.set(cacheKey, pattern)\n }\n return pattern.test(line)\n}\n\n// ============ 行类型检测 ============\n\n/**\n * 检测是否是空行或仅包含空白字符\n */\nexport function isEmptyLine(line: string): boolean {\n return RE_EMPTY_LINE.test(line)\n}\n\n/**\n * 检测是否是标题行\n */\nexport function isHeading(line: string): boolean {\n return RE_HEADING.test(line)\n}\n\n/**\n * 检测是否是 thematic break(水平线)\n */\nexport function isThematicBreak(line: string): boolean {\n return RE_THEMATIC_BREAK.test(line.trim())\n}\n\n/**\n * 检测是否是列表项开始\n *\n * CommonMark 规范:列表项可以是以下形式:\n * - `- text`(无缩进)\n * - `1. text`(有序列表)\n * - ` - text`(缩进4个空格,作为上一个列表项的延续)\n *\n * 注意:` - text` 这种形式,虽然 `-` 后面没有空格,\n * 但因为前面有4个空格的缩进,所以是列表项的有效形式。\n */\nexport function isListItemStart(line: string): { ordered: boolean; indent: number } | null {\n // 先检查是否以列表标记开头(-、*、+、数字)\n const hasListMarker = /^(\\s*)([-*+]|\\d{1,9}[.)])/.test(line)\n \n if (!hasListMarker) {\n return null\n }\n \n // 如果有列表标记,检查是否是列表项的延续(缩进4+个空格)\n const match = line.match(/^(\\s*)([-*+]|\\d{1,9}[.)])(.*)/)\n if (match) {\n const indent = match[1].length\n const marker = match[2]\n const rest = match[3]\n \n // 如果标记后有内容,检查是否是有效的列表项\n if (rest.trim()) {\n const isOrdered = /^\\d{1,9}[.)]/.test(marker)\n return { ordered: isOrdered, indent }\n }\n \n // 标记后只有空格,可能是缩进的列表项\n // 如 \" - text\" 或 \" 1. text\"\n if (/^\\s+$/.test(rest)) {\n const isOrdered = /^\\d{1,9}[.)]/.test(marker)\n return { ordered: isOrdered, indent }\n }\n }\n \n return null\n}\n\n/**\n * 检测是否是引用块开始\n */\nexport function isBlockquoteStart(line: string): boolean {\n return RE_BLOCKQUOTE.test(line)\n}\n\n/**\n * 检测是否是 HTML 块\n */\nexport function isHtmlBlock(line: string): boolean {\n return RE_HTML_BLOCK_1.test(line) || RE_HTML_BLOCK_2.test(line)\n}\n\n/**\n * 检测表格分隔行\n */\nexport function isTableDelimiter(line: string): boolean {\n return RE_TABLE_DELIMITER.test(line.trim())\n}\n\n// ============ 脚注检测 ============\n\n/**\n * 检测是否是脚注定义的起始行\n * 格式: [^id]: content\n * \n * @example\n * isFootnoteDefinitionStart('[^1]: 脚注内容') // true\n * isFootnoteDefinitionStart('[^note]: 内容') // true\n * isFootnoteDefinitionStart(' 缩进内容') // false\n */\nexport function isFootnoteDefinitionStart(line: string): boolean {\n return RE_FOOTNOTE_DEFINITION.test(line)\n}\n\n/**\n * 检测是否是脚注定义的延续行(缩进行)\n * 至少4个空格或1个tab\n * \n * @example\n * isFootnoteContinuation(' 第二行') // true\n * isFootnoteContinuation('\\t第二行') // true\n * isFootnoteContinuation(' 两个空格') // false\n */\nexport function isFootnoteContinuation(line: string): boolean {\n return RE_FOOTNOTE_CONTINUATION.test(line)\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 // 使用缓存的正则表达式\n const cacheKey = `${marker}-${minLength}`\n let pattern = containerPatternCache.get(cacheKey)\n if (!pattern) {\n const escapedMarker = marker.replace(RE_ESCAPE_SPECIAL, '\\\\$&')\n // 支持两种格式:\n // 1. ::: name attr (有空格分隔)\n // 2. :::name{...} (directive 语法,无空格)\n pattern = new RegExp(\n `^(\\\\s*)(${escapedMarker}{${minLength},})(?:\\\\s*(\\\\w[\\\\w-]*))?(?:\\\\{[^}]*\\\\})?(?:\\\\s+(.*))?\\\\s*$`\n )\n containerPatternCache.set(cacheKey, pattern)\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 inList: false,\n inFootnote: false,\n footnoteIdentifier: undefined\n }\n}\n\n/**\n * 检测是否是列表项的延续内容(缩进内容或空行)\n * @param line 当前行\n * @param listIndent 列表的基础缩进\n */\nfunction isListContinuation(line: string, listIndent: number): boolean {\n // 空行可能是列表内部的段落分隔\n if (isEmptyLine(line)) {\n return true\n }\n\n // 检查是否有足够的缩进(列表内容至少需要缩进到列表标记之后)\n // 通常列表标记后至少需要 2 个字符的缩进(如 \"1. \" 或 \"- \")\n const contentIndent = line.match(/^(\\s*)/)?.[1].length ?? 0\n return contentIndent > listIndent\n}\n\n/**\n * 更新代码块上下文\n */\nfunction updateCodeContext(line: string, context: BlockContext): BlockContext | null {\n const newContext = { ...context }\n\n if (context.inFencedCode) {\n if (detectFenceEnd(line, context)) {\n newContext.inFencedCode = false\n newContext.fenceChar = undefined\n newContext.fenceLength = undefined\n return newContext\n }\n return null\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 return null\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 // 检查是否是容器结束\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 // 检查是否是嵌套容器开始\n const nested = detectContainer(line, containerCfg)\n if (nested && !nested.isEnd) {\n newContext.containerDepth = context.containerDepth + 1\n return newContext\n }\n\n // ⚠️ 关键:在容器内,无论是什么内容(空行、列表、段落等),都保持 inContainer = true\n // 只有容器结束标记才能改变容器状态\n // 这里不需要做任何操作,因为 newContext 已经复制了 context,inContainer 已经是 true\n return newContext\n } else {\n // 不在容器内,检查是否是容器开始\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 // 脚注处理\n // 脚注定义会结束所有其他块(列表等),必须优先处理\n \n // 在脚注中,遇到新脚注定义:前一个脚注结束,新脚注开始\n if (context.inFootnote && isFootnoteDefinitionStart(line)) {\n const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1]\n newContext.footnoteIdentifier = identifier\n return newContext\n }\n \n // 不在脚注中,遇到脚注定义:脚注开始\n if (!context.inFootnote && isFootnoteDefinitionStart(line)) {\n const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1]\n newContext.inFootnote = true\n newContext.footnoteIdentifier = identifier\n return newContext\n }\n\n // 列表处理\n const listItem = isListItemStart(line)\n\n if (context.inList) {\n // 已经在列表中\n if (context.listMayEnd) {\n // 上一行是空行,需要确认列表是否结束\n if (listItem) {\n // 遇到新的列表项\n // 检查是否是同类型列表的延续\n if (listItem.ordered === context.listOrdered && listItem.indent === context.listIndent) {\n // 同类型同级别列表项,列表继续\n newContext.listMayEnd = false\n return newContext\n }\n // 不同类型或不同级别,列表结束,新列表开始\n newContext.inList = true\n newContext.listOrdered = listItem.ordered\n newContext.listIndent = listItem.indent\n newContext.listMayEnd = false\n return newContext\n } else if (isListContinuation(line, context.listIndent ?? 0)) {\n // 缩进内容或空行,列表继续\n newContext.listMayEnd = isEmptyLine(line)\n return newContext\n } else {\n // 非列表内容,列表结束\n newContext.inList = false\n newContext.listOrdered = undefined\n newContext.listIndent = undefined\n newContext.listMayEnd = false\n return newContext\n }\n } else {\n // 上一行不是空行\n if (listItem) {\n // 新列表项(可能是同级或嵌套)\n return newContext\n } else if (isEmptyLine(line)) {\n // 遇到空行,列表可能结束\n newContext.listMayEnd = true\n return newContext\n } else if (isListContinuation(line, context.listIndent ?? 0)) {\n // 缩进内容,列表继续\n return newContext\n } else {\n // 非缩进非列表内容,列表结束\n newContext.inList = false\n newContext.listOrdered = undefined\n newContext.listIndent = undefined\n newContext.listMayEnd = false\n return newContext\n }\n }\n } else {\n // 不在列表中\n if (listItem) {\n // 列表开始\n newContext.inList = true\n newContext.listOrdered = listItem.ordered\n newContext.listIndent = listItem.indent\n newContext.listMayEnd = false\n return newContext\n }\n }\n\n // 脚注处理\n if (context.inFootnote) {\n // 已经在脚注中\n if (isEmptyLine(line)) {\n // 空行可能结束脚注(但不立即结束,等待下一行判断)\n // 保持 inFootnote = true,这样可以处理脚注内部的多段落\n return newContext\n } else if (isListItemStart(line)) {\n // 列表项处理\n const listItemInfo = isListItemStart(line)!\n \n // 如果是无缩进的列表项(如 `- xxx`),则脚注结束\n // 如果是缩进的列表项(如 ` - xxx`),则是脚注的延续内容\n if (listItemInfo.indent === 0) {\n // 无缩进列表项:脚注结束,开始新列表\n newContext.inFootnote = false\n newContext.footnoteIdentifier = undefined\n // 继续处理列表项的逻辑(不在 else 分支,会继续执行列表处理)\n } else {\n // 缩进列表项:视为脚注的延续内容(可能包含嵌套列表)\n // 保持 inFootnote = true\n return newContext\n }\n } else if (isHeading(line)) {\n // 标题结束脚注\n newContext.inFootnote = false\n newContext.footnoteIdentifier = undefined\n return newContext\n } else if (detectFenceStart(line)) {\n // 代码块结束脚注\n newContext.inFootnote = false\n newContext.footnoteIdentifier = undefined\n return newContext\n } else if (isBlockquoteStart(line)) {\n // 引用块结束脚注\n newContext.inFootnote = false\n newContext.footnoteIdentifier = undefined\n return newContext\n } else if (isFootnoteContinuation(line)) {\n // 真正的脚注延续:以4+空格开头且不是列表项等\n return newContext\n } else if (isFootnoteDefinitionStart(line)) {\n // 新脚注开始,前一个脚注结束\n const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1]\n newContext.footnoteIdentifier = identifier\n return newContext\n } else {\n // 其他内容(普通文本、表格等),脚注结束\n newContext.inFootnote = false\n newContext.footnoteIdentifier = undefined\n return newContext\n }\n }\n\n return newContext\n}\n\n"]}
@@ -287,6 +287,10 @@ interface BlockContext {
287
287
  listIndent?: number;
288
288
  /** 遇到空行后,列表可能结束(等待下一行确认) */
289
289
  listMayEnd?: boolean;
290
+ /** 当前是否在脚注定义中 */
291
+ inFootnote?: boolean;
292
+ /** 脚注标识符 */
293
+ footnoteIdentifier?: string;
290
294
  }
291
295
  /**
292
296
  * 容器检测结果
@@ -343,6 +347,14 @@ declare function isHeading(line: string): boolean;
343
347
  declare function isThematicBreak(line: string): boolean;
344
348
  /**
345
349
  * 检测是否是列表项开始
350
+ *
351
+ * CommonMark 规范:列表项可以是以下形式:
352
+ * - `- text`(无缩进)
353
+ * - `1. text`(有序列表)
354
+ * - ` - text`(缩进4个空格,作为上一个列表项的延续)
355
+ *
356
+ * 注意:` - text` 这种形式,虽然 `-` 后面没有空格,
357
+ * 但因为前面有4个空格的缩进,所以是列表项的有效形式。
346
358
  */
347
359
  declare function isListItemStart(line: string): {
348
360
  ordered: boolean;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ParserOptions, I as IncrementalUpdate, a as ParsedBlock, D as DefinitionMap, F as FootnoteDefinitionMap, b as ParserState, B as BlockStatus } from './index-BfVDhalw.js';
2
- export { A as AstNode, c as BlockContext, e as BlockTypeInfo, C as ContainerConfig, d as ContainerMatch, J as HTML_ATTR_BLACKLIST, K as HTML_PROTOCOL_BLACKLIST, H as HTML_TAG_BLACKLIST, N as HtmlAttrInfo, R as HtmlContentType, M as HtmlElementNode, Q as HtmlTreeExtensionOptions, O as ParsedHtmlTag, s as createHtmlTreeTransformer, r as createInitialContext, o as detectContainer, p as detectContainerEnd, g as detectFenceEnd, f as detectFenceStart, x as detectHtmlContentType, E as findHtmlElementsByTag, G as htmlElementToString, L as htmlTreeExtension, q as isBlockBoundary, l as isBlockquoteStart, i as isEmptyLine, h as isHeading, m as isHtmlBlock, y as isHtmlElementNode, k as isListItemStart, n as isTableDelimiter, j as isThematicBreak, w as parseHtmlFragment, v as parseHtmlTag, t as transformHtmlNodes, u as updateContext, z as walkHtmlElements } from './index-BfVDhalw.js';
1
+ import { P as ParserOptions, I as IncrementalUpdate, a as ParsedBlock, D as DefinitionMap, F as FootnoteDefinitionMap, b as ParserState, B as BlockStatus } from './index-BMUkM7mT.js';
2
+ export { A as AstNode, c as BlockContext, e as BlockTypeInfo, C as ContainerConfig, d as ContainerMatch, J as HTML_ATTR_BLACKLIST, K as HTML_PROTOCOL_BLACKLIST, H as HTML_TAG_BLACKLIST, N as HtmlAttrInfo, R as HtmlContentType, M as HtmlElementNode, Q as HtmlTreeExtensionOptions, O as ParsedHtmlTag, s as createHtmlTreeTransformer, r as createInitialContext, o as detectContainer, p as detectContainerEnd, g as detectFenceEnd, f as detectFenceStart, x as detectHtmlContentType, E as findHtmlElementsByTag, G as htmlElementToString, L as htmlTreeExtension, q as isBlockBoundary, l as isBlockquoteStart, i as isEmptyLine, h as isHeading, m as isHtmlBlock, y as isHtmlElementNode, k as isListItemStart, n as isTableDelimiter, j as isThematicBreak, w as parseHtmlFragment, v as parseHtmlTag, t as transformHtmlNodes, u as updateContext, z as walkHtmlElements } from './index-BMUkM7mT.js';
3
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';
@@ -355,6 +355,11 @@ declare class BlockTransformer<T = unknown> {
355
355
  * 销毁,清理资源
356
356
  */
357
357
  destroy(): void;
358
+ /**
359
+ * 处理 block 内容更新时的字符数变化和进度调整
360
+ * 统一 push 和 update 方法中的重复逻辑
361
+ */
362
+ private handleContentChange;
358
363
  private getAllBlockIds;
359
364
  private setupVisibilityHandler;
360
365
  private removeVisibilityHandler;
@@ -364,6 +369,16 @@ declare class BlockTransformer<T = unknown> {
364
369
  private tick;
365
370
  /**
366
371
  * 从 AST 节点中提取指定范围的文本
372
+ *
373
+ * 优化说明:
374
+ * - 提前终止:当 charIndex >= end 时立即返回,避免不必要的遍历
375
+ * - 局部更新:charIndex 只在需要时更新,减少计算
376
+ * - 早期返回:发现足够的文本后可以提前退出(当前未实现,可作为未来优化)
377
+ *
378
+ * @param node 要提取文本的 AST 节点
379
+ * @param start 起始字符索引(包含)
380
+ * @param end 结束字符索引(不包含)
381
+ * @returns 提取的文本
367
382
  */
368
383
  private extractText;
369
384
  private getStep;
@@ -381,6 +396,11 @@ declare class BlockTransformer<T = unknown> {
381
396
  private updateCachedDisplayNode;
382
397
  /**
383
398
  * 获取总字符数(带缓存)
399
+ *
400
+ * 缓存策略:
401
+ * - 首次调用时计算并缓存
402
+ * - 内容更新时通过 clearCache() 清除缓存,下次重新计算
403
+ * - 切换到新 block 时也会清除缓存
384
404
  */
385
405
  private getTotalChars;
386
406
  /**
package/dist/index.js CHANGED
@@ -867,14 +867,12 @@ var RE_FENCE_START = /^(\s*)((`{3,})|(~{3,}))/;
867
867
  var RE_EMPTY_LINE = /^\s*$/;
868
868
  var RE_HEADING = /^#{1,6}\s/;
869
869
  var RE_THEMATIC_BREAK = /^(\*{3,}|-{3,}|_{3,})\s*$/;
870
- var RE_UNORDERED_LIST = /^(\s*)([-*+])\s/;
871
- var RE_ORDERED_LIST = /^(\s*)(\d{1,9})[.)]\s/;
872
870
  var RE_BLOCKQUOTE = /^\s{0,3}>/;
873
871
  var RE_HTML_BLOCK_1 = /^\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\?|!\[CDATA\[)/i;
874
872
  var RE_HTML_BLOCK_2 = /^\s{0,3}<\/?[a-zA-Z][a-zA-Z0-9-]*(\s|>|$)/;
875
873
  var RE_TABLE_DELIMITER = /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)*\|?$/;
876
874
  var RE_ESCAPE_SPECIAL = /[.*+?^${}()|[\]\\]/g;
877
- var RE_FOOTNOTE_DEFINITION = /^\[\^[^\]]+\]:\s/;
875
+ var RE_FOOTNOTE_DEFINITION = /^\[\^([^\]]+)\]:\s/;
878
876
  var RE_FOOTNOTE_CONTINUATION = /^(?: |\t)/;
879
877
  var fenceEndPatternCache = /* @__PURE__ */ new Map();
880
878
  var containerPatternCache = /* @__PURE__ */ new Map();
@@ -909,13 +907,23 @@ function isThematicBreak(line) {
909
907
  return RE_THEMATIC_BREAK.test(line.trim());
910
908
  }
911
909
  function isListItemStart(line) {
912
- const unordered = line.match(RE_UNORDERED_LIST);
913
- if (unordered) {
914
- return { ordered: false, indent: unordered[1].length };
910
+ const hasListMarker = /^(\s*)([-*+]|\d{1,9}[.)])/.test(line);
911
+ if (!hasListMarker) {
912
+ return null;
915
913
  }
916
- const ordered = line.match(RE_ORDERED_LIST);
917
- if (ordered) {
918
- return { ordered: true, indent: ordered[1].length };
914
+ const match = line.match(/^(\s*)([-*+]|\d{1,9}[.)])(.*)/);
915
+ if (match) {
916
+ const indent = match[1].length;
917
+ const marker = match[2];
918
+ const rest = match[3];
919
+ if (rest.trim()) {
920
+ const isOrdered = /^\d{1,9}[.)]/.test(marker);
921
+ return { ordered: isOrdered, indent };
922
+ }
923
+ if (/^\s+$/.test(rest)) {
924
+ const isOrdered = /^\d{1,9}[.)]/.test(marker);
925
+ return { ordered: isOrdered, indent };
926
+ }
919
927
  }
920
928
  return null;
921
929
  }
@@ -995,7 +1003,9 @@ function createInitialContext() {
995
1003
  blockquoteDepth: 0,
996
1004
  inContainer: false,
997
1005
  containerDepth: 0,
998
- inList: false
1006
+ inList: false,
1007
+ inFootnote: false,
1008
+ footnoteIdentifier: void 0
999
1009
  };
1000
1010
  }
1001
1011
  function isListContinuation(line, listIndent) {
@@ -1051,6 +1061,17 @@ function updateContext(line, context, containerConfig) {
1051
1061
  }
1052
1062
  }
1053
1063
  }
1064
+ if (context.inFootnote && isFootnoteDefinitionStart(line)) {
1065
+ const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1];
1066
+ newContext.footnoteIdentifier = identifier;
1067
+ return newContext;
1068
+ }
1069
+ if (!context.inFootnote && isFootnoteDefinitionStart(line)) {
1070
+ const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1];
1071
+ newContext.inFootnote = true;
1072
+ newContext.footnoteIdentifier = identifier;
1073
+ return newContext;
1074
+ }
1054
1075
  const listItem = isListItemStart(line);
1055
1076
  if (context.inList) {
1056
1077
  if (context.listMayEnd) {
@@ -1099,6 +1120,41 @@ function updateContext(line, context, containerConfig) {
1099
1120
  return newContext;
1100
1121
  }
1101
1122
  }
1123
+ if (context.inFootnote) {
1124
+ if (isEmptyLine(line)) {
1125
+ return newContext;
1126
+ } else if (isListItemStart(line)) {
1127
+ const listItemInfo = isListItemStart(line);
1128
+ if (listItemInfo.indent === 0) {
1129
+ newContext.inFootnote = false;
1130
+ newContext.footnoteIdentifier = void 0;
1131
+ } else {
1132
+ return newContext;
1133
+ }
1134
+ } else if (isHeading(line)) {
1135
+ newContext.inFootnote = false;
1136
+ newContext.footnoteIdentifier = void 0;
1137
+ return newContext;
1138
+ } else if (detectFenceStart(line)) {
1139
+ newContext.inFootnote = false;
1140
+ newContext.footnoteIdentifier = void 0;
1141
+ return newContext;
1142
+ } else if (isBlockquoteStart(line)) {
1143
+ newContext.inFootnote = false;
1144
+ newContext.footnoteIdentifier = void 0;
1145
+ return newContext;
1146
+ } else if (isFootnoteContinuation(line)) {
1147
+ return newContext;
1148
+ } else if (isFootnoteDefinitionStart(line)) {
1149
+ const identifier = line.match(RE_FOOTNOTE_DEFINITION)?.[1];
1150
+ newContext.footnoteIdentifier = identifier;
1151
+ return newContext;
1152
+ } else {
1153
+ newContext.inFootnote = false;
1154
+ newContext.footnoteIdentifier = void 0;
1155
+ return newContext;
1156
+ }
1157
+ }
1102
1158
  return newContext;
1103
1159
  }
1104
1160
 
@@ -1985,19 +2041,8 @@ var BlockTransformer = class {
1985
2041
  if (this.state.currentBlock) {
1986
2042
  const updated = blocks.find((b) => b.id === this.state.currentBlock.id);
1987
2043
  if (updated && updated.node !== this.state.currentBlock.node) {
1988
- const oldTotal = this.cachedTotalChars ?? this.countChars(this.state.currentBlock.node);
1989
- const newTotal = this.countChars(updated.node);
1990
- if (newTotal < oldTotal || newTotal < this.state.currentProgress) {
1991
- this.state.currentProgress = Math.min(this.state.currentProgress, newTotal);
1992
- this.chunks = [];
1993
- }
1994
- this.clearCache();
2044
+ this.handleContentChange(this.state.currentBlock.node, updated.node, true);
1995
2045
  this.state.currentBlock = updated;
1996
- if (!this.rafId && !this.isPaused) {
1997
- if (this.state.currentProgress < newTotal) {
1998
- this.startIfNeeded();
1999
- }
2000
- }
2001
2046
  }
2002
2047
  }
2003
2048
  }
@@ -2006,19 +2051,8 @@ var BlockTransformer = class {
2006
2051
  */
2007
2052
  update(block) {
2008
2053
  if (this.state.currentBlock?.id === block.id) {
2009
- const oldTotal = this.cachedTotalChars ?? this.countChars(this.state.currentBlock.node);
2010
- const newTotal = this.countChars(block.node);
2011
- if (newTotal !== oldTotal) {
2012
- this.clearCache();
2013
- }
2014
- if (newTotal < oldTotal || newTotal < this.state.currentProgress) {
2015
- this.state.currentProgress = Math.min(this.state.currentProgress, newTotal);
2016
- this.chunks = [];
2017
- }
2054
+ this.handleContentChange(this.state.currentBlock.node, block.node, false);
2018
2055
  this.state.currentBlock = block;
2019
- if (newTotal > oldTotal && !this.rafId && !this.isPaused && this.state.currentProgress >= oldTotal) {
2020
- this.startIfNeeded();
2021
- }
2022
2056
  }
2023
2057
  }
2024
2058
  /**
@@ -2165,6 +2199,30 @@ var BlockTransformer = class {
2165
2199
  this.removeVisibilityHandler();
2166
2200
  }
2167
2201
  // ============ 私有方法 ============
2202
+ /**
2203
+ * 处理 block 内容更新时的字符数变化和进度调整
2204
+ * 统一 push 和 update 方法中的重复逻辑
2205
+ */
2206
+ handleContentChange(oldNode, newNode, isUpdateFromPush) {
2207
+ const oldTotal = this.cachedTotalChars ?? this.countChars(oldNode);
2208
+ const newTotal = this.countChars(newNode);
2209
+ if (newTotal < oldTotal || newTotal < this.state.currentProgress) {
2210
+ this.state.currentProgress = Math.min(this.state.currentProgress, newTotal);
2211
+ this.chunks = [];
2212
+ }
2213
+ this.clearCache();
2214
+ if (isUpdateFromPush) {
2215
+ if (!this.rafId && !this.isPaused) {
2216
+ if (this.state.currentProgress < newTotal) {
2217
+ this.startIfNeeded();
2218
+ }
2219
+ }
2220
+ } else {
2221
+ if (newTotal > oldTotal && !this.rafId && !this.isPaused && this.state.currentProgress >= oldTotal) {
2222
+ this.startIfNeeded();
2223
+ }
2224
+ }
2225
+ }
2168
2226
  getAllBlockIds() {
2169
2227
  return new Set([
2170
2228
  ...this.state.completedBlocks.map((b) => b.id),
@@ -2251,8 +2309,21 @@ var BlockTransformer = class {
2251
2309
  }
2252
2310
  /**
2253
2311
  * 从 AST 节点中提取指定范围的文本
2312
+ *
2313
+ * 优化说明:
2314
+ * - 提前终止:当 charIndex >= end 时立即返回,避免不必要的遍历
2315
+ * - 局部更新:charIndex 只在需要时更新,减少计算
2316
+ * - 早期返回:发现足够的文本后可以提前退出(当前未实现,可作为未来优化)
2317
+ *
2318
+ * @param node 要提取文本的 AST 节点
2319
+ * @param start 起始字符索引(包含)
2320
+ * @param end 结束字符索引(不包含)
2321
+ * @returns 提取的文本
2254
2322
  */
2255
2323
  extractText(node, start, end) {
2324
+ if (start >= end) {
2325
+ return "";
2326
+ }
2256
2327
  let result = "";
2257
2328
  let charIndex = 0;
2258
2329
  function traverse(n) {
@@ -2260,12 +2331,12 @@ var BlockTransformer = class {
2260
2331
  if (n.value && typeof n.value === "string") {
2261
2332
  const nodeStart = charIndex;
2262
2333
  const nodeEnd = charIndex + n.value.length;
2263
- charIndex = nodeEnd;
2264
2334
  const overlapStart = Math.max(start, nodeStart);
2265
2335
  const overlapEnd = Math.min(end, nodeEnd);
2266
2336
  if (overlapStart < overlapEnd) {
2267
2337
  result += n.value.slice(overlapStart - nodeStart, overlapEnd - nodeStart);
2268
2338
  }
2339
+ charIndex = nodeEnd;
2269
2340
  return charIndex < end;
2270
2341
  }
2271
2342
  if (n.children && Array.isArray(n.children)) {
@@ -2383,12 +2454,21 @@ var BlockTransformer = class {
2383
2454
  }
2384
2455
  /**
2385
2456
  * 获取总字符数(带缓存)
2457
+ *
2458
+ * 缓存策略:
2459
+ * - 首次调用时计算并缓存
2460
+ * - 内容更新时通过 clearCache() 清除缓存,下次重新计算
2461
+ * - 切换到新 block 时也会清除缓存
2386
2462
  */
2387
2463
  getTotalChars() {
2388
- if (this.cachedTotalChars === null && this.state.currentBlock) {
2464
+ if (!this.state.currentBlock) {
2465
+ this.cachedTotalChars = null;
2466
+ return 0;
2467
+ }
2468
+ if (this.cachedTotalChars === null) {
2389
2469
  this.cachedTotalChars = this.countChars(this.state.currentBlock.node);
2390
2470
  }
2391
- return this.cachedTotalChars ?? 0;
2471
+ return this.cachedTotalChars;
2392
2472
  }
2393
2473
  /**
2394
2474
  * 清除缓存(当 block 切换或内容更新时)