From b70b948097fe3cc9b53a7e4296309ef0e40b36ba Mon Sep 17 00:00:00 2001 From: Yevhenii Date: Fri, 2 Oct 2026 18:08:02 +0300 Subject: [PATCH] feat: add clone to copy path data before transforming it Transformers such as toAbs, normalizeST and qtToC rewrite each command in place, so transforming a copy made from the commands array alone also changes the original. clone() copies every command with the CLONE transformer, the copy CALCULATE_BOUNDS already takes for the same reason. --- src/SVGPathData.ts | 8 ++++++++ src/tests/clone.test.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/tests/clone.test.ts diff --git a/src/SVGPathData.ts b/src/SVGPathData.ts index 0bf8727..8b56d87 100644 --- a/src/SVGPathData.ts +++ b/src/SVGPathData.ts @@ -19,6 +19,14 @@ export class SVGPathData extends TransformableSVG { return SVGPathData.encode(this.commands); } + /** + * Copies every command, so transforming the copy leaves this path data + * unchanged + */ + clone() { + return new SVGPathData(this.commands.map(SVGPathDataTransformer.CLONE())); + } + getBounds() { const boundsTransform = SVGPathDataTransformer.CALCULATE_BOUNDS(); diff --git a/src/tests/clone.test.ts b/src/tests/clone.test.ts new file mode 100644 index 0000000..1805e85 --- /dev/null +++ b/src/tests/clone.test.ts @@ -0,0 +1,30 @@ +import { describe, test, expect } from '@jest/globals'; +import { SVGPathData } from '../index.js'; + +const PATH = 'm10 10q10 0 10 10t10 10s10 10 20 0a5 5 0 0 1 10 0z'; + +describe('Cloning path data', () => { + test('encodes the same path', () => { + const pathData = new SVGPathData(PATH); + + expect(pathData.clone().encode()).toEqual(pathData.encode()); + }); + + test('transforming the clone leaves the original unchanged', () => { + const pathData = new SVGPathData(PATH); + const before = pathData.encode(); + + pathData.clone().toAbs().normalizeST().qtToC().aToC().translate(5, 5); + + expect(pathData.encode()).toEqual(before); + }); + + test('transforming the original leaves the clone unchanged', () => { + const pathData = new SVGPathData(PATH); + const clone = pathData.clone(); + + pathData.toAbs().normalizeST().qtToC().aToC().translate(5, 5); + + expect(clone.encode()).toEqual(new SVGPathData(PATH).encode()); + }); +});