@emasoft/svg-matrix 1.1.0 → 1.2.0
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/bin/svg-matrix.js +7 -6
- package/bin/svgm.js +109 -40
- package/dist/svg-matrix.min.js +7 -7
- package/dist/svg-toolbox.min.js +148 -228
- package/dist/svgm.min.js +152 -232
- package/dist/version.json +5 -5
- package/package.json +1 -1
- package/scripts/postinstall.js +72 -41
- package/scripts/test-postinstall.js +18 -16
- package/scripts/version-sync.js +78 -60
- package/src/animation-optimization.js +190 -98
- package/src/animation-references.js +11 -3
- package/src/arc-length.js +23 -20
- package/src/bezier-analysis.js +9 -13
- package/src/bezier-intersections.js +18 -4
- package/src/browser-verify.js +35 -8
- package/src/clip-path-resolver.js +285 -114
- package/src/convert-path-data.js +20 -8
- package/src/css-specificity.js +33 -9
- package/src/douglas-peucker.js +272 -141
- package/src/geometry-to-path.js +79 -22
- package/src/gjk-collision.js +287 -126
- package/src/index.js +56 -21
- package/src/inkscape-support.js +122 -101
- package/src/logger.js +43 -27
- package/src/marker-resolver.js +201 -121
- package/src/mask-resolver.js +231 -98
- package/src/matrix.js +9 -5
- package/src/mesh-gradient.js +22 -14
- package/src/off-canvas-detection.js +53 -17
- package/src/path-optimization.js +356 -171
- package/src/path-simplification.js +671 -256
- package/src/pattern-resolver.js +1 -3
- package/src/polygon-clip.js +396 -78
- package/src/svg-boolean-ops.js +90 -23
- package/src/svg-collections.js +1546 -667
- package/src/svg-flatten.js +152 -38
- package/src/svg-matrix-lib.js +2 -2
- package/src/svg-parser.js +5 -1
- package/src/svg-rendering-context.js +3 -1
- package/src/svg-toolbox-lib.js +2 -2
- package/src/svg-toolbox.js +99 -457
- package/src/svg-validation-data.js +513 -345
- package/src/svg2-polyfills.js +156 -93
- package/src/svgm-lib.js +8 -4
- package/src/transform-optimization.js +168 -51
- package/src/transforms2d.js +73 -40
- package/src/transforms3d.js +34 -27
- package/src/use-symbol-resolver.js +175 -76
- package/src/vector.js +80 -44
- package/src/vendor/inkscape-hatch-polyfill.js +143 -108
- package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
- package/src/vendor/inkscape-mesh-polyfill.js +953 -766
- package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
- package/src/verification.js +3 -4
package/dist/version.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
3
|
-
"buildTime": "2025-12-
|
|
2
|
+
"version": "1.2.0",
|
|
3
|
+
"buildTime": "2025-12-31T23:29:02.390Z",
|
|
4
4
|
"files": [
|
|
5
5
|
{
|
|
6
6
|
"name": "svg-matrix.min.js",
|
|
7
|
-
"size":
|
|
7
|
+
"size": 56106
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"name": "svg-toolbox.min.js",
|
|
11
|
-
"size":
|
|
11
|
+
"size": 577198
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"name": "svgm.min.js",
|
|
15
|
-
"size":
|
|
15
|
+
"size": 602581
|
|
16
16
|
}
|
|
17
17
|
]
|
|
18
18
|
}
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -10,74 +10,105 @@
|
|
|
10
10
|
* @license MIT
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { readFileSync, createWriteStream, existsSync } from
|
|
14
|
-
import { fileURLToPath } from
|
|
15
|
-
import { dirname, join } from
|
|
13
|
+
import { readFileSync, createWriteStream, existsSync } from "fs";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
16
|
|
|
17
17
|
function getVersion() {
|
|
18
18
|
try {
|
|
19
19
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
const pkg = JSON.parse(
|
|
21
|
-
|
|
20
|
+
const pkg = JSON.parse(
|
|
21
|
+
readFileSync(join(__dirname, "..", "package.json"), "utf8"),
|
|
22
|
+
);
|
|
23
|
+
return pkg.version || "unknown";
|
|
22
24
|
} catch {
|
|
23
|
-
return
|
|
25
|
+
return "unknown";
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
function shouldDisableColors() {
|
|
28
30
|
if (process.env.NO_COLOR !== undefined) return true;
|
|
29
|
-
if (process.platform ===
|
|
30
|
-
return !(
|
|
31
|
-
|
|
31
|
+
if (process.platform === "win32") {
|
|
32
|
+
return !(
|
|
33
|
+
process.env.WT_SESSION ||
|
|
34
|
+
process.env.ConEmuANSI === "ON" ||
|
|
35
|
+
process.env.TERM_PROGRAM ||
|
|
36
|
+
process.env.ANSICON
|
|
37
|
+
);
|
|
32
38
|
}
|
|
33
39
|
return false;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
function getColors(disabled) {
|
|
37
43
|
if (disabled) {
|
|
38
|
-
return {
|
|
39
|
-
|
|
44
|
+
return {
|
|
45
|
+
reset: "",
|
|
46
|
+
bright: "",
|
|
47
|
+
dim: "",
|
|
48
|
+
cyan: "",
|
|
49
|
+
green: "",
|
|
50
|
+
yellow: "",
|
|
51
|
+
magenta: "",
|
|
52
|
+
blue: "",
|
|
53
|
+
white: "",
|
|
54
|
+
};
|
|
40
55
|
}
|
|
41
56
|
return {
|
|
42
|
-
reset:
|
|
43
|
-
|
|
44
|
-
|
|
57
|
+
reset: "\x1b[0m",
|
|
58
|
+
bright: "\x1b[1m",
|
|
59
|
+
dim: "\x1b[2m",
|
|
60
|
+
cyan: "\x1b[36m",
|
|
61
|
+
green: "\x1b[32m",
|
|
62
|
+
yellow: "\x1b[33m",
|
|
63
|
+
magenta: "\x1b[35m",
|
|
64
|
+
blue: "\x1b[34m",
|
|
65
|
+
white: "\x1b[37m",
|
|
45
66
|
};
|
|
46
67
|
}
|
|
47
68
|
|
|
48
69
|
function supportsUnicode() {
|
|
49
|
-
if (process.platform ===
|
|
50
|
-
return !!(
|
|
51
|
-
|
|
70
|
+
if (process.platform === "win32") {
|
|
71
|
+
return !!(
|
|
72
|
+
process.env.WT_SESSION ||
|
|
73
|
+
process.env.CHCP === "65001" ||
|
|
74
|
+
process.env.ConEmuANSI === "ON" ||
|
|
75
|
+
process.env.TERM_PROGRAM
|
|
76
|
+
);
|
|
52
77
|
}
|
|
53
78
|
return true;
|
|
54
79
|
}
|
|
55
80
|
|
|
56
81
|
function isCI() {
|
|
57
|
-
return !!(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
return !!(
|
|
83
|
+
process.env.CI ||
|
|
84
|
+
process.env.CONTINUOUS_INTEGRATION ||
|
|
85
|
+
process.env.GITHUB_ACTIONS ||
|
|
86
|
+
process.env.GITLAB_CI ||
|
|
87
|
+
process.env.CIRCLECI ||
|
|
88
|
+
process.env.TRAVIS ||
|
|
89
|
+
process.env.JENKINS_URL ||
|
|
90
|
+
process.env.BUILD_ID
|
|
91
|
+
);
|
|
61
92
|
}
|
|
62
93
|
|
|
63
94
|
// Strip ANSI escape codes for accurate length calculation
|
|
64
95
|
function stripAnsi(s) {
|
|
65
|
-
return s.replace(/\x1b\[[0-9;]*m/g,
|
|
96
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
66
97
|
}
|
|
67
98
|
|
|
68
99
|
// Pad string to width W (accounting for ANSI codes)
|
|
69
100
|
function pad(s, w) {
|
|
70
101
|
const visible = stripAnsi(s).length;
|
|
71
|
-
return s +
|
|
102
|
+
return s + " ".repeat(Math.max(0, w - visible));
|
|
72
103
|
}
|
|
73
104
|
|
|
74
105
|
// Get a writable stream that bypasses npm's output suppression
|
|
75
106
|
function getOutputStream() {
|
|
76
107
|
// On Unix, try to write directly to /dev/tty (the terminal)
|
|
77
108
|
// This bypasses npm's stdout/stderr redirection
|
|
78
|
-
if (process.platform !==
|
|
109
|
+
if (process.platform !== "win32" && existsSync("/dev/tty")) {
|
|
79
110
|
try {
|
|
80
|
-
return createWriteStream(
|
|
111
|
+
return createWriteStream("/dev/tty");
|
|
81
112
|
} catch {
|
|
82
113
|
// Fall back to stderr
|
|
83
114
|
}
|
|
@@ -95,8 +126,8 @@ function showWelcome() {
|
|
|
95
126
|
const u = supportsUnicode();
|
|
96
127
|
|
|
97
128
|
const B = u
|
|
98
|
-
? { tl:
|
|
99
|
-
: { tl:
|
|
129
|
+
? { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│", dot: "•" }
|
|
130
|
+
: { tl: "+", tr: "+", bl: "+", br: "+", h: "-", v: "|", dot: "*" };
|
|
100
131
|
|
|
101
132
|
const W = 70;
|
|
102
133
|
const hr = B.h.repeat(W);
|
|
@@ -111,34 +142,34 @@ ${c.cyan}${B.tl}${hr}${B.tr}${c.reset}
|
|
|
111
142
|
${c.cyan}${B.v}${c.reset}${R(` ${c.bright}@emasoft/svg-matrix${c.reset} v${version}`)}${c.cyan}${B.v}${c.reset}
|
|
112
143
|
${c.cyan}${B.v}${c.reset}${R(` ${c.dim}Arbitrary-precision SVG transforms with decimal.js${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
113
144
|
${c.cyan}${B.v}${hr}${B.v}${c.reset}
|
|
114
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
145
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
115
146
|
${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}CLI Commands:${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
116
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
147
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
117
148
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}svg-matrix flatten${c.reset} ${c.dim}Bake transforms into path coordinates${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
118
149
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}svg-matrix convert${c.reset} ${c.dim}Convert shapes to <path> elements${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
119
150
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}svg-matrix normalize${c.reset} ${c.dim}Convert paths to cubic Beziers${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
120
151
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}svg-matrix info${c.reset} ${c.dim}Show SVG file information${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
121
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
152
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
122
153
|
${c.cyan}${B.v}${c.reset}${R(` ${c.dim}Run${c.reset} svg-matrix --help ${c.dim}or${c.reset} svg-matrix <cmd> --help`)}${c.cyan}${B.v}${c.reset}
|
|
123
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
154
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
124
155
|
${c.cyan}${B.v}${hr}${B.v}${c.reset}
|
|
125
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
156
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
126
157
|
${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}JavaScript API:${c.reset}`)}${c.cyan}${B.v}${c.reset}
|
|
127
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
158
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
128
159
|
${c.cyan}${B.v}${c.reset}${R(` ${c.magenta}import${c.reset} { Matrix, Vector, Transforms2D } ${c.magenta}from${c.reset} '@emasoft/svg-matrix'`)}${c.cyan}${B.v}${c.reset}
|
|
129
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
160
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
130
161
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot} Matrix${c.reset} Arbitrary-precision matrix operations`)}${c.cyan}${B.v}${c.reset}
|
|
131
162
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot} Vector${c.reset} High-precision vector math`)}${c.cyan}${B.v}${c.reset}
|
|
132
163
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot} Transforms2D${c.reset} rotate, scale, translate, skew, reflect`)}${c.cyan}${B.v}${c.reset}
|
|
133
164
|
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot} Transforms3D${c.reset} 3D affine transformations`)}${c.cyan}${B.v}${c.reset}
|
|
134
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
165
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
135
166
|
${c.cyan}${B.v}${hr}${B.v}${c.reset}
|
|
136
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
137
|
-
${c.cyan}${B.v}${c.reset}${R(` ${c.yellow}New in v1.0
|
|
138
|
-
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset}
|
|
139
|
-
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset}
|
|
140
|
-
${c.cyan}${B.v}${c.reset}${R(` ${c.green}${B.dot}${c.reset}
|
|
141
|
-
${c.cyan}${B.v}${c.reset}${R(
|
|
167
|
+
${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}
|
|
169
|
+
${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}
|
|
172
|
+
${c.cyan}${B.v}${c.reset}${R("")}${c.cyan}${B.v}${c.reset}
|
|
142
173
|
${c.cyan}${B.bl}${hr}${B.br}${c.reset}
|
|
143
174
|
|
|
144
175
|
${c.blue}Docs:${c.reset} https://github.com/Emasoft/SVG-MATRIX#readme
|
|
@@ -5,24 +5,24 @@
|
|
|
5
5
|
* proper rendering of box characters.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { spawn } from
|
|
8
|
+
import { spawn } from "child_process";
|
|
9
9
|
|
|
10
|
-
console.log(
|
|
10
|
+
console.log("\n=== Testing postinstall.js Unicode/ASCII support ===\n");
|
|
11
11
|
|
|
12
12
|
const tests = [
|
|
13
13
|
{
|
|
14
|
-
name:
|
|
15
|
-
env: { LANG:
|
|
14
|
+
name: "Unicode mode (UTF-8 locale)",
|
|
15
|
+
env: { LANG: "en_US.UTF-8" },
|
|
16
16
|
expectUnicode: true,
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
|
-
name:
|
|
20
|
-
env: { LANG:
|
|
19
|
+
name: "ASCII fallback (C locale)",
|
|
20
|
+
env: { LANG: "C" },
|
|
21
21
|
expectUnicode: false,
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
|
-
name:
|
|
25
|
-
env: { LC_CTYPE:
|
|
24
|
+
name: "UTF-8 in LC_CTYPE",
|
|
25
|
+
env: { LC_CTYPE: "en_US.UTF-8", LANG: "" },
|
|
26
26
|
expectUnicode: true,
|
|
27
27
|
},
|
|
28
28
|
];
|
|
@@ -37,18 +37,18 @@ async function runTest(test) {
|
|
|
37
37
|
// Prepare environment
|
|
38
38
|
const env = { ...process.env, ...test.env };
|
|
39
39
|
|
|
40
|
-
const child = spawn(
|
|
40
|
+
const child = spawn("node", ["scripts/postinstall.js"], {
|
|
41
41
|
env,
|
|
42
|
-
stdio:
|
|
42
|
+
stdio: "pipe",
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
let output =
|
|
45
|
+
let output = "";
|
|
46
46
|
|
|
47
|
-
child.stdout.on(
|
|
47
|
+
child.stdout.on("data", (data) => {
|
|
48
48
|
output += data.toString();
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
child.on(
|
|
51
|
+
child.on("close", () => {
|
|
52
52
|
// Check for Unicode or ASCII box characters
|
|
53
53
|
const hasUnicodeBox = /[╭╮╰╯─│]/.test(output);
|
|
54
54
|
const hasAsciiBox = /[+\-|]/.test(output);
|
|
@@ -60,12 +60,14 @@ async function runTest(test) {
|
|
|
60
60
|
console.log(` ✓ PASS: ASCII fallback characters detected\n`);
|
|
61
61
|
resolve(true);
|
|
62
62
|
} else {
|
|
63
|
-
console.log(
|
|
63
|
+
console.log(
|
|
64
|
+
` ✗ FAIL: Expected ${test.expectUnicode ? "Unicode" : "ASCII"} but got different output\n`,
|
|
65
|
+
);
|
|
64
66
|
resolve(false);
|
|
65
67
|
}
|
|
66
68
|
});
|
|
67
69
|
|
|
68
|
-
child.on(
|
|
70
|
+
child.on("error", (error) => {
|
|
69
71
|
console.log(` ✗ FAIL: ${error.message}\n`);
|
|
70
72
|
resolve(false);
|
|
71
73
|
});
|
|
@@ -82,7 +84,7 @@ async function runAllTests() {
|
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
console.log(
|
|
87
|
+
console.log("=== Test Results ===");
|
|
86
88
|
console.log(`Passed: ${passed}`);
|
|
87
89
|
console.log(`Failed: ${failed}`);
|
|
88
90
|
console.log(`Total: ${passed + failed}\n`);
|
package/scripts/version-sync.js
CHANGED
|
@@ -18,27 +18,41 @@
|
|
|
18
18
|
* @license MIT
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { readFileSync, writeFileSync } from
|
|
22
|
-
import { fileURLToPath } from
|
|
23
|
-
import { dirname, join } from
|
|
21
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
import { dirname, join } from "path";
|
|
24
24
|
|
|
25
25
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
-
const ROOT = join(__dirname,
|
|
26
|
+
const ROOT = join(__dirname, "..");
|
|
27
27
|
|
|
28
28
|
// ANSI colors for output
|
|
29
|
-
const colors =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
const colors =
|
|
30
|
+
process.env.NO_COLOR !== undefined
|
|
31
|
+
? {
|
|
32
|
+
reset: "",
|
|
33
|
+
red: "",
|
|
34
|
+
green: "",
|
|
35
|
+
yellow: "",
|
|
36
|
+
cyan: "",
|
|
37
|
+
dim: "",
|
|
38
|
+
bright: "",
|
|
39
|
+
}
|
|
40
|
+
: {
|
|
41
|
+
reset: "\x1b[0m",
|
|
42
|
+
red: "\x1b[31m",
|
|
43
|
+
green: "\x1b[32m",
|
|
44
|
+
yellow: "\x1b[33m",
|
|
45
|
+
cyan: "\x1b[36m",
|
|
46
|
+
dim: "\x1b[2m",
|
|
47
|
+
bright: "\x1b[1m",
|
|
48
|
+
};
|
|
35
49
|
|
|
36
50
|
/**
|
|
37
51
|
* Read the canonical version from package.json
|
|
38
52
|
* @returns {string} Version string
|
|
39
53
|
*/
|
|
40
54
|
function getPackageVersion() {
|
|
41
|
-
const pkg = JSON.parse(readFileSync(join(ROOT,
|
|
55
|
+
const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8"));
|
|
42
56
|
return pkg.version;
|
|
43
57
|
}
|
|
44
58
|
|
|
@@ -47,7 +61,7 @@ function getPackageVersion() {
|
|
|
47
61
|
* @returns {string|null} Version string or null if not found
|
|
48
62
|
*/
|
|
49
63
|
function getIndexVersion() {
|
|
50
|
-
const content = readFileSync(join(ROOT,
|
|
64
|
+
const content = readFileSync(join(ROOT, "src", "index.js"), "utf8");
|
|
51
65
|
const match = content.match(/export const VERSION = ['"]([^'"]+)['"]/);
|
|
52
66
|
return match ? match[1] : null;
|
|
53
67
|
}
|
|
@@ -57,7 +71,7 @@ function getIndexVersion() {
|
|
|
57
71
|
* @returns {string|null} Version string or null if not found
|
|
58
72
|
*/
|
|
59
73
|
function getIndexJsDocVersion() {
|
|
60
|
-
const content = readFileSync(join(ROOT,
|
|
74
|
+
const content = readFileSync(join(ROOT, "src", "index.js"), "utf8");
|
|
61
75
|
const match = content.match(/@version\s+(\S+)/);
|
|
62
76
|
return match ? match[1] : null;
|
|
63
77
|
}
|
|
@@ -69,7 +83,7 @@ function getIndexJsDocVersion() {
|
|
|
69
83
|
*/
|
|
70
84
|
function getLibVersion(filename) {
|
|
71
85
|
try {
|
|
72
|
-
const content = readFileSync(join(ROOT,
|
|
86
|
+
const content = readFileSync(join(ROOT, "src", filename), "utf8");
|
|
73
87
|
const match = content.match(/export const VERSION = ['"]([^'"]+)['"]/);
|
|
74
88
|
return match ? match[1] : null;
|
|
75
89
|
} catch {
|
|
@@ -84,25 +98,22 @@ function getLibVersion(filename) {
|
|
|
84
98
|
* @returns {boolean} True if updated
|
|
85
99
|
*/
|
|
86
100
|
function updateLibVersion(filename, version) {
|
|
87
|
-
const filePath = join(ROOT,
|
|
101
|
+
const filePath = join(ROOT, "src", filename);
|
|
88
102
|
try {
|
|
89
|
-
let content = readFileSync(filePath,
|
|
103
|
+
let content = readFileSync(filePath, "utf8");
|
|
90
104
|
const original = content;
|
|
91
105
|
|
|
92
106
|
// Update VERSION constant
|
|
93
107
|
content = content.replace(
|
|
94
108
|
/export const VERSION = ['"][^'"]+['"]/,
|
|
95
|
-
`export const VERSION = "${version}"
|
|
109
|
+
`export const VERSION = "${version}"`,
|
|
96
110
|
);
|
|
97
111
|
|
|
98
112
|
// Update @version in jsdoc
|
|
99
|
-
content = content.replace(
|
|
100
|
-
/@version\s+\S+/,
|
|
101
|
-
`@version ${version}`
|
|
102
|
-
);
|
|
113
|
+
content = content.replace(/@version\s+\S+/, `@version ${version}`);
|
|
103
114
|
|
|
104
115
|
if (content !== original) {
|
|
105
|
-
writeFileSync(filePath, content,
|
|
116
|
+
writeFileSync(filePath, content, "utf8");
|
|
106
117
|
return true;
|
|
107
118
|
}
|
|
108
119
|
} catch {
|
|
@@ -117,7 +128,9 @@ function updateLibVersion(filename, version) {
|
|
|
117
128
|
*/
|
|
118
129
|
function getLockfileVersion() {
|
|
119
130
|
try {
|
|
120
|
-
const lock = JSON.parse(
|
|
131
|
+
const lock = JSON.parse(
|
|
132
|
+
readFileSync(join(ROOT, "package-lock.json"), "utf8"),
|
|
133
|
+
);
|
|
121
134
|
return lock.version;
|
|
122
135
|
} catch {
|
|
123
136
|
return null;
|
|
@@ -130,24 +143,21 @@ function getLockfileVersion() {
|
|
|
130
143
|
* @returns {boolean} True if updated
|
|
131
144
|
*/
|
|
132
145
|
function updateIndexVersion(version) {
|
|
133
|
-
const filePath = join(ROOT,
|
|
134
|
-
let content = readFileSync(filePath,
|
|
146
|
+
const filePath = join(ROOT, "src", "index.js");
|
|
147
|
+
let content = readFileSync(filePath, "utf8");
|
|
135
148
|
const original = content;
|
|
136
149
|
|
|
137
150
|
// Update VERSION constant
|
|
138
151
|
content = content.replace(
|
|
139
152
|
/export const VERSION = ['"][^'"]+['"]/,
|
|
140
|
-
`export const VERSION = '${version}'
|
|
153
|
+
`export const VERSION = '${version}'`,
|
|
141
154
|
);
|
|
142
155
|
|
|
143
156
|
// Update @version in jsdoc
|
|
144
|
-
content = content.replace(
|
|
145
|
-
/@version\s+\S+/,
|
|
146
|
-
`@version ${version}`
|
|
147
|
-
);
|
|
157
|
+
content = content.replace(/@version\s+\S+/, `@version ${version}`);
|
|
148
158
|
|
|
149
159
|
if (content !== original) {
|
|
150
|
-
writeFileSync(filePath, content,
|
|
160
|
+
writeFileSync(filePath, content, "utf8");
|
|
151
161
|
return true;
|
|
152
162
|
}
|
|
153
163
|
return false;
|
|
@@ -159,19 +169,19 @@ function updateIndexVersion(version) {
|
|
|
159
169
|
* @returns {boolean} True if updated
|
|
160
170
|
*/
|
|
161
171
|
function updateLockfileVersion(version) {
|
|
162
|
-
const filePath = join(ROOT,
|
|
172
|
+
const filePath = join(ROOT, "package-lock.json");
|
|
163
173
|
try {
|
|
164
|
-
const lock = JSON.parse(readFileSync(filePath,
|
|
174
|
+
const lock = JSON.parse(readFileSync(filePath, "utf8"));
|
|
165
175
|
const original = JSON.stringify(lock);
|
|
166
176
|
|
|
167
177
|
lock.version = version;
|
|
168
|
-
if (lock.packages && lock.packages[
|
|
169
|
-
lock.packages[
|
|
178
|
+
if (lock.packages && lock.packages[""]) {
|
|
179
|
+
lock.packages[""].version = version;
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
const updated = JSON.stringify(lock, null, 2) +
|
|
182
|
+
const updated = JSON.stringify(lock, null, 2) + "\n";
|
|
173
183
|
if (updated !== original) {
|
|
174
|
-
writeFileSync(filePath, updated,
|
|
184
|
+
writeFileSync(filePath, updated, "utf8");
|
|
175
185
|
return true;
|
|
176
186
|
}
|
|
177
187
|
} catch {
|
|
@@ -182,9 +192,9 @@ function updateLockfileVersion(version) {
|
|
|
182
192
|
|
|
183
193
|
// Library entry points to sync (relative to src/)
|
|
184
194
|
const LIB_ENTRY_POINTS = [
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
195
|
+
"svg-matrix-lib.js",
|
|
196
|
+
"svg-toolbox-lib.js",
|
|
197
|
+
"svgm-lib.js",
|
|
188
198
|
];
|
|
189
199
|
|
|
190
200
|
/**
|
|
@@ -198,10 +208,10 @@ function checkVersions() {
|
|
|
198
208
|
const lockVersion = getLockfileVersion();
|
|
199
209
|
|
|
200
210
|
const versions = {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
211
|
+
"package.json": pkgVersion,
|
|
212
|
+
"src/index.js (VERSION)": indexVersion,
|
|
213
|
+
"src/index.js (@version)": jsDocVersion,
|
|
214
|
+
"package-lock.json": lockVersion,
|
|
205
215
|
};
|
|
206
216
|
|
|
207
217
|
// WHY: Check VERSION constants in all library entry points
|
|
@@ -214,10 +224,11 @@ function checkVersions() {
|
|
|
214
224
|
}
|
|
215
225
|
}
|
|
216
226
|
|
|
217
|
-
const inSync =
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
227
|
+
const inSync =
|
|
228
|
+
indexVersion === pkgVersion &&
|
|
229
|
+
jsDocVersion === pkgVersion &&
|
|
230
|
+
(lockVersion === null || lockVersion === pkgVersion) &&
|
|
231
|
+
allLibsInSync;
|
|
221
232
|
|
|
222
233
|
return { inSync, versions, canonical: pkgVersion };
|
|
223
234
|
}
|
|
@@ -228,7 +239,7 @@ function checkVersions() {
|
|
|
228
239
|
function main() {
|
|
229
240
|
const args = process.argv.slice(2);
|
|
230
241
|
|
|
231
|
-
if (args.includes(
|
|
242
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
232
243
|
console.log(`
|
|
233
244
|
${colors.bright}version-sync.js${colors.reset} - Synchronize version numbers across the codebase
|
|
234
245
|
|
|
@@ -247,22 +258,25 @@ ${colors.cyan}Files updated:${colors.reset}
|
|
|
247
258
|
process.exit(0);
|
|
248
259
|
}
|
|
249
260
|
|
|
250
|
-
const checkOnly = args.includes(
|
|
261
|
+
const checkOnly = args.includes("--check");
|
|
251
262
|
const { inSync, versions, canonical } = checkVersions();
|
|
252
263
|
|
|
253
264
|
console.log(`${colors.bright}Version Check${colors.reset}`);
|
|
254
|
-
console.log(`${colors.dim}${
|
|
265
|
+
console.log(`${colors.dim}${"─".repeat(50)}${colors.reset}`);
|
|
255
266
|
|
|
256
267
|
for (const [file, version] of Object.entries(versions)) {
|
|
257
|
-
const status =
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
const status =
|
|
269
|
+
version === canonical
|
|
270
|
+
? `${colors.green}OK${colors.reset}`
|
|
271
|
+
: version === null
|
|
272
|
+
? `${colors.yellow}N/A${colors.reset}`
|
|
273
|
+
: `${colors.red}MISMATCH${colors.reset}`;
|
|
274
|
+
console.log(
|
|
275
|
+
` ${file.padEnd(30)} ${(version || "N/A").padEnd(12)} ${status}`,
|
|
276
|
+
);
|
|
263
277
|
}
|
|
264
278
|
|
|
265
|
-
console.log(`${colors.dim}${
|
|
279
|
+
console.log(`${colors.dim}${"─".repeat(50)}${colors.reset}`);
|
|
266
280
|
console.log(` Canonical version: ${colors.cyan}${canonical}${colors.reset}`);
|
|
267
281
|
|
|
268
282
|
if (inSync) {
|
|
@@ -272,7 +286,9 @@ ${colors.cyan}Files updated:${colors.reset}
|
|
|
272
286
|
|
|
273
287
|
if (checkOnly) {
|
|
274
288
|
console.log(`\n${colors.red}Version mismatch detected!${colors.reset}`);
|
|
275
|
-
console.log(
|
|
289
|
+
console.log(
|
|
290
|
+
`Run ${colors.cyan}node scripts/version-sync.js${colors.reset} to fix.`,
|
|
291
|
+
);
|
|
276
292
|
process.exit(1);
|
|
277
293
|
}
|
|
278
294
|
|
|
@@ -298,7 +314,9 @@ ${colors.cyan}Files updated:${colors.reset}
|
|
|
298
314
|
}
|
|
299
315
|
|
|
300
316
|
if (updated > 0) {
|
|
301
|
-
console.log(
|
|
317
|
+
console.log(
|
|
318
|
+
`\n${colors.green}Synced ${updated} file(s) to version ${canonical}${colors.reset}`,
|
|
319
|
+
);
|
|
302
320
|
} else {
|
|
303
321
|
console.log(`\n${colors.green}All files already in sync.${colors.reset}`);
|
|
304
322
|
}
|