diff --git a/lib/dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-session.ts b/lib/dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-session.ts new file mode 100644 index 0000000..ac8c7ac --- /dev/null +++ b/lib/dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-session.ts @@ -0,0 +1,77 @@ +import type { DsnSession } from "../types" + +export const stringifyDsnSession = (session: DsnSession): string => { + const indent = " " + let result = "" + + // Start with session + result += `(session ${session.filename}\n` + + // Base design + result += `${indent}(base_design ${session.filename})\n` + + // Placement section + result += `${indent}(placement\n` + result += `${indent}${indent}(resolution ${session.placement.resolution.unit} ${session.placement.resolution.value})\n` + session.placement.components.forEach((component) => { + result += `${indent}${indent}(component ${component.name}\n` + result += `${indent}${indent}${indent}(place ${component.place.refdes} ${component.place.x} ${component.place.y} ${component.place.side} ${component.place.rotation})\n` + result += `${indent}${indent})\n` + }) + result += `${indent})\n` + + // Was_is section (if needed) + result += `${indent}(was_is\n${indent})\n` + + // Routes section + result += `${indent}(routes \n` + result += `${indent}${indent}(resolution ${session.routes.resolution.unit} ${session.routes.resolution.value})\n` + + // Parser subsection + result += `${indent}${indent}(parser\n` + result += `${indent}${indent}${indent}(host_cad ${JSON.stringify(session.routes.parser.host_cad)})\n` + result += `${indent}${indent}${indent}(host_version ${JSON.stringify(session.routes.parser.host_version)})\n` + result += `${indent}${indent})\n` + + // Library_out subsection + if (session.routes.library_out) { + result += `${indent}${indent}(library_out \n` + session.routes.library_out.padstacks.forEach((padstack) => { + result += `${indent}${indent}${indent}(padstack ${JSON.stringify(padstack.name)}\n` + padstack.shapes.forEach((shape) => { + if (shape.shapeType === "circle") { + result += `${indent}${indent}${indent}${indent}(shape\n` + result += `${indent}${indent}${indent}${indent}${indent}(circle ${shape.layer} ${shape.diameter} 0 0)\n` + result += `${indent}${indent}${indent}${indent})\n` + } + }) + result += `${indent}${indent}${indent}${indent}(attach ${padstack.attach})\n` + result += `${indent}${indent}${indent})\n` + }) + result += `${indent}${indent})\n` + } + + // Network_out subsection + result += `${indent}${indent}(network_out \n` + session.routes.network_out.nets.forEach((net) => { + result += `${indent}${indent}${indent}(net ${JSON.stringify(net.name)}\n` + net.wires.forEach((wire) => { + if (wire.path) { + result += `${indent}${indent}${indent}${indent}(wire\n` + result += `${indent}${indent}${indent}${indent}${indent}(path ${wire.path.layer} ${wire.path.width}\n` + result += `${indent}${indent}${indent}${indent}${indent}${indent}${wire.path.coordinates.join(" ")}\n` + result += `${indent}${indent}${indent}${indent}${indent})\n` + result += `${indent}${indent}${indent}${indent})\n` + } + }) + result += `${indent}${indent}${indent})\n` + }) + result += `${indent}${indent})\n` + + result += `${indent})\n` + + // Close session + result += `)\n` + + return result +} diff --git a/lib/index.ts b/lib/index.ts index 873ca1e..20a1504 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,6 +1,7 @@ export * from "./dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-json.ts" export * from "./dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-string.ts" export * from "./dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-json.ts" +export * from "./dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-session.ts" export * from "./dsn-pcb/dsn-json-to-circuit-json/convert-dsn-json-to-circuit-json.ts" export * from "./dsn-pcb/dsn-json-to-circuit-json/parse-dsn-to-circuit-json.ts" export * from "./dsn-pcb/dsn-json-to-circuit-json/parse-dsn-to-dsn-json.ts" diff --git a/tests/dsn-pcb/stringify-dsn-session.test.ts b/tests/dsn-pcb/stringify-dsn-session.test.ts new file mode 100644 index 0000000..28220e7 --- /dev/null +++ b/tests/dsn-pcb/stringify-dsn-session.test.ts @@ -0,0 +1,27 @@ +import { expect, test } from "bun:test" +import { parseDsnToDsnJson, stringifyDsnSession, type DsnSession } from "lib" +// @ts-ignore +import sessionFile from "../assets/freerouting-sessions/session1.ses" with { + type: "text", +} + +test("stringify session file", () => { + const sessionJson = parseDsnToDsnJson(sessionFile) as DsnSession + const stringified = stringifyDsnSession(sessionJson) + const reparsed = parseDsnToDsnJson(stringified) as DsnSession + + // Test that we can parse the generated string back to the same structure + expect(reparsed.filename).toBe(sessionJson.filename) + expect(reparsed.placement.components).toHaveLength( + sessionJson.placement.components.length, + ) + expect(reparsed.routes.network_out.nets).toHaveLength( + sessionJson.routes.network_out.nets.length, + ) + + // Test specific values + const originalNet = sessionJson.routes.network_out.nets[0] + const reparsedNet = reparsed.routes.network_out.nets[0] + expect(reparsedNet.name).toBe(originalNet.name) + expect(reparsedNet.wires).toHaveLength(originalNet.wires.length) +})