@emasoft/svg-matrix 1.2.1 → 1.3.1

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/dist/version.json CHANGED
@@ -1,18 +1,46 @@
1
1
  {
2
- "version": "1.2.1",
3
- "buildTime": "2026-01-01T23:13:01.462Z",
4
- "files": [
5
- {
6
- "name": "svg-matrix.min.js",
7
- "size": 56185
8
- },
9
- {
10
- "name": "svg-toolbox.min.js",
11
- "size": 577277
12
- },
13
- {
14
- "name": "svgm.min.js",
15
- "size": 602660
16
- }
17
- ]
2
+ "version": "1.3.1",
3
+ "buildTime": "2026-01-09T17:20:51.504Z",
4
+ "bundles": {
5
+ "esm": [
6
+ {
7
+ "name": "svg-matrix.min.js",
8
+ "size": 56185,
9
+ "gzipSize": 19446,
10
+ "description": "ESM bundle for bundlers/Node.js (includes decimal.js)"
11
+ },
12
+ {
13
+ "name": "svg-toolbox.min.js",
14
+ "size": 577130,
15
+ "gzipSize": 152266,
16
+ "description": "ESM bundle for bundlers/Node.js (includes decimal.js)"
17
+ },
18
+ {
19
+ "name": "svgm.min.js",
20
+ "size": 602513,
21
+ "gzipSize": 159440,
22
+ "description": "ESM bundle for bundlers/Node.js (includes decimal.js)"
23
+ }
24
+ ],
25
+ "iife": [
26
+ {
27
+ "name": "svg-matrix.global.min.js",
28
+ "size": 56568,
29
+ "gzipSize": 19669,
30
+ "description": "IIFE bundle for browsers via <script> (includes decimal.js)"
31
+ },
32
+ {
33
+ "name": "svg-toolbox.global.min.js",
34
+ "size": 577259,
35
+ "gzipSize": 151635,
36
+ "description": "IIFE bundle for browsers via <script> (includes decimal.js)"
37
+ },
38
+ {
39
+ "name": "svgm.global.min.js",
40
+ "size": 0,
41
+ "gzipSize": 0,
42
+ "description": "IIFE bundle for browsers via <script> (includes decimal.js)"
43
+ }
44
+ ]
45
+ }
18
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emasoft/svg-matrix",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "description": "Arbitrary-precision matrix, vector and affine transformation library for JavaScript using decimal.js",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -12,6 +12,8 @@
12
12
  "test:embed:w3c": "node test/test-embed-w3c.js",
13
13
  "test:embed:w3c:all": "node test/test-embed-w3c-all.js",
14
14
  "test:toolbox:8bits": "node test/test-toolbox-matrix-8bits.js",
15
+ "test:fuzz": "node test/test-path-fuzz.js",
16
+ "test:browser:bundles": "node test/test-browser-bundles.js",
15
17
  "test:embed:browser": "node test/test-embed-playwright.js",
16
18
  "ci-test": "npm ci && npm test",
17
19
  "lint": "node bin/svglinter.cjs",
@@ -47,7 +49,11 @@
47
49
  "3d",
48
50
  "rotation",
49
51
  "translation",
50
- "homogeneous"
52
+ "homogeneous",
53
+ "font",
54
+ "embed",
55
+ "google-fonts",
56
+ "subsetting"
51
57
  ],
