graphics-debug 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,23 +36,52 @@ https://github.com/user-attachments/assets/9f3f41e6-b0fe-416a-a551-ba5c5b920cad
36
36
  The `graphics` json object is very simple, here's the basic schema:
37
37
 
38
38
  ```typescript
39
+ interface Point {
40
+ x: number
41
+ y: number
42
+ color?: string
43
+ label?: string
44
+ layer?: string
45
+ step?: number
46
+ }
47
+
48
+ interface Line {
49
+ points: { x: number; y: number }[]
50
+ strokeWidth?: number
51
+ strokeColor?: string
52
+ strokeDash?: string
53
+ layer?: string
54
+ step?: number
55
+ label?: string
56
+ }
57
+
58
+ interface Rect {
59
+ center: { x: number; y: number }
60
+ width: number
61
+ height: number
62
+ fill?: string
63
+ stroke?: string
64
+ color?: string
65
+ layer?: string
66
+ step?: number
67
+ label?: string
68
+ }
69
+
70
+ interface Circle {
71
+ center: { x: number; y: number }
72
+ radius: number
73
+ fill?: string
74
+ stroke?: string
75
+ layer?: string
76
+ step?: number
77
+ label?: string
78
+ }
79
+
39
80
  interface GraphicsObject {
40
- points?: { x: number; y: number; color?: string; label?: string }[]
41
- lines?: { points: { x: number; y: number; stroke?: number }[] }[]
42
- rects?: Array<{
43
- center: { x: number; y: number }
44
- width: number
45
- height: number
46
- fill?: string
47
- stroke?: string
48
- }>
49
- circles?: Array<{
50
- center: { x: number; y: number }
51
- radius: number
52
- fill?: string
53
- stroke?: string
54
- }>
55
- grid?: { cellSize: number; label?: boolean }
81
+ points?: Point[]
82
+ lines?: Line[]
83
+ rects?: Rect[]
84
+ circles?: Circle[]
56
85
  coordinateSystem?: "cartesian" | "screen"
57
86
  title?: string
58
87
  }
@@ -131,6 +160,65 @@ const graphicsObjects = getGraphicsObjectsFromLogString(logString)
131
160
  // Array<GraphicsObject>
132
161
  ```
133
162
 
163
+ ### Generate SVG directly from a GraphicsObject
164
+
165
+ ```tsx
166
+ import { getSvgFromGraphicsObject } from "graphics-debug"
167
+
168
+ // Create your graphics object
169
+ const graphicsObject = {
170
+ points: [{ x: 0, y: 0, label: "Origin" }, { x: 100, y: 100, color: "red" }],
171
+ lines: [{ points: [{ x: 0, y: 0 }, { x: 100, y: 100 }], strokeColor: "blue" }],
172
+ title: "My Graph"
173
+ }
174
+
175
+ // Generate SVG string directly from the object
176
+ const svg = getSvgFromGraphicsObject(graphicsObject)
177
+ // Returns a formatted SVG string ready to be written to a file or embedded in HTML
178
+ ```
179
+
180
+ ### Testing GraphicsObjects with Bun's Test Framework
181
+
182
+ If you're using Bun for testing, you can use the `toMatchGraphicsSvg` matcher to compare graphics objects against saved snapshots.
183
+
184
+ First, install the required peer dependencies:
185
+
186
+ ```bash
187
+ bun add -d bun-match-svg looksSame
188
+ ```
189
+
190
+ Then use the matcher in your tests:
191
+
192
+ ```tsx
193
+ import { expect, test } from "bun:test"
194
+ import "graphics-debug/matcher"
195
+ import type { GraphicsObject } from "graphics-debug"
196
+
197
+ // Your test graphics object
198
+ const graphicsObject: GraphicsObject = {
199
+ points: [{ x: 0, y: 0, label: "Origin" }, { x: 100, y: 100, color: "red" }],
200
+ lines: [{ points: [{ x: 0, y: 0 }, { x: 100, y: 100 }], strokeColor: "blue" }],
201
+ title: "My Test Graphics"
202
+ }
203
+
204
+ test("should match the expected visualization", async () => {
205
+ // First run creates the snapshot
206
+ // Subsequent runs will compare against saved snapshot
207
+ await expect(graphicsObject).toMatchGraphicsSvg(import.meta.path)
208
+
209
+ // You can also provide a custom name for the snapshot:
210
+ await expect(graphicsObject).toMatchGraphicsSvg(import.meta.path, "custom-name")
211
+ })
212
+ ```
213
+
214
+ Snapshots are stored as SVG files in an `__snapshots__` directory next to your test file. To update snapshots, run your tests with the `-u` or `--update-snapshots` flag:
215
+
216
+ ```bash
217
+ bun test -u
218
+ ```
219
+
220
+ This is powered by the same technology as bun-match-svg but integrated specifically for GraphicsObject testing.
221
+
134
222
  ### Example Graphics JSON
