import { readFileSync, existsSync } from 'fs'; import yaml from 'js-yaml'; /** * 读取 CSV frontmatter 的参数 */ export interface ReadFrontmatterParams { /** * CSV 文件路径(相对路径相对于 MCP 服务器工作目录) */ csv_file: string; } /** * Frontmatter 数据结构 */ export interface DeckFrontmatter { /** * 字段定义 */ fields?: CardField[]; /** * Deck 配置 */ deck?: DeckConfig; /** * 其他自定义属性 */ [key: string]: unknown; } /** * 字段样式配置 * * 位置按照卡牌网格,安排 x,y,w,h 四个整数 * 如 5x8 网格中 1,1,5,8 表示覆盖整个卡牌的区域 * * 字体使用 f:8 来表示 8mm 字体 * * 朝向使用 u:n/w/s/e 表示字段的上侧朝向北西南东 */ export interface CardFieldStyle { /** * 位置:[x, y, w, h] 网格坐标和尺寸 * 例如:[1, 1, 5, 8] 表示从 (1,1) 开始,宽 5 格,高 8 格 */ pos?: [number, number, number, number]; /** * 字体大小:格式 "f:8" 表示 8mm 字体 */ font?: string; /** * 朝向:上侧朝向 "n" | "w" | "s" | "e"(北/西/南/东) */ up?: 'n' | 'w' | 's' | 'e'; } /** * 卡牌字段定义 */ export interface CardField { name: string; description?: string; examples?: string[]; style?: CardFieldStyle; [key: string]: unknown; } /** * Deck 配置 */ export interface DeckConfig { size?: string; grid?: string; bleed?: number; padding?: number; shape?: 'rectangle' | 'circle' | 'hex' | 'diamond'; layers?: string; back_layers?: string; [key: string]: unknown; } /** * 读取 CSV frontmatter 的结果 */ export interface ReadFrontmatterResult { success: boolean; frontmatter?: DeckFrontmatter; message: string; } /** * 解析 CSV 文件的 frontmatter */ function parseFrontMatter(content: string): { frontmatter?: DeckFrontmatter; csvContent: string } { const parts = content.trim().split(/(?:^|\n)---\s*\n/g); // 至少需要三个部分:空字符串、front matter、CSV 内容 if (parts.length !== 3 || parts[0] !== '') { return { csvContent: content }; } try { const frontmatterStr = parts[1].trim(); const frontmatter = yaml.load(frontmatterStr) as DeckFrontmatter | undefined; const csvContent = parts.slice(2).join('---\n').trimStart(); return { frontmatter, csvContent }; } catch (error) { console.warn('Failed to parse front matter:', error); return { csvContent: content }; } } /** * 读取 CSV 文件的 frontmatter */ export function readFrontmatter(params: ReadFrontmatterParams): ReadFrontmatterResult { const { csv_file } = params; // 检查文件是否存在 if (!existsSync(csv_file)) { return { success: false, message: `文件不存在:${csv_file}` }; } try { // 读取文件内容 const content = readFileSync(csv_file, 'utf-8'); // 解析 frontmatter const { frontmatter } = parseFrontMatter(content); if (!frontmatter) { return { success: true, frontmatter: {}, message: `文件 ${csv_file} 没有 frontmatter,返回空对象` }; } return { success: true, frontmatter, message: `成功读取 ${csv_file} 的 frontmatter` }; } catch (error) { return { success: false, message: `读取失败:${error instanceof Error ? error.message : '未知错误'}` }; } }