52
58
  "exports": {
53
59
  ".": {
@@ -84,15 +90,17 @@
84
90
  "bin": {
85
91
  "svg-matrix": "bin/svg-matrix.js",
86
92
  "svgm": "bin/svgm.js",
93
+ "svgfonts": "bin/svgfonts.js",
87
94
  "svglinter": "bin/svglinter.cjs"
88
95
  },
89
96
  "engines": {
90
- "node": ">=24.0.0"
97
+ "node": ">=18.0.0"
91
98
  },
92
99
  "files": [
93
100
  "src/",
94
101
  "bin/",
95
102
  "scripts/",
103
+ "templates/",
96
104
  "dist/",
97
105
  "LICENSE",
98
106
  "README.md"
@@ -93,6 +93,7 @@ function isCI() {
93
93
 
94
94
  // Strip ANSI escape codes for accurate length calculation
95
95
  function stripAnsi(s) {
96
+ // eslint-disable-next-line no-control-regex
96
97
  return s.replace(/\x1b\[[0-9;]*m/g, "");
97
98
  }
98
99
 
@@ -108,7 +109,12 @@ function getOutputStream() {
108
109
  // This bypasses npm's stdout/stderr redirection
109
110
  if (process.platform !== "win32" && existsSync("/dev/tty")) {
110
111
  try {
111
- return createWriteStream("/dev/tty");
112
+ // createWriteStream doesn't throw sync - it emits 'error' event async
113
+ // We must attach an error handler before returning to prevent crash
114
+ const stream = createWriteStream("/dev/tty");
115
+ // Silence errors and fall back to stderr on any stream error
116
+ stream.on("error", () => {});
117
+ return stream;
112
118
  } catch {
113
119
  // Fall back to stderr
114
120
  }
@@ -165,10 +171,10 @@ ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot} Transforms3D${c.reset} 3D af
165
171
  ${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
166
172
  ${c.cyan}${B.v}${hr}${B.v}${c.reset}
167
173
  ${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
168
- ${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}New in v1.1.0:${c.reset}`)}${c.cyan}${B.v}${c.reset}
174
+ ${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}Features:${c.reset}`)}${c.cyan}${B.v}${c.reset}
169
175
  ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} Universal browser bundles (dist/svg-matrix.min.js, etc.)`)}${c.cyan}${B.v}${c.reset}
170
- ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} I/O abstraction: loadInput/saveOutput for all environments`)}${c.cyan}${B.v}${c.reset}
171
- ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} 70+ SVG toolbox functions, 163+ tests passing`)}${c.cyan}${B.v}${c.reset}
176
+ ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} Font embedding with subsetting, caching, WOFF2 compression`)}${c.cyan}${B.v}${c.reset}
177
+ ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} 70+ SVG toolbox functions for path manipulation`)}${c.cyan}${B.v}${c.reset}
172
178
  ${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
173
179
  ${c.cyan}${B.bl}${hr}${B.br}${c.reset}
174
180
 
@@ -147,10 +147,10 @@ function updateIndexVersion(version) {
147
147
  let content = readFileSync(filePath, "utf8");
148
148
  const original = content;
149
149
 
150
- // Update VERSION constant
150
+ // WHY: Update VERSION constant, using double quotes for consistency with updateLibVersion()
151
151
  content = content.replace(
152
152
  /export const VERSION = ['"][^'"]+['"]/,
153
- `export const VERSION = '${version}'`,
153
+ `export const VERSION = "${version}"`,
154
154
  );
155
155
 
156
156
  // Update @version in jsdoc
@@ -141,8 +141,9 @@ export function parseTimingIds(value) {
141
141
  // Match patterns like "id.event" or "id.begin" or "id.end" with optional offset (+1s, -2s)
142
142
  // Events: click, mousedown, mouseup, mouseover, mouseout, focusin, focusout, etc.
143
143
  // Edge case: handle timing offsets like "id.begin+1s" or "id.end-2s"
144
+ // Edge case: handle repeat(n) syntax like "id.repeat(2)" for nth repeat event
144
145
  const match = trimmed.match(
145
- /^([a-zA-Z_][a-zA-Z0-9_-]*)\.(begin|end|click|mousedown|mouseup|mouseover|mouseout|mousemove|mouseenter|mouseleave|focusin|focusout|activate|repeat)(?:[+-]\d+(?:\.\d+)?[a-z]*)?/,
146
+ /^([a-zA-Z_][a-zA-Z0-9_-]*)\.(begin|end|click|mousedown|mouseup|mouseover|mouseout|mousemove|mouseenter|mouseleave|focusin|focusout|activate|repeat)(?:\(\d+\))?(?:[+-]\d+(?:\.\d+)?[a-z]*)?/,
146
147
  );
147
148
  if (match) {
148
149
  ids.push(match[1]);
@@ -586,7 +586,7 @@ function refineIntersection(bez1, bez2, t1, t2, tol) {
586
586
  // Check for convergence by step size
587
587
  if (dt1.abs().lt(tol) && dt2.abs().lt(tol)) {
588
588
  // BUGFIX: Compute fresh error value instead of using stale one from previous iteration
589
- // WHY: The `error` variable computed above (line 368) is from before the parameter update,
589
+ // WHY: The `error` variable computed above (line 553) is from before the parameter update,
590
590
  // so it may not reflect the final accuracy. We need to recompute error for the converged parameters.
591
591
  const [finalX, finalY] = bezierPoint(bez1, currentT1);
592
592
  const [finalX2, finalY2] = bezierPoint(bez2, currentT2);
@@ -14,7 +14,6 @@
14
14
  */
15
15
 
16
16
  import Decimal from "decimal.js";
17
- import { Matrix as _Matrix } from "./matrix.js";
18
17
  import * as SVGFlatten from "./svg-flatten.js";
19
18
 
20
19
  // Playwright is loaded dynamically to avoid crashes when not installed
@@ -1464,7 +1464,9 @@ export function resolveNestedClipPath(
1464
1464
  let clipPolygon = resolveClipPath(clipPathDef, targetElement, ctm, options);
1465
1465
 
1466
1466
  if (clipPathDef["clip-path"] && clipPolygon.length >= 3) {
1467
- const nestedRef = clipPathDef["clip-path"].replace(/^url\(#?|[)'"]/g, "");
1467
+ // Extract clipPath ID from url(#id), url('#id'), or url("#id") formats
1468
+ // WHY: Robust extraction handles quoted and unquoted references correctly
1469
+ const nestedRef = clipPathDef["clip-path"].replace(/^url\(['"]?#?|['"]?\)$/g, "");
1468
1470
  const nestedClipDef = defsMap.get(nestedRef);
1469
1471
  if (!nestedClipDef) {
1470
1472
  Logger.warn(
@@ -14,7 +14,6 @@
14
14
  */
15
15
 
16
16
  import Decimal from "decimal.js";
17
- import { Matrix as _Matrix } from "./matrix.js";
18
17
  import * as Transforms2D from "./transforms2d.js";
19
18
  import * as SVGFlatten from "./svg-flatten.js";
20
19
  import * as ClipPathResolver from "./clip-path-resolver.js";
@@ -22,7 +21,6 @@ import * as MaskResolver from "./mask-resolver.js";
22
21
  import * as UseSymbolResolver from "./use-symbol-resolver.js";
23
22
  import * as PatternResolver from "./pattern-resolver.js";
24
23
  import * as MarkerResolver from "./marker-resolver.js";
25
- import * as _MeshGradient from "./mesh-gradient.js";
26
24
  import * as GeometryToPath from "./geometry-to-path.js";
27
25
  import {
28
26
  parseSVG,
@@ -32,7 +30,6 @@ import {
32
30
  serializeSVG,
33
31
  findElementsWithAttribute,
34
32
  } from "./svg-parser.js";
35
- import { Logger as _Logger } from "./logger.js";
36
33
  import * as Verification from "./verification.js";
37
34
  import { parseCSSIds } from "./animation-references.js";
38
35
  import * as PolygonClip from "./polygon-clip.js";