Coverage for agentos/marketplace/skills/markdown-toolkit/markdown-toolkit.py: 3%

65 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-06 23:17 +0800

1""" 

2markdown-toolkit — Markdown 处理工具:转 HTML、提取标题、生成目录。 

3 

4Category: utility 

5""" 

6 

7 

8def run(action: str, file_path: str = "", text: str = "", output_path: str = "") -> str: 

9 """Markdown 处理工具。action: toc/to_html/headings/stats。""" 

10 import os 

11 import re 

12 

13 def _read(): 

14 if file_path and os.path.isfile(file_path): 

15 with open(file_path, encoding="utf-8") as f: 

16 return f.read() 

17 return text or "" 

18 

19 content = _read() 

20 if not content: 

21 return "[markdown-toolkit] 无内容输入" 

22 

23 try: 

24 if action == "stats": 

25 lines = content.split("\n") 

26 words = len(content.split()) 

27 chars = len(content) 

28 headings = len(re.findall(r"^#{1,6}\s", content, re.MULTILINE)) 

29 links = len(re.findall(r"\[.*?\]\(.*?\)", content)) 

30 code_blocks = len(re.findall(r"```", content)) // 2 

31 return f"行数: {len(lines)}, 词数: {words}, 字符: {chars}, 标题: {headings}, 链接: {links}, 代码块: {code_blocks}" # noqa: E501 

32 

33 if action == "headings": 

34 matches = re.findall(r"^(#{1,6})\s+(.+)$", content, re.MULTILINE) 

35 if not matches: 

36 return "[markdown-toolkit] 未找到标题" 

37 lines_out = [] 

38 for level, title in matches: 

39 indent = " " * (len(level) - 1) 

40 lines_out.append(f"{indent}- {title.strip()}") 

41 return f"共 {len(matches)} 个标题:\n" + "\n".join(lines_out) 

42 

43 if action == "toc": 

44 matches = re.findall(r"^(#{1,6})\s+(.+)$", content, re.MULTILINE) 

45 if not matches: 

46 return "[markdown-toolkit] 未找到标题" 

47 lines_out = ["# 目录", ""] 

48 for level, title in matches: 

49 depth = len(level) 

50 indent = " " * (depth - 1) 

51 anchor = re.sub(r"[^\w\s-]", "", title.strip()).lower().replace(" ", "-") 

52 lines_out.append(f"{indent}- [{title.strip()}](#{anchor})") 

53 return "\n".join(lines_out) 

54 

55 if action == "to_html": 

56 # Simple markdown-to-HTML converter (covers basics) 

57 html = content 

58 # Code blocks (```) 

59 html = re.sub( 

60 r"```(\w*)\n(.*?)```", 

61 r"<pre><code class='\1'>\2</code></pre>", 

62 html, 

63 flags=re.DOTALL, 

64 ) 

65 # Inline code 

66 html = re.sub(r"`([^`]+)`", r"<code>\1</code>", html) 

67 # Headings 

68 for i in range(6, 0, -1): 

69 html = re.sub(rf"^{'#'*i}\s+(.+)$", rf"<h{i}>\1</h{i}>", html, flags=re.MULTILINE) 

70 # Bold/Italic 

71 html = re.sub(r"\*\*\*(.+?)\*\*\*", r"<em><strong>\1</strong></em>", html) 

72 html = re.sub(r"\*\*(.+?)\*\*", r"<strong>\1</strong>", html) 

73 html = re.sub(r"\*(.+?)\*", r"<em>\1</em>", html) 

74 # Links 

75 html = re.sub(r"\[(.+?)\]\((.+?)\)", r'<a href="\2">\1</a>', html) 

76 # Images 

77 html = re.sub(r"!\[(.*?)\]\((.+?)\)", r'<img src="\2" alt="\1">', html) 

78 # Unordered lists 

79 html = re.sub(r"^- (.+)$", r"<li>\1</li>", html, flags=re.MULTILINE) 

80 # Paragraphs (double newline) 

81 html = re.sub(r"\n\n+", "</p><p>", html) 

82 html = f"<p>{html}</p>" 

83 if output_path: 

84 with open(output_path, "w", encoding="utf-8") as f: 

85 f.write(html) 

86 return f"已转换并写入: {output_path}" 

87 # return first 2000 chars if too long 

88 if len(html) > 2000: 

89 return html[:2000] + f"\n... (共{len(html)}字符)" 

90 return html 

91 

92 return f"[markdown-toolkit] 未知操作: {action}, 支持: toc/to_html/headings/stats" 

93 except Exception as e: 

94 return f"[markdown-toolkit] 失败: {e}" 

95 

96 

97__all__ = ["run"]