opencode-config/.opencode/draw-image/src/slot-parser.ts
Sergey 56b67d2d5c
feat(draw-image): SVG template renderer for on-brand covers (#134)
* feat(draw-image): add SVG template render engine

* feat(draw-image): add opencode plugin and tool tests

* test(draw-image): add vitest unit integration e2e suite

* chore(draw-image): wire CI dependabot docs and ADR

* docs(handoff): set PR number

* docs(handoff): fix PR number placeholder in frontmatter

* fix(ci): use tempfile and trailing newline in draw-image tests

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-29 23:42:50 +03:00

57 lines
No EOL
1.5 KiB
TypeScript

export type FitMode = "contain" | "cover" | "stretch"
export type SlotSpec = {
name: string
x: number
y: number
w: number
h: number
fit: FitMode
recolor: string
bg: string
border: string
radius: number
}
const SLOT_RE = /<!--\s*slot:\s*([^>]*?)-->/g
export function parseSlots(svg: string): SlotSpec[] {
const slots: SlotSpec[] = []
let m: RegExpExecArray | null
while ((m = SLOT_RE.exec(svg)) !== null) {
const body = m[1].trim()
const spec = parseSlotBody(body)
if (spec) slots.push(spec)
}
return slots
}
function parseSlotBody(body: string): SlotSpec | null {
const fields = new Map<string, string>()
for (const part of body.split(",")) {
const eq = part.indexOf("=")
if (eq === -1) continue
const key = part.slice(0, eq).trim()
const val = part.slice(eq + 1).trim()
fields.set(key, val)
}
const name = fields.get("name")
if (!name) return null
const x = num(fields, "x")
const y = num(fields, "y")
const w = num(fields, "w")
const h = num(fields, "h")
if ([x, y, w, h].some((v) => Number.isNaN(v))) return null
const fit = (fields.get("fit") as FitMode) ?? "contain"
const recolor = fields.get("recolor") ?? "none"
const bg = fields.get("bg") ?? "none"
const border = fields.get("border") ?? "none"
const radius = num(fields, "radius") || 0
return { name, x, y, w, h, fit, recolor, bg, border, radius }
}
function num(fields: Map<string, string>, key: string): number {
const v = fields.get(key)
if (v === undefined) return NaN
return parseFloat(v)
}