graphics-debug 0.0.1 → 0.0.2

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
@@ -6,10 +6,26 @@ Just pipe in output with graphics JSON objects into `graphics-debug` (or `gd`) t
6
6
  with all your graphics drawn-in.
7
7
 
8
8
  ```bash
9
- echo '{ graphics: { points: [{x: 0, y: 0, label: "hello world" }], title: "test graphic" } }' | graphics-debug
9
+ echo ':graphics { points: [{x: 0, y: 0, label: "hello world" }], title: "test graphic" } }' | graphics-debug
10
10
  # wrote to "test-graphic-1.debug.svg"
11
11
  ```
12
12
 
13
+ ```bash
14
+ # Run a program that has debug logs and pipe the output to graphics-debug
15
+ bun test path/to/test.ts |& graphics-debug --html
16
+ # wrote to "graphics.debug.html"
17
+
18
+ # another syntax for the same thing
19
+ bun test path/to/test.ts 2>&1 | graphics-debug --html
20
+ ```
21
+
22
+ Don't want to write files everywhere? Use the `--url` flag to get a url to view
23
+ the graphics in a browser.
24
+
25
+ ```bash
26
+ node myscript.js |& graphics-debug --url
27
+ ```
28
+
13
29
  Don't have access to the cli? Paste into the online version: `TBA`
14
30
 
15
31
  ## Format
@@ -18,41 +34,37 @@ The `graphics` json object is very simple, here's the basic schema:
18
34
 
19
35
  ```typescript
20
36
  interface GraphicsObject {
21
- graphics: {
22
- points?: { x: number; y: number; color?: string; label?: string }[]
23
- lines?: { points: { x: number; y: number; stroke?: number }[] }[]
24
- rects?: Array<{
25
- center: { x: number; y: number }
26
- width: number
27
- height: number
28
- fill?: string
29
- stroke?: string
30
- }>
31
- circles?: Array<{
32
- center: { x: number; y: number }
33
- radius: number
34
- fill?: string
35
- stroke?: string
36
- }>
37
- grid?: { cellSize: number; label?: boolean }
38
- coordinateSystem?: "cartesian" | "screen"
39
- title?: string
40
- }
37
+ points?: { x: number; y: number; color?: string; label?: string }[]
38
+ lines?: { points: { x: number; y: number; stroke?: number }[] }[]
39
+ rects?: Array<{
40
+ center: { x: number; y: number }
41
+ width: number
42
+ height: number
43
+ fill?: string
44
+ stroke?: string
45
+ }>
46
+ circles?: Array<{
47
+ center: { x: number; y: number }
48
+ radius: number
49
+ fill?: string
50
+ stroke?: string
51
+ }>
52
+ grid?: { cellSize: number; label?: boolean }
53
+ coordinateSystem?: "cartesian" | "screen"
54
+ title?: string
41
55
  }
42
56
  ```
43
57
 
