@v1hz/md2docx 2.1.1 → 2.3.0
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 +56 -14
- package/config/config.json +3 -0
- package/config/config.schema.json +15 -1
- package/config/style-config.json +21 -0
- package/config/style-config.schema.json +71 -0
- package/config/style.json +14 -14
- package/dist/index.js +275 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,17 +17,18 @@
|
|
|
17
17
|
|
|
18
18
|
## 功能
|
|
19
19
|
|
|
20
|
-
| 功能 | 说明
|
|
21
|
-
| ----------------- |
|
|
22
|
-
| 文档标题 | 从 YAML frontmatter、H1 或文件名提取标题
|
|
23
|
-
| 标题层级归一化 | 将最浅标题归一化为 H1,并修复标题层级跳跃
|
|
24
|
-
| 标题编号 | 生成 `1`、`1.1`、`1.1.1` 等编号,并可剥离常见的已有中英文编号
|
|
25
|
-
| 表格与图片编号 | 自动生成“表 1”“图 1:标题”等题注
|
|
26
|
-
| Mermaid 图表 | 使用 beautiful-mermaid 和 resvg-wasm 将 Mermaid 渲染为高 DPI PNG
|
|
27
|
-
| Word 样式 |
|
|
28
|
-
| Markdown 格式化 | 可只运行预处理流水线,输出格式化后的 Markdown
|
|
29
|
-
|
|
|
30
|
-
|
|
|
20
|
+
| 功能 | 说明 |
|
|
21
|
+
| ----------------- | ---------------------------------------------------------------- |
|
|
22
|
+
| 文档标题 | 从 YAML frontmatter、H1 或文件名提取标题 |
|
|
23
|
+
| 标题层级归一化 | 将最浅标题归一化为 H1,并修复标题层级跳跃 |
|
|
24
|
+
| 标题编号 | 生成 `1`、`1.1`、`1.1.1` 等编号,并可剥离常见的已有中英文编号 |
|
|
25
|
+
| 表格与图片编号 | 自动生成“表 1”“图 1:标题”等题注 |
|
|
26
|
+
| Mermaid 图表 | 使用 beautiful-mermaid 和 resvg-wasm 将 Mermaid 渲染为高 DPI PNG |
|
|
27
|
+
| Word 样式 | 支持受控语义化配置和完整底层样式,也可从现有 DOCX 提取样式 |
|
|
28
|
+
| Markdown 格式化 | 可只运行预处理流水线,输出格式化后的 Markdown |
|
|
29
|
+
| 去除分隔符 | 默认移除 `---`、`***`、`___` 等分隔符行,减少无用页面间距 |
|
|
30
|
+
| 集中缓存 | 中间文件统一存储到 `~/.md2docx/`,不会在当前目录创建 `tmp/` |
|
|
31
|
+
| Node 与可执行版本 | 支持 npm CLI,也支持构建不依赖 Node.js/Bun 的 Windows 可执行文件 |
|
|
31
32
|
|
|
32
33
|
## 安装方式
|
|
33
34
|
|
|
@@ -96,7 +97,7 @@ md2docx clean
|
|
|
96
97
|
| `<markdown>` | 位置参数;仅在没有其他转换选项时允许使用 |
|
|
97
98
|
| `-f, --file <path>` | Markdown 输入文件 |
|
|
98
99
|
| `-c, --config <path>` | 自定义配置 JSON |
|
|
99
|
-
| `-s, --style <path>` |
|
|
100
|
+
| `-s, --style <path>` | 语义化样式配置或完整底层样式 JSON |
|
|
100
101
|
| `-o, --output <path>` | DOCX 输出路径 |
|
|
101
102
|
| `--force` | 覆盖已有输出 |
|
|
102
103
|
| `-h, --help` | 显示帮助 |
|
|
@@ -168,6 +169,7 @@ md2docx export style -f template.docx → ./template_style.json
|
|
|
168
169
|
│ └── mermaid_*.png
|
|
169
170
|
├── resources/
|
|
170
171
|
│ ├── config.json
|
|
172
|
+
│ ├── style-config.json
|
|
171
173
|
│ ├── style.json
|
|
172
174
|
│ └── add-inline-code.lua
|
|
173
175
|
└── style/
|
|
@@ -208,10 +210,47 @@ CLI 不支持覆盖单个配置项,所有配置都通过 JSON 文件管理。
|
|
|
208
210
|
| `renderMermaid.enabled` | 将 Mermaid 渲染为 PNG | `true` |
|
|
209
211
|
| `renderMermaid.theme` | beautiful-mermaid 主题 | `"tokyo-night-light"` |
|
|
210
212
|
| `renderMermaid.density` | PNG 输出 DPI,最小值 72 | `200` |
|
|
213
|
+
| `removeThematicBreaks.enabled` | 移除 `---`、`***`、`___` 等分隔符行 | `true` |
|
|
211
214
|
|
|
212
215
|
## 样式定制
|
|
213
216
|
|
|
214
|
-
|
|
217
|
+
普通用户推荐使用受控的语义化样式配置,只修改程序明确开放的高频选项。其余颜色、尺寸、对齐方式、间距和 Word 样式继承关系继续由内置预设管理。
|
|
218
|
+
|
|
219
|
+
仓库中的 `config/style-config.json` 是可直接复制和修改的默认配置,`config/style-config.schema.json` 用于编辑器提示和校验。未指定 `--style` 时,转换会自动加载内嵌的默认 `style-config.json`,再将它编译到内置底层样式;不需要手工传入 `-s`。
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"$schema": "https://raw.githubusercontent.com/WXY-V1hZ/md2docx/main/config/style-config.schema.json",
|
|
224
|
+
"schemaVersion": 1,
|
|
225
|
+
"preset": "default",
|
|
226
|
+
"options": {
|
|
227
|
+
"body": {
|
|
228
|
+
"firstLineIndent": false
|
|
229
|
+
},
|
|
230
|
+
"headings": {
|
|
231
|
+
"1": {
|
|
232
|
+
"startOnNewPage": false
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"inlineCode": {
|
|
236
|
+
"background": false
|
|
237
|
+
},
|
|
238
|
+
"codeBlock": {
|
|
239
|
+
"border": false
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
将配置保存为 `style-config.json` 后使用:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
md2docx -f report.md -s style-config.json
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
字段缺失表示继承预设;`true` 表示使用预设效果;`false` 表示显式关闭。当前只开放正文首行缩进、一级标题另起一页、行内代码背景和代码块外框。完整设计见 [`docs/style-config-design.md`](docs/style-config-design.md)。
|
|
252
|
+
|
|
253
|
+
`config/style.json` 仍定义完整的底层 DOCX 样式,包括标题、段落、字符和表格样式。转换时,项目先将语义化配置编译到底层样式,再用 `docx` 生成 reference DOCX,最后通过 Pandoc 的 `--reference-doc` 应用样式。现有完整样式 JSON 可继续直接传给 `--style`。
|
|
215
254
|
|
|
216
255
|
### 从现有 DOCX 提取
|
|
217
256
|
|
|
@@ -220,7 +259,7 @@ md2docx export style -f template.docx
|
|
|
220
259
|
md2docx -f report.md -s template_style.json
|
|
221
260
|
```
|
|
222
261
|
|
|
223
|
-
###
|
|
262
|
+
### 高级手动维护
|
|
224
263
|
|
|
225
264
|
主要区域包括:
|
|
226
265
|
|
|
@@ -268,6 +307,8 @@ Markdown
|
|
|
268
307
|
↓
|
|
269
308
|
addTitle()
|
|
270
309
|
↓
|
|
310
|
+
removeThematicBreaks()
|
|
311
|
+
↓
|
|
271
312
|
normalizeHeadings()
|
|
272
313
|
↓
|
|
273
314
|
numberHeadings()
|
|
@@ -287,6 +328,7 @@ Pandoc + Lua filter
|
|
|
287
328
|
DOCX
|
|
288
329
|
```
|
|
289
330
|
|
|
331
|
+
`removeThematicBreaks()` 在标题处理之前执行,避免分隔符干扰文档结构。
|
|
290
332
|
`numberTables()` 必须先于 Mermaid 渲染;`numberPictures()` 必须后于 Mermaid 渲染,这样 Mermaid 生成的图片也能获得图题。
|
|
291
333
|
|
|
292
334
|
## 构建
|
package/config/config.json
CHANGED
|
@@ -141,6 +141,19 @@
|
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
143
|
"required": ["enabled", "strategy"]
|
|
144
|
+
},
|
|
145
|
+
"removeThematicBreaks": {
|
|
146
|
+
"description": "分隔符",
|
|
147
|
+
"type": "object",
|
|
148
|
+
"additionalProperties": false,
|
|
149
|
+
"properties": {
|
|
150
|
+
"enabled": {
|
|
151
|
+
"description": "自动移除 markdown 中的分隔符(---, ***, ___)",
|
|
152
|
+
"type": "boolean",
|
|
153
|
+
"default": true
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"required": ["enabled"]
|
|
144
157
|
}
|
|
145
158
|
},
|
|
146
159
|
"required": [
|
|
@@ -149,6 +162,7 @@
|
|
|
149
162
|
"normalizeHeadings",
|
|
150
163
|
"numberHeadings",
|
|
151
164
|
"renderMermaid",
|
|
152
|
-
"detectTitle"
|
|
165
|
+
"detectTitle",
|
|
166
|
+
"removeThematicBreaks"
|
|
153
167
|
]
|
|
154
168
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/WXY-V1hZ/md2docx/main/config/style-config.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"preset": "default",
|
|
5
|
+
"options": {
|
|
6
|
+
"body": {
|
|
7
|
+
"firstLineIndent": true
|
|
8
|
+
},
|
|
9
|
+
"headings": {
|
|
10
|
+
"1": {
|
|
11
|
+
"startOnNewPage": false
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"inlineCode": {
|
|
15
|
+
"background": true
|
|
16
|
+
},
|
|
17
|
+
"codeBlock": {
|
|
18
|
+
"border": true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/WXY-V1hZ/md2docx/main/config/style-config.schema.json",
|
|
4
|
+
"title": "md2docx 语义化样式配置",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "preset"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string"
|
|
11
|
+
},
|
|
12
|
+
"schemaVersion": {
|
|
13
|
+
"const": 1
|
|
14
|
+
},
|
|
15
|
+
"preset": {
|
|
16
|
+
"const": "default"
|
|
17
|
+
},
|
|
18
|
+
"options": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"properties": {
|
|
22
|
+
"body": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"properties": {
|
|
26
|
+
"firstLineIndent": {
|
|
27
|
+
"type": "boolean",
|
|
28
|
+
"description": "正文是否使用预设的首行缩进"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"headings": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"properties": {
|
|
36
|
+
"1": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"properties": {
|
|
40
|
+
"startOnNewPage": {
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"description": "一级标题是否另起一页"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"inlineCode": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"properties": {
|
|
52
|
+
"background": {
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"description": "行内代码是否使用预设背景"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"codeBlock": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"additionalProperties": false,
|
|
61
|
+
"properties": {
|
|
62
|
+
"border": {
|
|
63
|
+
"type": "boolean",
|
|
64
|
+
"description": "代码块是否使用预设外框"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
package/config/style.json
CHANGED
|
@@ -559,7 +559,7 @@
|
|
|
559
559
|
"eastAsia": "zh-CN"
|
|
560
560
|
},
|
|
561
561
|
"shading": {
|
|
562
|
-
"
|
|
562
|
+
"type": "pct5",
|
|
563
563
|
"color": "auto",
|
|
564
564
|
"fill": "auto"
|
|
565
565
|
}
|
|
@@ -571,40 +571,40 @@
|
|
|
571
571
|
},
|
|
572
572
|
"wordWrap": false,
|
|
573
573
|
"shading": {
|
|
574
|
-
"
|
|
574
|
+
"type": "clear",
|
|
575
575
|
"color": "F3F4F4",
|
|
576
576
|
"fill": "FFFFFF",
|
|
577
577
|
"themeFill": "background1"
|
|
578
578
|
},
|
|
579
579
|
"border": {
|
|
580
580
|
"top": {
|
|
581
|
-
"
|
|
581
|
+
"style": "single",
|
|
582
582
|
"color": "BFBFBF",
|
|
583
|
-
"
|
|
583
|
+
"size": 8,
|
|
584
584
|
"space": 10,
|
|
585
585
|
"themeColor": "background1",
|
|
586
586
|
"themeShade": "BF"
|
|
587
587
|
},
|
|
588
588
|
"left": {
|
|
589
|
-
"
|
|
589
|
+
"style": "single",
|
|
590
590
|
"color": "BFBFBF",
|
|
591
|
-
"
|
|
591
|
+
"size": 8,
|
|
592
592
|
"space": 10,
|
|
593
593
|
"themeColor": "background1",
|
|
594
594
|
"themeShade": "BF"
|
|
595
595
|
},
|
|
596
596
|
"bottom": {
|
|
597
|
-
"
|
|
597
|
+
"style": "single",
|
|
598
598
|
"color": "BFBFBF",
|
|
599
|
-
"
|
|
599
|
+
"size": 8,
|
|
600
600
|
"space": 10,
|
|
601
601
|
"themeColor": "background1",
|
|
602
602
|
"themeShade": "BF"
|
|
603
603
|
},
|
|
604
604
|
"right": {
|
|
605
|
-
"
|
|
605
|
+
"style": "single",
|
|
606
606
|
"color": "BFBFBF",
|
|
607
|
-
"
|
|
607
|
+
"size": 8,
|
|
608
608
|
"space": 10,
|
|
609
609
|
"themeColor": "background1",
|
|
610
610
|
"themeShade": "BF"
|
|
@@ -750,7 +750,7 @@
|
|
|
750
750
|
"eastAsia": "zh-CN"
|
|
751
751
|
},
|
|
752
752
|
"shading": {
|
|
753
|
-
"
|
|
753
|
+
"type": "clear",
|
|
754
754
|
"color": "F3F4F4",
|
|
755
755
|
"fill": "FFFFFF",
|
|
756
756
|
"themeFill": "background1"
|
|
@@ -844,16 +844,16 @@
|
|
|
844
844
|
"eastAsia": "zh-CN"
|
|
845
845
|
},
|
|
846
846
|
"shading": {
|
|
847
|
-
"
|
|
847
|
+
"type": "clear",
|
|
848
848
|
"color": "F3F4F4",
|
|
849
849
|
"fill": "F2F2F2",
|
|
850
850
|
"themeFill": "background1",
|
|
851
851
|
"themeFillShade": "F2"
|
|
852
852
|
},
|
|
853
853
|
"border": {
|
|
854
|
-
"
|
|
854
|
+
"style": "none",
|
|
855
855
|
"color": "auto",
|
|
856
|
-
"
|
|
856
|
+
"size": 0,
|
|
857
857
|
"space": 0
|
|
858
858
|
}
|
|
859
859
|
}
|
package/dist/index.js
CHANGED
|
@@ -103482,7 +103482,7 @@ Actual: ` + parser.attribValue);
|
|
|
103482
103482
|
var options;
|
|
103483
103483
|
var pureJsParser = true;
|
|
103484
103484
|
var currentElement;
|
|
103485
|
-
function
|
|
103485
|
+
function validateOptions2(userOptions) {
|
|
103486
103486
|
options = helper.copyOptions(userOptions);
|
|
103487
103487
|
helper.ensureFlagExists("ignoreDeclaration", options);
|
|
103488
103488
|
helper.ensureFlagExists("ignoreInstruction", options);
|
|
@@ -103730,7 +103730,7 @@ Actual: ` + parser.attribValue);
|
|
|
103730
103730
|
var parser = pureJsParser ? sax.parser(true, {}) : parser = new expat.Parser("UTF-8");
|
|
103731
103731
|
var result = {};
|
|
103732
103732
|
currentElement = result;
|
|
103733
|
-
options =
|
|
103733
|
+
options = validateOptions2(userOptions);
|
|
103734
103734
|
if (pureJsParser) {
|
|
103735
103735
|
parser.opt = { strictEntities: true };
|
|
103736
103736
|
parser.onopentag = onStartElement;
|
|
@@ -103764,13 +103764,13 @@ Actual: ` + parser.attribValue);
|
|
|
103764
103764
|
require_xml2json = /* @__PURE__ */ __commonJSMin((exports, module) => {
|
|
103765
103765
|
var helper = require_options_helper();
|
|
103766
103766
|
var xml2js = require_xml2js();
|
|
103767
|
-
function
|
|
103767
|
+
function validateOptions2(userOptions) {
|
|
103768
103768
|
var options = helper.copyOptions(userOptions);
|
|
103769
103769
|
helper.ensureSpacesExists(options);
|
|
103770
103770
|
return options;
|
|
103771
103771
|
}
|
|
103772
103772
|
module.exports = function(xml, userOptions) {
|
|
103773
|
-
var options =
|
|
103773
|
+
var options = validateOptions2(userOptions), js = xml2js(xml, options), json, parentKey = "compact" in options && options.compact ? "_parent" : "parent";
|
|
103774
103774
|
if ("addParent" in options && options.addParent)
|
|
103775
103775
|
json = JSON.stringify(js, function(k, v) {
|
|
103776
103776
|
return k === parentKey ? "_" : v;
|
|
@@ -103784,7 +103784,7 @@ Actual: ` + parser.attribValue);
|
|
|
103784
103784
|
var helper = require_options_helper();
|
|
103785
103785
|
var isArray = require_array_helper().isArray;
|
|
103786
103786
|
var currentElement, currentElementName;
|
|
103787
|
-
function
|
|
103787
|
+
function validateOptions2(userOptions) {
|
|
103788
103788
|
var options = helper.copyOptions(userOptions);
|
|
103789
103789
|
helper.ensureFlagExists("ignoreDeclaration", options);
|
|
103790
103790
|
helper.ensureFlagExists("ignoreInstruction", options);
|
|
@@ -104064,7 +104064,7 @@ Actual: ` + parser.attribValue);
|
|
|
104064
104064
|
return xml.join("");
|
|
104065
104065
|
}
|
|
104066
104066
|
module.exports = function(js, options) {
|
|
104067
|
-
options =
|
|
104067
|
+
options = validateOptions2(options);
|
|
104068
104068
|
var xml = [];
|
|
104069
104069
|
currentElement = js;
|
|
104070
104070
|
currentElementName = "_root_";
|
|
@@ -128401,7 +128401,7 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
|
128401
128401
|
// package.json
|
|
128402
128402
|
var package_default = {
|
|
128403
128403
|
name: "@v1hz/md2docx",
|
|
128404
|
-
version: "2.
|
|
128404
|
+
version: "2.3.0",
|
|
128405
128405
|
description: "基于 pandoc 的 Markdown 转 Word 工具,自动格式化 Markdown,支持自定义样式,AI 友好,用户友好。",
|
|
128406
128406
|
keywords: [
|
|
128407
128407
|
"converter",
|
|
@@ -128471,7 +128471,7 @@ var package_default = {
|
|
|
128471
128471
|
// src/cli.ts
|
|
128472
128472
|
function createProgram(version, actions) {
|
|
128473
128473
|
const program2 = new Command;
|
|
128474
|
-
program2.name("md2docx").description("将 Markdown 转换为 Word 文档").version(version, "-v, --version", "显示版本号").helpOption("-h, --help", "显示帮助").helpCommand(false).showHelpAfterError("使用 --help 查看帮助").showSuggestionAfterError().enablePositionalOptions().argument("[markdown]", "Markdown 文件(仅无其他转换选项时)").option("-f, --file <path>", "Markdown 文件").option("-c, --config <path>", "自定义配置文件").option("-s, --style <path>", "
|
|
128474
|
+
program2.name("md2docx").description("将 Markdown 转换为 Word 文档").version(version, "-v, --version", "显示版本号").helpOption("-h, --help", "显示帮助").helpCommand(false).showHelpAfterError("使用 --help 查看帮助").showSuggestionAfterError().enablePositionalOptions().argument("[markdown]", "Markdown 文件(仅无其他转换选项时)").option("-f, --file <path>", "Markdown 文件").option("-c, --config <path>", "自定义配置文件").option("-s, --style <path>", "自定义底层样式或语义化样式配置").option("-o, --output <path>", "输出 DOCX 文件").option("--force", "覆盖已有文件").action(async function(markdown, options) {
|
|
128475
128475
|
const hasAdditionalOptions = options.config !== undefined || options.style !== undefined || options.output !== undefined || options.force !== undefined;
|
|
128476
128476
|
if (markdown !== undefined) {
|
|
128477
128477
|
if (options.file !== undefined || hasAdditionalOptions) {
|
|
@@ -128595,6 +128595,7 @@ function validateConfig(value, path2) {
|
|
|
128595
128595
|
if (!Number.isInteger(mermaid.density) || mermaid.density < 72) {
|
|
128596
128596
|
invalidConfig(path2, "renderMermaid.density", "必须是不小于 72 的整数");
|
|
128597
128597
|
}
|
|
128598
|
+
validateEnabled(root.removeThematicBreaks, path2, "removeThematicBreaks");
|
|
128598
128599
|
const title = expectRecord(root.detectTitle, path2, "detectTitle");
|
|
128599
128600
|
expectBoolean(title.enabled, path2, "detectTitle.enabled");
|
|
128600
128601
|
const strategy = expectString(title.strategy, path2, "detectTitle.strategy");
|
|
@@ -146041,6 +146042,11 @@ function expandHexColor(color2) {
|
|
|
146041
146042
|
return color2.length === 4 ? `#${color2[1]}${color2[1]}${color2[2]}${color2[2]}${color2[3]}${color2[3]}` : color2;
|
|
146042
146043
|
}
|
|
146043
146044
|
|
|
146045
|
+
// src/preprocess/thematic-break.ts
|
|
146046
|
+
function removeThematicBreaks(root2) {
|
|
146047
|
+
root2.children = root2.children.filter((node2) => node2.type !== "thematicBreak");
|
|
146048
|
+
}
|
|
146049
|
+
|
|
146044
146050
|
// src/preprocess/index.ts
|
|
146045
146051
|
async function preprocess2(mdPath, cfg, outDir, assetUrlDir = outDir) {
|
|
146046
146052
|
const md = await readFile3(mdPath, "utf-8");
|
|
@@ -146051,6 +146057,9 @@ async function preprocess2(mdPath, cfg, outDir, assetUrlDir = outDir) {
|
|
|
146051
146057
|
headings.push(heading2);
|
|
146052
146058
|
});
|
|
146053
146059
|
addTitle(mdPath, ast, headings, cfg.detectTitle);
|
|
146060
|
+
if (cfg.removeThematicBreaks.enabled) {
|
|
146061
|
+
removeThematicBreaks(ast);
|
|
146062
|
+
}
|
|
146054
146063
|
if (cfg.normalizeHeadings.enabled || cfg.numberHeadings.enabled) {
|
|
146055
146064
|
normalizeHeadings(headings);
|
|
146056
146065
|
}
|
|
@@ -146102,6 +146111,9 @@ var config_default = `{
|
|
|
146102
146111
|
"detectTitle": {
|
|
146103
146112
|
"enabled": true,
|
|
146104
146113
|
"strategy": "first-h1"
|
|
146114
|
+
},
|
|
146115
|
+
"removeThematicBreaks": {
|
|
146116
|
+
"enabled": true
|
|
146105
146117
|
}
|
|
146106
146118
|
}
|
|
146107
146119
|
`;
|
|
@@ -146114,6 +146126,30 @@ function Code(el)
|
|
|
146114
146126
|
end
|
|
146115
146127
|
return { Code = Code }`;
|
|
146116
146128
|
|
|
146129
|
+
// config/style-config.json
|
|
146130
|
+
var style_config_default = `{
|
|
146131
|
+
"$schema": "https://raw.githubusercontent.com/WXY-V1hZ/md2docx/main/config/style-config.schema.json",
|
|
146132
|
+
"schemaVersion": 1,
|
|
146133
|
+
"preset": "default",
|
|
146134
|
+
"options": {
|
|
146135
|
+
"body": {
|
|
146136
|
+
"firstLineIndent": true
|
|
146137
|
+
},
|
|
146138
|
+
"headings": {
|
|
146139
|
+
"1": {
|
|
146140
|
+
"startOnNewPage": false
|
|
146141
|
+
}
|
|
146142
|
+
},
|
|
146143
|
+
"inlineCode": {
|
|
146144
|
+
"background": true
|
|
146145
|
+
},
|
|
146146
|
+
"codeBlock": {
|
|
146147
|
+
"border": true
|
|
146148
|
+
}
|
|
146149
|
+
}
|
|
146150
|
+
}
|
|
146151
|
+
`;
|
|
146152
|
+
|
|
146117
146153
|
// config/style.json
|
|
146118
146154
|
var style_default = `{
|
|
146119
146155
|
"default": {
|
|
@@ -146676,7 +146712,7 @@ var style_default = `{
|
|
|
146676
146712
|
"eastAsia": "zh-CN"
|
|
146677
146713
|
},
|
|
146678
146714
|
"shading": {
|
|
146679
|
-
"
|
|
146715
|
+
"type": "pct5",
|
|
146680
146716
|
"color": "auto",
|
|
146681
146717
|
"fill": "auto"
|
|
146682
146718
|
}
|
|
@@ -146688,40 +146724,40 @@ var style_default = `{
|
|
|
146688
146724
|
},
|
|
146689
146725
|
"wordWrap": false,
|
|
146690
146726
|
"shading": {
|
|
146691
|
-
"
|
|
146727
|
+
"type": "clear",
|
|
146692
146728
|
"color": "F3F4F4",
|
|
146693
146729
|
"fill": "FFFFFF",
|
|
146694
146730
|
"themeFill": "background1"
|
|
146695
146731
|
},
|
|
146696
146732
|
"border": {
|
|
146697
146733
|
"top": {
|
|
146698
|
-
"
|
|
146734
|
+
"style": "single",
|
|
146699
146735
|
"color": "BFBFBF",
|
|
146700
|
-
"
|
|
146736
|
+
"size": 8,
|
|
146701
146737
|
"space": 10,
|
|
146702
146738
|
"themeColor": "background1",
|
|
146703
146739
|
"themeShade": "BF"
|
|
146704
146740
|
},
|
|
146705
146741
|
"left": {
|
|
146706
|
-
"
|
|
146742
|
+
"style": "single",
|
|
146707
146743
|
"color": "BFBFBF",
|
|
146708
|
-
"
|
|
146744
|
+
"size": 8,
|
|
146709
146745
|
"space": 10,
|
|
146710
146746
|
"themeColor": "background1",
|
|
146711
146747
|
"themeShade": "BF"
|
|
146712
146748
|
},
|
|
146713
146749
|
"bottom": {
|
|
146714
|
-
"
|
|
146750
|
+
"style": "single",
|
|
146715
146751
|
"color": "BFBFBF",
|
|
146716
|
-
"
|
|
146752
|
+
"size": 8,
|
|
146717
146753
|
"space": 10,
|
|
146718
146754
|
"themeColor": "background1",
|
|
146719
146755
|
"themeShade": "BF"
|
|
146720
146756
|
},
|
|
146721
146757
|
"right": {
|
|
146722
|
-
"
|
|
146758
|
+
"style": "single",
|
|
146723
146759
|
"color": "BFBFBF",
|
|
146724
|
-
"
|
|
146760
|
+
"size": 8,
|
|
146725
146761
|
"space": 10,
|
|
146726
146762
|
"themeColor": "background1",
|
|
146727
146763
|
"themeShade": "BF"
|
|
@@ -146867,7 +146903,7 @@ var style_default = `{
|
|
|
146867
146903
|
"eastAsia": "zh-CN"
|
|
146868
146904
|
},
|
|
146869
146905
|
"shading": {
|
|
146870
|
-
"
|
|
146906
|
+
"type": "clear",
|
|
146871
146907
|
"color": "F3F4F4",
|
|
146872
146908
|
"fill": "FFFFFF",
|
|
146873
146909
|
"themeFill": "background1"
|
|
@@ -146961,16 +146997,16 @@ var style_default = `{
|
|
|
146961
146997
|
"eastAsia": "zh-CN"
|
|
146962
146998
|
},
|
|
146963
146999
|
"shading": {
|
|
146964
|
-
"
|
|
147000
|
+
"type": "clear",
|
|
146965
147001
|
"color": "F3F4F4",
|
|
146966
147002
|
"fill": "F2F2F2",
|
|
146967
147003
|
"themeFill": "background1",
|
|
146968
147004
|
"themeFillShade": "F2"
|
|
146969
147005
|
},
|
|
146970
147006
|
"border": {
|
|
146971
|
-
"
|
|
147007
|
+
"style": "none",
|
|
146972
147008
|
"color": "auto",
|
|
146973
|
-
"
|
|
147009
|
+
"size": 0,
|
|
146974
147010
|
"space": 0
|
|
146975
147011
|
}
|
|
146976
147012
|
}
|
|
@@ -147074,6 +147110,7 @@ var style_default = `{
|
|
|
147074
147110
|
|
|
147075
147111
|
// src/resources.ts
|
|
147076
147112
|
var DEFAULT_CONFIG_TEXT = config_default;
|
|
147113
|
+
var DEFAULT_STYLE_CONFIG_TEXT = style_config_default;
|
|
147077
147114
|
var DEFAULT_STYLE_TEXT = style_default;
|
|
147078
147115
|
function materializeResource(name2, content3) {
|
|
147079
147116
|
const directory = join4(TMP_DIR, "resources");
|
|
@@ -147090,18 +147127,216 @@ function materializeDefaultConfig() {
|
|
|
147090
147127
|
function materializeDefaultStyle() {
|
|
147091
147128
|
return materializeResource("style.json", DEFAULT_STYLE_TEXT);
|
|
147092
147129
|
}
|
|
147130
|
+
function materializeDefaultStyleConfig() {
|
|
147131
|
+
materializeDefaultStyle();
|
|
147132
|
+
return materializeResource("style-config.json", DEFAULT_STYLE_CONFIG_TEXT);
|
|
147133
|
+
}
|
|
147093
147134
|
function materializeLuaFilter() {
|
|
147094
147135
|
return materializeResource("add-inline-code.lua", add_inline_code_default);
|
|
147095
147136
|
}
|
|
147096
147137
|
|
|
147097
147138
|
// src/style/generate.ts
|
|
147098
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync4
|
|
147139
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4 } from "node:fs";
|
|
147099
147140
|
import { writeFile } from "node:fs/promises";
|
|
147100
147141
|
import { createHash as createHash2 } from "node:crypto";
|
|
147101
147142
|
import { dirname as dirname4 } from "path";
|
|
147102
|
-
|
|
147143
|
+
|
|
147144
|
+
// src/style/compiler.ts
|
|
147145
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
147146
|
+
|
|
147147
|
+
// src/style/config.ts
|
|
147148
|
+
function isStyleConfig(value2) {
|
|
147149
|
+
if (!isRecord(value2))
|
|
147150
|
+
return false;
|
|
147151
|
+
return "schemaVersion" in value2 || "preset" in value2 || "options" in value2;
|
|
147152
|
+
}
|
|
147153
|
+
function validateStyleConfig(value2, path3) {
|
|
147154
|
+
const root2 = expectRecord2(value2, path3, "样式配置");
|
|
147155
|
+
rejectUnknown(root2, ["$schema", "schemaVersion", "preset", "options"], path3, "样式配置");
|
|
147156
|
+
if (root2.$schema !== undefined)
|
|
147157
|
+
expectString2(root2.$schema, path3, "$schema");
|
|
147158
|
+
if (root2.schemaVersion !== 1)
|
|
147159
|
+
invalidStyleConfig(path3, "schemaVersion", "目前只支持版本 1");
|
|
147160
|
+
if (root2.preset !== "default")
|
|
147161
|
+
invalidStyleConfig(path3, "preset", '目前只支持 "default"');
|
|
147162
|
+
if (root2.options !== undefined)
|
|
147163
|
+
validateOptions(root2.options, path3);
|
|
147164
|
+
return root2;
|
|
147165
|
+
}
|
|
147166
|
+
function validateOptions(value2, path3) {
|
|
147167
|
+
const options = expectRecord2(value2, path3, "options");
|
|
147168
|
+
rejectUnknown(options, ["body", "headings", "inlineCode", "codeBlock"], path3, "options");
|
|
147169
|
+
if (options.body !== undefined) {
|
|
147170
|
+
const body = expectRecord2(options.body, path3, "options.body");
|
|
147171
|
+
rejectUnknown(body, ["firstLineIndent"], path3, "options.body");
|
|
147172
|
+
if (body.firstLineIndent !== undefined) {
|
|
147173
|
+
expectBoolean2(body.firstLineIndent, path3, "options.body.firstLineIndent");
|
|
147174
|
+
}
|
|
147175
|
+
}
|
|
147176
|
+
if (options.headings !== undefined) {
|
|
147177
|
+
const headings = expectRecord2(options.headings, path3, "options.headings");
|
|
147178
|
+
rejectUnknown(headings, ["1"], path3, "options.headings");
|
|
147179
|
+
if (headings["1"] !== undefined) {
|
|
147180
|
+
const heading1 = expectRecord2(headings["1"], path3, 'options.headings["1"]');
|
|
147181
|
+
rejectUnknown(heading1, ["startOnNewPage"], path3, 'options.headings["1"]');
|
|
147182
|
+
if (heading1.startOnNewPage !== undefined) {
|
|
147183
|
+
expectBoolean2(heading1.startOnNewPage, path3, 'options.headings["1"].startOnNewPage');
|
|
147184
|
+
}
|
|
147185
|
+
}
|
|
147186
|
+
}
|
|
147187
|
+
if (options.inlineCode !== undefined) {
|
|
147188
|
+
const inlineCode2 = expectRecord2(options.inlineCode, path3, "options.inlineCode");
|
|
147189
|
+
rejectUnknown(inlineCode2, ["background"], path3, "options.inlineCode");
|
|
147190
|
+
if (inlineCode2.background !== undefined) {
|
|
147191
|
+
expectBoolean2(inlineCode2.background, path3, "options.inlineCode.background");
|
|
147192
|
+
}
|
|
147193
|
+
}
|
|
147194
|
+
if (options.codeBlock !== undefined) {
|
|
147195
|
+
const codeBlock = expectRecord2(options.codeBlock, path3, "options.codeBlock");
|
|
147196
|
+
rejectUnknown(codeBlock, ["border"], path3, "options.codeBlock");
|
|
147197
|
+
if (codeBlock.border !== undefined) {
|
|
147198
|
+
expectBoolean2(codeBlock.border, path3, "options.codeBlock.border");
|
|
147199
|
+
}
|
|
147200
|
+
}
|
|
147201
|
+
}
|
|
147202
|
+
function rejectUnknown(value2, allowed, path3, field) {
|
|
147203
|
+
const unknown2 = Object.keys(value2).find((key) => !allowed.includes(key));
|
|
147204
|
+
if (unknown2 !== undefined)
|
|
147205
|
+
invalidStyleConfig(path3, `${field}.${unknown2}`, "不是支持的配置项");
|
|
147206
|
+
}
|
|
147207
|
+
function expectRecord2(value2, path3, field) {
|
|
147208
|
+
if (!isRecord(value2))
|
|
147209
|
+
invalidStyleConfig(path3, field, "必须是对象");
|
|
147210
|
+
return value2;
|
|
147211
|
+
}
|
|
147212
|
+
function isRecord(value2) {
|
|
147213
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
147214
|
+
}
|
|
147215
|
+
function expectBoolean2(value2, path3, field) {
|
|
147216
|
+
if (typeof value2 !== "boolean")
|
|
147217
|
+
invalidStyleConfig(path3, field, "必须是 boolean");
|
|
147218
|
+
}
|
|
147219
|
+
function expectString2(value2, path3, field) {
|
|
147220
|
+
if (typeof value2 !== "string")
|
|
147221
|
+
invalidStyleConfig(path3, field, "必须是字符串");
|
|
147222
|
+
}
|
|
147223
|
+
function invalidStyleConfig(path3, field, reason) {
|
|
147224
|
+
throw new Error(`样式配置无效:${path3}
|
|
147225
|
+
位置:${field}
|
|
147226
|
+
原因:${reason}`);
|
|
147227
|
+
}
|
|
147228
|
+
|
|
147229
|
+
// src/style/compiler.ts
|
|
147230
|
+
function loadEffectiveStyles(stylePath) {
|
|
147231
|
+
const source = parseJson(readFileSync2(stylePath, "utf-8"), stylePath);
|
|
147232
|
+
if (!isStyleConfig(source))
|
|
147233
|
+
return expectStyleDefinition(source, stylePath);
|
|
147234
|
+
const config = validateStyleConfig(source, stylePath);
|
|
147235
|
+
const preset = expectStyleDefinition(parseJson(DEFAULT_STYLE_TEXT, "内置默认样式"), "内置默认样式");
|
|
147236
|
+
return compileStyleConfig(preset, config);
|
|
147237
|
+
}
|
|
147238
|
+
function compileStyleConfig(preset, config) {
|
|
147239
|
+
const styles = structuredClone(preset);
|
|
147240
|
+
const options = config.options;
|
|
147241
|
+
if (!options)
|
|
147242
|
+
return styles;
|
|
147243
|
+
const firstLineIndent = options.body?.firstLineIndent;
|
|
147244
|
+
if (firstLineIndent !== undefined)
|
|
147245
|
+
applyBodyFirstLineIndent(styles, firstLineIndent);
|
|
147246
|
+
const startOnNewPage = options.headings?.["1"]?.startOnNewPage;
|
|
147247
|
+
if (startOnNewPage !== undefined)
|
|
147248
|
+
applyHeading1PageBreak(styles, startOnNewPage);
|
|
147249
|
+
const inlineCodeBackground = options.inlineCode?.background;
|
|
147250
|
+
if (inlineCodeBackground !== undefined) {
|
|
147251
|
+
applyInlineCodeBackground(styles, inlineCodeBackground);
|
|
147252
|
+
}
|
|
147253
|
+
const codeBlockBorder = options.codeBlock?.border;
|
|
147254
|
+
if (codeBlockBorder !== undefined)
|
|
147255
|
+
applyCodeBlockBorder(styles, codeBlockBorder);
|
|
147256
|
+
return styles;
|
|
147257
|
+
}
|
|
147258
|
+
function applyBodyFirstLineIndent(styles, enabled) {
|
|
147259
|
+
const firstParagraph = findStyle(styles, "paragraphStyles", "First Paragraph");
|
|
147260
|
+
const bodyText = findStyle(styles, "paragraphStyles", "Body Text");
|
|
147261
|
+
for (const style of [firstParagraph, bodyText]) {
|
|
147262
|
+
const paragraph2 = ensureObject(style, "paragraph");
|
|
147263
|
+
paragraph2.indent = {
|
|
147264
|
+
...optionalObject(paragraph2.indent),
|
|
147265
|
+
firstLine: enabled ? 200 : 0,
|
|
147266
|
+
firstLineChars: enabled ? 200 : 0
|
|
147267
|
+
};
|
|
147268
|
+
}
|
|
147269
|
+
}
|
|
147270
|
+
function applyHeading1PageBreak(styles, enabled) {
|
|
147271
|
+
const heading1 = findStyle(styles, "paragraphStyles", "heading 1");
|
|
147272
|
+
ensureObject(heading1, "paragraph").pageBreakBefore = enabled;
|
|
147273
|
+
}
|
|
147274
|
+
function applyInlineCodeBackground(styles, enabled) {
|
|
147275
|
+
const inlineCode2 = findStyle(styles, "characterStyles", "Inline Code");
|
|
147276
|
+
ensureObject(inlineCode2, "run").shading = {
|
|
147277
|
+
type: "clear",
|
|
147278
|
+
color: enabled ? "F3F4F4" : "auto",
|
|
147279
|
+
fill: enabled ? "F2F2F2" : "auto"
|
|
147280
|
+
};
|
|
147281
|
+
}
|
|
147282
|
+
function applyCodeBlockBorder(styles, enabled) {
|
|
147283
|
+
const sourceCode = findStyle(styles, "paragraphStyles", "Source Code");
|
|
147284
|
+
const border = () => ({
|
|
147285
|
+
style: enabled ? "single" : "none",
|
|
147286
|
+
color: enabled ? "BFBFBF" : "auto",
|
|
147287
|
+
size: enabled ? 8 : 0,
|
|
147288
|
+
space: enabled ? 10 : 0
|
|
147289
|
+
});
|
|
147290
|
+
ensureObject(sourceCode, "paragraph").border = {
|
|
147291
|
+
top: border(),
|
|
147292
|
+
left: border(),
|
|
147293
|
+
bottom: border(),
|
|
147294
|
+
right: border()
|
|
147295
|
+
};
|
|
147296
|
+
}
|
|
147297
|
+
function findStyle(styles, collectionName, name2) {
|
|
147298
|
+
const collection = styles[collectionName];
|
|
147299
|
+
if (!Array.isArray(collection)) {
|
|
147300
|
+
throw new Error(`内置样式缺少 ${collectionName},无法应用样式配置`);
|
|
147301
|
+
}
|
|
147302
|
+
const normalizedName = name2.toLowerCase();
|
|
147303
|
+
const style = collection.find((entry) => isRecord2(entry) && typeof entry.name === "string" && entry.name.toLowerCase() === normalizedName);
|
|
147304
|
+
if (!style)
|
|
147305
|
+
throw new Error(`内置样式缺少“${name2}”,无法应用样式配置`);
|
|
147306
|
+
return style;
|
|
147307
|
+
}
|
|
147308
|
+
function ensureObject(parent, key) {
|
|
147309
|
+
const current = parent[key];
|
|
147310
|
+
if (isRecord2(current))
|
|
147311
|
+
return current;
|
|
147312
|
+
const created = {};
|
|
147313
|
+
parent[key] = created;
|
|
147314
|
+
return created;
|
|
147315
|
+
}
|
|
147316
|
+
function optionalObject(value2) {
|
|
147317
|
+
return isRecord2(value2) ? value2 : {};
|
|
147318
|
+
}
|
|
147319
|
+
function parseJson(text5, path3) {
|
|
147320
|
+
try {
|
|
147321
|
+
return JSON.parse(text5);
|
|
147322
|
+
} catch (error) {
|
|
147323
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
147324
|
+
throw new Error(`样式文件不是有效的 JSON:${path3}
|
|
147325
|
+
${message}`);
|
|
147326
|
+
}
|
|
147327
|
+
}
|
|
147328
|
+
function expectStyleDefinition(value2, path3) {
|
|
147329
|
+
if (!isRecord2(value2))
|
|
147330
|
+
throw new Error(`样式文件必须是 JSON 对象:${path3}`);
|
|
147331
|
+
return value2;
|
|
147332
|
+
}
|
|
147333
|
+
function isRecord2(value2) {
|
|
147334
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
147335
|
+
}
|
|
147336
|
+
|
|
147337
|
+
// src/style/generate.ts
|
|
147338
|
+
async function generateTemplateDocxFromStyles(raw, outputPath) {
|
|
147103
147339
|
const { Document: Document2, Packer: Packer3 } = await Promise.resolve().then(() => (init_dist(), exports_dist));
|
|
147104
|
-
const raw = JSON.parse(readFileSync2(styleJsonPath, "utf-8"));
|
|
147105
147340
|
const tableStylesXml = raw.tableStylesXml;
|
|
147106
147341
|
const { tableStylesXml: _, ...styles } = raw;
|
|
147107
147342
|
const doc = new Document2({
|
|
@@ -147127,13 +147362,13 @@ async function generateTemplateDocx(styleJsonPath, outputPath) {
|
|
|
147127
147362
|
}
|
|
147128
147363
|
var generatePromises = new Map;
|
|
147129
147364
|
async function ensureTemplateDocx(styleJsonPath) {
|
|
147130
|
-
const
|
|
147131
|
-
const hash = createHash2("sha256").update(
|
|
147365
|
+
const styles = loadEffectiveStyles(styleJsonPath);
|
|
147366
|
+
const hash = createHash2("sha256").update(JSON.stringify(styles)).digest("hex").slice(0, 16);
|
|
147132
147367
|
const outputPath = styleTemplateDocx(hash);
|
|
147133
147368
|
if (!existsSync5(outputPath)) {
|
|
147134
147369
|
let promise = generatePromises.get(outputPath);
|
|
147135
147370
|
if (!promise) {
|
|
147136
|
-
promise =
|
|
147371
|
+
promise = generateTemplateDocxFromStyles(styles, outputPath).catch((error) => {
|
|
147137
147372
|
generatePromises.delete(outputPath);
|
|
147138
147373
|
throw error;
|
|
147139
147374
|
});
|
|
@@ -147150,7 +147385,7 @@ async function convertMarkdown(options) {
|
|
|
147150
147385
|
throw new Error("缺少必填参数:--file");
|
|
147151
147386
|
const input = resolveInputPath(options.file, [".md", ".markdown"], "Markdown 文件");
|
|
147152
147387
|
const configPath = options.config ? resolveInputPath(options.config, [".json"], "配置文件") : materializeDefaultConfig();
|
|
147153
|
-
const stylePath = options.style ? resolveInputPath(options.style, [".json"], "样式文件") :
|
|
147388
|
+
const stylePath = options.style ? resolveInputPath(options.style, [".json"], "样式文件") : materializeDefaultStyleConfig();
|
|
147154
147389
|
const baseName = parse4(input).name;
|
|
147155
147390
|
const output = resolveOutputPath(options.output, `${baseName}.docx`, [".docx"], "DOCX 输出文件");
|
|
147156
147391
|
prepareOutput(output, options.force ?? false);
|
|
@@ -147287,31 +147522,31 @@ function mapShd(shd) {
|
|
|
147287
147522
|
if (!shd)
|
|
147288
147523
|
return;
|
|
147289
147524
|
const sh = {};
|
|
147290
|
-
for (const a of [
|
|
147291
|
-
"val",
|
|
147292
|
-
"color",
|
|
147293
|
-
"fill",
|
|
147294
|
-
"themeColor",
|
|
147295
|
-
"themeTint",
|
|
147296
|
-
"themeFill",
|
|
147297
|
-
"themeFillShade",
|
|
147298
|
-
"themeShade"
|
|
147299
|
-
]) {
|
|
147525
|
+
for (const a of ["color", "fill"]) {
|
|
147300
147526
|
const v = wAttr(shd, a);
|
|
147301
147527
|
if (v !== null)
|
|
147302
147528
|
sh[a] = v;
|
|
147303
147529
|
}
|
|
147530
|
+
const type = wAttr(shd, "val");
|
|
147531
|
+
if (type !== null)
|
|
147532
|
+
sh.type = type;
|
|
147304
147533
|
return Object.keys(sh).length > 0 ? sh : undefined;
|
|
147305
147534
|
}
|
|
147306
147535
|
function mapBorder(bdr) {
|
|
147307
147536
|
if (!bdr)
|
|
147308
147537
|
return;
|
|
147309
147538
|
const b = {};
|
|
147310
|
-
for (const a of ["
|
|
147539
|
+
for (const a of ["color", "space"]) {
|
|
147311
147540
|
const v = wAttr(bdr, a);
|
|
147312
147541
|
if (v !== null)
|
|
147313
147542
|
b[a] = /^\d+$/.test(v) ? Number(v) : v;
|
|
147314
147543
|
}
|
|
147544
|
+
const style = wAttr(bdr, "val");
|
|
147545
|
+
if (style !== null)
|
|
147546
|
+
b.style = style;
|
|
147547
|
+
const size = wAttr(bdr, "sz");
|
|
147548
|
+
if (size !== null)
|
|
147549
|
+
b.size = /^\d+$/.test(size) ? Number(size) : size;
|
|
147315
147550
|
return Object.keys(b).length > 0 ? b : undefined;
|
|
147316
147551
|
}
|
|
147317
147552
|
function mapRunProps(rPr) {
|