@wenyan-md/core 3.0.8 → 3.0.10

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/core.js CHANGED
@@ -100,6 +100,12 @@ async function loadCssBySource(source) {
100
100
  throw new Error("Unknown source type");
101
101
  }
102
102
  }
103
+ function createSvgDataUrl(svg) {
104
+ if (!svg.hasAttribute("xmlns")) {
105
+ svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
106
+ }
107
+ return `data:image/svg+xml,${encodeURIComponent(svg.outerHTML)}`;
108
+ }
103
109
  const __vite_glob_0_0$1 = "pre{background:#282c34}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}";
104
110
  const __vite_glob_0_1$1 = "pre{background:#fafafa}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#383a42;background:#fafafa}.hljs-comment,.hljs-quote{color:#a0a1a7;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#a626a4}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e45649}.hljs-literal{color:#0184bb}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#50a14f}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#986801}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#4078f2}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#c18401}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}";
105
111
  const __vite_glob_0_2$1 = "pre{background:#282936}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#e9e9f4;background:#282936}.hljs ::selection,.hljs::selection{background-color:#4d4f68;color:#e9e9f4}.hljs-comment{color:#626483}.hljs-tag{color:#62d6e8}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#e9e9f4}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#ea51b2}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#b45bcf}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#00f769}.hljs-strong{font-weight:700;color:#00f769}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#ebff87}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#a1efe4}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#62d6e8}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#b45bcf}.hljs-emphasis{color:#b45bcf;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#00f769}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}\n";
