dsh-md-plus 0.1.0 → 0.2.1
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/CHANGELOG.md +22 -0
- package/README.md +77 -102
- package/lib/client.js +116 -5
- package/lib/index.js +12 -2
- package/lib/mermaid-runtime.js +2035 -1330
- package/package.json +67 -66
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
## 0.2.1 —— 2026-10-16
|
|
4
|
+
|
|
5
|
+
- 修掉「同一份代码显示两遍」:`DSH_LANGS` 还是老版本的语言表,`dart`、`scala`、`vue`、`powershell`、`csv`、`diff` 等 66 个别名被当成「DSH 不认识」,插件抢先补了一层高亮;随后 DSH 的懒加载语法到位、React 把 plain `<pre>` 换成自己的高亮节点,插件那份副本成了野节点留在原地,于是两份都在。现在语言表对齐 108 条别名。
|
|
6
|
+
- 加了一层兜底:DSH 接管某块后,插件撤掉自己插的副本(清 `data-md-plus` 标记)。语言表以后再落后也不会留永久双份,最多白干一次。
|
|
7
|
+
- README:修正「`dart` 不在 DSH 语言表里」的错误说法,示例换成 DSH 真不认的 `gdscript`。
|
|
8
|
+
- 测试扩到 53 条,新增「DSH 接管后不留副本」的回归用例;补高亮的用例换成插件独有语言,不再拿 `dart` 当反例。
|
|
9
|
+
|
|
10
|
+
## 0.2.0 —— 2026-10-08
|
|
11
|
+
|
|
12
|
+
- 修掉 mermaid 围栏在 DSH 0.2.0-rc.2 上画不出来(issue #1):头部语言名被占位文案「代码块」顶掉,插件读不到围栏语言;现在认不出标签就看正文的类型声明。
|
|
13
|
+
- 修掉渲染失败在页面底部堆积「炸弹图」,也不再让 mermaid 的错误卡片被当成图。
|
|
14
|
+
- 修掉 ≥4 列的表格出血到面板宽、右边被裁掉、滚动条要悬停才出现的问题:现在跟正文同宽,超出在表内横滚。
|
|
15
|
+
- mermaid 引擎 11.17.0 → 12.1.0:新增 usecase-beta / agentflow-beta,旧图种实测无回归;运行时约 3.4 MB → 5.0 MB。
|
|
16
|
+
- 测试扩到 52 条,测试与预览页改用聊天区的真实头部形状。
|
|
17
|
+
- 注意:mermaid 12 的新图种标识符只认字母数字下划线,中文要写进标签,`actor Customer("用户")` 可以。
|
|
18
|
+
- 注意:DSH 0.2.0-rc.2 上「给 DSH 不认识的语言补高亮」仍然失效,得靠宿主露出语言名,详见 README。
|
|
19
|
+
|
|
20
|
+
## 0.1.0 —— 2026-09-29
|
|
21
|
+
|
|
22
|
+
首次发布:代码块卡片重做、补 Shiki 语法高亮、自带 mermaid 渲染、表格样式重做。
|
package/README.md
CHANGED
|
@@ -1,102 +1,77 @@
|
|
|
1
|
-
# dsh-md-plus
|
|
2
|
-
|
|
3
|
-
给 DeepSeek Harness Web / Desktop 的 Markdown
|
|
4
|
-
|
|
5
|
-

|
|
6
|
-
|
|
7
|
-
## 它解决什么
|
|
8
|
-
|
|
9
|
-
###
|
|
10
|
-
|
|
11
|
-
DSH
|
|
12
|
-
|
|
13
|
-
| 元素 | 改前 | 改后 |
|
|
14
|
-
|---|---|---|
|
|
15
|
-
| 头部左侧 | 空(无语言时) | `</>` 图标 +
|
|
16
|
-
| 头部右侧 | 文字「复制」 | 图标按钮:不换行 + 复制 |
|
|
17
|
-
| 顶栏背景 | 与卡片之间有一条白带 |
|
|
18
|
-
| 卡顶到代码 | 一大段空白 | 约一行代码高 |
|
|
19
|
-
|
|
20
|
-
样式是纯 CSS 打在 `.md-code-block`
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```powershell
|
|
80
|
-
npm install # 会顺带跑 prepare → build,装完 lib/ 就是新的
|
|
81
|
-
npm run build # 产出 lib/ 下四个文件
|
|
82
|
-
npm run check # 语法检查 + 45 条 host/client 行为测试
|
|
83
|
-
npm run preview # 离线生成 preview.html(含真渲出来的 mermaid 图)
|
|
84
|
-
npm run shot # 用 headless Chrome 把 preview.html 截成 docs/preview.png
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
注意测试跑的是 `lib/` 里的构建产物,所以顺序永远是 **先 `npm run build` 再 `npm test`**(`npm run check` 不含 build)。
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
## 已知边界
|
|
92
|
-
|
|
93
|
-
- 两个运行时按需加载:高亮约 6.5 MB(171 门语言语法),mermaid 约 3.4 MB。都只在真正用到时才下载;**首次**遇到新语言时多花约 100ms 解析。
|
|
94
|
-
- 依赖 DSH 的 `.md-code-block`、`[data-code-block-content]`、`[data-code-block-banner]`、`data-streaming` 这几个稳定钩子。DSH 升级若改了它们,需要跟着改 `src/client.js` 顶部的选择器常量。
|
|
95
|
-
- 头部图标按钮里那个「不换行」是插件自己加的(`decorate()` 往 `.action` 里插一个 `<button>`)。参考图里那个 `→|` 图标原功能未知,先做成了横向滚动切换,要换功能改一处即可。
|
|
96
|
-
- **滚轮缩放会接管页面滚动**:鼠标悬在图上时滚轮用来缩放,页面不会跟着滚。想改成按住 `Ctrl/⌘` 才缩放,只需在 `bindViewport()` 的 wheel 回调开头加一句 `if (!event.ctrlKey && !event.metaKey) return;`。
|
|
97
|
-
- 很宽的图会被缩到容器宽度,字会变小;放大后靠拖拽看细节。
|
|
98
|
-
- 目前只做代码块、mermaid 与表格。引用、列表间距、标题层级、目录等属于后续阶段。
|
|
99
|
-
|
|
100
|
-
## 许可证
|
|
101
|
-
|
|
102
|
-
MIT,见 [LICENSE](./LICENSE)。
|
|
1
|
+
# dsh-md-plus
|
|
2
|
+
|
|
3
|
+
给 DeepSeek Harness Web / Desktop 的 Markdown 显示增强插件,做四件事:重做代码块卡片、给 DSH 不认识的语言补语法高亮、自己渲染 mermaid 图形、重做表格样式。
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## 它解决什么
|
|
8
|
+
|
|
9
|
+
### 代码块样式
|
|
10
|
+
|
|
11
|
+
DSH 原生的头部是「小灰字 + 文字复制按钮」,没写语言时左边空一片,卡顶到第一行代码之间还留着大段空白。重做成一张完整的卡片:
|
|
12
|
+
|
|
13
|
+
| 元素 | 改前 | 改后 |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| 头部左侧 | 空(无语言时) | `</>` 图标 + 语言名,无语言显示 `Plain text` |
|
|
16
|
+
| 头部右侧 | 文字「复制」 | 图标按钮:不换行 + 复制 |
|
|
17
|
+
| 顶栏背景 | 与卡片之间有一条白带 | 与卡片同色 |
|
|
18
|
+
| 卡顶到代码 | 一大段空白 | 约一行代码高 |
|
|
19
|
+
|
|
20
|
+
样式是纯 CSS 打在 `.md-code-block` 上,所以所有语言(包括 DSH 自己高亮的 JSON/TS/Python)都吃同一套外观。想调间距,改 `src/client.js` 里 banner 的 `padding` 末位和 pre 的 `padding` 首位。
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### mermaid 图形
|
|
25
|
+
|
|
26
|
+
mermaid 围栏由插件渲染成 SVG,头部右侧可在「图形 / 代码」之间切换,复制按钮复制的仍是图源。配色和节点圆角在 `src/mermaid-theme.js`。
|
|
27
|
+
|
|
28
|
+
认图先看头部语言名(`mermaid` / `mmd` / `mermaidjs`),认不出再看正文里的类型声明(`flowchart`、`graph`、`sequenceDiagram` 等)。0.2.0-rc.2 上头部是占位文案,走的就是正文这条。
|
|
29
|
+
|
|
30
|
+
### 表格样式
|
|
31
|
+
|
|
32
|
+
DSH 原生表格无边框、分隔线半透明、表头没底色,首列还贴着左边缘。重做成:
|
|
33
|
+
|
|
34
|
+
| 元素 | 取值 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| 表头底 / 字 | `#f7f7f7` / `#181818` 加粗 |
|
|
37
|
+
| 边框 | `#ebebeb` 1px,只有横线 |
|
|
38
|
+
| 圆角 | 外 8px / 内 7px,只收外圈四角 |
|
|
39
|
+
| 首 / 末列内边距 | 16px(DSH 原本清零) |
|
|
40
|
+
| 悬停行 | `#fafafa` |
|
|
41
|
+
|
|
42
|
+
深色主题另有一套(`#1f1f1f` 表头 / `#2f2f2f` 线)。抓手用结构选择器 `div:has(> table)` 而不是 DSH 的哈希类名,DSH 换哈希也不失效。
|
|
43
|
+
|
|
44
|
+
## 安装与卸载
|
|
45
|
+
|
|
46
|
+
```powershell
|
|
47
|
+
dsh plugin --profile desktop add dsh-md-plus # 也可以用 github:JosephHy/dsh-md-plus
|
|
48
|
+
dsh plugin --profile desktop remove dsh-md-plus
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 开发
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
npm install # 顺带跑 prepare → build
|
|
55
|
+
npm run build # 产出 lib/ 下四个文件
|
|
56
|
+
npm run check # 语法检查 + 53 条测试
|
|
57
|
+
npm run preview # 生成 preview.html(含真渲出来的 mermaid 图)
|
|
58
|
+
npm run shot # 用 headless Chrome 把 preview.html 截成 docs/preview.png
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
测试跑的是 `lib/` 里的产物,所以先 `npm run build` 再 `npm test`(`npm run check` 不含 build)。
|
|
62
|
+
|
|
63
|
+
测试和预览页里的代码块都按聊天区的真实头部形状搭(`CodeToolbar`,语言名走占位回退)。
|
|
64
|
+
|
|
65
|
+
## 已知边界
|
|
66
|
+
|
|
67
|
+
- 0.2.0-rc.2 起,头部那行语言名由宿主决定显示什么:认这门语言就显示语言名,不认就显示本地化占位文案(中文「代码块」)。认不出来就读不到围栏语言,插件无法转化,且还不报错。mermaid 这条改看正文:跳过 `%%` 注释和开头的 `---` frontmatter,正文里有行以 mermaid 类型关键字开头就当图。这条只管认图,不参与补高亮的判断。
|
|
68
|
+
- 同一个原因让补高亮在 0.2.0-rc.2 上基本失效:`gdscript`、`nushell` 这类 DSH 不认的语言,头部是占位文案,插件问不到 Shiki 该用哪套语法,只能没颜色。反过来 DSH 认得的那 108 种(`dart`、`vue`、`scala` …)由 DSH 自己上色,插件不碰。
|
|
69
|
+
- `DSH_LANGS` 是 DSH `LANG_ALIASES` 的快照(对齐 108 条)。DSH 加语言后这份快照会落后,落后只会让它多管一门 DSH 也在管的高亮 —— 撤回兜底能保证不出现双份,但会白干一次高亮;想干净就跟着同步。
|
|
70
|
+
- mermaid 12 的新图种(`usecase-beta`、`agentflow-beta`)标识符只认字母数字下划线,中文得写进标签:`actor Customer("用户")` 可以,`actor 用户` 会解析失败。
|
|
71
|
+
- 高亮约 6.4 MB、mermaid 约 5.0 MB,按需下载,第一次用到时多花约 100ms 解析。
|
|
72
|
+
- 依赖宿主 `.md-code-block`、`[data-code-block-content]`、`[data-code-block-banner]`、`data-streaming` 这几个钩子,DSH 改了要跟着改 `src/client.js` 顶部的常量和 `MMD_TYPE`。
|
|
73
|
+
- 目前只管代码块、mermaid 和表格。
|
|
74
|
+
|
|
75
|
+
## 许可证
|
|
76
|
+
|
|
77
|
+
MIT,见 [LICENSE](./LICENSE)。
|
package/lib/client.js
CHANGED
|
@@ -70,9 +70,76 @@ window.__ModuleLoader__.load({
|
|
|
70
70
|
"less",
|
|
71
71
|
"sql",
|
|
72
72
|
"xml",
|
|
73
|
-
"lua"
|
|
73
|
+
"lua",
|
|
74
|
+
"bat",
|
|
75
|
+
"batch",
|
|
76
|
+
"powershell",
|
|
77
|
+
"ps1",
|
|
78
|
+
"ps",
|
|
79
|
+
"fish",
|
|
80
|
+
"properties",
|
|
81
|
+
"dotenv",
|
|
82
|
+
"env",
|
|
83
|
+
"log",
|
|
84
|
+
"csv",
|
|
85
|
+
"diff",
|
|
86
|
+
"patch",
|
|
87
|
+
"http",
|
|
88
|
+
"rst",
|
|
89
|
+
"latex",
|
|
90
|
+
"tex",
|
|
91
|
+
"bibtex",
|
|
92
|
+
"bib",
|
|
93
|
+
"asciidoc",
|
|
94
|
+
"adoc",
|
|
95
|
+
"r",
|
|
96
|
+
"julia",
|
|
97
|
+
"jl",
|
|
98
|
+
"dart",
|
|
99
|
+
"scala",
|
|
100
|
+
"clojure",
|
|
101
|
+
"clj",
|
|
102
|
+
"erlang",
|
|
103
|
+
"erl",
|
|
104
|
+
"elixir",
|
|
105
|
+
"ex",
|
|
106
|
+
"exs",
|
|
107
|
+
"haskell",
|
|
108
|
+
"hs",
|
|
109
|
+
"fsharp",
|
|
110
|
+
"fs",
|
|
111
|
+
"fsi",
|
|
112
|
+
"fsx",
|
|
113
|
+
"vb",
|
|
114
|
+
"vbnet",
|
|
115
|
+
"perl",
|
|
116
|
+
"pl",
|
|
117
|
+
"pm",
|
|
118
|
+
"verilog",
|
|
119
|
+
"v",
|
|
120
|
+
"system-verilog",
|
|
121
|
+
"systemverilog",
|
|
122
|
+
"sv",
|
|
123
|
+
"svh",
|
|
124
|
+
"graphql",
|
|
125
|
+
"gql",
|
|
126
|
+
"proto",
|
|
127
|
+
"protobuf",
|
|
128
|
+
"hcl",
|
|
129
|
+
"tf",
|
|
130
|
+
"tfvars",
|
|
131
|
+
"nix",
|
|
132
|
+
"vue",
|
|
133
|
+
"svelte",
|
|
134
|
+
"make",
|
|
135
|
+
"makefile",
|
|
136
|
+
"mk",
|
|
137
|
+
"cmake",
|
|
138
|
+
"groovy",
|
|
139
|
+
"gradle"
|
|
74
140
|
]);
|
|
75
141
|
var MMD_LANGS = /* @__PURE__ */ new Set(["mermaid", "mermaidjs", "mmd"]);
|
|
142
|
+
var MMD_TYPE = /^\s*(flowchart|graph|sequenceDiagram|classDiagram|stateDiagram(-v2)?|erDiagram|journey|gantt|pie|mindmap|timeline|gitGraph|quadrantChart|xychart-beta|sankey-beta|block-beta|packet-beta|architecture-beta|usecase-beta|agentflow-beta|C4Context|requirementDiagram|kanban|radar|treemap|venn|ishikawa|wardley|cynefin|treeView|zenuml)\b/im;
|
|
76
143
|
function icon(paths) {
|
|
77
144
|
var svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>" + paths + "</svg>";
|
|
78
145
|
return 'url("data:image/svg+xml,' + encodeURIComponent(svg) + '")';
|
|
@@ -177,7 +244,18 @@ window.__ModuleLoader__.load({
|
|
|
177
244
|
// 最后一行的下边线交给 table 自己的边框,免得叠成双线
|
|
178
245
|
TABLE + " > table tr:last-child td{border-bottom:0}",
|
|
179
246
|
// 宽表横向扫读时给个落点
|
|
180
|
-
TABLE + " > table tbody tr:hover td{background:var(--md-plus-tbl-hover)}"
|
|
247
|
+
TABLE + " > table tbody tr:hover td{background:var(--md-plus-tbl-hover)}",
|
|
248
|
+
// 宽表(≥4 列)不收着不行。宿主给这类表加了 .md-table-wide,并让它「出血」:
|
|
249
|
+
// 包裹层撑到面板宽,再用 padding-left 把表推到正文栏左侧。那个 padding 会吃掉
|
|
250
|
+
// 可用宽度,结果是表格比正文宽出一截、右边还被裁掉,而滚动条只在鼠标悬停时
|
|
251
|
+
// 才出现——文字表落进这个区间就很难读。这里按回正文栏宽,超出改为表内横滚。
|
|
252
|
+
// 特异性 (0,2,2),压得住宿主的 .Pg4CGa_body .md-table-wide (0,2,0)。
|
|
253
|
+
TABLE + ".md-table-wide{width:100%;max-width:100%;margin-inline:0;padding-inline:0;overflow-x:auto}",
|
|
254
|
+
// 塞得下就撑满正文栏,塞不下保持自然宽度让外面滚,不把列挤成一列一个字
|
|
255
|
+
TABLE + ".md-table-wide > table{width:100%;max-width:none;min-width:max-content}",
|
|
256
|
+
// 宿主原本是「悬停才出滚动条」,所以悬停时会把预留的滚动条高度收掉;
|
|
257
|
+
// 现在滚动条常驻,再收掉就会跳 5px,固定住。
|
|
258
|
+
TABLE + ".md-table-wide:hover{padding-bottom:var(--dsh-scrollbar-width,5px)}"
|
|
181
259
|
].join("\n");
|
|
182
260
|
var scripts = /* @__PURE__ */ new Map();
|
|
183
261
|
var pending = /* @__PURE__ */ new Set();
|
|
@@ -213,6 +291,22 @@ window.__ModuleLoader__.load({
|
|
|
213
291
|
var info = banner?.firstElementChild;
|
|
214
292
|
return (info?.textContent ?? "").trim().toLowerCase();
|
|
215
293
|
}
|
|
294
|
+
function sniffDiagramType(code) {
|
|
295
|
+
var text = code;
|
|
296
|
+
if (text.startsWith("---")) {
|
|
297
|
+
var blank = text.indexOf("\n");
|
|
298
|
+
var close = blank < 0 ? -1 : text.indexOf("\n---", blank);
|
|
299
|
+
text = close < 0 ? "" : text.slice(close + 4);
|
|
300
|
+
}
|
|
301
|
+
var body = text.split("\n").filter((line) => !line.trimStart().startsWith("%%")).join("\n");
|
|
302
|
+
return MMD_TYPE.exec(body)?.[1] ?? null;
|
|
303
|
+
}
|
|
304
|
+
function diagramKind(block) {
|
|
305
|
+
if (MMD_LANGS.has(readLang(block))) return "diagram";
|
|
306
|
+
var pre = block.querySelector(CONTENT + " pre");
|
|
307
|
+
if (pre === null) return null;
|
|
308
|
+
return sniffDiagramType(pre.textContent ?? "") === null ? null : "diagram";
|
|
309
|
+
}
|
|
216
310
|
function isOurs(node) {
|
|
217
311
|
var element = node?.nodeType === 1 ? node : node?.parentElement;
|
|
218
312
|
return element?.closest?.("." + HOST_CLASS + ", ." + BTN_CLASS + ", ." + MMD_CLASS) != null;
|
|
@@ -292,7 +386,7 @@ window.__ModuleLoader__.load({
|
|
|
292
386
|
var copy = banner?.querySelector("button:not(." + BTN_CLASS + ")");
|
|
293
387
|
var action = copy?.parentElement;
|
|
294
388
|
if (action === null || action === void 0) return;
|
|
295
|
-
var specs =
|
|
389
|
+
var specs = readLang(block) !== "" && diagramKind(block) !== null ? MMD_BUTTONS : PLAIN_BUTTONS;
|
|
296
390
|
for (const existing of action.querySelectorAll("." + BTN_CLASS)) {
|
|
297
391
|
if (specs.some((spec) => existing.classList.contains(spec.cls))) continue;
|
|
298
392
|
existing.remove();
|
|
@@ -310,16 +404,26 @@ window.__ModuleLoader__.load({
|
|
|
310
404
|
injected.add(created);
|
|
311
405
|
}
|
|
312
406
|
}
|
|
407
|
+
function releaseTakenOver(block, content) {
|
|
408
|
+
var host = content.querySelector("." + HOST_CLASS);
|
|
409
|
+
if (host === null) return false;
|
|
410
|
+
if (content.querySelector("pre.shiki:not(.md-plus-pre)") === null) return false;
|
|
411
|
+
host.remove();
|
|
412
|
+
block.removeAttribute(KEY_ATTR);
|
|
413
|
+
block.removeAttribute(DONE_ATTR);
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
313
416
|
async function enhance(block) {
|
|
314
417
|
if (!block.isConnected) return;
|
|
315
418
|
if (block.closest("[data-streaming]") !== null) return;
|
|
316
419
|
var content = block.querySelector(CONTENT);
|
|
317
420
|
if (content === null) return;
|
|
421
|
+
if (releaseTakenOver(block, content)) return;
|
|
318
422
|
var pre = content.querySelector("pre");
|
|
319
423
|
if (pre === null || pre.classList.contains("shiki")) return;
|
|
320
424
|
var lang = readLang(block);
|
|
321
425
|
if (lang === "") return;
|
|
322
|
-
if (
|
|
426
|
+
if (diagramKind(block) !== null) {
|
|
323
427
|
await renderDiagram(block, content, pre);
|
|
324
428
|
return;
|
|
325
429
|
}
|
|
@@ -373,6 +477,10 @@ window.__ModuleLoader__.load({
|
|
|
373
477
|
return;
|
|
374
478
|
}
|
|
375
479
|
if (typeof svg !== "string" || svg === "") return;
|
|
480
|
+
if (svg.includes('aria-roledescription="error"')) {
|
|
481
|
+
failDiagram(block, content, pre, key, new Error("mermaid \u8FD4\u56DE\u7684\u662F\u9519\u8BEF\u5361\u7247"));
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
376
484
|
if (!pre.isConnected || (pre.textContent ?? "").trim() !== code) {
|
|
377
485
|
schedule(block);
|
|
378
486
|
return;
|
|
@@ -491,7 +599,8 @@ window.__ModuleLoader__.load({
|
|
|
491
599
|
content.querySelector("." + MMD_CLASS)?.remove();
|
|
492
600
|
var note = content.querySelector("." + MMD_CLASS + "-error") ?? document.createElement("p");
|
|
493
601
|
note.className = MMD_CLASS + "-error";
|
|
494
|
-
|
|
602
|
+
var reason = (error?.message ?? String(error)).split("\n")[0] ?? "";
|
|
603
|
+
note.textContent = "mermaid \u6E32\u67D3\u5931\u8D25\uFF1A" + reason;
|
|
495
604
|
content.appendChild(note);
|
|
496
605
|
block.setAttribute(KEY_ATTR, key);
|
|
497
606
|
block.setAttribute(MMD_ATTR, "failed");
|
|
@@ -525,6 +634,8 @@ window.__ModuleLoader__.load({
|
|
|
525
634
|
script.remove();
|
|
526
635
|
}
|
|
527
636
|
scripts.clear();
|
|
637
|
+
delete window[HL_GLOBAL];
|
|
638
|
+
delete window[MMD_GLOBAL];
|
|
528
639
|
};
|
|
529
640
|
}, "dsh-md-plus: code block styling, highlighting and diagrams");
|
|
530
641
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// dsh-md-plus 宿主半:只做一件事——把两个浏览器端运行时经同源路由发出去。
|
|
2
2
|
// 皮肤与行为全在浏览器半(lib/client.js),这里不做别的。
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
4
|
|
|
5
5
|
export const name = "dsh-md-plus";
|
|
6
6
|
export const inject = ["webServer"];
|
|
@@ -26,10 +26,20 @@ export function apply(ctx) {
|
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
try {
|
|
29
|
+
// 文件名不带内容指纹,原来的一年 immutable 会让升级后的运行时发不出去:
|
|
30
|
+
// 改成每次回源校验,没变就 304。
|
|
31
|
+
const info = await stat(source);
|
|
32
|
+
const etag = `W/"${info.size.toString(16)}-${Math.floor(info.mtimeMs).toString(16)}"`;
|
|
33
|
+
if (req.headers?.["if-none-match"] === etag) {
|
|
34
|
+
res.writeHead(304, { etag, "cache-control": "no-cache" });
|
|
35
|
+
res.end();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
29
38
|
const body = await readFile(source);
|
|
30
39
|
res.writeHead(200, {
|
|
31
40
|
"content-type": "text/javascript; charset=utf-8",
|
|
32
|
-
"cache-control": "
|
|
41
|
+
"cache-control": "no-cache",
|
|
42
|
+
etag,
|
|
33
43
|
});
|
|
34
44
|
res.end(req.method === "HEAD" ? undefined : body);
|
|
35
45
|
} catch {
|