Files
NotesAgentic/frontend/src/features/editor/noteMetadata.ts
T

24 lines
1.5 KiB
TypeScript

// TODO(desktop): 第三阶段顶部「段落 → 导入为笔记属性」复用属性解析边界,
// 补齐无损 YAML、冲突合并与可撤销事务;见 docs/contracts/Tauri-Rust桌面客户端需求说明-第三阶段.md。
export interface NoteMetadata { prefix: string; yaml: string; body: string; title: string; tags: string[] }
export function splitNoteMetadata(source: string): NoteMetadata | null {
const match = source.match(/^\uFEFF?(---|\*\*\*)[ \t]*\r?\n([\s\S]*?)\r?\n(?:-{3,}|\.\.\.)[ \t]*(?:\r?\n|$)/)
if (!match) return null
const yaml = match[2]!
// Only recognize metadata with explicit fields, not ordinary thematic breaks.
const title = yaml.match(/^title:[ \t]*(.*)$/m)?.[1]?.trim() ?? ''
const rawTags = yaml.match(/^tags:[ \t]*(.*)$/m)?.[1]?.trim()
if (!title && rawTags === undefined) return null
// Complex YAML values remain editable in source mode, never partially rewritten.
if (/^(?:[|>]|\{)/.test(title) || (rawTags === '' && /^\s+-\s/m.test(yaml))) return null
const tags = rawTags?.replace(/^\[|\]$/g, '').split(',').map(tag => tag.trim().replace(/^['"]|['"]$/g, '')).filter(Boolean) ?? []
return { prefix: match[0], yaml, body: source.slice(match[0].length), title: title.replace(/^['"]|['"]$/g, ''), tags }
}
export function updateMetadataTags(metadata: NoteMetadata, tags: string[]): string {
const line = `tags: ${JSON.stringify([...new Set(tags)])}`
const yaml = /^tags:/m.test(metadata.yaml) ? metadata.yaml.replace(/^tags:.*$/m, () => line) : `${metadata.yaml}\n${line}`
return `---\n${yaml.trim()}\n---\n`
}