ExportShapeTool: Fix SVG export

This commit is contained in:
Dominik Jain 2025-10-16 16:13:54 +02:00
parent 7463ba3eaf
commit 6c6204806f
3 changed files with 34 additions and 10 deletions

View File

@ -4,10 +4,22 @@ type CallToolContent = CallToolResult["content"][number];
type TextItem = Extract<CallToolContent, { type: "text" }>;
type ImageItem = Extract<CallToolContent, { type: "image" }>;
class TextContent implements TextItem {
export class TextContent implements TextItem {
[x: string]: unknown;
readonly type = "text" as const;
constructor(public text: string) {}
/**
* @param data - Text data as string or as object (from JSON representation where indices are mapped to character codes)
*/
public static textData(data: string | object): string {
if (typeof data === "object") {
// convert object containing character codes (as obtained from JSON conversion of string) back to string
return String.fromCharCode(...(Object.values(data) as number[]));
} else {
return data;
}
}
}
class ImageContent implements ImageItem {
@ -58,6 +70,16 @@ export class TextResponse extends ToolResponse {
constructor(text: string) {
super([new TextContent(text)]);
}
/**
* Creates a TextResponse from text data given as string or as object (from JSON representation where indices are mapped to
* character codes).
*
* @param data - Text data as string or as object (from JSON representation where indices are mapped to character codes)
*/
public static fromData(data: string | object): TextResponse {
return new TextResponse(TextContent.textData(data));
}
}
export class PNGResponse extends ToolResponse {

View File

@ -1,6 +1,6 @@
import { z } from "zod";
import { Tool } from "../Tool";
import { PNGImageContent, PNGResponse, TextResponse, ToolResponse } from "../ToolResponse";
import { PNGImageContent, PNGResponse, TextContent, TextResponse, ToolResponse } from "../ToolResponse";
import "reflect-metadata";
import { PenpotMcpServer } from "../PenpotMcpServer";
import { ExecuteCodePluginTask } from "../tasks/ExecuteCodePluginTask";
@ -86,14 +86,14 @@ export class ExportShapeTool extends Tool<ExportShapeArgs> {
if (args.format === "png") {
return new PNGResponse(imageData);
} else {
return new TextResponse(imageData);
return TextResponse.fromData(imageData);
}
} else {
// save image to file
if (args.format === "png") {
FileUtils.writeBinaryFile(args.filePath, PNGImageContent.byteData(imageData));
} else {
FileUtils.writeTextFile(args.filePath, imageData);
FileUtils.writeTextFile(args.filePath, TextContent.textData(imageData));
}
return new TextResponse(`The shape has been exported to ${args.filePath}`);
}

View File

@ -1,3 +1,6 @@
import * as path from "path";
import * as fs from "fs";
export class FileUtils {
/**
* Checks whether the given file path is absolute and raises an error if not.
@ -5,16 +8,15 @@ export class FileUtils {
* @param filePath - The file path to check
*/
public static checkPathIsAbsolute(filePath: string): void {
if (!require("path").isAbsolute(filePath)) {
if (!path.isAbsolute(filePath)) {
throw new Error(`The specified file path must be absolute: ${filePath}`);
}
}
public static createParentDirectories(filePath: string): void {
const path = require("path");
const dir = path.dirname(filePath);
if (!require("fs").existsSync(dir)) {
require("fs").mkdirSync(dir, { recursive: true });
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
@ -26,7 +28,7 @@ export class FileUtils {
*/
public static writeBinaryFile(filePath: string, bytes: Uint8Array): void {
this.createParentDirectories(filePath);
require("fs").writeFileSync(filePath, Buffer.from(bytes));
fs.writeFileSync(filePath, Buffer.from(bytes));
}
/**
@ -37,6 +39,6 @@ export class FileUtils {
*/
public static writeTextFile(filePath: string, text: string): void {
this.createParentDirectories(filePath);
require("fs").writeFileSync(filePath, text, { encoding: "utf-8" });
fs.writeFileSync(filePath, text, { encoding: "utf-8" });
}
}