import { describe, expect, it } from "vitest"; import { parseSvgSource } from "../../src/document/source-parser"; import { applyToPoint } from "../../src/domain/affine"; import { resolveTransformChain } from "../../src/domain/transform-chain"; function semantic(source: string) { const result = parseSvgSource(source, 1); expect(result.semantic).not.toBeNull(); return result.semantic!; } describe("ancestor transform chains", () => { it("composes root, ancestor and local transforms in SVG order", () => { const document = semantic( '', ); const child = [...document.nodes.values()].find( (node) => node.id === "child", )!; const chain = resolveTransformChain(document, child.key); expect(chain.entries).toHaveLength(3); expect(applyToPoint(chain.matrix, { x: 1, y: 1 })).toMatchObject({ x: -1, y: 5, }); const restored = applyToPoint( chain.inverse!, applyToPoint(chain.matrix, { x: 7, y: -4 }), ); expect(restored.x).toBeCloseTo(7); expect(restored.y).toBeCloseTo(-4); }); it("refuses deterministic coordinate editing through singular or CSS transforms", () => { const document = semantic( '', ); const path = [...document.nodes.values()].find((node) => node.id === "p")!; const chain = resolveTransformChain(document, path.key); expect(chain.inverse).toBeNull(); expect(chain.diagnostics).toContainEqual( expect.stringContaining("CSS transforms"), ); }); });