128 lines
2.7 KiB
TypeScript
128 lines
2.7 KiB
TypeScript
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 卡牌字段定义
|
|||
|
|
*/
|
|||
|
|
export interface CardField {
|
|||
|
|
name: string;
|
|||
|
|
description?: string;
|
|||
|
|
examples?: string[];
|
|||
|
|
[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 : '未知错误'}`
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|