@emasoft/svg-matrix 1.0.16 → 1.0.18

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
@@ -68,6 +68,26 @@ npm install @emasoft/svg-matrix
68
68
 
69
69
  This downloads the library into a folder called `node_modules` in your project.
70
70
 
71
+ #### Upgrading to the Latest Version
72
+
73
+ To update to the latest version:
74
+
75
+ ```bash
76
+ npm update @emasoft/svg-matrix
77
+ ```
78
+
79
+ Or to install a specific version:
80
+
81
+ ```bash
82
+ npm install @emasoft/svg-matrix@latest
83
+ ```
84
+
85
+ To check your current version:
86
+
87
+ ```bash
88
+ npm list @emasoft/svg-matrix
89
+ ```
90
+
71
91
  #### Step 2: Create a JavaScript file
72
92
 
73
93
  Create a new file called `example.js` in your project folder.
@@ -408,6 +428,15 @@ This library requires ES modules (modern browsers). For IE11 or very old browser
408
428
  The library includes a command-line interface for batch processing SVG files.
409
429
 
410
430
  ```bash
431
+ # Show help
432
+ svg-matrix --help
433
+
434
+ # Show command-specific help
435
+ svg-matrix flatten --help
436
+
437
+ # Show version
438
+ svg-matrix --version
439
+
411
440
  # Process single file
412
441
  svg-matrix flatten input.svg -o output.svg
413
442
 
@@ -425,9 +454,6 @@ svg-matrix normalize input.svg -o output.svg
425
454
 
426
455
  # Show SVG file info
427
456
  svg-matrix info input.svg
428
-
429
- # Show help
430
- svg-matrix help
431
457
  ```
432
458
 
433
459
  ### CLI Options
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emasoft/svg-matrix",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
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",
@@ -9,7 +9,11 @@
9
9
  "test:browser": "node test/browser-verify.mjs",
10
10
  "test:playwright": "node test/playwright-diagnose.js",
11
11
  "ci-test": "npm ci && npm test",
12
- "prepublishOnly": "npm test",
12
+ "version:sync": "node scripts/version-sync.js",
13
+ "version:check": "node scripts/version-sync.js --check",
14
+ "preversion": "npm run version:sync",
15
+ "version": "node scripts/version-sync.js && git add src/index.js package-lock.json",
16
+ "prepublishOnly": "npm run version:check && npm test",
13
17
  "postinstall": "node scripts/postinstall.js || true"
14
18
  },
15
19
  "repository": {
@@ -98,7 +98,7 @@ function showWelcome() {
98
98
  ? { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│', dot: '•' }
99
99
  : { tl: '+', tr: '+', bl: '+', br: '+', h: '-', v: '|', dot: '*' };
100
100
 
101
- const W = 66;
101
+ const W = 70;
102
102
  const hr = B.h.repeat(W);
103
103
  const R = (s) => pad(s, W);
104
104
 
@@ -137,7 +137,7 @@ ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot} Transforms3D${c.reset} 3D af
137
137
  ${c.cyan}${B.v}${c.reset}${R('')}${c.cyan}${B.v}${c.reset}
138
138
  ${c.cyan}${B.v}${hr}${B.v}${c.reset}
139
139
  ${c.cyan}${B.v}${c.reset}${R('')}${c.cyan}${B.v}${c.reset}
140
- ${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}New in v1.0.16:${c.reset}`)}${c.cyan}${B.v}${c.reset}
140
+ ${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}New in v1.0.18:${c.reset}`)}${c.cyan}${B.v}${c.reset}
141
141
  ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} Enhanced CLI help: svg-matrix <command> --help`)}${c.cyan}${B.v}${c.reset}
142
142
  ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} High-precision Bezier circle/ellipse approximation`)}${c.cyan}${B.v}${c.reset}
