@cliven/mddocx 1.0.1 → 1.0.3

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,8 +1,8 @@
1
1
  {
2
2
  "name": "mddocx",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Markdown 转学术格式 Word 文档 (DOCX)。支持三线表、图题/表题自动编号、页码、页眉等学术论文排版规范。",
5
- "author": "Quan Guanyu",
5
+ "author": { "name": "Quan Guanyu" },
6
6
  "keywords": ["markdown", "docx", "word", "academic", "论文", "学术", "转换"],
7
7
  "skills": "./skills/"
8
8
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mddocx",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "description": "Markdown 转学术格式 Word 文档 (DOCX)。支持三线表、图题/表题自动编号、页码、页眉等学术论文排版规范。",
5
5
  "author": "Quan Guanyu",
6
6
  "homepage": "https://github.com/Trisia/mddocx",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mddocx",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Markdown 转学术格式 Word 文档 (DOCX)。支持三线表、图题/表题自动编号、页码、页眉等学术论文排版规范。",
5
5
  "author": "Quan Guanyu",
6
6
  "homepage": "https://github.com/Trisia/mddocx",
package/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # mddocx — Markdown 转学术格式 DOCX
2
2
 
3
- [![Claude Code](https://img.shields.io/badge/Agent-Claude%20Code-orange?logo=claude)](https://claude.com/code)
3
+ [![Claude Code](https://img.shields.io/badge/Agent-Claude%20Code-orange?logo=claude)](https://www.claudepluginhub.com/plugins/trisia-mddocx)
4
4
  [![Codex](https://img.shields.io/badge/Agent-Codex-blue?logo=openai)](https://github.com/openai/codex)
5
5
  [![Cursor](https://img.shields.io/badge/Agent-Cursor-6c47ff?logo=cursor)](https://cursor.com)
6
6
  [![OpenCode](https://img.shields.io/badge/Agent-OpenCode-teal)](https://opencode.ai)
7
+ [![npm](https://img.shields.io/npm/v/@cliven/mddocx?color=red)](https://www.npmjs.com/package/@cliven/mddocx)
7
8
  [![Version](https://img.shields.io/github/v/release/Trisia/mddocx)](https://github.com/Trisia/mddocx/releases)
8
9
  [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
9
10
  [![Python](https://img.shields.io/badge/python-3.9%2B-blue?logo=python)](https://python.org)
@@ -18,24 +19,14 @@
18
19
 
19
20
  ### 🤖 一键安装
20
21
 
21
- 复制粘贴给任意智能体即可安装:
22
+ 将以下内容复制粘贴给任意智能体(Claude Code / Codex / OpenCode / Cursor)即可安装。
22
23
 
23
- ```copy
24
- 请帮我安装 mddocx 插件:
25
-
26
- git clone https://github.com/Trisia/mddocx /tmp/mddocx
27
- mkdir -p ~/.claude/skills/mddoc
28
- cp -r /tmp/mddocx/skills/mddoc/* ~/.claude/skills/mddoc/
29
- rm -rf /tmp/mddocx
24
+ > 各平台专属安装说明详见 **[INSTALL.md](INSTALL.md)**。
30
25
 
31
- python3 -m venv ~/.claude/venvs/mddocx
32
- ~/.claude/venvs/mddocx/bin/pip install python-docx Pillow requests mistune
26
+ ```copy
27
+ 请根据 https://github.com/Trisia/mddocx/blob/main/INSTALL.md 中对应平台的说明,帮我安装 mddocx
33
28
  ```
34
29
 
35
- ### 📖 完整安装指南
36
-
37
- 支持 **Claude Code** / **Codex** / **OpenCode** / **Cursor** / **通用** 等多种方式,详见 **[INSTALL.md](INSTALL.md)**。
38
-
39
30
  ### 依赖
40
31
 
41
32
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cliven/mddocx",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Markdown 转学术格式 DOCX",
5
5
  "type": "module",
6
6
  "main": ".opencode/plugins/mddocx.js",
@@ -28,7 +28,7 @@ python <skill-path>/scripts/md2docx.py --text "# 标题\n\n正文内容" -o out.
28
28
  1. **读取输入** — 若用户粘贴 Markdown 文本则直接读取;若用户提供文件路径(含 `@` 引用)则读取该文件
29
29
  2. **安装依赖**(如未安装)— `pip install python-docx Pillow requests mistune`
30
30
  3. **执行转换** — 优先使用内置脚本 `scripts/md2docx.py`;若 Markdown 结构特殊则参照下方格式规范编写自定义脚本
31
- 4. **确定输出** — 文件路径输入→同目录;粘贴内容→当前目录;文件名=「题目.docx」,题目从第一个 `# 标题` 提取
31
+ 4. **确定输出** — 文件路径输入→同目录;粘贴内容→当前目录;文件名=「题目.docx」(题目从第一个 `# 标题` 提取;若无 `#` 标题则使用输入文件名,`--text` 模式为「未命名文档.docx」)
32
32
  5. **验证** — 检查 outline level、图片嵌入、页眉、分页符
33
33
 
34
34
  ---
@@ -118,6 +118,14 @@ set_cn_font(run, '黑体', size_pt=16)
118
118
  add_empty(doc)
119
119
  ```
120
120
 
121
+ ### 无标题文档
122
+
123
+ 当输入 Markdown 没有 `#` 标题时:
124
+ - 跳过标题页,文档从第一个内容节点开始排版
125
+ - 页眉右侧显示「未命名文档」代替标题
126
+ - 页眉左侧「xxxxx」保持不变
127
+ - 输出文件名:文件输入使用输入文件名(如 `paper.md` → `paper.docx`),`--text` 模式使用「未命名文档.docx」
128
+
121
129
  ### 一级标题(后续 `#`)
122
130
 
123
131
  三号黑体(16pt)、居中、上下各空一行、outline_level=1、**前加分页符**。
@@ -205,7 +213,7 @@ p.add_run().add_picture(img_path, width=img_width(img_path))
205
213
 
206
214
  ### 图题
207
215
 
208
- 图片下方(不空行)、小五(9pt)宋体加粗居中、格式 `图<章>-<序号> <alt>`、逐章编号。
216
+ 图片下方(不空行)、小五(9pt)宋体加粗居中、逐章编号。有章标题时格式 `图<章>-<序号> <alt>`,无章标题时格式 `图<序号> <alt>`。若 alt 为空,自动使用图片文件名(不含扩展名)作为图题。
209
217
 
210
218
  ```python
211
219
  p = doc.add_paragraph()
@@ -217,7 +225,7 @@ add_empty(doc) # 图题下方空一行
217
225
 
218
226
  ### 表格 + 表题
219
227
 
220
- **三线表**(顶线1.5pt/表头底线0.75pt/底线1.5pt粗,无竖线)。表题在上方(不空行)、五号(10.5pt)宋体加粗居中、格式`表<章>-<序号> <描述>`。
228
+ **三线表**(顶线1.5pt/表头底线0.75pt/底线1.5pt粗,无竖线)。表题在上方(不空行)、五号(10.5pt)宋体加粗居中。有章标题时格式`表<章>-<序号> <描述>`,无章标题时格式`表<序号> <描述>`。
221
229
 
222
230
  ```python
223
231
  # 表题
@@ -462,6 +470,7 @@ set_cn_font(run_cont, '宋体', size_pt=10.5)
462
470
  ## 生成后自检清单
463
471
 
464
472
  - [ ] 题目:16pt黑体、居中、无outline、上下各空一行
473
+ - [ ] 无标题文档:跳过标题页、页眉显示「未命名文档」
465
474
  - [ ] 一级标题:16pt黑体、outline_level=1、前有分页符、上下各空一行
466
475
  - [ ] 二级标题:14pt黑体、顶格、outline_level=2、不加粗、**上下不空行**
467
476
  - [ ] 三级标题:12pt宋体、首行缩进Pt(21)、outline_level=3、不加粗、**上下不空行**
@@ -482,7 +491,7 @@ set_cn_font(run_cont, '宋体', size_pt=10.5)
482
491
 
483
492
  ## 注意事项
484
493
 
485
- - **第一个 `#` 是题目**(不设 outline),后续 `#` 是一级标题(outline_level=1
494
+ - **第一个 `#` 是题目**(不设 outline),后续 `#` 是一级标题(outline_level=1);若无 `#` 标题仍可正常生成文档
486
495
  - **图片尺寸用 `Cm()`,不手算 EMU** — `add_picture(width=Cm(x))` 自动转换
487
496
  - **图片下载必设 User-Agent** — 否则 CDN/Wikipedia 返回 400
488
497
  - **图题编号自动生成** — alt text 作为描述文字,图/表编号独立逐章编序
@@ -838,7 +838,7 @@ def extract_title_text(title_node):
838
838
  return text.strip()
839
839
 
840
840
 
841
- def generate_docx(nodes, output_path, title_text):
841
+ def generate_docx(nodes, output_path, title_text=None):
842
842
  """根据节点列表生成 docx 文件"""
843
843
  doc = Document()
844
844
 
@@ -869,7 +869,7 @@ def generate_docx(nodes, output_path, title_text):
869
869
  hp_right = header.add_paragraph()
870
870
  hp_right.alignment = WD_ALIGN_PARAGRAPH.RIGHT
871
871
  hp_right.paragraph_format.space_before = Pt(0)
872
- run_r = hp_right.add_run(title_text)
872
+ run_r = hp_right.add_run(title_text or '未命名文档')
873
873
  set_run_font(run_r, '黑体', size_pt=9)
874
874
 
875
875
  # --- 页脚/页码设置 ---
@@ -906,6 +906,7 @@ def generate_docx(nodes, output_path, title_text):
906
906
 
907
907
  # --- 计数器 ---
908
908
  chapter_path = [1] # 一级标题序号
909
+ has_chapter = False # 是否遇到章标题(# 一级标题)
909
910
  fig_counter = {} # key: chapter index tuple, value: counter
910
911
  tab_counter = {}
911
912
  eq_counter = {}
@@ -929,10 +930,14 @@ def generate_docx(nodes, output_path, title_text):
929
930
  return eq_counter[key]
930
931
 
931
932
  def make_fig_label():
932
- return f"图{chapter_path[0]}-{incr_fig()}"
933
+ if has_chapter:
934
+ return f"图{chapter_path[0]}-{incr_fig()}"
935
+ return f"图{incr_fig()}"
933
936
 
934
937
  def make_tab_label():
935
- return f"表{chapter_path[0]}-{incr_tab()}"
938
+ if has_chapter:
939
+ return f"表{chapter_path[0]}-{incr_tab()}"
940
+ return f"表{incr_tab()}"
936
941
 
937
942
  # --- 遍历节点生成内容 ---
938
943
  for node in nodes:
@@ -950,6 +955,7 @@ def generate_docx(nodes, output_path, title_text):
950
955
  lv = node['level']
951
956
  if lv == 1:
952
957
  # 一级标题:新页 + 三号黑体居中
958
+ has_chapter = True
953
959
  chapter_path[0] += 1
954
960
  chapter_path[1:] = [0] # reset sub-levels
955
961
 
@@ -1017,6 +1023,9 @@ def generate_docx(nodes, output_path, title_text):
1017
1023
  run_img.add_picture(img_path, width=w)
1018
1024
 
1019
1025
  # 图题:小五宋体加粗居中
1026
+ # alt 为空时,使用图片文件名(不含扩展名)作为默认图题
1027
+ if not alt:
1028
+ alt = os.path.splitext(os.path.basename(url))[0]
1020
1029
  p_cap = doc.add_paragraph()
1021
1030
  p_cap.alignment = WD_ALIGN_PARAGRAPH.CENTER
1022
1031
  run_cap = p_cap.add_run(f'{make_fig_label()} {alt}')
@@ -1177,19 +1186,21 @@ def main():
1177
1186
  # 解析
1178
1187
  nodes = parse_markdown(md_content)
1179
1188
 
1180
- # 提取题目
1189
+ # 提取题目(可选)
1181
1190
  title_node = next((n for n in nodes if n['type'] == 'title'), None)
1182
- if title_node is None:
1183
- print("错误:未找到文档标题(第一个 # 标题)", file=sys.stderr)
1184
- sys.exit(1)
1185
- title_text = extract_title_text(title_node)
1191
+ title_text = extract_title_text(title_node) if title_node else None
1186
1192
 
1187
1193
  # 确定输出路径
1188
1194
  if args.output:
1189
1195
  output_path = args.output
1190
- else:
1196
+ elif title_text:
1191
1197
  safe_name = re.sub(r'[\\/*?:"<>|]', '', title_text)
1192
1198
  output_path = os.path.join(source_dir, f'{safe_name}.docx')
1199
+ elif args.text:
1200
+ output_path = os.path.join(source_dir, '未命名文档.docx')
1201
+ else:
1202
+ stem = os.path.splitext(os.path.basename(args.input))[0]
1203
+ output_path = os.path.join(source_dir, f'{stem}.docx')
1193
1204
 
1194
1205
  # 生成
1195
1206
  generate_docx(nodes, output_path, title_text)