Remove unused `isSparkTableHeader` import and simplify condition since spark tables are handled upstream by `coerceSparkTables`.
85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
import type { MarkedExtension, Tokens } from "marked";
|
||
|
||
/**
|
||
* 将表格数据转换为 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('"') ||
|
||
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");
|
||
}
|
||
|
||
export default function markedTable(): MarkedExtension {
|
||
return {
|
||
renderer: {
|
||
table(token: Tokens.Table) {
|
||
const header = token.header;
|
||
let roll = "";
|
||
let remix = "";
|
||
|
||
// Spark tables (dice-formula first column) are handled upstream by
|
||
// `coerceSparkTables` in the content registry — they're rewritten to
|
||
// `:md-table` directives before rendering. This renderer only handles
|
||
// label-based tables (md-table-label / md-roll-label / md-remix-label).
|
||
const labelIndex = header.findIndex((cell) => {
|
||
if (cell.text === "md-roll-label") {
|
||
roll = " roll=true";
|
||
return true;
|
||
} else if (cell.text === "md-remix-label") {
|
||
roll = " roll=true remix=true";
|
||
return true;
|
||
}
|
||
return cell.text === "md-table-label" || cell.text === "label";
|
||
});
|
||
|
||
// 默认表格渲染 - 使用 marked 默认行为
|
||
if (labelIndex === -1) return false;
|
||
|
||
const headers = token.header.map((cell) => cell.text);
|
||
headers[labelIndex] = "label";
|
||
const rows = token.rows.map((row) => row.map((cell) => cell.text));
|
||
|
||
if (header.findIndex((header) => header.text === "body") < 0) {
|
||
// 收集所有非 label 列的表头
|
||
const bodyColumns = headers.filter((cell) => cell !== "label");
|
||
|
||
// 构建 body 列的模板:**列名**:{{列名}}\n\n
|
||
const bodyTemplate = bodyColumns
|
||
.map((col) => `**${col}**:{{${col}}}`)
|
||
.join("\n\n");
|
||
|
||
headers.push("body");
|
||
rows.forEach((row) => {
|
||
row.push(bodyTemplate);
|
||
});
|
||
}
|
||
|
||
// 生成 CSV 数据
|
||
const csvData = tableToCSV(headers, rows);
|
||
|
||
// 渲染为 md-table 组件,内联 CSV 数据
|
||
// data-spark attribute is injected by the CLI directive scanner,
|
||
// not computed here.
|
||
return `<md-table ${roll}${remix}>${csvData}</md-table>\n`;
|
||
},
|
||
},
|
||
};
|
||
}
|