ttrpg-tools/src/cli/tools/frontmatter/read-frontmatter.ts

155 lines
3.4 KiB
TypeScript
Raw Normal View History

2026-03-18 12:08:28 +08:00
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;
}
2026-03-18 13:48:19 +08:00
/**
*
*
* 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';
}
2026-03-18 12:08:28 +08:00
/**
*
*/
export interface CardField {
name: string;
description?: string;
examples?: string[];
2026-03-18 13:48:19 +08:00
style?: CardFieldStyle;
2026-03-18 12:08:28 +08:00
[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 : '未知错误'}`
};
}
}