@@ -196,7 +202,7 @@ async function handleFrontMatter(markdown) {
196
202
  const { attributes, body } = fm(markdown);
197
203
  const result = { content: body || "" };
198
204
  let head = "";
199
- const { title, description, cover, author, source_url, need_open_comment, only_fans_can_comment, image_list } = attributes;
205
+ const { title, description, cover, author, source_url, need_open_comment, only_fans_can_comment, image_list, type } = attributes;
200
206
  if (title) {
201
207
  result.title = title;
202
208
  }
@@ -207,9 +213,6 @@ async function handleFrontMatter(markdown) {
207
213
  if (cover) {
208
214
  result.cover = cover;
209
215
  }
210
- if (head) {
211
- result.content = head + result.content;
212
- }
213
216
  if (author) {
214
217
  result.author = author;
215
218
  }
@@ -225,6 +228,12 @@ async function handleFrontMatter(markdown) {
225
228
  if (image_list) {
226
229
  result.image_list = image_list;
227
230
  }
231
+ if (type) {
232
+ result.type = type;
233
+ }
234
+ if (head) {
235
+ result.content = head + result.content;
236
+ }
228
237
  return result;
229
238
  }
230
239
  const parseOptions = {
@@ -467,6 +476,44 @@ function createMarkedClient() {
467
476
  };
468
477
  }
469
478
  },
479
+ // Obsidian WikiLinks 图片语法扩展 ![[filename]] / ![[filename|alt]] / ![[filename|width]] / ![[filename|widthxheight]]
480
+ {
481
+ name: "wikiImage",
482
+ level: "inline",
483
+ start(src) {
484
+ return src.match(/!\[\[/)?.index;
485
+ },
486
+ tokenizer(src) {
487
+ const rule = /^!\[\[([^\]|]+?)(?:\|([^\]]*))?\]\]/;
488
+ const match = rule.exec(src);
489
+ if (!match) return;
490
+ const href = match[1].trim();
491
+ const modifier = match[2]?.trim() ?? "";
492
+ const dimOnly = /^(\d+)(?:x(\d+))?$/.exec(modifier);
493
+ const alt = dimOnly ? "" : modifier;
494
+ const width = dimOnly ? dimOnly[1] : "";
495
+ const height = dimOnly ? dimOnly[2] ?? "" : "";
496
+ return {
497
+ type: "wikiImage",
498
+ raw: match[0],
499
+ href,
500
+ alt,
501
+ width,
502
+ height,
503
+ tokens: []
504
+ };
505
+ },
506
+ renderer(token) {
507
+ const href = normalizeHref(token.href);
508
+ const altAttr = token.alt ? ` alt="${token.alt}"` : "";
509
+ const titleAttr = token.alt ? ` title="${token.alt}"` : "";
510
+ const styleParts = [];
511
+ if (token.width) styleParts.push(`width:${token.width}px`);
512
+ if (token.height) styleParts.push(`height:${token.height}px`);
513
+ const styleAttr = styleParts.length ? ` style="${styleParts.join("; ")}"` : "";
514
+ return `<img src="${href}"${altAttr}${titleAttr}${styleAttr}>`;
515
+ }
516
+ },
470
517
  // 自定义图片语法扩展 ![](){...}
471
518
  {
472
519
  name: "attributeImage",
@@ -646,24 +693,7 @@ function containsMermaidCodeBlock(html) {
646
693
  return html.includes("language-mermaid");
647
694
  }
648
695
  const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
649
- function wechatPostRender(element) {
650
- const mathElements = element.querySelectorAll("mjx-container");
651
- mathElements.forEach((mathContainer) => {
652
- const svg = mathContainer.querySelector("svg");
653
- if (!svg) return;
654
- svg.style.width = svg.getAttribute("width") || "";
655
- svg.style.height = svg.getAttribute("height") || "";
656
- svg.removeAttribute("width");
657
- svg.removeAttribute("height");
658
- const parent = mathContainer.parentElement;
659
- if (parent) {
660
- mathContainer.remove();
661
- parent.appendChild(svg);
662
- if (parent.classList.contains("block-equation")) {
663
- parent.setAttribute("style", "text-align: center; margin-bottom: 1rem;");
664
- }
665
- }
666
- });
696
+ function postRenderMermaidDiagrams(element) {
667
697
  const mermaidSvgs = element.querySelectorAll('[data-wenyan-diagram="mermaid"] svg');
668
698
  mermaidSvgs.forEach((svg) => {
669
699
  svg.style.maxWidth = "100%";
@@ -671,21 +701,6 @@ function wechatPostRender(element) {
671
701
  inlineMermaidSvgStyles(svg);
672
702
  flattenMermaidMarkers(svg);
673
703
  });
674
- const codeElements = element.querySelectorAll("pre code");
675
- codeElements.forEach((codeEl) => {
676
- codeEl.innerHTML = codeEl.innerHTML.replace(/\n/g, "<br>").replace(/(>[^<]+)|(^[^<]+)/g, (str) => str.replace(/\s/g, "&nbsp;"));
677
- });
678
- const listElements = element.querySelectorAll("li");
679
- listElements.forEach((li) => {
680
- const doc = element.ownerDocument;
681
- const section = doc.createElement("section");
682
- while (li.firstChild) {
683
- section.appendChild(li.firstChild);
684
- }
685
- li.appendChild(section);
686
- });
687
- element.style.color = "rgb(0, 0, 0)";
688
- element.style.caretColor = "rgb(0, 0, 0)";
689
704
  }
690
705
  function inlineMermaidSvgStyles(svg) {
691
706
  const styleElements = Array.from(svg.querySelectorAll("style"));
@@ -949,6 +964,50 @@ function isInlineStyleTarget(node) {
949
964
  }
950
965
  return node instanceof defaultView.SVGElement || node instanceof defaultView.HTMLElement;
951
966
  }
967
+ function wechatPostRender(element) {
968
+ const mathElements = element.querySelectorAll("mjx-container");
969
+ mathElements.forEach((mathContainer) => {
970
+ const svg = mathContainer.querySelector("svg");
971
+ if (!svg) return;
972
+ svg.style.width = svg.getAttribute("width") || "";
973
+ svg.style.height = svg.getAttribute("height") || "";
974
+ svg.removeAttribute("width");
975
+ svg.removeAttribute("height");
976
+ const parent = mathContainer.parentElement;
977
+ if (parent) {
978
+ mathContainer.remove();
979
+ parent.appendChild(svg);
980
+ if (parent.classList.contains("block-equation")) {
981
+ parent.setAttribute("style", "text-align: center; margin-bottom: 1rem;");
982
+ }
983
+ }
984
+ });
985
+ postRenderMermaidDiagrams(element);
986
+ const codeElements = element.querySelectorAll("pre code");
987
+ codeElements.forEach((codeEl) => {
988
+ codeEl.innerHTML = codeEl.innerHTML.replace(/\n/g, "<br>").replace(/(>[^<]+)|(^[^<]+)/g, (str) => str.replace(/\s/g, "&nbsp;"));
989
+ });
990
+ const listElements = element.querySelectorAll("li");
991
+ listElements.forEach((li) => {
992
+ const doc = element.ownerDocument;
993
+ const section = doc.createElement("section");
994
+ while (li.firstChild) {
995
+ section.appendChild(li.firstChild);
996
+ }
997
+ li.appendChild(section);
998
+ });
999
+ const nestedLists = element.querySelectorAll(
1000
+ "li > section > ul, li > section > ol"
1001
+ );
1002
+ nestedLists.forEach((nestedList) => {
1003
+ const li = nestedList.closest("li");
1004
+ if (li) {
1005
+ li.insertAdjacentElement("afterend", nestedList);
1006
+ }
1007
+ });
1008
+ element.style.color = "rgb(0, 0, 0)";
1009
+ element.style.caretColor = "rgb(0, 0, 0)";
1010
+ }
952
1011
  const themeModifier = createCssModifier({});
953
1012
  function renderTheme(wenyanElement, themeCss) {
954
1013
  const modifiedCss = themeModifier(themeCss);
@@ -1492,6 +1551,8 @@ function getContentForZhihu(wenyanElement) {
1492
1551
  return wenyanElement.outerHTML;
1493
1552
  }
1494
1553
  function getContentForToutiao(wenyanElement) {
1554
+ postRenderMermaidDiagrams(wenyanElement);
1555
+ processMermaid(wenyanElement);
1495
1556
  const containers = wenyanElement.querySelectorAll("mjx-container");
1496
1557
  const doc = wenyanElement.ownerDocument;
1497
1558
  containers.forEach((container) => {
@@ -1500,11 +1561,7 @@ function getContentForToutiao(wenyanElement) {
1500
1561
  return;
1501
1562
  }
1502
1563
  const img = doc.createElement("img");
1503
- if (!svg.hasAttribute("xmlns")) {
1504
- svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
1505
- }
1506
- const encodedSVG = encodeURIComponent(svg.outerHTML);
1507
- img.src = `data:image/svg+xml,${encodedSVG}`;
1564
+ img.src = createSvgDataUrl(svg);
1508
1565
  const style = svg.getAttribute("style");
1509
1566
  if (style) {
1510
1567
  img.setAttribute("style", style);
@@ -1519,10 +1576,67 @@ function getContentForToutiao(wenyanElement) {
1519
1576
  });
1520
1577
  return wenyanElement.outerHTML;
1521
1578
  }
1579
+ function processMermaid(root) {
1580
+ const figures = root.querySelectorAll('[data-wenyan-diagram="mermaid"]');
1581
+ const doc = root.ownerDocument;
1582
+ figures.forEach((figure) => {
1583
+ const svg = figure.querySelector("svg");
1584
+ if (!svg) {
1585
+ return;
1586
+ }
1587
+ let svgString = svg.outerHTML;
1588
+ svgString = fixMermaidSvgForServerRender(svgString);
1589
+ const img = doc.createElement("img");
1590
+ const encodedData = btoa(unescape(encodeURIComponent(svgString)));
1591
+ img.src = `data:image/svg+xml;base64,${encodedData}`;
1592
+ const style = svg.getAttribute("style");
1593
+ if (style) {
1594
+ img.setAttribute("style", style);
1595
+ }
1596
+ const ariaLabel = figure.getAttribute("aria-label") || figure.getAttribute("title") || svg.getAttribute("aria-label") || svg.getAttribute("title");
1597
+ if (ariaLabel) {
1598
+ img.alt = ariaLabel;
1599
+ }
1600
+ figure.replaceWith(img);
1601
+ });
1602
+ }
1603
+ function fixMermaidSvgForServerRender(svgString) {
1604
+ const baseFontSize = 16;
1605
+ let fixedSvg = svgString;
1606
+ fixedSvg = fixedSvg.replace(/([xy]|dx|dy)="([-0-9.]+)em"/g, (_, attr, val) => {
1607
+ const pxValue = parseFloat(val) * baseFontSize;
1608
+ return `${attr}="${pxValue}px"`;
1609
+ });
1610
+ let previousSvg;
1611
+ do {
1612
+ previousSvg = fixedSvg;
1613
+ fixedSvg = fixedSvg.replace(/<tspan(?![^>]*\b[xy]=)[^>]*>([\s\S]*?)<\/tspan>/g, "$1");
1614
+ } while (fixedSvg !== previousSvg);
1615
+ fixedSvg = fixedSvg.replace(/<tspan([^>]+)>/g, (match, attrs) => {
1616
+ const yMatch = attrs.match(/y="([-0-9.]+)(?:px)?"/);
1617
+ const dyMatch = attrs.match(/dy="([-0-9.]+)(?:px)?"/);
1618
+ if (yMatch && dyMatch) {
1619
+ const yVal = parseFloat(yMatch[1]);
1620
+ const dyVal = parseFloat(dyMatch[1]);
1621
+ const finalY = yVal + dyVal;
1622
+ let newAttrs = attrs.replace(/y="[-0-9.]+(?:px)?"\s*/, "").replace(/dy="[-0-9.]+(?:px)?"\s*/, "");
1623
+ return `<tspan ${newAttrs.trim()} y="${finalY}">`;
1624
+ }
1625
+ return match;
1626
+ });
1627
+ fixedSvg = fixedSvg.replace(/class="([^"]*?)text-inner-tspan([^"]*?)"/g, 'class="$1$2"');
1628
+ fixedSvg = fixedSvg.replace(/\sclass=""/g, "");
1629
+ return fixedSvg;
1630
+ }
1631
+ const DEFAULT_MERMAID_FONT_FAMILY = "'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC', 'Source Han Sans SC', Arial, sans-serif";
1522
1632
  const DEFAULT_MERMAID_CONFIG = {
1633
+ fontFamily: DEFAULT_MERMAID_FONT_FAMILY,
1523
1634
  htmlLabels: false,
1524
1635
  flowchart: {
1525
1636
  htmlLabels: false
1637
+ },
1638
+ themeVariables: {
1639
+ fontFamily: DEFAULT_MERMAID_FONT_FAMILY
1526
1640
  }
1527
1641
  };
1528
1642
  async function replaceMermaidCodeBlocks(root, renderDiagram) {
@@ -1587,6 +1701,7 @@ function createMermaidRenderError(error) {
1587
1701
  }
1588
1702
  function createMermaidConfig(overrides = {}) {
1589
1703
  const flowchartOverrides = getRecord(overrides.flowchart);
1704
+ const themeVariablesOverrides = getRecord(overrides.themeVariables);
1590
1705
  return {
1591
1706
  ...DEFAULT_MERMAID_CONFIG,
1592
1707
  startOnLoad: false,
@@ -1595,6 +1710,10 @@ function createMermaidConfig(overrides = {}) {
1595
1710
  flowchart: {
1596
1711
  ...getRecord(DEFAULT_MERMAID_CONFIG.flowchart),
1597
1712
  ...flowchartOverrides
1713
+ },
1714
+ themeVariables: {
1715
+ ...getRecord(DEFAULT_MERMAID_CONFIG.themeVariables),
1716
+ ...themeVariablesOverrides
1598
1717
  }
1599
1718
  };
1600
1719
  }
@@ -1625,12 +1744,15 @@ async function createWenyanCore(options = {}) {
1625
1744
  async handleFrontMatter(markdown) {
1626
1745
  return await handleFrontMatter(markdown);
1627
1746
  },
1628
- async renderMarkdown(markdown) {
1747
+ async renderMarkdown(markdown, disableMermaid = false) {
1629
1748
  let html = await markedClient.parse(markdown);
1630
1749
  if (isConvertMathJax) {
1631
1750
  html = mathJaxParser.parser(html);
1632
1751
  }
1633
- return await mermaidParser.parser(html);
1752
+ if (!disableMermaid) {
1753
+ html = await mermaidParser.parser(html);
1754
+ }
1755
+ return html;
1634
1756
  },
1635
1757
  async applyStylesWithTheme(wenyanElement, options2 = {}) {
1636
1758
  const {
@@ -15,7 +15,7 @@ export interface ApplyStylesOptions {
15
15
  }
16
16
  export declare function createWenyanCore(options?: WenyanOptions): Promise<{
17
17
  handleFrontMatter(markdown: string): Promise<FrontMatterResult>;
18
- renderMarkdown(markdown: string): Promise<string>;
18
+ renderMarkdown(markdown: string, disableMermaid?: boolean): Promise<string>;
19
19
  applyStylesWithTheme(wenyanElement: HTMLElement, options?: ApplyStylesOptions): Promise<string>;
20
20
  applyStylesWithResolvedCss(wenyanElement: HTMLElement, options: {
21
21
  themeCss: string;
@@ -8,5 +8,6 @@ export interface FrontMatterResult {
8
8
  need_open_comment?: boolean;
9
9
  only_fans_can_comment?: boolean;
10
10
  image_list?: string[];
11
+ type?: string;
11
12
  }
12
13
  export declare function handleFrontMatter(markdown: string): Promise<FrontMatterResult>;
@@ -0,0 +1 @@
1
+ export declare function postRenderMermaidDiagrams(element: HTMLElement): void;
@@ -22,3 +22,4 @@ export type CssSource = {
22
22
  url: string;
23
23
  };
24
24
  export declare function loadCssBySource(source: CssSource): Promise<string>;
25
+ export declare function createSvgDataUrl(svg: SVGSVGElement): string;
package/dist/wechat.js CHANGED
@@ -40,9 +40,13 @@ function createWechatClient(httpAdapter) {
40
40
  }
41
41
  };
42
42
  }
43
+ const WECHAT_ERROR_HINTS = {
44
+ 45166: "内容超长。小绿书模式有内容长度限制,请精简正文后重试。"
45
+ };
43
46
  function assertWechatSuccess(data) {
44
47
  if ("errcode" in data) {
45
- throw new Error(`${data.errcode}: ${data.errmsg}`);
48
+ const hint = WECHAT_ERROR_HINTS[data.errcode];
49
+ throw new Error(hint ? `${data.errcode}: ${hint} (${data.errmsg})` : `${data.errcode}: ${data.errmsg}`);
46
50
  }
47
51
  }
48
52
  export {
package/dist/wrapper.js CHANGED
@@ -269,7 +269,8 @@ function needUpload(url) {
269
269
  return !/^(https?:\/\/|data:|asset:\/\/)/i.test(url);
270
270
  }
271
271
  async function uploadLocalImage(originalUrl, serverUrl, headers, relativePath) {
272
- const imagePath = RuntimeEnv.resolveLocalPath(originalUrl, relativePath);
272
+ const decodedUrl = decodeURIComponent(originalUrl);
273
+ const imagePath = RuntimeEnv.resolveLocalPath(decodedUrl, relativePath);
273
274
  let fileBuffer;
274
275
  try {
275
276
  fileBuffer = await readBinaryFile(imagePath);
@@ -435,7 +436,8 @@ async function uploadImage(imageUrl, accessToken, fileName, relativePath, appId)
435
436
  const contentType = response.headers.get("content-type") || "image/jpeg";
436
437
  fileData = new Blob([arrayBuffer], { type: contentType });
437
438
  } else {
438
- const resolvedPath = RuntimeEnv.resolveLocalPath(imageUrl, relativePath);
439
+ const decodedUrl = decodeURIComponent(imageUrl);
440
+ const resolvedPath = RuntimeEnv.resolveLocalPath(decodedUrl, relativePath);
439
441
  const stats = await stat(resolvedPath);
440
442
  if (stats.size === 0) {
441
443
  throw new Error(`本地图片大小为0,无法上传: ${resolvedPath}`);
@@ -731,14 +733,14 @@ function ensureSvgPolyfills(window) {
731
733
  value() {
732
734
  const tagName = this.tagName.toLowerCase();
733
735
  if (tagName === "text" || tagName === "tspan") {
734
- const text = this.textContent ?? "";
735
- const width = Math.max(text.length * 8, 16);
736
+ const width = getEstimatedTextWidth(this);
737
+ const height = getEstimatedFontSize(this);
736
738
  return {
737
739
  x: 0,
738
- y: -16,
740
+ y: -height,
739
741
  width,
740
- height: 16,
741
- top: -16,
742
+ height,
743
+ top: -height,
742
744
  right: width,
743
745
  bottom: 0,
744
746
  left: 0,
@@ -809,12 +811,61 @@ function ensureSvgPolyfills(window) {
809
811
  configurable: true,
810
812
  writable: true,
811
813
  value() {
812
- const text = this.textContent ?? "";
813
- return Math.max(text.length * 8, 16);
814
+ return getEstimatedTextWidth(this);
814
815
  }
815
816
  });
816
817
  }
817
818
  }
819
+ function getEstimatedTextWidth(element) {
820
+ const text = element.textContent ?? "";
821
+ const fontSize = getEstimatedFontSize(element);
822
+ const visualLength = Array.from(text).reduce((length, character) => {
823
+ return length + (isWideCharacter(character) ? 2 : 1);
824
+ }, 0);
825
+ return Math.max(visualLength * (fontSize / 2), fontSize);
826
+ }
827
+ function getEstimatedFontSize(element) {
828
+ const inlineFontSize = element.getAttribute("font-size");
829
+ if (inlineFontSize) {
830
+ const parsed = Number.parseFloat(inlineFontSize);
831
+ if (Number.isFinite(parsed)) {
832
+ return parsed;
833
+ }
834
+ }
835
+ const computedFontSize = element.ownerDocument.defaultView?.getComputedStyle(element).fontSize;
836
+ if (computedFontSize) {
837
+ const parsed = Number.parseFloat(computedFontSize);
838
+ if (Number.isFinite(parsed)) {
839
+ return parsed;
840
+ }
841
+ }
842
+ return 16;
843
+ }
844
+ function isWideCharacter(character) {
845
+ return character.codePointAt(0) > 255;
846
+ }
847
+ async function extractAndCleanImages(body) {
848
+ const html = await wenyanCoreInstance.renderMarkdown(body);
849
+ const dom = new JSDOM(`<body><section id="wenyan">${html}</section></body>`);
850
+ const document = dom.window.document;
851
+ const wenyan = document.getElementById("wenyan");
852
+ const images = Array.from(wenyan.querySelectorAll("img"));
853
+ const imagePaths = images.map((img) => img.getAttribute("src")).filter((src) => !!src).map((src) => {
854
+ try {
855
+ return decodeURI(src);
856
+ } catch {
857
+ return src;
858
+ }
859
+ });
860
+ for (const img of images) {
861
+ const parent = img.parentElement;
862
+ img.remove();
863
+ if (parent && parent.tagName === "P" && parent.textContent?.trim() === "") {
864
+ parent.remove();
865
+ }
866
+ }
867
+ return { imagePaths, cleanedHtml: wenyan.outerHTML };
868
+ }
818
869
  const nodeMermaidRenderer = createNodeMermaidRenderer();
819
870
  const wenyanCoreInstance = await createWenyanCore({
820
871
  mermaid: {
@@ -859,6 +910,13 @@ async function renderStyledContent(content, options = {}, coreInstance = wenyanC
859
910
  async function prepareRenderContext(inputContent, options, getInputContent) {
860
911
  const { content, absoluteDirPath } = await getInputContent(inputContent, options.file);
861
912
  const preHandlerContent = await wenyanCoreInstance.handleFrontMatter(content);
913
+ if (preHandlerContent.type === "image" && !preHandlerContent.image_list) {
914
+ const { imagePaths, cleanedHtml } = await extractAndCleanImages(preHandlerContent.content);
915
+ if (imagePaths.length > 0) {
916
+ preHandlerContent.image_list = imagePaths;
917
+ preHandlerContent.content = cleanedHtml;
918
+ }
919
+ }
862
920
  if (preHandlerContent.image_list && preHandlerContent.image_list.length > 0) {
863
921
  return { gzhContent: preHandlerContent, absoluteDirPath };
864
922
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wenyan-md/core",
3
- "version": "3.0.8",
3
+ "version": "3.0.10",
4
4
  "description": "Core library for Wenyan markdown rendering & publishing",
5
5
  "author": "Lei <caol64@gmail.com> (https://github.com/caol64)",
6
6
  "license": "Apache-2.0",