135
223
 
136
224
  An example graphics JSON file is provided in the repository to help you get started quickly.
@@ -0,0 +1,5 @@
1
+ declare module "bun:test" {
2
+ interface Matchers<T = unknown> {
3
+ toMatchGraphicsSvg(testPath: string, svgName?: string): Promise<MatcherResult>;
4
+ }
5
+ }
@@ -0,0 +1,60 @@
1
+ import {
2
+ getSvgFromGraphicsObject
3
+ } from "../chunk-5FZF67ET.js";
4
+
5
+ // lib/matcher.ts
6
+ import { expect } from "bun:test";
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import looksSame from "looks-same";
10
+ async function toMatchGraphicsSvg(receivedMaybePromise, testPathOriginal, svgName) {
11
+ const received = await receivedMaybePromise;
12
+ const testPath = testPathOriginal.replace(/\.test\.tsx?$/, "");
13
+ const snapshotDir = path.join(path.dirname(testPath), "__snapshots__");
14
+ const snapshotName = svgName ? `${svgName}.snap.svg` : `${path.basename(testPath)}.snap.svg`;
15
+ const filePath = path.join(snapshotDir, snapshotName);
16
+ if (!fs.existsSync(snapshotDir)) {
17
+ fs.mkdirSync(snapshotDir, { recursive: true });
18
+ }
19
+ const receivedSvg = getSvgFromGraphicsObject(received);
20
+ const updateSnapshot = process.argv.includes("--update-snapshots") || process.argv.includes("-u") || Boolean(process.env["BUN_UPDATE_SNAPSHOTS"]);
21
+ if (!fs.existsSync(filePath) || updateSnapshot) {
22
+ console.log("Writing snapshot to", filePath);
23
+ fs.writeFileSync(filePath, receivedSvg);
24
+ return {
25
+ message: () => `Snapshot created at ${filePath}`,
26
+ pass: true
27
+ };
28
+ }
29
+ const existingSnapshot = fs.readFileSync(filePath, "utf-8");
30
+ const result = await looksSame(
31
+ Buffer.from(receivedSvg),
32
+ Buffer.from(existingSnapshot),
33
+ {
34
+ strict: false,
35
+ tolerance: 2
36
+ }
37
+ );
38
+ if (result.equal) {
39
+ return {
40
+ message: () => "Snapshot matches",
41
+ pass: true
42
+ };
43
+ }
44
+ const diffPath = filePath.replace(".snap.svg", ".diff.png");
45
+ await looksSame.createDiff({
46
+ reference: Buffer.from(existingSnapshot),
47
+ current: Buffer.from(receivedSvg),
48
+ diff: diffPath,
49
+ highlightColor: "#ff00ff"
50
+ });
51
+ return {
52
+ message: () => `Snapshot does not match. Diff saved at ${diffPath}`,
53
+ pass: false
54
+ };
55
+ }
56
+ expect.extend({
57
+ // biome-ignore lint/suspicious/noExplicitAny: bun's types don't expose matcher type
58
+ toMatchGraphicsSvg
59
+ });
60
+ //# sourceMappingURL=matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../lib/matcher.ts"],"sourcesContent":["import { expect, type MatcherResult } from \"bun:test\"\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\nimport looksSame from \"looks-same\"\nimport { GraphicsObject } from \"./types\"\nimport { getSvgFromGraphicsObject } from \"./getSvgFromGraphicsObject\"\n\n/**\n * Custom matcher for Bun tests to compare GraphicsObjects as SVGs\n * \n * @param this Matcher context\n * @param receivedMaybePromise GraphicsObject or Promise<GraphicsObject> to test\n * @param testPathOriginal Path to the test file\n * @param svgName Optional name for the snapshot\n * @returns Matcher result\n */\nasync function toMatchGraphicsSvg(\n // biome-ignore lint/suspicious/noExplicitAny: bun doesn't expose matcher type\n this: any,\n receivedMaybePromise: GraphicsObject | Promise<GraphicsObject>,\n testPathOriginal: string,\n svgName?: string,\n): Promise<MatcherResult> {\n const received = await receivedMaybePromise\n const testPath = testPathOriginal.replace(/\\.test\\.tsx?$/, \"\")\n const snapshotDir = path.join(path.dirname(testPath), \"__snapshots__\")\n const snapshotName = svgName\n ? `${svgName}.snap.svg`\n : `${path.basename(testPath)}.snap.svg`\n const filePath = path.join(snapshotDir, snapshotName)\n\n if (!fs.existsSync(snapshotDir)) {\n fs.mkdirSync(snapshotDir, { recursive: true })\n }\n\n // Convert GraphicsObject to SVG\n const receivedSvg = getSvgFromGraphicsObject(received)\n\n const updateSnapshot =\n process.argv.includes(\"--update-snapshots\") ||\n process.argv.includes(\"-u\") ||\n Boolean(process.env[\"BUN_UPDATE_SNAPSHOTS\"])\n\n if (!fs.existsSync(filePath) || updateSnapshot) {\n console.log(\"Writing snapshot to\", filePath)\n fs.writeFileSync(filePath, receivedSvg)\n return {\n message: () => `Snapshot created at ${filePath}`,\n pass: true,\n }\n }\n\n const existingSnapshot = fs.readFileSync(filePath, \"utf-8\")\n\n const result: any = await looksSame(\n Buffer.from(receivedSvg),\n Buffer.from(existingSnapshot),\n {\n strict: false,\n tolerance: 2,\n },\n )\n\n if (result.equal) {\n return {\n message: () => \"Snapshot matches\",\n pass: true,\n }\n }\n\n const diffPath = filePath.replace(\".snap.svg\", \".diff.png\")\n await looksSame.createDiff({\n reference: Buffer.from(existingSnapshot),\n current: Buffer.from(receivedSvg),\n diff: diffPath,\n highlightColor: \"#ff00ff\",\n })\n\n return {\n message: () => `Snapshot does not match. Diff saved at ${diffPath}`,\n pass: false,\n }\n}\n\n// Add the custom matcher to the expect object\nexpect.extend({\n // biome-ignore lint/suspicious/noExplicitAny: bun's types don't expose matcher type\n toMatchGraphicsSvg: toMatchGraphicsSvg as any,\n})\n\n// Extend the TypeScript interface for the matcher\ndeclare module \"bun:test\" {\n interface Matchers<T = unknown> {\n toMatchGraphicsSvg(\n testPath: string,\n svgName?: string,\n ): Promise<MatcherResult>\n }\n}"],"mappings":";;;;;AAAA,SAAS,cAAkC;AAC3C,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,OAAO,eAAe;AAatB,eAAe,mBAGb,sBACA,kBACA,SACwB;AACxB,QAAM,WAAW,MAAM;AACvB,QAAM,WAAW,iBAAiB,QAAQ,iBAAiB,EAAE;AAC7D,QAAM,cAAmB,UAAU,aAAQ,QAAQ,GAAG,eAAe;AACrE,QAAM,eAAe,UACjB,GAAG,OAAO,cACV,GAAQ,cAAS,QAAQ,CAAC;AAC9B,QAAM,WAAgB,UAAK,aAAa,YAAY;AAEpD,MAAI,CAAI,cAAW,WAAW,GAAG;AAC/B,IAAG,aAAU,aAAa,EAAE,WAAW,KAAK,CAAC;AAAA,EAC/C;AAGA,QAAM,cAAc,yBAAyB,QAAQ;AAErD,QAAM,iBACJ,QAAQ,KAAK,SAAS,oBAAoB,KAC1C,QAAQ,KAAK,SAAS,IAAI,KAC1B,QAAQ,QAAQ,IAAI,sBAAsB,CAAC;AAE7C,MAAI,CAAI,cAAW,QAAQ,KAAK,gBAAgB;AAC9C,YAAQ,IAAI,uBAAuB,QAAQ;AAC3C,IAAG,iBAAc,UAAU,WAAW;AACtC,WAAO;AAAA,MACL,SAAS,MAAM,uBAAuB,QAAQ;AAAA,MAC9C,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,mBAAsB,gBAAa,UAAU,OAAO;AAE1D,QAAM,SAAc,MAAM;AAAA,IACxB,OAAO,KAAK,WAAW;AAAA,IACvB,OAAO,KAAK,gBAAgB;AAAA,IAC5B;AAAA,MACE,QAAQ;AAAA,MACR,WAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI,OAAO,OAAO;AAChB,WAAO;AAAA,MACL,SAAS,MAAM;AAAA,MACf,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,WAAW,SAAS,QAAQ,aAAa,WAAW;AAC1D,QAAM,UAAU,WAAW;AAAA,IACzB,WAAW,OAAO,KAAK,gBAAgB;AAAA,IACvC,SAAS,OAAO,KAAK,WAAW;AAAA,IAChC,MAAM;AAAA,IACN,gBAAgB;AAAA,EAClB,CAAC;AAED,SAAO;AAAA,IACL,SAAS,MAAM,0CAA0C,QAAQ;AAAA,IACjE,MAAM;AAAA,EACR;AACF;AAGA,OAAO,OAAO;AAAA;AAAA,EAEZ;AACF,CAAC;","names":[]}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "graphics-debug",
3
3
  "main": "dist/lib/index.js",