44
- When emiting a graphics object, keep the `{ graphics }` object on a single line,
45
- `graphics-debug` won't parse multi-line `{ graphics }` objects. You can have
46
- other content on same line as the `{ graphics }` object. This means you can't
47
- use `console.log` to emit graphics objects, use the [debug](https://www.npmjs.com/package/debug)
48
- library or `console.log(JSON.stringify(...))` instead.
49
-
50
58
  ## Library Usage
51
59
 
52
60
  ### Writing `graphics-debug` compatible logs
53
61
 
54
62
  The best way to write `graphics-debug` compatible logs is to use the [`debug` library](https://www.npmjs.com/package/debug).
55
63
 
64
+ You should **always JSON.stringify graphics objects**, otherwise the graphics
65
+ will take up more lines and will not have the correct depth (there will be
66
+ missing information)
67
+
56
68
  ```tsx
57
69
  import Debug from "debug"
58
70
 
@@ -61,22 +73,22 @@ const debugGraphics = Debug("mypackage:graphics")
61
73
  const A = { x: 0, y: 0, label: "A" }
62
74
  const B = { x: 1, y: 1, label: "B" }
63
75
 
64
- debugGraphics({
65
- graphics: {
76
+ debugGraphics(
77
+ JSON.stringify({
66
78
  points: [A, B],
67
79
  title: "initial points for my algorithm",
68
- },
69
- })
80
+ })
81
+ )
70
82
 
71
83
  // ... do some algorithm stuff e.g....
72
84
  const C = { x: (A.x + B.x) / 2, y: (A.y + B.y) / 2, label: "C" }
73
85
 
74
- debugGraphics({
75
- graphics: {
86
+ debugGraphics(
87
+ JSON.stringify({
76
88
  points: [A, B, C],
77
89
  title: "final points for my algorithm",
78
- },
79
- })
90
+ })
91
+ )
80
92
  ```
81
93
 
82
94
  To see the output, you'll need to run `DEBUG=mypackage:graphics` in your terminal
@@ -96,7 +108,7 @@ import {
96
108
 
97
109
  const logString = `
98
110
  hello world! This is some other content that will be ignored
99
- here's some graphics: { graphics: { points: [{x: 0, y: 0, label: "hello world" }], title: "test graphic" } }
111
+ here's some :graphics { points: [{x: 0, y: 0, label: "hello world" }], title: "test graphic" }
100
112
  `
101
113
 
102
114
  const svg = getSvgFromLogString(logString)
@@ -115,3 +127,7 @@ import { getGraphicsObjectsFromLogString } from "graphics-debug"
115
127
  const graphicsObjects = getGraphicsObjectsFromLogString(logString)
116
128
  // Array<GraphicsObject>
117
129
  ```
130
+
131
+ ```
132
+
133
+ ```
@@ -0,0 +1,267 @@
1
+ // lib/getSvgFromGraphicsObject.ts
2
+ import {
3
+ compose,
4
+ translate,
5
+ scale,
6
+ applyToPoint
7
+ } from "transformation-matrix";
8
+ import { stringify } from "svgson";
9
+ import pretty from "pretty";
10
+ var DEFAULT_SVG_SIZE = 640;
11
+ var PADDING = 40;
12
+ function getBounds(graphics) {
13
+ const points = [
14
+ ...graphics.points || [],
15
+ ...(graphics.lines || []).flatMap((line) => line.points),
16
+ ...(graphics.rects || []).flatMap((rect) => {
17
+ const halfWidth = rect.width / 2;
18
+ const halfHeight = rect.height / 2;
19
+ return [
20
+ { x: rect.center.x - halfWidth, y: rect.center.y - halfHeight },
21
+ { x: rect.center.x + halfWidth, y: rect.center.y - halfHeight },
22
+ { x: rect.center.x - halfWidth, y: rect.center.y + halfHeight },
23
+ { x: rect.center.x + halfWidth, y: rect.center.y + halfHeight }
24
+ ];
25
+ }),
26
+ ...(graphics.circles || []).flatMap((circle) => [
27
+ { x: circle.center.x - circle.radius, y: circle.center.y },
28
+ // left
29
+ { x: circle.center.x + circle.radius, y: circle.center.y },
30
+ // right
31
+ { x: circle.center.x, y: circle.center.y - circle.radius },
32
+ // top
33
+ { x: circle.center.x, y: circle.center.y + circle.radius }
34
+ // bottom
35
+ ])
36
+ ];
37
+ if (points.length === 0) {
38
+ return { minX: -1, maxX: 1, minY: -1, maxY: 1 };
39
+ }
40
+ return points.reduce(
41
+ (bounds, point) => ({
42
+ minX: Math.min(bounds.minX, point.x),
43
+ maxX: Math.max(bounds.maxX, point.x),
44
+ minY: Math.min(bounds.minY, point.y),
45
+ maxY: Math.max(bounds.maxY, point.y)
46
+ }),
47
+ { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity }
48
+ );
49
+ }
50
+ function getProjectionMatrix(bounds, coordinateSystem) {
51
+ const width = bounds.maxX - bounds.minX;
52
+ const height = bounds.maxY - bounds.minY;
53
+ const scale_factor = Math.min(
54
+ (DEFAULT_SVG_SIZE - 2 * PADDING) / width,
55
+ (DEFAULT_SVG_SIZE - 2 * PADDING) / height
56
+ );
57
+ return compose(
58
+ translate(DEFAULT_SVG_SIZE / 2, DEFAULT_SVG_SIZE / 2),
59
+ scale(
60
+ scale_factor,
61
+ coordinateSystem === "screen" ? -scale_factor : scale_factor
62
+ ),
63
+ translate(-(bounds.minX + width / 2), -(bounds.minY + height / 2))
64
+ );
65
+ }
66
+ function projectPoint(point, matrix) {
67
+ const projected = applyToPoint(matrix, { x: point.x, y: point.y });
68
+ return { ...point, ...projected };
69
+ }
70
+ function getSvgFromGraphicsObject(graphics) {
71
+ const bounds = getBounds(graphics);
72
+ const matrix = compose(getProjectionMatrix(bounds, graphics.coordinateSystem));
73
+ const svgObject = {
74
+ name: "svg",
75
+ type: "element",
76
+ attributes: {
77
+ width: DEFAULT_SVG_SIZE.toString(),
78
+ height: DEFAULT_SVG_SIZE.toString(),
79
+ viewBox: `0 0 ${DEFAULT_SVG_SIZE} ${DEFAULT_SVG_SIZE}`,
80
+ xmlns: "http://www.w3.org/2000/svg"
81
+ },
82
+ children: [
83
+ // Points
84
+ ...(graphics.points || []).map((point) => {
85
+ const projected = projectPoint(point, matrix);
86
+ return {
87
+ name: "g",
88
+ type: "element",
89
+ children: [
90
+ {
91
+ name: "circle",
92
+ type: "element",
93
+ attributes: {
94
+ cx: projected.x.toString(),
95
+ cy: projected.y.toString(),
96
+ r: "3",
97
+ fill: point.color || "black"
98
+ }
99
+ },
100
+ ...point.label ? [
101
+ {
102
+ name: "text",
103
+ type: "element",
104
+ attributes: {
105
+ x: (projected.x + 5).toString(),
106
+ y: (projected.y - 5).toString(),
107
+ "font-family": "sans-serif",
108
+ "font-size": "12"
109
+ },
110
+ children: [{ type: "text", value: point.label }]
111
+ }
112
+ ] : []
113
+ ]
114
+ };
115
+ }),
116
+ // Lines
117
+ ...(graphics.lines || []).map((line) => ({
118
+ name: "polyline",
119
+ type: "element",
120
+ attributes: {
121
+ points: line.points.map((p) => projectPoint(p, matrix)).map((p) => `${p.x},${p.y}`).join(" "),
122
+ fill: "none",
123
+ stroke: "black",
124
+ "stroke-width": (line.points[0].stroke || 1).toString()
125
+ }
126
+ })),
127
+ // Rectangles
128
+ ...(graphics.rects || []).map((rect) => {
129
+ const projected = projectPoint(rect.center, matrix);
130
+ const scaledWidth = rect.width * matrix.a;
131
+ const scaledHeight = rect.height * matrix.d;
132
+ return {
133
+ name: "rect",
134
+ type: "element",
135
+ attributes: {
136
+ x: (projected.x - scaledWidth / 2).toString(),
137
+ y: (projected.y - scaledHeight / 2).toString(),
138
+ width: scaledWidth.toString(),
139
+ height: Math.abs(scaledHeight).toString(),
140
+ fill: rect.fill || "none",
141
+ stroke: rect.stroke || "black"
142
+ }
143
+ };
144
+ }),
145
+ // Circles
146
+ ...(graphics.circles || []).map((circle) => {
147
+ const projected = projectPoint(circle.center, matrix);
148
+ const scaledRadius = circle.radius * Math.abs(matrix.a);
149
+ return {
150
+ name: "circle",
151
+ type: "element",
152
+ attributes: {
153
+ cx: projected.x.toString(),
154
+ cy: projected.y.toString(),
155
+ r: scaledRadius.toString(),
156
+ fill: circle.fill || "none",
157
+ stroke: circle.stroke || "black"
158
+ }
159
+ };
160
+ }),
161
+ // Crosshair lines and coordinates (initially hidden)
162
+ {
163
+ name: "g",
164
+ type: "element",
165
+ attributes: {
166
+ id: "crosshair",
167
+ style: "display: none"
168
+ },
169
+ children: [
170
+ {
171
+ name: "line",
172
+ type: "element",
173
+ attributes: {
174
+ id: "crosshair-h",
175
+ y1: "0",
176
+ y2: DEFAULT_SVG_SIZE.toString(),
177
+ stroke: "#666",
178
+ "stroke-width": "0.5"
179
+ }
180
+ },
181
+ {
182
+ name: "line",
183
+ type: "element",
184
+ attributes: {
185
+ id: "crosshair-v",
186
+ x1: "0",
187
+ x2: DEFAULT_SVG_SIZE.toString(),
188
+ stroke: "#666",
189
+ "stroke-width": "0.5"
190
+ }
191
+ },
192
+ {
193
+ name: "text",
194
+ type: "element",
195
+ attributes: {
196
+ id: "coordinates",
197
+ "font-family": "monospace",
198
+ "font-size": "12",
199
+ fill: "#666"
200
+ },
201
+ children: [{ type: "text", value: "" }]
202
+ }
203
+ ]
204
+ },
205
+ // Mouse tracking script
206
+ {
207
+ name: "script",
208
+ type: "element",
209
+ children: [
210
+ {
211
+ type: "text",
212
+ value: `
213
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
214
+ const svg = e.currentTarget;
215
+ const rect = svg.getBoundingClientRect();
216
+ const x = e.clientX - rect.left;
217
+ const y = e.clientY - rect.top;
218
+ const crosshair = svg.getElementById('crosshair');
219
+ const h = svg.getElementById('crosshair-h');
220
+ const v = svg.getElementById('crosshair-v');
221
+ const coords = svg.getElementById('coordinates');
222
+
223
+ crosshair.style.display = 'block';
224
+ h.setAttribute('x1', '0');
225
+ h.setAttribute('x2', '${DEFAULT_SVG_SIZE}');
226
+ h.setAttribute('y1', y);
227
+ h.setAttribute('y2', y);
228
+ v.setAttribute('x1', x);
229
+ v.setAttribute('x2', x);
230
+ v.setAttribute('y1', '0');
231
+ v.setAttribute('y2', '${DEFAULT_SVG_SIZE}');
232
+
233
+ // Calculate real coordinates using inverse transformation
234
+ const matrix = ${JSON.stringify(matrix)};
235
+ // Manually invert and apply the affine transform
236
+ // Since we only use translate and scale, we can directly compute:
237
+ // x' = (x - tx) / sx
238
+ // y' = (y - ty) / sy
239
+ const sx = matrix.a;
240
+ const sy = matrix.d;
241
+ const tx = matrix.e;
242
+ const ty = matrix.f;
243
+ const realPoint = {
244
+ x: (x - tx) / sx,
245
+ y: -(y - ty) / sy // Flip y back since we used negative scale
246
+ }
247
+
248
+ coords.textContent = \`(\${realPoint.x.toFixed(2)}, \${realPoint.y.toFixed(2)})\`;
249
+ coords.setAttribute('x', (x + 5).toString());
250
+ coords.setAttribute('y', (y - 5).toString());
251
+ });
252
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
253
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
254
+ });
255
+ `
256
+ }
257
+ ]
258
+ }
259
+ ]
260
+ };
261
+ return pretty(stringify(svgObject));
262
+ }
263
+
264
+ export {
265
+ getSvgFromGraphicsObject
266
+ };
267
+ //# sourceMappingURL=chunk-4FN266Q5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/getSvgFromGraphicsObject.ts"],"sourcesContent":["import {\n transform,\n compose,\n translate,\n scale,\n applyToPoint,\n identity,\n type Matrix,\n} from \"transformation-matrix\"\nimport type { GraphicsObject, Point } from \"./types\"\nimport { stringify } from \"svgson\"\nimport pretty from \"pretty\"\n\nconst DEFAULT_SVG_SIZE = 640\nconst PADDING = 40\n\ninterface Bounds {\n minX: number\n maxX: number\n minY: number\n maxY: number\n}\n\nfunction getBounds(graphics: GraphicsObject): Bounds {\n const points: Point[] = [\n ...(graphics.points || []),\n ...(graphics.lines || []).flatMap((line) => line.points),\n ...(graphics.rects || []).flatMap((rect) => {\n const halfWidth = rect.width / 2\n const halfHeight = rect.height / 2\n return [\n { x: rect.center.x - halfWidth, y: rect.center.y - halfHeight },\n { x: rect.center.x + halfWidth, y: rect.center.y - halfHeight },\n { x: rect.center.x - halfWidth, y: rect.center.y + halfHeight },\n { x: rect.center.x + halfWidth, y: rect.center.y + halfHeight },\n ]\n }),\n ...(graphics.circles || []).flatMap((circle) => [\n { x: circle.center.x - circle.radius, y: circle.center.y }, // left\n { x: circle.center.x + circle.radius, y: circle.center.y }, // right\n { x: circle.center.x, y: circle.center.y - circle.radius }, // top\n { x: circle.center.x, y: circle.center.y + circle.radius }, // bottom\n ]),\n ]\n\n if (points.length === 0) {\n return { minX: -1, maxX: 1, minY: -1, maxY: 1 }\n }\n\n return points.reduce(\n (bounds, point) => ({\n minX: Math.min(bounds.minX, point.x),\n maxX: Math.max(bounds.maxX, point.x),\n minY: Math.min(bounds.minY, point.y),\n maxY: Math.max(bounds.maxY, point.y),\n }),\n { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity },\n )\n}\n\nfunction getProjectionMatrix(\n bounds: Bounds,\n coordinateSystem: GraphicsObject[\"coordinateSystem\"],\n) {\n const width = bounds.maxX - bounds.minX\n const height = bounds.maxY - bounds.minY\n\n const scale_factor = Math.min(\n (DEFAULT_SVG_SIZE - 2 * PADDING) / width,\n (DEFAULT_SVG_SIZE - 2 * PADDING) / height,\n )\n\n return compose(\n translate(DEFAULT_SVG_SIZE / 2, DEFAULT_SVG_SIZE / 2),\n scale(\n scale_factor,\n coordinateSystem === \"screen\" ? -scale_factor : scale_factor,\n ),\n translate(-(bounds.minX + width / 2), -(bounds.minY + height / 2)),\n )\n}\n\nfunction projectPoint(point: Point, matrix: Matrix) {\n const projected = applyToPoint(matrix, { x: point.x, y: point.y })\n return { ...point, ...projected }\n}\n\nexport function getSvgFromGraphicsObject(graphics: GraphicsObject): string {\n const bounds = getBounds(graphics)\n const matrix = compose(getProjectionMatrix(bounds, graphics.coordinateSystem))\n\n const svgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n width: DEFAULT_SVG_SIZE.toString(),\n height: DEFAULT_SVG_SIZE.toString(),\n viewBox: `0 0 ${DEFAULT_SVG_SIZE} ${DEFAULT_SVG_SIZE}`,\n xmlns: \"http://www.w3.org/2000/svg\",\n },\n children: [\n // Points\n ...(graphics.points || []).map((point) => {\n const projected = projectPoint(point, matrix)\n return {\n name: \"g\",\n type: \"element\",\n children: [\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n cx: projected.x.toString(),\n cy: projected.y.toString(),\n r: \"3\",\n fill: point.color || \"black\",\n },\n },\n ...(point.label\n ? [\n {\n name: \"text\",\n type: \"element\",\n attributes: {\n x: (projected.x + 5).toString(),\n y: (projected.y - 5).toString(),\n \"font-family\": \"sans-serif\",\n \"font-size\": \"12\",\n },\n children: [{ type: \"text\", value: point.label }],\n },\n ]\n : []),\n ],\n }\n }),\n // Lines\n ...(graphics.lines || []).map((line) => ({\n name: \"polyline\",\n type: \"element\",\n attributes: {\n points: line.points\n .map((p) => projectPoint(p, matrix))\n .map((p) => `${p.x},${p.y}`)\n .join(\" \"),\n fill: \"none\",\n stroke: \"black\",\n \"stroke-width\": (line.points[0].stroke || 1).toString(),\n },\n })),\n // Rectangles\n ...(graphics.rects || []).map((rect) => {\n const projected = projectPoint(rect.center, matrix)\n const scaledWidth = rect.width * matrix.a\n const scaledHeight = rect.height * matrix.d\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n x: (projected.x - scaledWidth / 2).toString(),\n y: (projected.y - scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: Math.abs(scaledHeight).toString(),\n fill: rect.fill || \"none\",\n stroke: rect.stroke || \"black\",\n },\n }\n }),\n // Circles\n ...(graphics.circles || []).map((circle) => {\n const projected = projectPoint(circle.center, matrix)\n const scaledRadius = circle.radius * Math.abs(matrix.a)\n return {\n name: \"circle\",\n type: \"element\",\n attributes: {\n cx: projected.x.toString(),\n cy: projected.y.toString(),\n r: scaledRadius.toString(),\n fill: circle.fill || \"none\",\n stroke: circle.stroke || \"black\",\n },\n }\n }),\n // Crosshair lines and coordinates (initially hidden)\n {\n name: \"g\",\n type: \"element\",\n attributes: {\n id: \"crosshair\",\n style: \"display: none\",\n },\n children: [\n {\n name: \"line\",\n type: \"element\",\n attributes: {\n id: \"crosshair-h\",\n y1: \"0\",\n y2: DEFAULT_SVG_SIZE.toString(),\n stroke: \"#666\",\n \"stroke-width\": \"0.5\",\n },\n },\n {\n name: \"line\",\n type: \"element\",\n attributes: {\n id: \"crosshair-v\",\n x1: \"0\",\n x2: DEFAULT_SVG_SIZE.toString(),\n stroke: \"#666\",\n \"stroke-width\": \"0.5\",\n },\n },\n {\n name: \"text\",\n type: \"element\",\n attributes: {\n id: \"coordinates\",\n \"font-family\": \"monospace\",\n \"font-size\": \"12\",\n fill: \"#666\",\n },\n children: [{ type: \"text\", value: \"\" }],\n },\n ],\n },\n // Mouse tracking script\n {\n name: \"script\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n document.currentScript.parentElement.addEventListener('mousemove', (e) => {\n const svg = e.currentTarget;\n const rect = svg.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n const crosshair = svg.getElementById('crosshair');\n const h = svg.getElementById('crosshair-h');\n const v = svg.getElementById('crosshair-v');\n const coords = svg.getElementById('coordinates');\n \n crosshair.style.display = 'block';\n h.setAttribute('x1', '0');\n h.setAttribute('x2', '${DEFAULT_SVG_SIZE}');\n h.setAttribute('y1', y);\n h.setAttribute('y2', y);\n v.setAttribute('x1', x);\n v.setAttribute('x2', x);\n v.setAttribute('y1', '0');\n v.setAttribute('y2', '${DEFAULT_SVG_SIZE}');\n\n // Calculate real coordinates using inverse transformation\n const matrix = ${JSON.stringify(matrix)};\n // Manually invert and apply the affine transform\n // Since we only use translate and scale, we can directly compute:\n // x' = (x - tx) / sx\n // y' = (y - ty) / sy\n const sx = matrix.a;\n const sy = matrix.d;\n const tx = matrix.e; \n const ty = matrix.f;\n const realPoint = {\n x: (x - tx) / sx,\n y: -(y - ty) / sy // Flip y back since we used negative scale\n }\n \n coords.textContent = \\`(\\${realPoint.x.toFixed(2)}, \\${realPoint.y.toFixed(2)})\\`;\n coords.setAttribute('x', (x + 5).toString());\n coords.setAttribute('y', (y - 5).toString());\n });\n document.currentScript.parentElement.addEventListener('mouseleave', () => {\n document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';\n });\n `,\n },\n ],\n },\n ],\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n return pretty(stringify(svgObject as any))\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,268 @@
1
+ // lib/getSvgFromGraphicsObject.ts
2
+ import {
3
+ compose,
4
+ translate,
5
+ scale,
6
+ applyToPoint
7
+ } from "transformation-matrix";
8
+ import { stringify } from "svgson";
9
+ import pretty from "pretty";
10
+ var DEFAULT_SVG_SIZE = 640;
11
+ var PADDING = 40;
12
+ function getBounds(graphics) {
13
+ const points = [
14
+ ...graphics.points || [],
15
+ ...(graphics.lines || []).flatMap((line) => line.points),
16
+ ...(graphics.rects || []).flatMap((rect) => {
17
+ const halfWidth = rect.width / 2;
18
+ const halfHeight = rect.height / 2;
19
+ return [
20
+ { x: rect.centerX - halfWidth, y: rect.centerY - halfHeight },
21
+ { x: rect.centerX + halfWidth, y: rect.centerY - halfHeight },
22
+ { x: rect.centerX - halfWidth, y: rect.centerY + halfHeight },
23
+ { x: rect.centerX + halfWidth, y: rect.centerY + halfHeight }
24
+ ];
25
+ }),
26
+ ...(graphics.circles || []).flatMap((circle) => [
27
+ { x: circle.center.x - circle.radius, y: circle.center.y },
28
+ // left
29
+ { x: circle.center.x + circle.radius, y: circle.center.y },
30
+ // right
31
+ { x: circle.center.x, y: circle.center.y - circle.radius },
32
+ // top
33
+ { x: circle.center.x, y: circle.center.y + circle.radius }
34
+ // bottom
35
+ ])
36
+ ];
37
+ if (points.length === 0) {
38
+ return { minX: -1, maxX: 1, minY: -1, maxY: 1 };
39
+ }
40
+ return points.reduce(
41
+ (bounds, point) => ({
42
+ minX: Math.min(bounds.minX, point.x),
43
+ maxX: Math.max(bounds.maxX, point.x),
44
+ minY: Math.min(bounds.minY, point.y),
45
+ maxY: Math.max(bounds.maxY, point.y)
46
+ }),
47
+ { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity }
48
+ );
49
+ }
50
+ function getProjectionMatrix(bounds, coordinateSystem) {
51
+ const width = bounds.maxX - bounds.minX;
52
+ const height = bounds.maxY - bounds.minY;
53
+ const scale_factor = Math.min(
54
+ (DEFAULT_SVG_SIZE - 2 * PADDING) / width,
55
+ (DEFAULT_SVG_SIZE - 2 * PADDING) / height
56
+ );
57
+ return compose(
58
+ translate(DEFAULT_SVG_SIZE / 2, DEFAULT_SVG_SIZE / 2),
59
+ scale(
60
+ scale_factor,
61
+ coordinateSystem === "screen" ? -scale_factor : scale_factor
62
+ ),
63
+ translate(-(bounds.minX + width / 2), -(bounds.minY + height / 2))
64
+ );
65
+ }
66
+ function projectPoint(point, matrix) {
67
+ const projected = applyToPoint(matrix, { x: point.x, y: point.y });
68
+ return { ...point, ...projected };
69
+ }
70
+ function getSvgFromGraphicsObject(graphicsObj) {
71
+ const { graphics } = graphicsObj;
72
+ const bounds = getBounds(graphics);
73
+ const matrix = compose(getProjectionMatrix(bounds, graphics.coordinateSystem));
74
+ const svgObject = {
75
+ name: "svg",
76
+ type: "element",
77
+ attributes: {
78
+ width: DEFAULT_SVG_SIZE.toString(),
79
+ height: DEFAULT_SVG_SIZE.toString(),
80
+ viewBox: `0 0 ${DEFAULT_SVG_SIZE} ${DEFAULT_SVG_SIZE}`,
81
+ xmlns: "http://www.w3.org/2000/svg"
82
+ },
83
+ children: [
84
+ // Points
85
+ ...(graphics.points || []).map((point) => {
86
+ const projected = projectPoint(point, matrix);
87
+ return {
88
+ name: "g",
89
+ type: "element",
90
+ children: [
91
+ {
92
+ name: "circle",
93
+ type: "element",
94
+ attributes: {
95
+ cx: projected.x.toString(),
96
+ cy: projected.y.toString(),
97
+ r: "3",
98
+ fill: point.color || "black"
99
+ }
100
+ },
101
+ ...point.label ? [
102
+ {
103
+ name: "text",
104
+ type: "element",
105
+ attributes: {
106
+ x: (projected.x + 5).toString(),
107
+ y: (projected.y - 5).toString(),
108
+ "font-family": "sans-serif",
109
+ "font-size": "12"
110
+ },
111
+ children: [{ type: "text", value: point.label }]
112
+ }
113
+ ] : []
114
+ ]
115
+ };
116
+ }),
117
+ // Lines
118
+ ...(graphics.lines || []).map((line) => ({
119
+ name: "polyline",
120
+ type: "element",
121
+ attributes: {
122
+ points: line.points.map((p) => projectPoint(p, matrix)).map((p) => `${p.x},${p.y}`).join(" "),
123
+ fill: "none",
124
+ stroke: "black",
125
+ "stroke-width": (line.points[0].stroke || 1).toString()
126
+ }
127
+ })),
128
+ // Rectangles
129
+ ...(graphics.rects || []).map((rect) => {
130
+ const projected = projectPoint({ x: rect.centerX, y: rect.centerY }, matrix);
131
+ const scaledWidth = rect.width * matrix.a;
132
+ const scaledHeight = rect.height * matrix.d;
133
+ return {
134
+ name: "rect",
135
+ type: "element",
136
+ attributes: {
137
+ x: (projected.x - scaledWidth / 2).toString(),
138
+ y: (projected.y - scaledHeight / 2).toString(),
139
+ width: scaledWidth.toString(),
140
+ height: Math.abs(scaledHeight).toString(),
141
+ fill: rect.fill || "none",
142
+ stroke: rect.stroke || "black"
143
+ }
144
+ };
145
+ }),
146
+ // Circles
147
+ ...(graphics.circles || []).map((circle) => {
148
+ const projected = projectPoint(circle.center, matrix);
149
+ const scaledRadius = circle.radius * Math.abs(matrix.a);
150
+ return {
151
+ name: "circle",
152
+ type: "element",
153
+ attributes: {
154
+ cx: projected.x.toString(),
155
+ cy: projected.y.toString(),
156
+ r: scaledRadius.toString(),
157
+ fill: circle.fill || "none",
158
+ stroke: circle.stroke || "black"
159
+ }
160
+ };
161
+ }),
162
+ // Crosshair lines and coordinates (initially hidden)
163
+ {
164
+ name: "g",
165
+ type: "element",
166
+ attributes: {
167
+ id: "crosshair",
168
+ style: "display: none"
169
+ },
170
+ children: [
171
+ {
172
+ name: "line",
173
+ type: "element",
174
+ attributes: {
175
+ id: "crosshair-h",
176
+ y1: "0",
177
+ y2: DEFAULT_SVG_SIZE.toString(),
178
+ stroke: "#666",
179
+ "stroke-width": "0.5"
180
+ }
181
+ },
182
+ {
183
+ name: "line",
184
+ type: "element",
185
+ attributes: {
186
+ id: "crosshair-v",
187
+ x1: "0",
188
+ x2: DEFAULT_SVG_SIZE.toString(),
189
+ stroke: "#666",
190
+ "stroke-width": "0.5"
191
+ }
192
+ },
193
+ {
194
+ name: "text",
195
+ type: "element",
196
+ attributes: {
197
+ id: "coordinates",
198
+ "font-family": "monospace",
199
+ "font-size": "12",
200
+ fill: "#666"
201
+ },
202
+ children: [{ type: "text", value: "" }]
203
+ }
204
+ ]
205
+ },
206
+ // Mouse tracking script
207
+ {
208
+ name: "script",
209
+ type: "element",
210
+ children: [
211
+ {
212
+ type: "text",
213
+ value: `
214
+ document.currentScript.parentElement.addEventListener('mousemove', (e) => {
215
+ const svg = e.currentTarget;
216
+ const rect = svg.getBoundingClientRect();
217
+ const x = e.clientX - rect.left;
218
+ const y = e.clientY - rect.top;
219
+ const crosshair = svg.getElementById('crosshair');
220
+ const h = svg.getElementById('crosshair-h');
221
+ const v = svg.getElementById('crosshair-v');
222
+ const coords = svg.getElementById('coordinates');
223
+
224
+ crosshair.style.display = 'block';
225
+ h.setAttribute('x1', '0');
226
+ h.setAttribute('x2', '${DEFAULT_SVG_SIZE}');
227
+ h.setAttribute('y1', y);
228
+ h.setAttribute('y2', y);
229
+ v.setAttribute('x1', x);
230
+ v.setAttribute('x2', x);
231
+ v.setAttribute('y1', '0');
232
+ v.setAttribute('y2', '${DEFAULT_SVG_SIZE}');
233
+
234
+ // Calculate real coordinates using inverse transformation
235
+ const matrix = ${JSON.stringify(matrix)};
236
+ // Manually invert and apply the affine transform
237
+ // Since we only use translate and scale, we can directly compute:
238
+ // x' = (x - tx) / sx
239
+ // y' = (y - ty) / sy
240
+ const sx = matrix.a;
241
+ const sy = matrix.d;
242
+ const tx = matrix.e;
243
+ const ty = matrix.f;
244
+ const realPoint = {
245
+ x: (x - tx) / sx,
246
+ y: -(y - ty) / sy // Flip y back since we used negative scale
247
+ }
248
+
249
+ coords.textContent = \`(\${realPoint.x.toFixed(2)}, \${realPoint.y.toFixed(2)})\`;
250
+ coords.setAttribute('x', (x + 5).toString());
251
+ coords.setAttribute('y', (y - 5).toString());
252
+ });
253
+ document.currentScript.parentElement.addEventListener('mouseleave', () => {
254
+ document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
255
+ });
256
+ `
257
+ }
258
+ ]
259
+ }
260
+ ]
261
+ };
262
+ return pretty(stringify(svgObject));
263
+ }
264
+
265
+ export {
266
+ getSvgFromGraphicsObject
267
+ };
268
+ //# sourceMappingURL=chunk-J2MYQBX3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/getSvgFromGraphicsObject.ts"],"sourcesContent":["import {\n transform,\n compose,\n translate,\n scale,\n applyToPoint,\n identity,\n type Matrix,\n} from \"transformation-matrix\"\nimport type { GraphicsObject, Point } from \"./types\"\nimport { stringify } from \"svgson\"\nimport pretty from \"pretty\"\n\nconst DEFAULT_SVG_SIZE = 640\nconst PADDING = 40\n\ninterface Bounds {\n minX: number\n maxX: number\n minY: number\n maxY: number\n}\n\nfunction getBounds(graphics: GraphicsObject[\"graphics\"]): Bounds {\n const points: Point[] = [\n ...(graphics.points || []),\n ...(graphics.lines || []).flatMap((line) => line.points),\n ...(graphics.rects || []).flatMap((rect) => {\n const halfWidth = rect.width / 2\n const halfHeight = rect.height / 2\n return [\n { x: rect.centerX - halfWidth, y: rect.centerY - halfHeight },\n { x: rect.centerX + halfWidth, y: rect.centerY - halfHeight },\n { x: rect.centerX - halfWidth, y: rect.centerY + halfHeight },\n { x: rect.centerX + halfWidth, y: rect.centerY + halfHeight },\n ]\n }),\n ...(graphics.circles || []).flatMap((circle) => [\n { x: circle.center.x - circle.radius, y: circle.center.y }, // left\n { x: circle.center.x + circle.radius, y: circle.center.y }, // right\n { x: circle.center.x, y: circle.center.y - circle.radius }, // top\n { x: circle.center.x, y: circle.center.y + circle.radius }, // bottom\n ]),\n ]\n\n if (points.length === 0) {\n return { minX: -1, maxX: 1, minY: -1, maxY: 1 }\n }\n\n return points.reduce(\n (bounds, point) => ({\n minX: Math.min(bounds.minX, point.x),\n maxX: Math.max(bounds.maxX, point.x),\n minY: Math.min(bounds.minY, point.y),\n maxY: Math.max(bounds.maxY, point.y),\n }),\n { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity },\n )\n}\n\nfunction getProjectionMatrix(\n bounds: Bounds,\n coordinateSystem: GraphicsObject[\"graphics\"][\"coordinateSystem\"],\n) {\n const width = bounds.maxX - bounds.minX\n const height = bounds.maxY - bounds.minY\n\n const scale_factor = Math.min(\n (DEFAULT_SVG_SIZE - 2 * PADDING) / width,\n (DEFAULT_SVG_SIZE - 2 * PADDING) / height,\n )\n\n return compose(\n translate(DEFAULT_SVG_SIZE / 2, DEFAULT_SVG_SIZE / 2),\n scale(\n scale_factor,\n coordinateSystem === \"screen\" ? -scale_factor : scale_factor,\n ),\n translate(-(bounds.minX + width / 2), -(bounds.minY + height / 2)),\n )\n}\n\nfunction projectPoint(point: Point, matrix: Matrix) {\n const projected = applyToPoint(matrix, { x: point.x, y: point.y })\n return { ...point, ...projected }\n}\n\nexport function getSvgFromGraphicsObject(graphicsObj: GraphicsObject): string {\n const { graphics } = graphicsObj\n const bounds = getBounds(graphics)\n const matrix = compose(getProjectionMatrix(bounds, graphics.coordinateSystem))\n\n const svgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n width: DEFAULT_SVG_SIZE.toString(),\n height: DEFAULT_SVG_SIZE.toString(),\n viewBox: `0 0 ${DEFAULT_SVG_SIZE} ${DEFAULT_SVG_SIZE}`,\n xmlns: \"http://www.w3.org/2000/svg\",\n },\n children: [\n // Points\n ...(graphics.points || []).map((point) => {\n const projected = projectPoint(point, matrix)\n return {\n name: \"g\",\n type: \"element\",\n children: [\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n cx: projected.x.toString(),\n cy: projected.y.toString(),\n r: \"3\",\n fill: point.color || \"black\",\n },\n },\n ...(point.label\n ? [\n {\n name: \"text\",\n type: \"element\",\n attributes: {\n x: (projected.x + 5).toString(),\n y: (projected.y - 5).toString(),\n \"font-family\": \"sans-serif\",\n \"font-size\": \"12\",\n },\n children: [{ type: \"text\", value: point.label }],\n },\n ]\n : []),\n ],\n }\n }),\n // Lines\n ...(graphics.lines || []).map((line) => ({\n name: \"polyline\",\n type: \"element\",\n attributes: {\n points: line.points\n .map((p) => projectPoint(p, matrix))\n .map((p) => `${p.x},${p.y}`)\n .join(\" \"),\n fill: \"none\",\n stroke: \"black\",\n \"stroke-width\": (line.points[0].stroke || 1).toString(),\n },\n })),\n // Rectangles\n ...(graphics.rects || []).map((rect) => {\n const projected = projectPoint({x: rect.centerX, y: rect.centerY}, matrix)\n const scaledWidth = rect.width * matrix.a\n const scaledHeight = rect.height * matrix.d\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n x: (projected.x - scaledWidth / 2).toString(),\n y: (projected.y - scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: Math.abs(scaledHeight).toString(),\n fill: rect.fill || \"none\",\n stroke: rect.stroke || \"black\",\n },\n }\n }),\n // Circles\n ...(graphics.circles || []).map((circle) => {\n const projected = projectPoint(circle.center, matrix)\n const scaledRadius = circle.radius * Math.abs(matrix.a)\n return {\n name: \"circle\",\n type: \"element\",\n attributes: {\n cx: projected.x.toString(),\n cy: projected.y.toString(),\n r: scaledRadius.toString(),\n fill: circle.fill || \"none\",\n stroke: circle.stroke || \"black\",\n },\n }\n }),\n // Crosshair lines and coordinates (initially hidden)\n {\n name: \"g\",\n type: \"element\",\n attributes: {\n id: \"crosshair\",\n style: \"display: none\",\n },\n children: [\n {\n name: \"line\",\n type: \"element\",\n attributes: {\n id: \"crosshair-h\",\n y1: \"0\",\n y2: DEFAULT_SVG_SIZE.toString(),\n stroke: \"#666\",\n \"stroke-width\": \"0.5\",\n },\n },\n {\n name: \"line\",\n type: \"element\",\n attributes: {\n id: \"crosshair-v\",\n x1: \"0\",\n x2: DEFAULT_SVG_SIZE.toString(),\n stroke: \"#666\",\n \"stroke-width\": \"0.5\",\n },\n },\n {\n name: \"text\",\n type: \"element\",\n attributes: {\n id: \"coordinates\",\n \"font-family\": \"monospace\",\n \"font-size\": \"12\",\n fill: \"#666\",\n },\n children: [{ type: \"text\", value: \"\" }],\n },\n ],\n },\n // Mouse tracking script\n {\n name: \"script\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n document.currentScript.parentElement.addEventListener('mousemove', (e) => {\n const svg = e.currentTarget;\n const rect = svg.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n const crosshair = svg.getElementById('crosshair');\n const h = svg.getElementById('crosshair-h');\n const v = svg.getElementById('crosshair-v');\n const coords = svg.getElementById('coordinates');\n \n crosshair.style.display = 'block';\n h.setAttribute('x1', '0');\n h.setAttribute('x2', '${DEFAULT_SVG_SIZE}');\n h.setAttribute('y1', y);\n h.setAttribute('y2', y);\n v.setAttribute('x1', x);\n v.setAttribute('x2', x);\n v.setAttribute('y1', '0');\n v.setAttribute('y2', '${DEFAULT_SVG_SIZE}');\n\n // Calculate real coordinates using inverse transformation\n const matrix = ${JSON.stringify(matrix)};\n // Manually invert and apply the affine transform\n // Since we only use translate and scale, we can directly compute:\n // x' = (x - tx) / sx\n // y' = (y - ty) / sy\n const sx = matrix.a;\n const sy = matrix.d;\n const tx = matrix.e; \n const ty = matrix.f;\n const realPoint = {\n x: (x - tx) / sx,\n y: -(y - ty) / sy // Flip y back since we used negative scale\n }\n \n coords.textContent = \\`(\\${realPoint.x.toFixed(2)}, \\${realPoint.y.toFixed(2)})\\`;\n coords.setAttribute('x', (x + 5).toString());\n coords.setAttribute('y', (y - 5).toString());\n });\n document.currentScript.parentElement.addEventListener('mouseleave', () => {\n document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';\n });\n `,\n },\n ],\n },\n ],\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: TODO\n return pretty(stringify(svgObject as any))\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,56 @@
1
+ import {
2
+ getGraphicsObjectsFromLogString
3
+ } from "./chunk-NG6H63SM.js";
4
+ import {
5
+ getSvgFromGraphicsObject
6
+ } from "./chunk-4FN266Q5.js";
7
+
8
+ // lib/index.ts
9
+ function getSvgFromLogString(logString) {
10
+ const objects = getGraphicsObjectsFromLogString(logString);
11
+ if (objects.length === 0) return "";
12
+ return getSvgFromGraphicsObject(objects[0]);
13
+ }
14
+ function getHtmlFromLogString(logString) {
15
+ const svgs = getSvgsFromLogString(logString);
16
+ if (svgs.length === 0) return "";
17
+ const sections = svgs.map(
18
+ ({ title, svg }) => `
19
+ <section>
20
+ <h2>${title}</h2>
21
+ ${svg}
22
+ </section>
23
+ `
24
+ ).join("\n");
25
+ return `
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head>
29
+ <title>Graphics Debug Output</title>
30
+ <style>
31
+ body { font-family: system-ui; max-width: 1200px; margin: 0 auto; padding: 20px; }
32
+ h1 { color: #333; }
33
+ section { margin: 40px 0; }
34
+ svg { max-width: 100%; height: auto; border: 1px solid #eee; }
35
+ </style>
36
+ </head>
37
+ <body>
38
+ <h1>Graphics Debug Output</h1>
39
+ ${sections}
40
+ </body>
41
+ </html>`;
42
+ }
43
+ function getSvgsFromLogString(logString) {
44
+ const objects = getGraphicsObjectsFromLogString(logString);
45
+ return objects.map((obj) => ({
46
+ title: obj.title || "Untitled Graphic",
47
+ svg: getSvgFromGraphicsObject(obj)
48
+ }));
49
+ }
50
+
51
+ export {
52
+ getSvgFromLogString,
53
+ getHtmlFromLogString,
54
+ getSvgsFromLogString
55
+ };
56
+ //# sourceMappingURL=chunk-MADVCBD7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/index.ts"],"sourcesContent":["import { getGraphicsObjectsFromLogString } from \"./getGraphicsObjectsFromLogString\"\nimport { getSvgFromGraphicsObject } from \"./getSvgFromGraphicsObject\"\n\nexport type { Point, Line, Rect, Circle, GraphicsObject } from \"./types\"\nexport { getGraphicsObjectsFromLogString } from \"./getGraphicsObjectsFromLogString\"\nexport { getSvgFromGraphicsObject } from \"./getSvgFromGraphicsObject\"\n\nexport function getSvgFromLogString(logString: string): string {\n const objects = getGraphicsObjectsFromLogString(logString)\n if (objects.length === 0) return \"\"\n return getSvgFromGraphicsObject(objects[0])\n}\n\nexport function getHtmlFromLogString(logString: string): string {\n const svgs = getSvgsFromLogString(logString)\n if (svgs.length === 0) return \"\"\n\n const sections = svgs\n .map(\n ({ title, svg }) => `\n <section>\n <h2>${title}</h2>\n ${svg}\n </section>\n `,\n )\n .join(\"\\n\")\n\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <title>Graphics Debug Output</title>\n <style>\n body { font-family: system-ui; max-width: 1200px; margin: 0 auto; padding: 20px; }\n h1 { color: #333; }\n section { margin: 40px 0; }\n svg { max-width: 100%; height: auto; border: 1px solid #eee; }\n </style>\n</head>\n<body>\n <h1>Graphics Debug Output</h1>\n ${sections}\n</body>\n</html>`\n}\n\nexport function getSvgsFromLogString(\n logString: string,\n): Array<{ title: string; svg: string }> {\n const objects = getGraphicsObjectsFromLogString(logString)\n return objects.map((obj) => ({\n title: obj.title || \"Untitled Graphic\",\n svg: getSvgFromGraphicsObject(obj),\n }))\n}\n"],"mappings":";;;;;;;;AAOO,SAAS,oBAAoB,WAA2B;AAC7D,QAAM,UAAU,gCAAgC,SAAS;AACzD,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,yBAAyB,QAAQ,CAAC,CAAC;AAC5C;AAEO,SAAS,qBAAqB,WAA2B;AAC9D,QAAM,OAAO,qBAAqB,SAAS;AAC3C,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QAAM,WAAW,KACd;AAAA,IACC,CAAC,EAAE,OAAO,IAAI,MAAM;AAAA;AAAA,YAEd,KAAK;AAAA,QACT,GAAG;AAAA;AAAA;AAAA,EAGP,EACC,KAAK,IAAI;AAEZ,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcL,QAAQ;AAAA;AAAA;AAGZ;AAEO,SAAS,qBACd,WACuC;AACvC,QAAM,UAAU,gCAAgC,SAAS;AACzD,SAAO,QAAQ,IAAI,CAAC,SAAS;AAAA,IAC3B,OAAO,IAAI,SAAS;AAAA,IACpB,KAAK,yBAAyB,GAAG;AAAA,EACnC,EAAE;AACJ;","names":[]}
@@ -0,0 +1,56 @@
1
+ import {
2
+ getGraphicsObjectsFromLogString
3
+ } from "./chunk-646ISP7J.js";
4
+ import {
5
+ getSvgFromGraphicsObject
6
+ } from "./chunk-J2MYQBX3.js";
7
+
8
+ // lib/index.ts
9
+ function getSvgFromLogString(logString) {
10
+ const objects = getGraphicsObjectsFromLogString(logString);
11
+ if (objects.length === 0) return "";
12
+ return getSvgFromGraphicsObject(objects[0]);
13
+ }
14
+ function getHtmlFromLogString(logString) {
15
+ const svgs = getSvgsFromLogString(logString);
16
+ if (svgs.length === 0) return "";
17
+ const sections = svgs.map(
18
+ ({ title, svg }) => `
19
+ <section>
20
+ <h2>${title}</h2>
21
+ ${svg}
22
+ </section>
23
+ `
24
+ ).join("\n");
25
+ return `
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head>
29
+ <title>Graphics Debug Output</title>
30
+ <style>
31
+ body { font-family: system-ui; max-width: 1200px; margin: 0 auto; padding: 20px; }
32
+ h1 { color: #333; }
33
+ section { margin: 40px 0; }
34
+ svg { max-width: 100%; height: auto; border: 1px solid #eee; }
35
+ </style>
36
+ </head>
37
+ <body>
38
+ <h1>Graphics Debug Output</h1>
39
+ ${sections}
40
+ </body>
41
+ </html>`;
42
+ }
43
+ function getSvgsFromLogString(logString) {
44
+ const objects = getGraphicsObjectsFromLogString(logString);
45
+ return objects.map((obj) => ({
46
+ title: obj.graphics.title || "Untitled Graphic",
47
+ svg: getSvgFromGraphicsObject(obj)
48
+ }));
49
+ }
50
+
51
+ export {
52
+ getSvgFromLogString,
53
+ getHtmlFromLogString,
54
+ getSvgsFromLogString
55
+ };
56
+ //# sourceMappingURL=chunk-MJCYFLWQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/index.ts"],"sourcesContent":["import { getGraphicsObjectsFromLogString } from \"./getGraphicsObjectsFromLogString\"\nimport { getSvgFromGraphicsObject } from \"./getSvgFromGraphicsObject\"\n\nexport type { Point, Line, Rect, Circle, GraphicsObject } from \"./types\"\nexport { getGraphicsObjectsFromLogString } from \"./getGraphicsObjectsFromLogString\"\nexport { getSvgFromGraphicsObject } from \"./getSvgFromGraphicsObject\"\n\nexport function getSvgFromLogString(logString: string): string {\n const objects = getGraphicsObjectsFromLogString(logString)\n if (objects.length === 0) return \"\"\n return getSvgFromGraphicsObject(objects[0])\n}\n\nexport function getHtmlFromLogString(logString: string): string {\n const svgs = getSvgsFromLogString(logString)\n if (svgs.length === 0) return \"\"\n\n const sections = svgs\n .map(\n ({ title, svg }) => `\n <section>\n <h2>${title}</h2>\n ${svg}\n </section>\n `,\n )\n .join(\"\\n\")\n\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <title>Graphics Debug Output</title>\n <style>\n body { font-family: system-ui; max-width: 1200px; margin: 0 auto; padding: 20px; }\n h1 { color: #333; }\n section { margin: 40px 0; }\n svg { max-width: 100%; height: auto; border: 1px solid #eee; }\n </style>\n</head>\n<body>\n <h1>Graphics Debug Output</h1>\n ${sections}\n</body>\n</html>`\n}\n\nexport function getSvgsFromLogString(\n logString: string,\n): Array<{ title: string; svg: string }> {\n const objects = getGraphicsObjectsFromLogString(logString)\n return objects.map((obj) => ({\n title: obj.graphics.title || \"Untitled Graphic\",\n svg: getSvgFromGraphicsObject(obj),\n }))\n}\n"],"mappings":";;;;;;;;AAOO,SAAS,oBAAoB,WAA2B;AAC7D,QAAM,UAAU,gCAAgC,SAAS;AACzD,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,yBAAyB,QAAQ,CAAC,CAAC;AAC5C;AAEO,SAAS,qBAAqB,WAA2B;AAC9D,QAAM,OAAO,qBAAqB,SAAS;AAC3C,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QAAM,WAAW,KACd;AAAA,IACC,CAAC,EAAE,OAAO,IAAI,MAAM;AAAA;AAAA,YAEd,KAAK;AAAA,QACT,GAAG;AAAA;AAAA;AAAA,EAGP,EACC,KAAK,IAAI;AAEZ,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcL,QAAQ;AAAA;AAAA;AAGZ;AAEO,SAAS,qBACd,WACuC;AACvC,QAAM,UAAU,gCAAgC,SAAS;AACzD,SAAO,QAAQ,IAAI,CAAC,SAAS;AAAA,IAC3B,OAAO,IAAI,SAAS,SAAS;AAAA,IAC7B,KAAK,yBAAyB,GAAG;AAAA,EACnC,EAAE;AACJ;","names":[]}
@@ -0,0 +1,36 @@
1
+ // lib/getGraphicsObjectsFromLogString.ts
2
+ function getGraphicsObjectsFromLogString(logString) {
3
+ const results = [];
4
+ const graphicsRegex = /(?:\{[\s]*(?:"graphics"|graphics)[\s]*:[\s]*\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}[\s]*\})|(?::graphics\s+\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})/g;
5
+ const matches = logString.match(graphicsRegex);
6
+ if (!matches) return results;
7
+ for (const match of matches) {
8
+ try {
9
+ const jsonPart = match.includes(":graphics") ? match.substring(match.indexOf("{")) : match;
10
+ const parsed = JSON.parse(jsonPart);
11
+ if (parsed.graphics) {
12
+ results.push(parsed.graphics);
13
+ } else {
14
+ results.push(parsed);
15
+ }
16
+ } catch (e) {
17
+ try {
18
+ const fixed = match.replace(/(\b\w+)(?=\s*:)/g, '"$1"').replace(/,(\s*[}\]])/g, "$1").replace(/:\s*'([^']*)'/g, ':"$1"');
19
+ const parsed = JSON.parse(fixed);
20
+ if (parsed.graphics) {
21
+ results.push(parsed.graphics);
22
+ } else {
23
+ results.push(parsed);
24
+ }
25
+ } catch (e2) {
26
+ console.warn("Failed to parse graphics object:", match, e2);
27
+ }
28
+ }
29
+ }
30
+ return results;
31
+ }
32
+
33
+ export {
34
+ getGraphicsObjectsFromLogString
35
+ };
36
+ //# sourceMappingURL=chunk-NG6H63SM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/getGraphicsObjectsFromLogString.ts"],"sourcesContent":["import type { GraphicsObject } from \"./types\"\n\n/**\n * Extracts graphics objects from a debug log string\n * Handles both well-formatted JSON and relaxed JSON syntax (unquoted keys)\n */\nexport function getGraphicsObjectsFromLogString(\n logString: string,\n): GraphicsObject[] {\n const results: GraphicsObject[] = []\n\n // Match both {graphics: ...} and :graphics {...} patterns\n const graphicsRegex =\n /(?:\\{[\\s]*(?:\"graphics\"|graphics)[\\s]*:[\\s]*\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}[\\s]*\\})|(?::graphics\\s+\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\})/g\n const matches = logString.match(graphicsRegex)\n\n if (!matches) return results\n\n for (const match of matches) {\n try {\n // First try parsing as regular JSON\n // Extract just the JSON part if it's a debug line\n const jsonPart = match.includes(\":graphics\")\n ? match.substring(match.indexOf(\"{\"))\n : match\n\n const parsed = JSON.parse(jsonPart)\n\n // Wrap non-graphics objects in a graphics wrapper\n if (parsed.graphics) {\n results.push(parsed.graphics)\n } else {\n results.push(parsed)\n }\n } catch (e) {\n try {\n // If that fails, fix JSON formatting issues:\n // 1. Add quotes around unquoted keys\n // 2. Handle potential trailing commas\n const fixed = match\n .replace(/(\\b\\w+)(?=\\s*:)/g, '\"$1\"') // Quote unquoted keys more precisely\n .replace(/,(\\s*[}\\]])/g, \"$1\") // Remove trailing commas\n .replace(/:\\s*'([^']*)'/g, ':\"$1\"') // Convert single quotes to double quotes\n\n const parsed = JSON.parse(fixed)\n if (parsed.graphics) {\n results.push(parsed.graphics)\n } else {\n results.push(parsed)\n }\n } catch (e) {\n // Skip invalid entries but log the error and the problematic match\n console.warn(\"Failed to parse graphics object:\", match, e)\n }\n }\n }\n\n return results\n}\n"],"mappings":";AAMO,SAAS,gCACd,WACkB;AAClB,QAAM,UAA4B,CAAC;AAGnC,QAAM,gBACJ;AACF,QAAM,UAAU,UAAU,MAAM,aAAa;AAE7C,MAAI,CAAC,QAAS,QAAO;AAErB,aAAW,SAAS,SAAS;AAC3B,QAAI;AAGF,YAAM,WAAW,MAAM,SAAS,WAAW,IACvC,MAAM,UAAU,MAAM,QAAQ,GAAG,CAAC,IAClC;AAEJ,YAAM,SAAS,KAAK,MAAM,QAAQ;AAGlC,UAAI,OAAO,UAAU;AACnB,gBAAQ,KAAK,OAAO,QAAQ;AAAA,MAC9B,OAAO;AACL,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAAA,IACF,SAAS,GAAG;AACV,UAAI;AAIF,cAAM,QAAQ,MACX,QAAQ,oBAAoB,MAAM,EAClC,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,kBAAkB,OAAO;AAEpC,cAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,YAAI,OAAO,UAAU;AACnB,kBAAQ,KAAK,OAAO,QAAQ;AAAA,QAC9B,OAAO;AACL,kBAAQ,KAAK,MAAM;AAAA,QACrB;AAAA,MACF,SAASA,IAAG;AAEV,gBAAQ,KAAK,oCAAoC,OAAOA,EAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":["e"]}
package/dist/cli/cli.js CHANGED
@@ -2,26 +2,28 @@
2
2
  import {
3
3
  getHtmlFromLogString,
4
4
  getSvgsFromLogString
5
- } from "../chunk-GDKEOGZB.js";
5
+ } from "../chunk-MADVCBD7.js";
6
6
  import {
7
7
  getGraphicsObjectsFromLogString
8
- } from "../chunk-646ISP7J.js";
9
- import "../chunk-G7UBPMLZ.js";
8
+ } from "../chunk-NG6H63SM.js";
9
+ import "../chunk-4FN266Q5.js";
10
10
 
