stream-markdown-parser 0.0.59-beta.8 → 0.0.59

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/README.md CHANGED
@@ -227,7 +227,7 @@ Processes raw markdown-it tokens into a flat array.
227
227
 
228
228
  #### `parseInlineTokens(tokens, content?, preToken?, options?)`
229
229
 
230
- Parses inline markdown-it-ts tokens into renderer nodes. Pass the inline token array plus the optional raw `content` string (from the parent token), an optional previous token, and inline parse options (`requireClosingStrong`, `customHtmlTags`).
230
+ Parses inline markdown-it-ts tokens into renderer nodes. Pass the inline token array plus the optional raw `content` string (from the parent token), an optional previous token, and inline parse options (`requireClosingStrong`, `customHtmlTags`, `validateLink`).
231
231
 
232
232
  ### Configuration Functions
233
233
 
@@ -255,6 +255,8 @@ interface ParseOptions {
255
255
  postTransformTokens?: (tokens: Token[]) => Token[]
256
256
  // Custom HTML-like tags to emit as custom nodes (e.g. ['thinking'])
257
257
  customHtmlTags?: string[]
258
+ // Validate link href before emitting a `link` node; false -> plain text
259
+ validateLink?: (url: string) => boolean
258
260
  // When true, treats the input as complete (end-of-stream)
259
261
  final?: boolean
260
262
  // Require closing `**` for strong parsing (default: false)
@@ -279,6 +281,22 @@ const tagged = nodes.map(node =>
279
281
 
280
282
  Use the metadata in your renderer to show custom UI without mangling the original Markdown.
281
283
 
284
+ Example — enforce safe link protocols:
285
+
286
+ ```ts
287
+ const md = getMarkdown('safe-links')
288
+ md.set?.({
289
+ validateLink: (url: string) => !/^\s*javascript:/i.test(url.trim()),
290
+ })
291
+
292
+ const nodes = parseMarkdownToStructure(
293
+ '[ok](https://example.com) [bad](javascript:alert(1))',
294
+ md,
295
+ { final: true },
296
+ )
297
+ // "ok" stays a link node; "bad" is downgraded to plain text
298
+ ```
299
+
282
300
  ### Unknown HTML-like tags
283
301
 
284
302
  By default, non-standard HTML-like tags (for example `<question>`) are rendered as raw HTML elements once they are complete; during streaming, partial tags are kept as **literal text** to avoid flicker. If you want them emitted as custom nodes (`type: 'question'` with parsed attrs/content), opt in via `customHtmlTags`.
package/README.zh-CN.md CHANGED
@@ -226,7 +226,7 @@ interface GetMarkdownOptions {
226
226
 
227
227
  #### `parseInlineTokens(tokens, content?, preToken?, options?)`
228
228
 
229
- 解析内联 markdown-it-ts tokens 并产出节点。可传入原始 `content`(来自父 token)、可选的前一个 token,以及 inline 解析选项(`requireClosingStrong`、`customHtmlTags`)。
229
+ 解析内联 markdown-it-ts tokens 并产出节点。可传入原始 `content`(来自父 token)、可选的前一个 token,以及 inline 解析选项(`requireClosingStrong`、`customHtmlTags`、`validateLink`)。
230
230
 
231
231
  ### 配置函数
232
232
 
@@ -254,6 +254,8 @@ interface ParseOptions {
254
254
  postTransformTokens?: (tokens: Token[]) => Token[]
255
255
  // 自定义 HTML 类标签,作为自定义节点输出(如 ['thinking'])
256
256
  customHtmlTags?: string[]
257
+ // 输出 link 节点前校验 href;返回 false 时降级为纯文本
258
+ validateLink?: (url: string) => boolean
257
259
  // true 表示输入已结束(end-of-stream)
258
260
  final?: boolean
259
261
  // 解析 strong 时要求闭合 `**`(默认 false)
@@ -278,6 +280,22 @@ const tagged = nodes.map(node =>
278
280
 
279
281
  在渲染器中读取 `node.meta` 即可渲染自定义 UI,而无需直接修改 Markdown 文本。
280
282
 
283
+ 示例 —— 限制链接协议,拦截不安全链接:
284
+
285
+ ```ts
286
+ const md = getMarkdown('safe-links')
287
+ md.set?.({
288
+ validateLink: (url: string) => !/^\s*javascript:/i.test(url.trim()),
289
+ })
290
+
291
+ const nodes = parseMarkdownToStructure(
292
+ '[ok](https://example.com) [bad](javascript:alert(1))',
293
+ md,
294
+ { final: true },
295
+ )
296
+ // "ok" 保持为 link 节点;"bad" 会降级为纯文本
297
+ ```
298
+
281
299
  ### 未知 HTML 类标签
282
300
 
283
301
  默认情况下,非标准的 HTML 类标签(例如 `<question>`)在完整闭合时会按原生 HTML 渲染(作为自定义元素输出);流式场景下未闭合的片段会先按**纯文本**处理以避免闪烁。若希望它们作为自定义节点输出(`type: 'question'`,携带 attrs/content),需要在 `customHtmlTags` 中显式声明。
package/dist/index.d.ts CHANGED
@@ -336,6 +336,14 @@ interface ParseOptions {
336
336
  * to enable mid-state suppression for the same tags during streaming.
337
337
  */
338
338
  customHtmlTags?: string[];
339
+ /**
340
+ * If provided, link nodes are only emitted when this returns true for the href.
341
+ * When it returns false, the link is rendered as plain text (the link text only).
342
+ * Typically set from the MarkdownIt instance (e.g. md.options.validateLink or
343
+ * md.set({ validateLink })) so that unsafe URLs (e.g. javascript:) are not
344
+ * output as links.
345
+ */
346
+ validateLink?: (url: string) => boolean;
339
347
  debug?: boolean;
340
348
  }
341
349
  type PostTransformNodesHook = (nodes: ParsedNode[]) => ParsedNode[];
@@ -344,6 +352,7 @@ type PostTransformNodesHook = (nodes: ParsedNode[]) => ParsedNode[];
344
352
  declare function parseInlineTokens(tokens: MarkdownToken[], raw?: string, pPreToken?: MarkdownToken, options?: {
345
353
  requireClosingStrong?: boolean;
346
354
  customHtmlTags?: readonly string[];
355
+ validateLink?: (url: string) => boolean;
347
356
  }): ParsedNode[];
348
357
  //#endregion
349
358
  //#region src/parser/index.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/factory.ts","../src/types.ts","../src/parser/inline-parsers/index.ts","../src/parser/index.ts","../src/config.ts","../src/findMatchingClose.ts","../src/parser/inline-parsers/fence-parser.ts","../src/plugins/containers.ts","../src/plugins/isMathLike.ts","../src/plugins/math.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/factory.ts","../src/types.ts","../src/parser/inline-parsers/index.ts","../src/parser/index.ts","../src/config.ts","../src/findMatchingClose.ts","../src/parser/inline-parsers/fence-parser.ts","../src/plugins/containers.ts","../src/plugins/isMathLike.ts","../src/plugins/math.ts","../src/index.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7830,6 +7830,7 @@ function applyFixIndentedCodeBlock(md, options = {}) {
7830
7830
 
7831
7831
  //#endregion
7832
7832
  //#region src/plugins/fixLinkTokens.ts
7833
+ const LINKIFY_HARD_STOP_CHARS = ["!"];
7833
7834
  function textToken(content) {
7834
7835
  return {
7835
7836
  type: "text",
@@ -7906,6 +7907,38 @@ function createLinkToken(text$1, href, loading) {
7906
7907
  raw: String(`[${text$1}](${href})`)
7907
7908
  };
7908
7909
  }
7910
+ function appendToLinkToken(link$1, suffix) {
7911
+ if (!link$1 || !suffix) return;
7912
+ link$1.href = String(link$1.href ?? "") + suffix;
7913
+ link$1.text = String(link$1.text ?? "") + suffix;
7914
+ link$1.raw = String(`[${link$1.text}](${link$1.href})`);
7915
+ if (Array.isArray(link$1.children) && link$1.children.length) {
7916
+ const last = link$1.children[link$1.children.length - 1];
7917
+ if (last?.type === "text") {
7918
+ last.content = String(last.content ?? "") + suffix;
7919
+ last.raw = String(last.raw ?? "") + suffix;
7920
+ } else link$1.children.push(textToken(suffix));
7921
+ }
7922
+ }
7923
+ function firstIndexOfAny(input, chars) {
7924
+ let first = -1;
7925
+ for (const ch of chars) {
7926
+ const idx = input.indexOf(ch);
7927
+ if (idx !== -1 && (first === -1 || idx < first)) first = idx;
7928
+ }
7929
+ return first;
7930
+ }
7931
+ function getHrefFromLinkOpen(token) {
7932
+ const href = token?.attrs?.find((attr) => attr?.[0] === "href")?.[1];
7933
+ return typeof href === "string" ? href : "";
7934
+ }
7935
+ function setHrefOnLinkOpen(token, href) {
7936
+ if (!token) return;
7937
+ token.attrs = Array.isArray(token.attrs) ? token.attrs : [];
7938
+ const idx = token.attrs.findIndex((attr) => attr?.[0] === "href");
7939
+ if (idx >= 0) token.attrs[idx][1] = href;
7940
+ else token.attrs.push(["href", href]);
7941
+ }
7909
7942
  function applyFixLinkTokens(md) {
7910
7943
  md.core.ruler.after("inline", "fix_link_tokens", (state) => {
7911
7944
  const toks = state.tokens ?? [];
@@ -7920,12 +7953,57 @@ function applyFixLinkTokens(md) {
7920
7953
  });
7921
7954
  }
7922
7955
  function fixLinkToken(tokens) {
7923
- if (tokens.length < 4) return tokens;
7956
+ if (tokens.length < 3) return tokens;
7924
7957
  if (tokens.some((token) => token.type === "code_inline")) return tokens;
7925
7958
  for (let i = 0; i <= tokens.length - 1; i++) {
7926
7959
  if (i < 0) i = 0;
7927
7960
  const curToken = tokens[i];
7928
7961
  if (!curToken) break;
7962
+ if (curToken.type === "link_open" && (curToken.markup === "linkify" || curToken.markup === "autolink")) {
7963
+ let closeIdx = -1;
7964
+ for (let j = i + 1; j < tokens.length; j++) if (tokens[j]?.type === "link_close") {
7965
+ closeIdx = j;
7966
+ break;
7967
+ }
7968
+ if (closeIdx !== -1) {
7969
+ const href = getHrefFromLinkOpen(curToken);
7970
+ const hrefStop = firstIndexOfAny(href, LINKIFY_HARD_STOP_CHARS);
7971
+ for (let j = i + 1; j < closeIdx; j++) {
7972
+ const t = tokens[j];
7973
+ if (t?.type !== "text" || typeof t.content !== "string") continue;
7974
+ const stopAt = firstIndexOfAny(t.content, LINKIFY_HARD_STOP_CHARS);
7975
+ if (stopAt === -1) continue;
7976
+ const stopChar = t.content[stopAt];
7977
+ const before = t.content.slice(0, stopAt);
7978
+ let tail = t.content.slice(stopAt);
7979
+ for (let k = j + 1; k < closeIdx; k++) {
7980
+ const tk = tokens[k];
7981
+ if (tk?.type === "text" && typeof tk.content === "string") tail += tk.content;
7982
+ }
7983
+ t.content = before;
7984
+ t.raw = before;
7985
+ const removeCount = closeIdx - (j + 1);
7986
+ if (removeCount > 0) {
7987
+ tokens.splice(j + 1, removeCount);
7988
+ closeIdx = j + 1;
7989
+ }
7990
+ let newHref = href;
7991
+ if (hrefStop !== -1) newHref = href.slice(0, hrefStop);
7992
+ else if (tail) {
7993
+ const encodedTail = encodeURI(tail);
7994
+ if (encodedTail && href.endsWith(encodedTail)) newHref = href.slice(0, href.length - encodedTail.length);
7995
+ else {
7996
+ const encodedStop = stopChar ? encodeURI(stopChar) : "";
7997
+ const idx = encodedStop ? href.indexOf(encodedStop) : -1;
7998
+ if (idx !== -1) newHref = href.slice(0, idx);
7999
+ }
8000
+ }
8001
+ if (newHref !== href) setHrefOnLinkOpen(curToken, newHref);
8002
+ if (tail) tokens.splice(closeIdx + 1, 0, textToken(tail));
8003
+ break;
8004
+ }
8005
+ }
8006
+ }
7929
8007
  if (curToken?.type === "em_open" && tokens[i - 1]?.type === "text" && tokens[i - 1].content?.endsWith("*")) {
7930
8008
  const beforeText = tokens[i - 1].content?.replace(/(\*+)$/, "") || "";
7931
8009
  tokens[i - 1].content = beforeText;
@@ -8197,6 +8275,21 @@ function fixLinkToken(tokens) {
8197
8275
  }
8198
8276
  }
8199
8277
  }
8278
+ for (let i = 0; i < tokens.length - 1; i++) {
8279
+ const t = tokens[i];
8280
+ const next = tokens[i + 1];
8281
+ if (t?.type !== "link" || next?.type !== "text" || typeof next.content !== "string") continue;
8282
+ if (!next.content.startsWith("!")) continue;
8283
+ const href = String(t.href ?? "");
8284
+ if (String(t.text ?? "") !== href) continue;
8285
+ if (!href.endsWith("=") && !href.endsWith("#")) continue;
8286
+ appendToLinkToken(t, "!");
8287
+ const rest = next.content.slice(1);
8288
+ if (rest) {
8289
+ next.content = rest;
8290
+ next.raw = rest;
8291
+ } else tokens.splice(i + 1, 1);
8292
+ }
8200
8293
  return tokens;
8201
8294
  }
8202
8295
 
@@ -9411,7 +9504,8 @@ function parseEmphasisToken(tokens, startIndex, options) {
9411
9504
  }
9412
9505
  children.push(...parseInlineTokens(innerTokens, void 0, void 0, {
9413
9506
  requireClosingStrong: options?.requireClosingStrong,
9414
- customHtmlTags: options?.customHtmlTags
9507
+ customHtmlTags: options?.customHtmlTags,
9508
+ validateLink: options?.validateLink
9415
9509
  }));
9416
9510
  return {
9417
9511
  node: {
@@ -9933,7 +10027,8 @@ function parseStrongToken(tokens, startIndex, raw, options) {
9933
10027
  }
9934
10028
  children.push(...parseInlineTokens(innerTokens, raw, void 0, {
9935
10029
  requireClosingStrong: options?.requireClosingStrong,
9936
- customHtmlTags: options?.customHtmlTags
10030
+ customHtmlTags: options?.customHtmlTags,
10031
+ validateLink: options?.validateLink
9937
10032
  }));
9938
10033
  return {
9939
10034
  node: {
@@ -10036,6 +10131,28 @@ function countUnescapedAsterisks(str) {
10036
10131
  }
10037
10132
  return count;
10038
10133
  }
10134
+ const WORD_CHAR_RE = /[\p{L}\p{N}]/u;
10135
+ const WORD_ONLY_RE = /^[\p{L}\p{N}]+$/u;
10136
+ function isWordChar(ch) {
10137
+ if (!ch) return false;
10138
+ return WORD_CHAR_RE.test(ch);
10139
+ }
10140
+ function isWordOnly(text$1) {
10141
+ if (!text$1) return false;
10142
+ return WORD_ONLY_RE.test(text$1);
10143
+ }
10144
+ function getAsteriskRunInfo(content, start) {
10145
+ let end = start;
10146
+ while (end < content.length && content[end] === "*") end++;
10147
+ const prev = start > 0 ? content[start - 1] : void 0;
10148
+ const next = end < content.length ? content[end] : void 0;
10149
+ return {
10150
+ len: end - start,
10151
+ prev,
10152
+ next,
10153
+ intraword: isWordChar(prev) && isWordChar(next)
10154
+ };
10155
+ }
10039
10156
  function parseInlineTokens(tokens, raw, pPreToken, options) {
10040
10157
  if (!tokens || tokens.length === 0) return [];
10041
10158
  const result = [];
@@ -10127,15 +10244,32 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
10127
10244
  return true;
10128
10245
  }
10129
10246
  }
10247
+ const runInfo = getAsteriskRunInfo(content, openIdx);
10130
10248
  const exec = STRONG_PAIR_RE.exec(content);
10131
10249
  let inner = "";
10132
10250
  let after = "";
10133
10251
  if (exec && typeof exec.index === "number") {
10134
10252
  inner = exec[1];
10135
10253
  after = content.slice(exec.index + exec[0].length);
10254
+ const closeRunInfo = getAsteriskRunInfo(content, exec.index + exec[0].length - 2);
10255
+ if (runInfo.intraword && closeRunInfo.intraword && !isWordOnly(inner)) {
10256
+ pushText(content.slice(beforeText.length), content.slice(beforeText.length));
10257
+ i++;
10258
+ return true;
10259
+ }
10260
+ if (!inner && runInfo.len >= 4 && runInfo.intraword) {
10261
+ pushText(content.slice(beforeText.length), content.slice(beforeText.length));
10262
+ i++;
10263
+ return true;
10264
+ }
10136
10265
  } else {
10137
10266
  if (requireClosingStrong) {
10138
- pushText(content, content);
10267
+ pushText(content.slice(beforeText.length), content.slice(beforeText.length));
10268
+ i++;
10269
+ return true;
10270
+ }
10271
+ if (runInfo.intraword) {
10272
+ pushText(content.slice(beforeText.length), content.slice(beforeText.length));
10139
10273
  i++;
10140
10274
  return true;
10141
10275
  }
@@ -10201,7 +10335,13 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
10201
10335
  };
10202
10336
  result.push(currentTextNode);
10203
10337
  }
10338
+ const runInfo = getAsteriskRunInfo(content, idx);
10204
10339
  const closeIndex = content.indexOf("*", idx + 1);
10340
+ if (closeIndex === -1 && runInfo.intraword) {
10341
+ pushText(content.slice(idx), content.slice(idx));
10342
+ i++;
10343
+ return true;
10344
+ }
10205
10345
  const { node } = parseEmphasisToken([
10206
10346
  {
10207
10347
  type: "em_open",
@@ -10497,7 +10637,11 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
10497
10637
  i++;
10498
10638
  break;
10499
10639
  default:
10500
- pushToken(token);
10640
+ if (token.type === "link" && token.href != null && options?.validateLink && !options.validateLink(token.href)) {
10641
+ resetCurrentTextNode();
10642
+ const displayText = String(token.text ?? "");
10643
+ pushText(displayText, displayText);
10644
+ } else pushToken(token);
10501
10645
  i++;
10502
10646
  break;
10503
10647
  }
@@ -10577,6 +10721,10 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
10577
10721
  resetCurrentTextNode();
10578
10722
  const { node, nextIndex } = parseLinkToken(tokens, i, { requireClosingStrong });
10579
10723
  i = nextIndex;
10724
+ if (options?.validateLink && !options.validateLink(node.href)) {
10725
+ pushText(node.text, node.text);
10726
+ return;
10727
+ }
10580
10728
  const hrefAttr = token.attrs?.find(([name]) => name === "href")?.[1];
10581
10729
  const hrefStr = String(hrefAttr ?? "");
10582
10730
  if (raw && hrefStr) {
@@ -10630,9 +10778,11 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
10630
10778
  loading$1 = false;
10631
10779
  } else if (last?.type === "text" && last.content === ".") i++;
10632
10780
  if (textNodeContent) pushText(textNodeContent, textNodeContent);
10633
- pushParsed({
10781
+ const hrefFromToken = String(textToken$1.content ?? "");
10782
+ if (options?.validateLink && !options.validateLink(hrefFromToken)) pushText(text$1, text$1);
10783
+ else pushParsed({
10634
10784
  type: "link",
10635
- href: String(textToken$1.content ?? ""),
10785
+ href: hrefFromToken,
10636
10786
  title: null,
10637
10787
  text: text$1,
10638
10788
  children: [{
@@ -10723,7 +10873,8 @@ function parseInlineTokens(tokens, raw, pPreToken, options) {
10723
10873
  const { node } = parseEmphasisToken(newTokens, 0, options);
10724
10874
  pushNode(node);
10725
10875
  }
10726
- } else pushParsed({
10876
+ } else if (options?.validateLink && !options.validateLink(href)) pushText(text$1, text$1);
10877
+ else pushParsed({
10727
10878
  type: "link",
10728
10879
  href,
10729
10880
  title: null,
@@ -10866,7 +11017,8 @@ function parseList(tokens, index, options) {
10866
11017
  type: "paragraph",
10867
11018
  children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), preToken, {
10868
11019
  requireClosingStrong: options?.requireClosingStrong,
10869
- customHtmlTags: options?.customHtmlTags
11020
+ customHtmlTags: options?.customHtmlTags,
11021
+ validateLink: options?.validateLink
10870
11022
  }),
10871
11023
  raw: String(contentToken.content ?? "")
10872
11024
  });
@@ -10923,7 +11075,8 @@ function parseAdmonition(tokens, index, match, options) {
10923
11075
  type: "paragraph",
10924
11076
  children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
10925
11077
  requireClosingStrong: options?.requireClosingStrong,
10926
- customHtmlTags: options?.customHtmlTags
11078
+ customHtmlTags: options?.customHtmlTags,
11079
+ validateLink: options?.validateLink
10927
11080
  }),
10928
11081
  raw: String(contentToken.content ?? "")
10929
11082
  });
@@ -10995,7 +11148,8 @@ function parseContainer(tokens, index, options) {
10995
11148
  type: "paragraph",
10996
11149
  children: parseInlineTokens(_children || [], void 0, void 0, {
10997
11150
  requireClosingStrong: options?.requireClosingStrong,
10998
- customHtmlTags: options?.customHtmlTags
11151
+ customHtmlTags: options?.customHtmlTags,
11152
+ validateLink: options?.validateLink
10999
11153
  }),
11000
11154
  raw: String(contentToken.content ?? "").replace(/\n:+$/, "").replace(/\n\s*:::\s*$/, "")
11001
11155
  });
@@ -11052,7 +11206,8 @@ function parseBlockquote(tokens, index, options) {
11052
11206
  type: "paragraph",
11053
11207
  children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
11054
11208
  requireClosingStrong: options?.requireClosingStrong,
11055
- customHtmlTags: options?.customHtmlTags
11209
+ customHtmlTags: options?.customHtmlTags,
11210
+ validateLink: options?.validateLink
11056
11211
  }),
11057
11212
  raw: String(contentToken.content ?? "")
11058
11213
  });
@@ -11116,7 +11271,8 @@ function parseDefinitionList(tokens, index, options) {
11116
11271
  const termToken = tokens[j + 1];
11117
11272
  termNodes = parseInlineTokens(termToken.children || [], void 0, void 0, {
11118
11273
  requireClosingStrong: options?.requireClosingStrong,
11119
- customHtmlTags: options?.customHtmlTags
11274
+ customHtmlTags: options?.customHtmlTags,
11275
+ validateLink: options?.validateLink
11120
11276
  });
11121
11277
  j += 3;
11122
11278
  } else if (tokens[j].type === "dd_open") {
@@ -11128,7 +11284,8 @@ function parseDefinitionList(tokens, index, options) {
11128
11284
  type: "paragraph",
11129
11285
  children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
11130
11286
  requireClosingStrong: options?.requireClosingStrong,
11131
- customHtmlTags: options?.customHtmlTags
11287
+ customHtmlTags: options?.customHtmlTags,
11288
+ validateLink: options?.validateLink
11132
11289
  }),
11133
11290
  raw: String(contentToken.content ?? "")
11134
11291
  });
@@ -11167,7 +11324,8 @@ function parseFootnote(tokens, index, options) {
11167
11324
  type: "paragraph",
11168
11325
  children: parseInlineTokens(contentToken.children || [], String(contentToken.content ?? ""), void 0, {
11169
11326
  requireClosingStrong: options?.requireClosingStrong,
11170
- customHtmlTags: options?.customHtmlTags
11327
+ customHtmlTags: options?.customHtmlTags,
11328
+ validateLink: options?.validateLink
11171
11329
  }),
11172
11330
  raw: String(contentToken.content ?? "")
11173
11331
  });
@@ -11198,7 +11356,8 @@ function parseHeading(tokens, index, options) {
11198
11356
  ...attrsRecord ? { attrs: attrsRecord } : {},
11199
11357
  children: parseInlineTokens(headingContentToken.children || [], headingContent, void 0, {
11200
11358
  requireClosingStrong: options?.requireClosingStrong,
11201
- customHtmlTags: options?.customHtmlTags
11359
+ customHtmlTags: options?.customHtmlTags,
11360
+ validateLink: options?.validateLink
11202
11361
  }),
11203
11362
  raw: headingContent
11204
11363
  };
@@ -11313,7 +11472,8 @@ function parseTable(tokens, index, options) {
11313
11472
  header: isHeaderCell || isHeader,
11314
11473
  children: parseInlineTokens(contentToken.children || [], content, void 0, {
11315
11474
  requireClosingStrong: options?.requireClosingStrong,
11316
- customHtmlTags: options?.customHtmlTags
11475
+ customHtmlTags: options?.customHtmlTags,
11476
+ validateLink: options?.validateLink
11317
11477
  }),
11318
11478
  raw: content,
11319
11479
  align
@@ -11413,7 +11573,8 @@ function parseVmrContainer(tokens, index, options) {
11413
11573
  type: "paragraph",
11414
11574
  children: parseInlineTokens(childrenArr || [], void 0, void 0, {
11415
11575
  requireClosingStrong: options?.requireClosingStrong,
11416
- customHtmlTags: options?.customHtmlTags
11576
+ customHtmlTags: options?.customHtmlTags,
11577
+ validateLink: options?.validateLink
11417
11578
  }),
11418
11579
  raw: String(contentToken.content ?? "")
11419
11580
  });
@@ -11676,7 +11837,8 @@ function parseParagraph(tokens, index, options) {
11676
11837
  type: "paragraph",
11677
11838
  children: parseInlineTokens(paragraphContentToken.children || [], paragraphContent, void 0, {
11678
11839
  requireClosingStrong: options?.requireClosingStrong,
11679
- customHtmlTags: options?.customHtmlTags
11840
+ customHtmlTags: options?.customHtmlTags,
11841
+ validateLink: options?.validateLink
11680
11842
  }),
11681
11843
  raw: paragraphContent
11682
11844
  };
@@ -12010,6 +12172,87 @@ function normalizeCustomHtmlOpeningTagSameLine(markdown, tags) {
12010
12172
  }
12011
12173
  return out;
12012
12174
  }
12175
+ function ensureBlankLineAfterCustomHtmlCloseBeforeBlockMarkerSameLine(markdown, tags) {
12176
+ if (!markdown || !tags.length) return markdown;
12177
+ const tagSet = new Set(tags.map((t) => String(t ?? "").toLowerCase()));
12178
+ if (!tagSet.size) return markdown;
12179
+ const isIndentWs = (ch) => ch === " " || ch === " ";
12180
+ const parseBlockquotePrefix = (rawLine) => {
12181
+ let i = 0;
12182
+ let saw = false;
12183
+ let prefixEnd = 0;
12184
+ while (i < rawLine.length) {
12185
+ while (i < rawLine.length && isIndentWs(rawLine[i])) i++;
12186
+ if (i >= rawLine.length || rawLine[i] !== ">") break;
12187
+ saw = true;
12188
+ i++;
12189
+ while (i < rawLine.length && isIndentWs(rawLine[i])) i++;
12190
+ prefixEnd = i;
12191
+ }
12192
+ if (!saw) return null;
12193
+ return {
12194
+ prefix: rawLine.slice(0, prefixEnd),
12195
+ content: rawLine.slice(prefixEnd)
12196
+ };
12197
+ };
12198
+ const parseFenceMarker = (line) => {
12199
+ let i = 0;
12200
+ while (i < line.length && isIndentWs(line[i])) i++;
12201
+ const ch = line[i];
12202
+ if (ch !== "`" && ch !== "~") return null;
12203
+ let j = i;
12204
+ while (j < line.length && line[j] === ch) j++;
12205
+ const len = j - i;
12206
+ if (len < 3) return null;
12207
+ return {
12208
+ markerChar: ch,
12209
+ markerLen: len,
12210
+ rest: line.slice(j)
12211
+ };
12212
+ };
12213
+ const closeTagRes = Array.from(tagSet).map((tag) => {
12214
+ return new RegExp(String.raw`(<\s*\/\s*${tag}\s*>)${"(?=[\\t ]*(?:#{1,6}[\\t ]+|>|(?:[*+-]|\\d+[.)])[\\t ]+|(?:`{3,}|~{3,})|\\||\\$\\$|:{3,}|\\[\\^[^\\]]+\\]:|(?:-{3,}|\\*{3,}|_{3,})))"}`, "gi");
12215
+ });
12216
+ let inFence = false;
12217
+ let fenceChar = "";
12218
+ let fenceLen = 0;
12219
+ let out = "";
12220
+ let idx = 0;
12221
+ while (idx < markdown.length) {
12222
+ const nl = markdown.indexOf("\n", idx);
12223
+ const hasNl = nl !== -1;
12224
+ const isCrlf = hasNl && nl > idx && markdown[nl - 1] === "\r";
12225
+ const lineEnd = hasNl ? isCrlf ? nl - 1 : nl : markdown.length;
12226
+ const rawLine = markdown.slice(idx, lineEnd);
12227
+ const newline$1 = hasNl ? isCrlf ? "\r\n" : "\n" : "";
12228
+ const bq = parseBlockquotePrefix(rawLine);
12229
+ const prefix = bq?.prefix ?? "";
12230
+ const contentLine = bq?.content ?? rawLine;
12231
+ const fenceMatch = parseFenceMarker(contentLine);
12232
+ if (fenceMatch) if (inFence) {
12233
+ if (fenceMatch.markerChar === fenceChar && fenceMatch.markerLen >= fenceLen) {
12234
+ if (/^\s*$/.test(fenceMatch.rest)) {
12235
+ inFence = false;
12236
+ fenceChar = "";
12237
+ fenceLen = 0;
12238
+ }
12239
+ }
12240
+ } else {
12241
+ inFence = true;
12242
+ fenceChar = fenceMatch.markerChar;
12243
+ fenceLen = fenceMatch.markerLen;
12244
+ }
12245
+ let nextContent = contentLine;
12246
+ if (!inFence && nextContent.includes("</")) for (const re of closeTagRes) nextContent = nextContent.replace(re, "$1\n\n");
12247
+ if (prefix) {
12248
+ const withPrefix = prefix + nextContent.split("\n").join(`\n${prefix}`);
12249
+ out += withPrefix;
12250
+ } else out += nextContent;
12251
+ out += newline$1;
12252
+ idx = hasNl ? nl + 1 : markdown.length;
12253
+ }
12254
+ return out;
12255
+ }
12013
12256
  function ensureBlankLineBeforeCustomHtmlBlocks(markdown, tags) {
12014
12257
  if (!markdown || !tags.length) return markdown;
12015
12258
  const tagSet = new Set(tags.map((t) => String(t ?? "").toLowerCase()));
@@ -12243,6 +12486,7 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
12243
12486
  if (tags.length) {
12244
12487
  safeMarkdown = normalizeCustomHtmlOpeningTagSameLine(safeMarkdown, tags);
12245
12488
  safeMarkdown = ensureBlankLineBeforeCustomHtmlBlocks(safeMarkdown, tags);
12489
+ safeMarkdown = ensureBlankLineAfterCustomHtmlCloseBeforeBlockMarkerSameLine(safeMarkdown, tags);
12246
12490
  if (!safeMarkdown.includes("</")) {} else for (const tag of tags) {
12247
12491
  const re = new RegExp(String.raw`(^[\t ]*<\s*\/\s*${tag}\s*>[\t ]*)(\r?\n)(?![\t ]*\r?\n|$)`, "gim");
12248
12492
  safeMarkdown = safeMarkdown.replace(re, "$1$2$2");
@@ -12256,8 +12500,11 @@ function parseMarkdownToStructure(markdown, md, options = {}) {
12256
12500
  const post = options.postTransformTokens;
12257
12501
  let transformedTokens = tokens;
12258
12502
  if (pre && typeof pre === "function") transformedTokens = pre(transformedTokens) || transformedTokens;
12503
+ const mdAny = md;
12504
+ const validateLink$1 = options.validateLink ?? mdAny.options?.validateLink ?? (typeof mdAny.validateLink === "function" ? mdAny.validateLink : void 0);
12259
12505
  const internalOptions = {
12260
12506
  ...options,
12507
+ validateLink: validateLink$1,
12261
12508
  __sourceMarkdown: safeMarkdown,
12262
12509
  __customHtmlBlockCursor: 0
12263
12510
  };
@@ -12337,7 +12584,8 @@ function processTokens(tokens, options) {
12337
12584
  {
12338
12585
  const parsed = parseInlineTokens(token.children || [], String(token.content ?? ""), void 0, {
12339
12586
  requireClosingStrong: options?.requireClosingStrong,
12340
- customHtmlTags: options?.customHtmlTags
12587
+ customHtmlTags: options?.customHtmlTags,
12588
+ validateLink: options?.validateLink
12341
12589
  });
12342
12590
  if (parsed.length === 0) {} else if (parsed.every((n) => n.type === "html_block")) result.push(...parsed);
12343
12591
  else result.push({