@mkbabb/value.js 0.10.0 → 0.11.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/LICENSE +1 -1
- package/README.md +9 -9
- package/dist/index.d.ts +4 -3
- package/dist/math.d.ts +16 -0
- package/dist/parsing/utils.d.ts +14 -0
- package/dist/units/color/dispatch.d.ts +0 -1
- package/dist/units/color/index.d.ts +2 -1
- package/dist/units/index.d.ts +32 -0
- package/dist/units/interpolate.d.ts +24 -1
- package/dist/units/normalize.d.ts +10 -0
- package/dist/value.js +1197 -1072
- package/package.json +5 -15
- package/scripts/migrate-keyframes-js-lerp.mjs +0 -257
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mkbabb/value.js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "CSS value units for color, length, angles, & c.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
],
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
|
+
"development": "./src/index.ts",
|
|
27
28
|
"types": "./dist/index.d.ts",
|
|
28
29
|
"import": "./dist/value.js",
|
|
29
30
|
"default": "./dist/value.js"
|
|
30
31
|
}
|
|
31
32
|
},
|
|
32
33
|
"files": [
|
|
33
|
-
"dist"
|
|
34
|
-
"scripts/migrate-*.mjs"
|
|
34
|
+
"dist"
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
37
|
"dev": "vite --port 9000",
|
|
@@ -41,18 +41,8 @@
|
|
|
41
41
|
"build:watch": "vite build --mode production --watch",
|
|
42
42
|
"gh-pages": "vite build --mode gh-pages",
|
|
43
43
|
"prepare": "test -f dist/value.js || npm run build",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"proof:no-deprecated": "node scripts/proof-no-deprecated.mjs",
|
|
47
|
-
"proof:no-ts-ignore": "node scripts/proof-no-ts-ignore.mjs",
|
|
48
|
-
"proof:as-any-budget": "node scripts/proof-as-any-budget.mjs",
|
|
49
|
-
"proof:as-unknown-as-budget": "node scripts/proof-as-unknown-as-budget.mjs",
|
|
50
|
-
"proof:codemod-publication": "node scripts/proof-codemod-publication.mjs",
|
|
51
|
-
"proof:no-deep": "node scripts/proof-no-deep.mjs",
|
|
52
|
-
"proof:no-bare-builtins": "node scripts/proof-no-bare-builtins.mjs",
|
|
53
|
-
"codemod:keyframes-lerp": "node scripts/migrate-keyframes-js-lerp.mjs",
|
|
54
|
-
"bench": "node bench/color-channel-access.mjs && node bench/color2-direct-paths.mjs && node bench/parser-namelookup.mjs",
|
|
55
|
-
"typecheck": "vue-tsc --noEmit",
|
|
44
|
+
"bench": "node bench/color-channel-access.mjs && node bench/color2-direct-paths.mjs && node bench/parser-namelookup.mjs && node bench/computed-endpoint.mjs",
|
|
45
|
+
"typecheck": "node scripts/check-types.mjs",
|
|
56
46
|
"lint": "eslint . --max-warnings=0",
|
|
57
47
|
"test": "vitest",
|
|
58
48
|
"test:e2e": "playwright test"
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Migrates keyframes.js's `lerp(t, a, b)` → `lerp(a, b, t)` call sites
|
|
4
|
-
* (the v0.6.0 silent-breakage finding documented in
|
|
5
|
-
* value.js docs/tranches/E/coordination/Q.md §5).
|
|
6
|
-
*
|
|
7
|
-
* Authored at value.js tranche E, wave W4, Lane F. Lane F's PRODUCT is the
|
|
8
|
-
* migration scaffolding — value.js does NOT write keyframes.js directly per the
|
|
9
|
-
* precept-bound cross-repo boundary. The keyframes.js maintainer applies this
|
|
10
|
-
* codemod locally; the verification protocol lives in `coordination/Q.md §5.4`.
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
*
|
|
14
|
-
* node scripts/migrate-keyframes-js-lerp.mjs <path/to/keyframes.js> [--dry-run]
|
|
15
|
-
*
|
|
16
|
-
* <path/to/keyframes.js> Absolute or relative path to a keyframes.js checkout
|
|
17
|
-
* root (the directory containing `src/animation/`).
|
|
18
|
-
*
|
|
19
|
-
* --dry-run Print the diff WITHOUT writing. Exits 0 even when
|
|
20
|
-
* rewrites are detected.
|
|
21
|
-
*
|
|
22
|
-
* Strategy (conservative — refuses to rewrite anything it can't recognise):
|
|
23
|
-
*
|
|
24
|
-
* For each of the two known call sites discovered by E.W4 Lane F's audit,
|
|
25
|
-
* match the EXACT multi-line shape and rewrite the argument order from
|
|
26
|
-
* `lerp(t, a, b)` → `lerp(a, b, t)`, preserving:
|
|
27
|
-
* - the exact indentation of the original block,
|
|
28
|
-
* - any inline `!` non-null assertions and `as` casts,
|
|
29
|
-
* - the trailing comma + closing paren style.
|
|
30
|
-
*
|
|
31
|
-
* Sites covered (verbatim per keyframes.js @ HEAD `0909177`):
|
|
32
|
-
* 1. src/animation/numeric.ts:159 — `lerp(eased, seg.startVals[i]!, seg.stopVals[i]!)`
|
|
33
|
-
* 2. src/animation/group.ts:251 — `lerp(layer.weight, existing.value, incoming.value)`
|
|
34
|
-
*
|
|
35
|
-
* Each rewrite ASSERTS that the post-rewrite `lerp(` occurrence count equals
|
|
36
|
-
* the pre-rewrite count — the codemod never adds or removes call sites.
|
|
37
|
-
*
|
|
38
|
-
* If a site doesn't match its expected shape (e.g. the maintainer has already
|
|
39
|
-
* re-styled the block, the line has shifted, the args differ), the codemod
|
|
40
|
-
* REFUSES to rewrite that site and prints a diagnostic. The keyframes.js
|
|
41
|
-
* maintainer applies the migration manually using the diffs in
|
|
42
|
-
* `coordination/Q.md §5.2`.
|
|
43
|
-
*
|
|
44
|
-
* Exit codes:
|
|
45
|
-
*
|
|
46
|
-
* 0 All known sites either rewritten successfully or already migrated.
|
|
47
|
-
* 1 Usage error, path not found, or a site failed the conservative match
|
|
48
|
-
* AND was not already in the post-migration shape — manual intervention
|
|
49
|
-
* required.
|
|
50
|
-
*/
|
|
51
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
52
|
-
import path from "node:path";
|
|
53
|
-
import process from "node:process";
|
|
54
|
-
|
|
55
|
-
const USAGE = `Usage: node scripts/migrate-keyframes-js-lerp.mjs <path/to/keyframes.js> [--dry-run]
|
|
56
|
-
|
|
57
|
-
Migrates keyframes.js's two \`lerp(t, a, b)\` call sites to value.js's
|
|
58
|
-
v0.6.0 \`lerp(a, b, t)\` canonical order.
|
|
59
|
-
|
|
60
|
-
Arguments:
|
|
61
|
-
<path/to/keyframes.js> Path to a keyframes.js checkout root.
|
|
62
|
-
|
|
63
|
-
Flags:
|
|
64
|
-
--dry-run Print the diff but do not write.
|
|
65
|
-
-h, --help Print this message.
|
|
66
|
-
|
|
67
|
-
See value.js docs/tranches/E/coordination/Q.md §5 for full context.
|
|
68
|
-
`;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* The known call sites. Each entry describes the relative path inside the
|
|
72
|
-
* keyframes.js checkout, the legacy (pre-migration) source snippet, and the
|
|
73
|
-
* canonical (post-migration) snippet. The snippets are matched verbatim.
|
|
74
|
-
*
|
|
75
|
-
* Indentation is significant — these strings reproduce the exact bytes from
|
|
76
|
-
* keyframes.js @ HEAD `0909177`, verified at E.W4 Lane F dispatch.
|
|
77
|
-
*/
|
|
78
|
-
const SITES = [
|
|
79
|
-
{
|
|
80
|
-
relPath: "src/animation/numeric.ts",
|
|
81
|
-
legacy: ` (this.result as Record<string, number>)[seg.keys[i]!] = lerp(
|
|
82
|
-
eased,
|
|
83
|
-
seg.startVals[i]!,
|
|
84
|
-
seg.stopVals[i]!,
|
|
85
|
-
);`,
|
|
86
|
-
canonical: ` (this.result as Record<string, number>)[seg.keys[i]!] = lerp(
|
|
87
|
-
seg.startVals[i]!,
|
|
88
|
-
seg.stopVals[i]!,
|
|
89
|
-
eased,
|
|
90
|
-
);`,
|
|
91
|
-
description:
|
|
92
|
-
"numeric.ts:159 — per-segment numeric interpolation in NumericAnimator.update()",
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
relPath: "src/animation/group.ts",
|
|
96
|
-
legacy: ` existing.value = lerp(
|
|
97
|
-
layer.weight,
|
|
98
|
-
existing.value,
|
|
99
|
-
incoming.value,
|
|
100
|
-
);`,
|
|
101
|
-
canonical: ` existing.value = lerp(
|
|
102
|
-
existing.value,
|
|
103
|
-
incoming.value,
|
|
104
|
-
layer.weight,
|
|
105
|
-
);`,
|
|
106
|
-
description:
|
|
107
|
-
"group.ts:251 — weighted-blend lerp in AnimationGroup.tick() weighted branch",
|
|
108
|
-
},
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Print a minimal unified-style diff for a single site. We do not depend on
|
|
113
|
-
* the system `diff(1)` so the codemod is hermetic.
|
|
114
|
-
*/
|
|
115
|
-
function renderSiteDiff(relPath, legacy, canonical) {
|
|
116
|
-
const minus = legacy.split("\n").map((l) => `- ${l}`);
|
|
117
|
-
const plus = canonical.split("\n").map((l) => `+ ${l}`);
|
|
118
|
-
return [`--- a/${relPath}`, `+++ b/${relPath}`, ...minus, ...plus].join(
|
|
119
|
-
"\n",
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Count total `lerp(` occurrences in a source string. Used as the parity
|
|
125
|
-
* assertion — a rewrite must never change the total count.
|
|
126
|
-
*/
|
|
127
|
-
function countLerpCalls(source) {
|
|
128
|
-
const matches = source.match(/\blerp\(/g);
|
|
129
|
-
return matches ? matches.length : 0;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function main(argv) {
|
|
133
|
-
const args = argv.slice(2);
|
|
134
|
-
|
|
135
|
-
if (args.length === 0 || args.includes("-h") || args.includes("--help")) {
|
|
136
|
-
process.stdout.write(USAGE);
|
|
137
|
-
process.exit(args.length === 0 ? 1 : 0);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const dryRun = args.includes("--dry-run");
|
|
141
|
-
const positional = args.filter((a) => !a.startsWith("--") && !a.startsWith("-h"));
|
|
142
|
-
|
|
143
|
-
if (positional.length !== 1) {
|
|
144
|
-
process.stderr.write(USAGE);
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const root = path.resolve(positional[0]);
|
|
149
|
-
|
|
150
|
-
if (!existsSync(root)) {
|
|
151
|
-
process.stderr.write(`error: path does not exist: ${root}\n`);
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const srcAnimation = path.join(root, "src/animation");
|
|
156
|
-
if (!existsSync(srcAnimation)) {
|
|
157
|
-
process.stderr.write(
|
|
158
|
-
`error: ${root} does not appear to be a keyframes.js checkout ` +
|
|
159
|
-
`(missing src/animation/)\n`,
|
|
160
|
-
);
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
process.stdout.write(
|
|
165
|
-
`migrate-keyframes-js-lerp: target = ${root}` +
|
|
166
|
-
(dryRun ? " (dry-run)" : "") +
|
|
167
|
-
"\n\n",
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
let rewriteCount = 0;
|
|
171
|
-
let alreadyMigratedCount = 0;
|
|
172
|
-
let unmatchedCount = 0;
|
|
173
|
-
const failures = [];
|
|
174
|
-
|
|
175
|
-
for (const site of SITES) {
|
|
176
|
-
const filePath = path.join(root, site.relPath);
|
|
177
|
-
|
|
178
|
-
if (!existsSync(filePath)) {
|
|
179
|
-
process.stderr.write(
|
|
180
|
-
`[skip] ${site.relPath} — file missing (the keyframes.js layout has changed)\n`,
|
|
181
|
-
);
|
|
182
|
-
failures.push(site.relPath);
|
|
183
|
-
unmatchedCount++;
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const before = readFileSync(filePath, "utf8");
|
|
188
|
-
const beforeLerpCount = countLerpCalls(before);
|
|
189
|
-
|
|
190
|
-
const hasLegacy = before.includes(site.legacy);
|
|
191
|
-
const hasCanonical = before.includes(site.canonical);
|
|
192
|
-
|
|
193
|
-
if (hasLegacy) {
|
|
194
|
-
const after = before.replace(site.legacy, site.canonical);
|
|
195
|
-
const afterLerpCount = countLerpCalls(after);
|
|
196
|
-
|
|
197
|
-
if (afterLerpCount !== beforeLerpCount) {
|
|
198
|
-
process.stderr.write(
|
|
199
|
-
`[abort] ${site.relPath} — parity check failed ` +
|
|
200
|
-
`(${beforeLerpCount} → ${afterLerpCount} lerp() calls). ` +
|
|
201
|
-
`Refusing to write.\n`,
|
|
202
|
-
);
|
|
203
|
-
failures.push(site.relPath);
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
process.stdout.write(`[rewrite] ${site.relPath}\n`);
|
|
208
|
-
process.stdout.write(` ${site.description}\n`);
|
|
209
|
-
process.stdout.write(
|
|
210
|
-
renderSiteDiff(site.relPath, site.legacy, site.canonical) +
|
|
211
|
-
"\n\n",
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
if (!dryRun) {
|
|
215
|
-
writeFileSync(filePath, after, "utf8");
|
|
216
|
-
}
|
|
217
|
-
rewriteCount++;
|
|
218
|
-
} else if (hasCanonical) {
|
|
219
|
-
process.stdout.write(
|
|
220
|
-
`[already-migrated] ${site.relPath} — canonical (a, b, t) order present; skipping\n\n`,
|
|
221
|
-
);
|
|
222
|
-
alreadyMigratedCount++;
|
|
223
|
-
} else {
|
|
224
|
-
process.stderr.write(
|
|
225
|
-
`[unmatched] ${site.relPath} — neither legacy nor canonical shape found.\n` +
|
|
226
|
-
` The block at this site has drifted from the ` +
|
|
227
|
-
`audit-recorded shape; the codemod cannot rewrite safely.\n` +
|
|
228
|
-
` Apply the diff manually per ` +
|
|
229
|
-
`coordination/Q.md §5.2.\n\n`,
|
|
230
|
-
);
|
|
231
|
-
failures.push(site.relPath);
|
|
232
|
-
unmatchedCount++;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
process.stdout.write("---\n");
|
|
237
|
-
process.stdout.write(
|
|
238
|
-
`summary: rewritten=${rewriteCount}, already-migrated=${alreadyMigratedCount}, unmatched=${unmatchedCount}\n`,
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
if (dryRun) {
|
|
242
|
-
process.stdout.write(
|
|
243
|
-
"dry-run: no files were modified. Re-run without --dry-run to apply.\n",
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (failures.length > 0) {
|
|
248
|
-
process.stderr.write(
|
|
249
|
-
`\nfailed sites:\n${failures.map((f) => ` - ${f}`).join("\n")}\n`,
|
|
250
|
-
);
|
|
251
|
-
process.exit(1);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
process.exit(0);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
main(process.argv);
|