fix(tools): follow weight variables in both readings of a keyframe

A keyframe that sets a font only while it runs makes scanWeights scan
the file twice: once with the keyframe over the rule that runs it, once
with the rule after it. The wrapper merged only the findings and the
deferred weights of the second pass, so a weight read through a variable
(`font-weight: $w`, `var(--w)`, `font: $w ...`) that meets JetBrains
Mono only after a non-holding animation was never followed to its
definition. Merge the references too; findIndirectWeights already
dedupes a reference both passes record. Definitions, call sites, loads
and declaration counts do not depend on the reading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-10-04 09:14:38 +02:00
1 parent e8b181fcea
commit 15200b33f2
2 files changed
+38

No files matched your search

+2
View File
@@ -904,6 +904,8 @@ export function scanWeights(file, written) {
return {
...running,
findings: union(running.findings, after.findings),
// A variable a weight reads is followed from either reading.
references: union(running.references, after.references),
deferred: union(running.deferred, after.deferred),
};
}
+36
View File
@@ -4360,6 +4360,42 @@ test('reads a keyframe where a rule runs it, over its own', () => {
}
});
test('follows a weight variable in either reading of a keyframe that does not hold', () => {
const mono = "'JetBrains Mono'";
const roboto = '@keyframes k { to { font-family: Roboto; } }';
const report = (body) =>
findOffScaleWeights('libs/s11/g.scss', body).findings.map(
({ name, value, cap }) => `${name}: ${value} cap ${cap}`
);
for (const [source, expected] of [
// Mono once it has run: the variable meets the cap where it is set.
[
`$w: 700; ${roboto} .x { font-family: ${mono}; animation: k 1ms; font-weight: $w; }`,
['$w: 700 cap 500'],
],
[
`:root { --w: 700; } ${roboto} .x { font-family: ${mono}; animation: k 1ms; font-weight: var(--w); }`,
['--w: 700 cap 500'],
],
[
`$w: 700; ${roboto} .x { animation: k 1ms; font: $w 12px/1 ${mono}; }`,
['$w: 700 cap 500'],
],
// Mono only while it runs.
[
`$w: 700; .x { font-family: Roboto; animation: k 1ms; font-weight: $w; } @keyframes k { to { font-family: ${mono}; } }`,
['$w: 700 cap 500'],
],
// One that holds its frame keeps Roboto after it.
[
`$w: 700; ${roboto} .x { font-family: ${mono}; animation: k 1ms forwards; font-weight: $w; }`,
[],
],
]) {
assert.deepEqual(report(source), expected, source);
}
});
test('reads an `@at-root` rule where Sass writes it out', () => {
const mono = "'JetBrains Mono'";
const media = '@media (min-width: 1px)';