figma-local-context-mcp/src/services/export-node.ts
2026-05-20 19:14:51 +08:00

68 lines
1.8 KiB
TypeScript

import fs from "node:fs"
import path from "node:path"
import { Resvg } from "@resvg/resvg-js"
import { loadFigFile } from "./fig-file.js"
import { renderNodeToSvg } from "./fig-node-svg.js"
import { keyForGuid, sanitizeFilePart } from "../utils/node-id.js"
export type ExportNodeOptions = {
filePath: string
nodeQuery: string
outputPath?: string
format: "svg" | "png"
scale: number
background?: string
}
export type ExportNodeResult = {
filePath: string
outputPath: string
format: "svg" | "png"
scale: number
width: number
height: number
node: {
id: string
name?: string
type?: string
}
}
export function exportFigNode(options: ExportNodeOptions): ExportNodeResult {
const figJson = loadFigFile(options.filePath)
const rendered = renderNodeToSvg(figJson, {
nodeQuery: options.nodeQuery,
scale: options.scale,
background: options.background
})
const outputPath = path.resolve(options.outputPath ?? defaultOutputPath(options))
fs.mkdirSync(path.dirname(outputPath), { recursive: true })
if (options.format === "svg") {
fs.writeFileSync(outputPath, rendered.svg)
} else {
fs.writeFileSync(outputPath, new Resvg(rendered.svg).render().asPng())
}
return {
filePath: path.resolve(options.filePath),
outputPath,
format: options.format,
scale: options.scale,
width: rendered.width,
height: rendered.height,
node: {
id: keyForGuid(rendered.node.guid),
name: rendered.node.name,
type: rendered.node.type
}
}
}
function defaultOutputPath(options: ExportNodeOptions): string {
const input = path.parse(options.filePath)
const nodePart = sanitizeFilePart(options.nodeQuery)
const scalePart = options.format === "png" ? `@${options.scale}x` : ""
return path.join(process.cwd(), `${input.name}-${nodePart}${scalePart}.${options.format}`)
}