T24: Add try/catch to export functions, use shared types, return ExportResult

This commit is contained in:
2026-06-22 23:49:18 +00:00
parent 4f0d750741
commit 056e552ef4
+65 -72
View File
@@ -1,64 +1,14 @@
import type { YjsDocument } from '../crdt/YjsDocument'; import type { YjsDocument } from '../crdt/YjsDocument';
import type {
CADLayer,
CADProperties,
CADElement,
ExportData,
ExportOptions,
ExportResult,
} from '../types/cad.types';
// ── Types ─────────────────────────────────────────────────────────────────── // ── Helpers ───────────────────────────────────────────────────────────────────
interface CADLayer {
id: string;
name: string;
visible: boolean;
locked: boolean;
color?: string;
lineType?: string;
transparency?: number;
sortOrder?: number;
}
interface CADProperties {
fill?: string;
stroke?: string;
strokeWidth?: number;
rotation?: number;
lineType?: 'solid' | 'dashed' | 'dotted';
radius?: number;
x1?: number;
y1?: number;
x2?: number;
y2?: number;
points?: Array<{ x: number; y: number }>;
text?: string;
fontSize?: number;
startAngle?: number;
endAngle?: number;
[key: string]: unknown;
}
interface CADElement {
id: string;
type: string;
layerId: string;
x: number;
y: number;
width: number;
height: number;
properties: CADProperties;
}
interface ExportData {
version: string;
exportedAt: number;
projectMeta: Record<string, unknown>;
layers: CADLayer[];
elements: CADElement[];
}
interface ExportOptions {
includeHiddenLayers?: boolean;
includeInvisibleElements?: boolean;
pageSize?: 'a4' | 'a3' | 'letter';
landscape?: boolean;
}
// ── Helpers ──────────────────────────────────────────────────────────────────
function hexToRgb(hex: string): { r: number; g: number; b: number } { function hexToRgb(hex: string): { r: number; g: number; b: number } {
const clean = hex.replace('#', ''); const clean = hex.replace('#', '');
@@ -150,22 +100,39 @@ function downloadBlob(content: string | Blob, filename: string, mimeType: string
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }
// ── JSON Export ────────────────────────────────────────────────────────────── // ── JSON Export ──────────────────────────────────────────────────────────────
export function exportJSON(yjsDoc: YjsDocument, filename = 'cad-export.json'): void { export function exportJSON(yjsDoc: YjsDocument, filename = 'cad-export.json'): ExportResult {
try {
const data = collectExportData(yjsDoc, {}); const data = collectExportData(yjsDoc, {});
const json = JSON.stringify(data, null, 2); const json = JSON.stringify(data, null, 2);
downloadBlob(json, filename, 'application/json'); downloadBlob(json, filename, 'application/json');
return { success: true, data: json };
} catch (e) {
return {
success: false,
error: `exportJSON failed: ${(e as Error).message}`,
};
}
} }
export function exportJSONString(yjsDoc: YjsDocument): string { export function exportJSONString(yjsDoc: YjsDocument): ExportResult {
try {
const data = collectExportData(yjsDoc, {}); const data = collectExportData(yjsDoc, {});
return JSON.stringify(data, null, 2); const json = JSON.stringify(data, null, 2);
return { success: true, data: json };
} catch (e) {
return {
success: false,
error: `exportJSONString failed: ${(e as Error).message}`,
};
}
} }
// ── SVG Export ─────────────────────────────────────────────────────────────── // ── SVG Export ───────────────────────────────────────────────────────────────
export function exportSVG(yjsDoc: YjsDocument, filename = 'cad-export.svg', options: ExportOptions = {}): void { export function exportSVG(yjsDoc: YjsDocument, filename = 'cad-export.svg', options: ExportOptions = {}): ExportResult {
try {
const data = collectExportData(yjsDoc, options); const data = collectExportData(yjsDoc, options);
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
@@ -262,11 +229,19 @@ export function exportSVG(yjsDoc: YjsDocument, filename = 'cad-export.svg', opti
svgParts.push('</svg>'); svgParts.push('</svg>');
const svg = svgParts.join('\n'); const svg = svgParts.join('\n');
downloadBlob(svg, filename, 'image/svg+xml'); downloadBlob(svg, filename, 'image/svg+xml');
return { success: true, data: svg };
} catch (e) {
return {
success: false,
error: `exportSVG failed: ${(e as Error).message}`,
};
}
} }
// ── DXF Export ─────────────────────────────────────────────────────────────── // ── DXF Export ───────────────────────────────────────────────────────────────
export function exportDXF(yjsDoc: YjsDocument, filename = 'cad-export.dxf', options: ExportOptions = {}): void { export function exportDXF(yjsDoc: YjsDocument, filename = 'cad-export.dxf', options: ExportOptions = {}): ExportResult {
try {
const data = collectExportData(yjsDoc, options); const data = collectExportData(yjsDoc, options);
const lines: string[] = []; const lines: string[] = [];
@@ -424,15 +399,23 @@ export function exportDXF(yjsDoc: YjsDocument, filename = 'cad-export.dxf', opti
const dxf = lines.join('\n'); const dxf = lines.join('\n');
downloadBlob(dxf, filename, 'application/dxf'); downloadBlob(dxf, filename, 'application/dxf');
return { success: true, data: dxf };
} catch (e) {
return {
success: false,
error: `exportDXF failed: ${(e as Error).message}`,
};
}
} }
// ── PDF Export ─────────────────────────────────────────────────────────────── // ── PDF Export ───────────────────────────────────────────────────────────────
export async function exportPDF( export async function exportPDF(
yjsDoc: YjsDocument, yjsDoc: YjsDocument,
filename = 'cad-export.pdf', filename = 'cad-export.pdf',
options: ExportOptions = {} options: ExportOptions = {}
): Promise<void> { ): Promise<ExportResult> {
try {
const data = collectExportData(yjsDoc, options); const data = collectExportData(yjsDoc, options);
const { jsPDF } = await import('jspdf'); const { jsPDF } = await import('jspdf');
@@ -553,9 +536,16 @@ export async function exportPDF(
); );
pdf.save(filename); pdf.save(filename);
return { success: true };
} catch (e) {
return {
success: false,
error: `exportPDF failed: ${(e as Error).message}`,
};
}
} }
// ── Unified Export ─────────────────────────────────────────────────────────── // ── Unified Export ─────────────────────────────────────────────────────────────
export type ExportFormat = 'json' | 'svg' | 'dxf' | 'pdf'; export type ExportFormat = 'json' | 'svg' | 'dxf' | 'pdf';
@@ -564,7 +554,7 @@ export async function exportDrawing(
format: ExportFormat, format: ExportFormat,
filename?: string, filename?: string,
options?: ExportOptions options?: ExportOptions
): Promise<void> { ): Promise<ExportResult> {
const ext = format; const ext = format;
const name = filename || `cad-export.${ext}`; const name = filename || `cad-export.${ext}`;
@@ -578,6 +568,9 @@ export async function exportDrawing(
case 'pdf': case 'pdf':
return exportPDF(yjsDoc, name, options); return exportPDF(yjsDoc, name, options);
default: default:
throw new Error(`Unsupported export format: ${format}`); return {
success: false,
error: `Unsupported export format: ${format}`,
};
} }
} }