feat: auto-convert tables
This commit is contained in:
parent
6b411c2f24
commit
6f57970711
|
|
@ -1,4 +1,4 @@
|
||||||
import { Marked } from 'marked';
|
import { Marked, type MarkedExtension, type Tokens } from 'marked';
|
||||||
import {createDirectives, presetDirectiveConfigs} from 'marked-directive';
|
import {createDirectives, presetDirectiveConfigs} from 'marked-directive';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import markedAlert from "marked-alert";
|
import markedAlert from "marked-alert";
|
||||||
|
|
@ -14,6 +14,28 @@ function overrideIconPrefix(path?: string){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将表格数据转换为 CSV 格式字符串
|
||||||
|
* @param headers 表头数组
|
||||||
|
* @param rows 表格数据行
|
||||||
|
* @returns CSV 格式字符串
|
||||||
|
*/
|
||||||
|
function tableToCSV(headers: string[], rows: string[][]): string {
|
||||||
|
const escapeCell = (cell: string) => {
|
||||||
|
// 如果单元格包含逗号、换行或引号,需要转义
|
||||||
|
if (cell.includes(',') || cell.includes('\n') || cell.includes('"')) {
|
||||||
|
return `"${cell.replace(/"/g, '""')}"`;
|
||||||
|
}
|
||||||
|
return cell;
|
||||||
|
};
|
||||||
|
|
||||||
|
const headerLine = headers.map(escapeCell).join(',');
|
||||||
|
const dataLines = rows.map(row => row.map(escapeCell).join(','));
|
||||||
|
|
||||||
|
return [headerLine, ...dataLines].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
// 使用 marked-directive 来支持指令语法
|
// 使用 marked-directive 来支持指令语法
|
||||||
const marked = new Marked()
|
const marked = new Marked()
|
||||||
.use(gfmHeadingId())
|
.use(gfmHeadingId())
|
||||||
|
|
@ -56,20 +78,20 @@ const marked = new Marked()
|
||||||
if (match) {
|
if (match) {
|
||||||
const yamlContent = match[1]?.trim() || '';
|
const yamlContent = match[1]?.trim() || '';
|
||||||
const props = yaml.load(yamlContent) as Record<string, unknown> || {};
|
const props = yaml.load(yamlContent) as Record<string, unknown> || {};
|
||||||
|
|
||||||
// 提取 tag 名称,默认为 tag-unknown
|
// 提取 tag 名称,默认为 tag-unknown
|
||||||
const tagName = (props.tag as string) || 'tag-unknown';
|
const tagName = (props.tag as string) || 'tag-unknown';
|
||||||
|
|
||||||
// 移除 tag 属性,剩下的作为 HTML 属性
|
// 移除 tag 属性,剩下的作为 HTML 属性
|
||||||
const { tag, ...rest } = props;
|
const { tag, ...rest } = props;
|
||||||
|
|
||||||
// 提取 innerText 内容(如果有 body 字段)
|
// 提取 innerText 内容(如果有 body 字段)
|
||||||
let content = '';
|
let content = '';
|
||||||
if ('body' in rest) {
|
if ('body' in rest) {
|
||||||
content = String(rest.body || '');
|
content = String(rest.body || '');
|
||||||
delete (rest as Record<string, unknown>).body;
|
delete (rest as Record<string, unknown>).body;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建属性字符串
|
// 构建属性字符串
|
||||||
const propsStr = Object.entries(rest)
|
const propsStr = Object.entries(rest)
|
||||||
.map(([key, value]) => {
|
.map(([key, value]) => {
|
||||||
|
|
@ -81,7 +103,7 @@ const marked = new Marked()
|
||||||
return `${key}="${strValue}"`;
|
return `${key}="${strValue}"`;
|
||||||
})
|
})
|
||||||
.join(' ');
|
.join(' ');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'code-block-yaml-tag',
|
type: 'code-block-yaml-tag',
|
||||||
raw: match[0],
|
raw: match[0],
|
||||||
|
|
@ -99,6 +121,36 @@ const marked = new Marked()
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 覆盖默认的 table renderer 以支持自动转换
|
||||||
|
marked.use({
|
||||||
|
renderer: {
|
||||||
|
table(token: Tokens.Table) {
|
||||||
|
// 检查表头是否包含 md-table-label
|
||||||
|
const header = token.header;
|
||||||
|
const labelIndex = header.findIndex(cell => cell.text === 'md-table-label');
|
||||||
|
|
||||||
|
if (labelIndex !== -1) {
|
||||||
|
// 将 md-table-label 列转换为 label
|
||||||
|
const headers = header.map(cell => cell.text === 'md-table-label' ? 'label' : cell.text);
|
||||||
|
|
||||||
|
// 转换所有行
|
||||||
|
const rows = token.rows.map(row =>
|
||||||
|
row.map(cell => cell.text)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 生成 CSV 数据
|
||||||
|
const csvData = tableToCSV(headers, rows);
|
||||||
|
|
||||||
|
// 渲染为 md-table 组件,内联 CSV 数据
|
||||||
|
return `<md-table>${csvData}</md-table>\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认表格渲染 - 使用 marked 默认行为
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as MarkedExtension);
|
||||||
|
|
||||||
export function parseMarkdown(content: string, iconPrefix?: string): string {
|
export function parseMarkdown(content: string, iconPrefix?: string): string {
|
||||||
using prefix = overrideIconPrefix(iconPrefix);
|
using prefix = overrideIconPrefix(iconPrefix);
|
||||||
return marked.parse(content.trimStart()) as string;
|
return marked.parse(content.trimStart()) as string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue