feat: yaml tag block

This commit is contained in:
hypercross 2026-02-28 11:42:42 +08:00
parent 2b5bcfff93
commit 19256b501f
4 changed files with 113 additions and 1 deletions

35
content/deck-test.md Normal file
View File

@ -0,0 +1,35 @@
# yaml/tag 代码块格式测试
## 使用 yaml/tag 语法创建 md-deck
```yaml/tag
tag: md-deck
body: ./sparks.csv
size: 54x86
grid: 5x8
bleed: 1
padding: 2
font-size: 3
```
## 使用 body 字段添加内容
```yaml/tag
tag: tag-box
class: note
body: |
这是一个提示框
```
## 带引号的值
```yaml/tag
tag: tag-alert
type: warning
class: my-alert
body: 这是一个警告信息
```
## 旧的指令语法仍然可用
:md-deck[./sparks.csv]{size="54x86" grid="5x8"}

19
package-lock.json generated
View File

@ -13,6 +13,7 @@
"chokidar": "^5.0.0", "chokidar": "^5.0.0",
"commander": "^12.1.0", "commander": "^12.1.0",
"csv-parse": "^5.5.6", "csv-parse": "^5.5.6",
"js-yaml": "^4.1.1",
"marked": "^14.1.0", "marked": "^14.1.0",
"marked-directive": "^1.0.7", "marked-directive": "^1.0.7",
"solid-element": "^1.9.1", "solid-element": "^1.9.1",
@ -2251,6 +2252,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/attributes-parser": { "node_modules/attributes-parser": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/attributes-parser/-/attributes-parser-2.2.3.tgz", "resolved": "https://registry.npmjs.org/attributes-parser/-/attributes-parser-2.2.3.tgz",
@ -2669,6 +2676,18 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jsesc": { "node_modules/jsesc": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",

View File

@ -34,6 +34,7 @@
"chokidar": "^5.0.0", "chokidar": "^5.0.0",
"commander": "^12.1.0", "commander": "^12.1.0",
"csv-parse": "^5.5.6", "csv-parse": "^5.5.6",
"js-yaml": "^4.1.1",
"marked": "^14.1.0", "marked": "^14.1.0",
"marked-directive": "^1.0.7", "marked-directive": "^1.0.7",
"solid-element": "^1.9.1", "solid-element": "^1.9.1",

View File

@ -1,5 +1,6 @@
import { Marked } from 'marked'; import { Marked } from 'marked';
import {createDirectives, presetDirectiveConfigs} from 'marked-directive'; import {createDirectives, presetDirectiveConfigs} from 'marked-directive';
import yaml from 'js-yaml';
// 使用 marked-directive 来支持指令语法 // 使用 marked-directive 来支持指令语法
const marked = new Marked().use(createDirectives([ const marked = new Marked().use(createDirectives([
@ -23,7 +24,63 @@ const marked = new Marked().use(createDirectives([
return false; return false;
} }
}, },
])); ]), {
// 自定义代码块渲染器,支持 yaml/tag 格式
extensions: [{
name: 'code-block-yaml-tag',
level: 'block',
start(src: string) {
// 检测 ```yaml/tag 开头的代码块
return src.match(/^```yaml\/tag\s*\n/m)?.index;
},
tokenizer(src: string) {
const rule = /^```yaml\/tag\s*\n([\s\S]*?)\n```/;
const match = rule.exec(src);
if (match) {
const yamlContent = match[1]?.trim() || '';
const props = yaml.load(yamlContent) as Record<string, unknown> || {};
// 提取 tag 名称,默认为 tag-unknown
const tagName = (props.tag as string) || 'tag-unknown';
// 移除 tag 属性,剩下的作为 HTML 属性
const { tag, ...rest } = props;
// 提取 innerText 内容(如果有 body 字段)
let content = '';
if ('body' in rest) {
content = String(rest.body || '');
delete (rest as Record<string, unknown>).body;
}
// 构建属性字符串
const propsStr = Object.entries(rest)
.map(([key, value]) => {
const strValue = String(value);
// 如果值包含空格或特殊字符,添加引号
if (strValue.includes(' ') || strValue.includes('"')) {
return `${key}="${strValue.replace(/"/g, '&quot;')}"`;
}
return `${key}="${strValue}"`;
})
.join(' ');
return {
type: 'code-block-yaml-tag',
raw: match[0],
tagName,
props: propsStr,
content
};
}
},
renderer(token: any) {
// 渲染为自定义 HTML 标签
const propsAttr = token.props ? ` ${token.props}` : '';
return `<${token.tagName}${propsAttr}>${token.content || ''}</${token.tagName}>\n`;
}
}]
});
export function parseMarkdown(content: string): string { export function parseMarkdown(content: string): string {
return marked.parse(content.trimStart()) as string; return marked.parse(content.trimStart()) as string;