Files
SoonMachine/app/src/main/utils/parse-soon.ts
T
2026-05-27 00:17:13 +08:00

86 lines
2.9 KiB
TypeScript

import path from 'path'
import { pathToFileURL } from 'url'
export interface TemplateFieldRow {
label: string
value: string
}
export interface ParsedSoonTemplate {
frontImageUrl: string
backImageUrl: string
fields: TemplateFieldRow[]
}
function pickArray(obj: Record<string, unknown>, key: string): Record<string, unknown>[] {
const entry = Object.entries(obj).find(([k]) => k.toLowerCase() === key.toLowerCase())
if (!Array.isArray(entry?.[1])) return []
return (entry[1] as unknown[]).filter((x) => x && typeof x === 'object') as Record<string, unknown>[]
}
function pickStr(item: Record<string, unknown>, keys: string[]): string {
for (const k of keys) {
const hit = Object.entries(item).find(([name]) => name.toLowerCase() === k.toLowerCase())
if (hit && hit[1] != null && String(hit[1]).trim()) return String(hit[1]).trim()
}
return ''
}
function sideOf(item: Record<string, unknown>): 'front' | 'back' | '' {
const raw = pickStr(item, ['side', 'face', 'surface', 'cardface']).toLowerCase()
if (!raw) return ''
if (['front', '0', 'f', '正面', '正'].includes(raw)) return 'front'
if (['back', '1', 'b', '背面', '背'].includes(raw)) return 'back'
return ''
}
function sideLabel(side: 'front' | 'back'): string {
return side === 'front' ? '正面' : '背面'
}
function resolveAssetPath(soonPath: string, ref: string): string {
if (!ref) return ''
const clean = ref.replace(/^file:\/\//i, '')
const abs = path.isAbsolute(clean) ? clean : path.join(path.dirname(soonPath), clean)
return pathToFileURL(abs).href
}
function toFieldLabel(name: string, side: 'front' | 'back'): string {
return `${name} [${sideLabel(side)}]`
}
export function parseSoonTemplate(soonPath: string, raw: Record<string, unknown>): ParsedSoonTemplate {
const imgs = pickArray(raw, 'Img')
const texts = pickArray(raw, 'Text')
let frontImageUrl = ''
let backImageUrl = ''
const fields: TemplateFieldRow[] = []
imgs.forEach((item, idx) => {
const fileRef = pickStr(item, ['file', 'path', 'img', 'image', 'src', 'filename'])
if (!fileRef) return
let side = sideOf(item)
if (!side) side = idx === 0 ? 'front' : idx === 1 ? 'back' : 'front'
const url = resolveAssetPath(soonPath, fileRef)
if (side === 'front') {
if (!frontImageUrl) frontImageUrl = url
const name = pickStr(item, ['name', 'field', 'key']) || 'IMAGE'
fields.push({ label: toFieldLabel(name, 'front'), value: fileRef })
} else if (!backImageUrl) {
backImageUrl = url
}
})
texts.forEach((item) => {
const name = pickStr(item, ['name', 'field', 'key', 'id'])
if (!name) return
const value = pickStr(item, ['value', 'text', 'default', 'content', 'data'])
let side = sideOf(item)
if (!side) side = /image|img|front/i.test(name) ? 'front' : 'back'
fields.push({ label: toFieldLabel(name, side), value })
})
return { frontImageUrl, backImageUrl, fields }
}