11
11
  // cli/cli.ts
12
12
  import { parseArgs } from "node:util";
13
13
  import "node:fs";
14
14
  import { writeFileSync } from "node:fs";
15
15
  async function getInput() {
16
- if (process.stdin.isTTY) {
16
+ if (process.stdin.isTTY && process.stderr.isTTY) {
17
17
  console.error(
18
18
  "Error: No input provided. Pipe in content with graphics objects."
19
19
  );
20
20
  process.exit(1);
21
21
  }
22
22
  const chunks = [];
23
- for await (const chunk of process.stdin) {
24
- chunks.push(chunk);
23
+ if (!process.stdin.isTTY) {
24
+ for await (const chunk of process.stdin) {
25
+ chunks.push(chunk);
26
+ }
25
27
  }
26
28
  return chunks.join("");
27
29
  }
@@ -54,6 +56,11 @@ Examples:
54
56
  writeFileSync("graphicsdebug.debug.html", html);
55
57
  console.log('Wrote to "graphicsdebug.debug.html"');
56
58
  } else if (values.url) {
59
+ const graphicsObjects = getGraphicsObjectsFromLogString(input);
60
+ if (graphicsObjects.length === 0) {
61
+ console.error("No graphics objects found in input");
62
+ process.exit(0);
63
+ }
57
64
  const { url } = await fetch("https://gdstore.seve.workers.dev/store", {
58
65
  method: "POST",
59
66
  body: JSON.stringify({
@@ -63,6 +70,8 @@ Examples:
63
70
  "Content-Type": "application/json"
64
71
  }
65
72
  }).then((res) => res.json());
73
+ const token = url.split("/get/").pop();
74
+ console.log(`https://graphicsdebug.com/t/${token}`);
66
75
  } else {
67
76
  const svgs = getSvgsFromLogString(input);
68
77
  svgs.forEach((svg, i) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../cli/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\"\nimport { readFileSync } from \"node:fs\"\nimport { writeFileSync } from \"node:fs\"\nimport {\n getSvgsFromLogString,\n getHtmlFromLogString,\n getGraphicsObjectsFromLogString,\n} from \"../lib\"\n\nasync function getInput(): Promise<string> {\n // Check if there's data being piped in\n if (process.stdin.isTTY) {\n console.error(\n \"Error: No input provided. Pipe in content with graphics objects.\",\n )\n process.exit(1)\n }\n\n const chunks = []\n for await (const chunk of process.stdin) {\n chunks.push(chunk)\n }\n return chunks.join(\"\")\n}\n\nasync function main() {\n const { values } = parseArgs({\n options: {\n html: { type: \"boolean\" },\n url: { type: \"boolean\" },\n help: { type: \"boolean\" },\n },\n })\n\n if (values.help) {\n console.log(`\nUsage: graphics-debug [options]\n\nOptions:\n --html Output a single HTML file with all graphics\n --url Print a url to view the graphics in a browser\n --help Show this help message\n\nExamples:\n cat debug.log | graphics-debug\n echo '{ graphics: { points: [{x: 0, y: 0}] } }' | graphics-debug --html\n `)\n process.exit(0)\n }\n\n const input = await getInput()\n\n if (values.html) {\n const html = getHtmlFromLogString(input)\n writeFileSync(\"graphicsdebug.debug.html\", html)\n console.log('Wrote to \"graphicsdebug.debug.html\"')\n } else if (values.url) {\n const { url } = await fetch(\"https://gdstore.seve.workers.dev/store\", {\n method: \"POST\",\n body: JSON.stringify({\n graphicsObjects: getGraphicsObjectsFromLogString(input),\n }),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n }).then((res) => res.json())\n\n // console.log(\"https://graphicsdebug.com/\")\n // console.log(`Debug Graphics: ${url}`)\n } else {\n const svgs = getSvgsFromLogString(input)\n svgs.forEach((svg, i) => {\n const filename = `${svg.title.toLowerCase().replace(/\\s+/g, \"-\")}-${i + 1}.debug.svg`\n writeFileSync(filename, svg.svg)\n console.log(`Wrote to \"${filename}\"`)\n })\n }\n}\n\nmain().catch((err) => {\n console.error(\"Error:\", err)\n process.exit(1)\n})\n"],"mappings":";;;;;;;;;;;AACA,SAAS,iBAAiB;AAC1B,OAA6B;AAC7B,SAAS,qBAAqB;AAO9B,eAAe,WAA4B;AAEzC,MAAI,QAAQ,MAAM,OAAO;AACvB,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,CAAC;AAChB,mBAAiB,SAAS,QAAQ,OAAO;AACvC,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,OAAO,KAAK,EAAE;AACvB;AAEA,eAAe,OAAO;AACpB,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,SAAS;AAAA,MACP,MAAM,EAAE,MAAM,UAAU;AAAA,MACxB,KAAK,EAAE,MAAM,UAAU;AAAA,MACvB,MAAM,EAAE,MAAM,UAAU;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,MAAI,OAAO,MAAM;AACf,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAWX;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM,SAAS;AAE7B,MAAI,OAAO,MAAM;AACf,UAAM,OAAO,qBAAqB,KAAK;AACvC,kBAAc,4BAA4B,IAAI;AAC9C,YAAQ,IAAI,qCAAqC;AAAA,EACnD,WAAW,OAAO,KAAK;AACrB,UAAM,EAAE,IAAI,IAAI,MAAM,MAAM,0CAA0C;AAAA,MACpE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU;AAAA,QACnB,iBAAiB,gCAAgC,KAAK;AAAA,MACxD,CAAC;AAAA,MACD,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,EAI7B,OAAO;AACL,UAAM,OAAO,qBAAqB,KAAK;AACvC,SAAK,QAAQ,CAAC,KAAK,MAAM;AACvB,YAAM,WAAW,GAAG,IAAI,MAAM,YAAY,EAAE,QAAQ,QAAQ,GAAG,CAAC,IAAI,IAAI,CAAC;AACzE,oBAAc,UAAU,IAAI,GAAG;AAC/B,cAAQ,IAAI,aAAa,QAAQ,GAAG;AAAA,IACtC,CAAC;AAAA,EACH;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,UAAU,GAAG;AAC3B,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../cli/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { parseArgs } from \"node:util\"\nimport { readFileSync } from \"node:fs\"\nimport { writeFileSync } from \"node:fs\"\nimport {\n getSvgsFromLogString,\n getHtmlFromLogString,\n getGraphicsObjectsFromLogString,\n} from \"../lib\"\n\nasync function getInput(): Promise<string> {\n // Check if there's data being piped in\n if (process.stdin.isTTY && process.stderr.isTTY) {\n console.error(\n \"Error: No input provided. Pipe in content with graphics objects.\",\n )\n process.exit(1)\n }\n\n const chunks = []\n\n // Read from stdin if available\n if (!process.stdin.isTTY) {\n for await (const chunk of process.stdin) {\n chunks.push(chunk)\n }\n }\n\n return chunks.join(\"\")\n}\n\nasync function main() {\n const { values } = parseArgs({\n options: {\n html: { type: \"boolean\" },\n url: { type: \"boolean\" },\n help: { type: \"boolean\" },\n },\n })\n\n if (values.help) {\n console.log(`\nUsage: graphics-debug [options]\n\nOptions:\n --html Output a single HTML file with all graphics\n --url Print a url to view the graphics in a browser\n --help Show this help message\n\nExamples:\n cat debug.log | graphics-debug\n echo '{ graphics: { points: [{x: 0, y: 0}] } }' | graphics-debug --html\n `)\n process.exit(0)\n }\n\n const input = await getInput()\n\n if (values.html) {\n const html = getHtmlFromLogString(input)\n writeFileSync(\"graphicsdebug.debug.html\", html)\n console.log('Wrote to \"graphicsdebug.debug.html\"')\n } else if (values.url) {\n const graphicsObjects = getGraphicsObjectsFromLogString(input)\n if (graphicsObjects.length === 0) {\n console.error(\"No graphics objects found in input\")\n process.exit(0)\n }\n\n const { url } = await fetch(\"https://gdstore.seve.workers.dev/store\", {\n method: \"POST\",\n body: JSON.stringify({\n graphicsObjects: getGraphicsObjectsFromLogString(input),\n }),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n }).then((res) => res.json())\n\n const token = url.split(\"/get/\").pop()\n\n console.log(`https://graphicsdebug.com/t/${token}`)\n } else {\n const svgs = getSvgsFromLogString(input)\n svgs.forEach((svg, i) => {\n const filename = `${svg.title.toLowerCase().replace(/\\s+/g, \"-\")}-${i + 1}.debug.svg`\n writeFileSync(filename, svg.svg)\n console.log(`Wrote to \"${filename}\"`)\n })\n }\n}\n\nmain().catch((err) => {\n console.error(\"Error:\", err)\n process.exit(1)\n})\n"],"mappings":";;;;;;;;;;;AACA,SAAS,iBAAiB;AAC1B,OAA6B;AAC7B,SAAS,qBAAqB;AAO9B,eAAe,WAA4B;AAEzC,MAAI,QAAQ,MAAM,SAAS,QAAQ,OAAO,OAAO;AAC/C,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,CAAC;AAGhB,MAAI,CAAC,QAAQ,MAAM,OAAO;AACxB,qBAAiB,SAAS,QAAQ,OAAO;AACvC,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,SAAO,OAAO,KAAK,EAAE;AACvB;AAEA,eAAe,OAAO;AACpB,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,SAAS;AAAA,MACP,MAAM,EAAE,MAAM,UAAU;AAAA,MACxB,KAAK,EAAE,MAAM,UAAU;AAAA,MACvB,MAAM,EAAE,MAAM,UAAU;AAAA,IAC1B;AAAA,EACF,CAAC;AAED,MAAI,OAAO,MAAM;AACf,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAWX;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM,SAAS;AAE7B,MAAI,OAAO,MAAM;AACf,UAAM,OAAO,qBAAqB,KAAK;AACvC,kBAAc,4BAA4B,IAAI;AAC9C,YAAQ,IAAI,qCAAqC;AAAA,EACnD,WAAW,OAAO,KAAK;AACrB,UAAM,kBAAkB,gCAAgC,KAAK;AAC7D,QAAI,gBAAgB,WAAW,GAAG;AAChC,cAAQ,MAAM,oCAAoC;AAClD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,EAAE,IAAI,IAAI,MAAM,MAAM,0CAA0C;AAAA,MACpE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU;AAAA,QACnB,iBAAiB,gCAAgC,KAAK;AAAA,MACxD,CAAC;AAAA,MACD,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC;AAE3B,UAAM,QAAQ,IAAI,MAAM,OAAO,EAAE,IAAI;AAErC,YAAQ,IAAI,+BAA+B,KAAK,EAAE;AAAA,EACpD,OAAO;AACL,UAAM,OAAO,qBAAqB,KAAK;AACvC,SAAK,QAAQ,CAAC,KAAK,MAAM;AACvB,YAAM,WAAW,GAAG,IAAI,MAAM,YAAY,EAAE,QAAQ,QAAQ,GAAG,CAAC,IAAI,IAAI,CAAC;AACzE,oBAAc,UAAU,IAAI,GAAG;AAC/B,cAAQ,IAAI,aAAa,QAAQ,GAAG;AAAA,IACtC,CAAC;AAAA,EACH;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,UAAU,GAAG;AAC3B,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getGraphicsObjectsFromLogString
3
- } from "../chunk-646ISP7J.js";
3
+ } from "../chunk-NG6H63SM.js";
4
4
  export {
5
5
  getGraphicsObjectsFromLogString
6
6
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getSvgFromGraphicsObject
3
- } from "../chunk-G7UBPMLZ.js";
3
+ } from "../chunk-4FN266Q5.js";
4
4
  export {
5
5
  getSvgFromGraphicsObject
6
6
  };