143
143
  ${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset} E2E verification always enabled for precision`)}${c.cyan}${B.v}${c.reset}
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview Version synchronization script for @emasoft/svg-matrix
4
+ * Ensures all version references in the codebase match package.json.
5
+ *
6
+ * This script:
7
+ * 1. Reads the canonical version from package.json
8
+ * 2. Updates src/index.js (VERSION constant and @version jsdoc)
9
+ * 3. Can optionally update package-lock.json
10
+ * 4. Validates that all versions are in sync
11
+ *
12
+ * Usage:
13
+ * node scripts/version-sync.js # Sync versions
14
+ * node scripts/version-sync.js --check # Check only (exit 1 if mismatch)
15
+ * node scripts/version-sync.js --help # Show help
16
+ *
17
+ * @module scripts/version-sync
18
+ * @license MIT
19
+ */
20
+
21
+ import { readFileSync, writeFileSync } from 'fs';
22
+ import { fileURLToPath } from 'url';
23
+ import { dirname, join } from 'path';
24
+
25
+ const __dirname = dirname(fileURLToPath(import.meta.url));
26
+ const ROOT = join(__dirname, '..');
27
+
28
+ // ANSI colors for output
29
+ const colors = process.env.NO_COLOR !== undefined ? {
30
+ reset: '', red: '', green: '', yellow: '', cyan: '', dim: '', bright: '',
31
+ } : {
32
+ reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m',
33
+ yellow: '\x1b[33m', cyan: '\x1b[36m', dim: '\x1b[2m', bright: '\x1b[1m',
34
+ };
35
+
36
+ /**
37
+ * Read the canonical version from package.json
38
+ * @returns {string} Version string
39
+ */
40
+ function getPackageVersion() {
41
+ const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'));
42
+ return pkg.version;
43
+ }
44
+
45
+ /**
46
+ * Get version from src/index.js VERSION constant
47
+ * @returns {string|null} Version string or null if not found
48
+ */
49
+ function getIndexVersion() {
50
+ const content = readFileSync(join(ROOT, 'src', 'index.js'), 'utf8');
51
+ const match = content.match(/export const VERSION = ['"]([^'"]+)['"]/);
52
+ return match ? match[1] : null;
53
+ }
54
+
55
+ /**
56
+ * Get @version from src/index.js jsdoc
57
+ * @returns {string|null} Version string or null if not found
58
+ */
59
+ function getIndexJsDocVersion() {
60
+ const content = readFileSync(join(ROOT, 'src', 'index.js'), 'utf8');
61
+ const match = content.match(/@version\s+(\S+)/);
62
+ return match ? match[1] : null;
63
+ }
64
+
65
+ /**
66
+ * Get version from package-lock.json root
67
+ * @returns {string|null} Version string or null if not found
68
+ */
69
+ function getLockfileVersion() {
70
+ try {
71
+ const lock = JSON.parse(readFileSync(join(ROOT, 'package-lock.json'), 'utf8'));
72
+ return lock.version;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Update src/index.js VERSION constant
80
+ * @param {string} version - New version
81
+ * @returns {boolean} True if updated
82
+ */
83
+ function updateIndexVersion(version) {
84
+ const filePath = join(ROOT, 'src', 'index.js');
85
+ let content = readFileSync(filePath, 'utf8');
86
+ const original = content;
87
+
88
+ // Update VERSION constant
89
+ content = content.replace(
90
+ /export const VERSION = ['"][^'"]+['"]/,
91
+ `export const VERSION = '${version}'`
92
+ );
93
+
94
+ // Update @version in jsdoc
95
+ content = content.replace(
96
+ /@version\s+\S+/,
97
+ `@version ${version}`
98
+ );
99
+
100
+ if (content !== original) {
101
+ writeFileSync(filePath, content, 'utf8');
102
+ return true;
103
+ }
104
+ return false;
105
+ }
106
+
107
+ /**
108
+ * Update package-lock.json version
109
+ * @param {string} version - New version
110
+ * @returns {boolean} True if updated
111
+ */
112
+ function updateLockfileVersion(version) {
113
+ const filePath = join(ROOT, 'package-lock.json');
114
+ try {
115
+ const lock = JSON.parse(readFileSync(filePath, 'utf8'));
116
+ const original = JSON.stringify(lock);
117
+
118
+ lock.version = version;
119
+ if (lock.packages && lock.packages['']) {
120
+ lock.packages[''].version = version;
121
+ }
122
+
123
+ const updated = JSON.stringify(lock, null, 2) + '\n';
124
+ if (updated !== original) {
125
+ writeFileSync(filePath, updated, 'utf8');
126
+ return true;
127
+ }
128
+ } catch {
129
+ // Lockfile might not exist
130
+ }
131
+ return false;
132
+ }
133
+
134
+ /**
135
+ * Check if all versions are in sync
136
+ * @returns {{inSync: boolean, versions: Object}}
137
+ */
138
+ function checkVersions() {
139
+ const pkgVersion = getPackageVersion();
140
+ const indexVersion = getIndexVersion();
141
+ const jsDocVersion = getIndexJsDocVersion();
142
+ const lockVersion = getLockfileVersion();
143
+
144
+ const versions = {
145
+ 'package.json': pkgVersion,
146
+ 'src/index.js (VERSION)': indexVersion,
147
+ 'src/index.js (@version)': jsDocVersion,
148
+ 'package-lock.json': lockVersion,
149
+ };
150
+
151
+ const inSync = indexVersion === pkgVersion &&
152
+ jsDocVersion === pkgVersion &&
153
+ (lockVersion === null || lockVersion === pkgVersion);
154
+
155
+ return { inSync, versions, canonical: pkgVersion };
156
+ }
157
+
158
+ /**
159
+ * Main function
160
+ */
161
+ function main() {
162
+ const args = process.argv.slice(2);
163
+
164
+ if (args.includes('--help') || args.includes('-h')) {
165
+ console.log(`
166
+ ${colors.bright}version-sync.js${colors.reset} - Synchronize version numbers across the codebase
167
+
168
+ ${colors.cyan}Usage:${colors.reset}
169
+ node scripts/version-sync.js Sync all versions to package.json
170
+ node scripts/version-sync.js --check Check only (exit 1 if mismatch)
171
+ node scripts/version-sync.js --help Show this help
172
+
173
+ ${colors.cyan}Files updated:${colors.reset}
174
+ - src/index.js (VERSION constant)
175
+ - src/index.js (@version jsdoc)
176
+ - package-lock.json (if present)
177
+ `);
178
+ process.exit(0);
179
+ }
180
+
181
+ const checkOnly = args.includes('--check');
182
+ const { inSync, versions, canonical } = checkVersions();
183
+
184
+ console.log(`${colors.bright}Version Check${colors.reset}`);
185
+ console.log(`${colors.dim}${'─'.repeat(50)}${colors.reset}`);
186
+
187
+ for (const [file, version] of Object.entries(versions)) {
188
+ const status = version === canonical
189
+ ? `${colors.green}OK${colors.reset}`
190
+ : version === null
191
+ ? `${colors.yellow}N/A${colors.reset}`
192
+ : `${colors.red}MISMATCH${colors.reset}`;
193
+ console.log(` ${file.padEnd(30)} ${(version || 'N/A').padEnd(12)} ${status}`);
194
+ }
195
+
196
+ console.log(`${colors.dim}${'─'.repeat(50)}${colors.reset}`);
197
+ console.log(` Canonical version: ${colors.cyan}${canonical}${colors.reset}`);
198
+
199
+ if (inSync) {
200
+ console.log(`\n${colors.green}All versions are in sync.${colors.reset}`);
201
+ process.exit(0);
202
+ }
203
+
204
+ if (checkOnly) {
205
+ console.log(`\n${colors.red}Version mismatch detected!${colors.reset}`);
206
+ console.log(`Run ${colors.cyan}node scripts/version-sync.js${colors.reset} to fix.`);
207
+ process.exit(1);
208
+ }
209
+
210
+ // Sync versions
211
+ console.log(`\n${colors.yellow}Syncing versions...${colors.reset}`);
212
+
213
+ let updated = 0;
214
+ if (updateIndexVersion(canonical)) {
215
+ console.log(` ${colors.green}Updated${colors.reset} src/index.js`);
216
+ updated++;
217
+ }
218
+ if (updateLockfileVersion(canonical)) {
219
+ console.log(` ${colors.green}Updated${colors.reset} package-lock.json`);
220
+ updated++;
221
+ }
222
+
223
+ if (updated > 0) {
224
+ console.log(`\n${colors.green}Synced ${updated} file(s) to version ${canonical}${colors.reset}`);
225
+ } else {
226
+ console.log(`\n${colors.green}All files already in sync.${colors.reset}`);
227
+ }
228
+ }
229
+
230
+ main();
package/src/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * SVG path conversion, and 2D/3D affine transformations using Decimal.js.
6
6
  *
7
7
  * @module @emasoft/svg-matrix
8
- * @version 1.0.16
8
+ * @version 1.0.18
9
9
  * @license MIT
10
10
  *
11
11
  * @example
@@ -58,7 +58,7 @@ Decimal.set({ precision: 80 });
58
58
  * Library version
59
59
  * @constant {string}
60
60
  */
61
- export const VERSION = '1.0.16';
61
+ export const VERSION = '1.0.18';
62
62
 
63
63
  /**
64
64
  * Default precision for path output (decimal places)