4
4
  "type": "module",
5
- "version": "0.0.21",
5
+ "version": "0.0.23",
6
6
  "files": [
7
7
  "dist"
8
8
  ],
@@ -14,6 +14,10 @@
14
14
  "./react": {
15
15
  "types": "./dist/lib/react.d.ts",
16
16
  "import": "./dist/lib/react.js"
17
+ },
18
+ "./matcher": {
19
+ "types": "./dist/lib/matcher.d.ts",
20
+ "import": "./dist/lib/matcher.js"
17
21
  }
18
22
  },
19
23
  "bin": {
@@ -38,7 +42,6 @@
38
42
  "@types/react": "^18.3.12",
39
43
  "@types/react-dom": "^18.3.1",
40
44
  "@vitejs/plugin-react": "^4.3.3",
41
- "bun-match-svg": "^0.0.8",
42
45
  "commander": "^12.1.0",
43
46
  "debug": "^4.3.7",
44
47
  "jsdom": "^25.0.1",
@@ -51,7 +54,9 @@
51
54
  "vite-tsconfig-paths": "^5.1.4"
52
55
  },
53
56
  "peerDependencies": {
54
- "typescript": "^5.0.0"
57
+ "typescript": "^5.0.0",
58
+ "bun-match-svg": "^0.0.9",
59
+ "looks-same": "^9.0.1"
55
60
  },
56
61
  "dependencies": {
57
62
  "@types/react-router-dom": "^5.3.3",