package/dist/lib/index.js CHANGED
@@ -2,13 +2,13 @@ import {
2
2
  getHtmlFromLogString,
3
3
  getSvgFromLogString,
4
4
  getSvgsFromLogString
5
- } from "../chunk-GDKEOGZB.js";
5
+ } from "../chunk-MADVCBD7.js";
6
6
  import {
7
7
  getGraphicsObjectsFromLogString
8
- } from "../chunk-646ISP7J.js";
8
+ } from "../chunk-NG6H63SM.js";
9
9
  import {
10
10
  getSvgFromGraphicsObject
11
- } from "../chunk-G7UBPMLZ.js";
11
+ } from "../chunk-4FN266Q5.js";
12
12
  export {
13
13
  getGraphicsObjectsFromLogString,
14
14
  getHtmlFromLogString,
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.1",
5
+ "version": "0.0.2",
6
6
  "files": [
7
7
  "dist"
8
8
  ],
@@ -11,26 +11,36 @@
11
11
  "gd": "./dist/cli/cli.js"
12
12
  },
13
13
  "scripts": {
14
+ "start": "vite",
14
15
  "build": "tsup-node ./cli ./lib --format esm --sourcemap",
15
16
  "format": "biome format --write .",
16
- "format:check": "biome format ."
17
+ "format:check": "biome format .",
18
+ "vercel-build": "vite build"
17
19
  },
18
20
  "devDependencies": {
19
21
  "@biomejs/biome": "^1.9.4",
20
22
  "@types/bun": "latest",
23
+ "@types/debug": "^4.1.12",
21
24
  "@types/pretty": "^2.0.3",
22
25
  "@types/react": "^18.3.12",
23
26
  "@types/react-dom": "^18.3.1",
27
+ "@vitejs/plugin-react": "^4.3.3",
24
28
  "bun-match-svg": "^0.0.8",
25
29
  "commander": "^12.1.0",
30
+ "debug": "^4.3.7",
26
31
  "react": "^18.3.1",
27
32
  "react-dom": "^18.3.1",
28
- "tsup": "^8.3.5"
33
+ "tsup": "^8.3.5",
34
+ "vite": "^5.4.11"
29
35
  },
30
36
  "peerDependencies": {
31
37
  "typescript": "^5.0.0"
32
38
  },
33
39
  "dependencies": {
34
- "pretty": "^2.0.0"
40
+ "@types/react-router-dom": "^5.3.3",
41
+ "pretty": "^2.0.0",
42
+ "react-router-dom": "^6.28.0",
43
+ "svgson": "^5.3.1",
44
+ "transformation-matrix": "^2.16.1"
35
45
  }
36
46
  }