@rulecad/versions 0.1.2 → 0.1.4
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/package.json +2 -2
- package/versions.d.mts +3 -3
- package/versions.mjs +14 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulecad/versions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Semver for physical parts: a change to what other parts fit against is major, so you know when an old print stops fitting.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@rulecad/variables": "^0.1.0",
|
|
37
|
+
"@rulecad/variables": "^0.1.0 || ^0.2.0",
|
|
38
38
|
"@rulecad/keyboard-layout": "^0.1.0"
|
|
39
39
|
},
|
|
40
40
|
"types": "./versions.d.mts"
|
package/versions.d.mts
CHANGED
|
@@ -14,9 +14,9 @@ export function compare(before: Snapshot, after: Snapshot): {
|
|
|
14
14
|
text: string;
|
|
15
15
|
}[];
|
|
16
16
|
};
|
|
17
|
-
export function parse(v:
|
|
18
|
-
export function newer(x:
|
|
19
|
-
export function bigger(k1:
|
|
17
|
+
export function parse(v: string): number[];
|
|
18
|
+
export function newer(x: string, y: string): boolean;
|
|
19
|
+
export function bigger(k1: "major" | "minor" | "patch", k2: "major" | "minor" | "patch"): "patch" | "minor" | "major";
|
|
20
20
|
/**
|
|
21
21
|
* a design: its .json, resolve()'s entries and its code
|
|
22
22
|
*/
|
package/versions.mjs
CHANGED
|
@@ -12,13 +12,17 @@ import { project } from '@rulecad/keyboard-layout';
|
|
|
12
12
|
/** @typedef {{ object: object, entries: { name: string, value: any }[], js: string, layouts?: Record<string, object>, engine?: string }} Snapshot a design: its .json, resolve()'s entries and its code */
|
|
13
13
|
|
|
14
14
|
const KINDS = ['patch', 'minor', 'major'];
|
|
15
|
+
/** A version's three numbers. @param {string} v '1.2.3' @returns {number[]} */
|
|
15
16
|
export const parse = (v) => { const m = String(v).match(/^(\d+)\.(\d+)\.(\d+)$/); if (!m) throw new Error(`"${v}" isn't a version like 1.2.0`); return m.slice(1).map(Number); };
|
|
16
17
|
/** The next version. @param {string} v '1.2.3' @param {'major' | 'minor' | 'patch'} kind @returns {string} */
|
|
17
18
|
export function bump(v, kind) {
|
|
18
19
|
const [a, b, c] = parse(v);
|
|
20
|
+
if (!KINDS.includes(kind)) throw new Error(`a bump is major, minor or patch (got ${JSON.stringify(kind)})`);
|
|
19
21
|
return kind === 'major' ? `${a + 1}.0.0` : kind === 'minor' ? `${a}.${b + 1}.0` : `${a}.${b}.${c + 1}`;
|
|
20
22
|
}
|
|
23
|
+
/** Whether version x is after version y. @param {string} x @param {string} y @returns {boolean} */
|
|
21
24
|
export const newer = (x, y) => { const [p, q] = [parse(x), parse(y)]; for (let i = 0; i < 3; i++) if (p[i] !== q[i]) return p[i] > q[i]; return false; };
|
|
25
|
+
/** The bigger of two bumps. @param {'major' | 'minor' | 'patch'} k1 @param {'major' | 'minor' | 'patch'} k2 */
|
|
22
26
|
export const bigger = (k1, k2) => (KINDS.indexOf(k1) >= KINDS.indexOf(k2) ? k1 : k2);
|
|
23
27
|
|
|
24
28
|
|
|
@@ -45,6 +49,9 @@ export function compare(before, after) {
|
|
|
45
49
|
const reasons = [], add = (kind, text) => reasons.push({ kind, text });
|
|
46
50
|
const val = (r, name) => r.entries.find((e) => e.name === name);
|
|
47
51
|
const v = (r, name) => fmt(val(r, name).value); // for reading: 4.2, not 4.199999999999999
|
|
52
|
+
// a change, for reading; where rounding would show the same number twice (4.2 → 4.2), the numbers as they are
|
|
53
|
+
const change = (name) => (v(before, name) === v(after, name) ? `${val(before, name).value} → ${val(after, name).value}` : `${v(before, name)} → ${v(after, name)}`);
|
|
54
|
+
const sorted = (x) => (Array.isArray(x) ? x.map(sorted) : x && typeof x === 'object' ? Object.fromEntries(Object.keys(x).sort().map((k) => [k, sorted(x[k])])) : x); // (the same settings in another order are the same)
|
|
48
55
|
const vars = (r) => r.object.variables || {};
|
|
49
56
|
const same = (a, b) => (typeof a === 'number' && typeof b === 'number' ? Math.abs(a - b) < 1e-9 : a === b); // numbers, or choices
|
|
50
57
|
|
|
@@ -53,14 +60,15 @@ export function compare(before, after) {
|
|
|
53
60
|
if (d.interface) {
|
|
54
61
|
if (!now) add('major', `interface ${name} removed`);
|
|
55
62
|
else if (!now.interface) add('major', `${name} is no longer interface`);
|
|
56
|
-
else if (!same(val(before, name).value, val(after, name).value)) add('major', `interface ${name} ${
|
|
63
|
+
else if (!same(val(before, name).value, val(after, name).value)) add('major', `interface ${name} ${change(name)}`);
|
|
64
|
+
else if ((d.unit || '') !== (now.unit || '')) add('major', `interface ${name} is now in ${now.unit || 'no unit'} (was ${d.unit || 'no unit'})`);
|
|
57
65
|
} else if (!now) add('patch', `${name} removed`);
|
|
58
|
-
else if (!same(val(before, name).value, val(after, name).value)) add('patch', `${name} ${
|
|
66
|
+
else if (!same(val(before, name).value, val(after, name).value)) add('patch', `${name} ${change(name)}`);
|
|
59
67
|
}
|
|
60
68
|
for (const [name, d] of Object.entries(vars(after))) {
|
|
61
69
|
const was = vars(before)[name];
|
|
62
|
-
if (d.interface &&
|
|
63
|
-
if (d.interface && !was) add('minor', `interface ${name} added (${v(after, name)})`);
|
|
70
|
+
if (d.interface && was && !was.interface) add('minor', `${name} is now interface (${v(after, name)}): other parts may depend on it from here`);
|
|
71
|
+
else if (d.interface && !was) add('minor', `interface ${name} added (${v(after, name)})`);
|
|
64
72
|
else if (!was) add('patch', `${name} added`);
|
|
65
73
|
if ((d.type === 'text' || d.type === 'anchor') && !was?.type) add('minor', `${name} can now be set (${d.type})`); // a new input
|
|
66
74
|
if (d.choice) { // a choice: options added are new ways to build it; options taken away break what used them
|
|
@@ -69,6 +77,7 @@ export function compare(before, after) {
|
|
|
69
77
|
}
|
|
70
78
|
if (d.tweak && !was?.tweak) add('minor', `${name} can now be set (${d.tweak.min} to ${d.tweak.max})`);
|
|
71
79
|
else if (d.tweak && was?.tweak && (d.tweak.min !== was.tweak.min || d.tweak.max !== was.tweak.max)) add('patch', `${name} range now ${d.tweak.min} to ${d.tweak.max}`);
|
|
80
|
+
else if (!d.tweak && was?.tweak) add(d.interface ? 'major' : 'patch', `${name} can no longer be set (it was ${was.tweak.min} to ${was.tweak.max})`);
|
|
72
81
|
}
|
|
73
82
|
// Values the design builds from that changed without any variable changing: a rule's value
|
|
74
83
|
for (const e of after.entries) if (e.name.includes('.')) { const b = val(before, e.name); if (b && !same(b.value, e.value)) add('patch', `rule ${e.name} ${fmt(b.value)} → ${fmt(e.value)}`); }
|
|
@@ -90,7 +99,7 @@ export function compare(before, after) {
|
|
|
90
99
|
const vb = before.object.variants || {}, va = after.object.variants || {};
|
|
91
100
|
for (const [k, v] of Object.entries(vb)) {
|
|
92
101
|
if (!va[k]) add('major', `variant ${k} removed`);
|
|
93
|
-
else if (JSON.stringify(v) !== JSON.stringify(va[k])) add('major', `variant ${k} changed`);
|
|
102
|
+
else if (JSON.stringify(sorted(v)) !== JSON.stringify(sorted(va[k]))) add('major', `variant ${k} changed`);
|
|
94
103
|
}
|
|
95
104
|
for (const k of Object.keys(va)) if (!vb[k]) add('minor', `variant ${k} added`);
|
|
96
105
|
// Layout files: compared only on what this object reads of each key (its layout variable's fields), plus positions
|