Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions packages/cli/src/linter/model/color-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,10 @@ function parseHue(s: string): number {
let val = 0;
if (lower.endsWith('deg')) {
val = parseFloat(lower.slice(0, -3));
} else if (lower.endsWith('rad')) {
val = (parseFloat(lower.slice(0, -3)) * 180) / Math.PI;
} else if (lower.endsWith('grad')) {
val = (parseFloat(lower.slice(0, -4)) * 360) / 400;
} else if (lower.endsWith('rad')) {
val = (parseFloat(lower.slice(0, -3)) * 180) / Math.PI;
} else if (lower.endsWith('turn')) {
val = parseFloat(lower.slice(0, -4)) * 360;
} else {
Expand Down Expand Up @@ -437,19 +437,17 @@ function parseColorWithWeight(subArg: string): { colorStr: string; weight: numbe
return { colorStr: parts[0]!, weight: null };
}

// Identify which item is the percentage
// CSS color-mix weights are percentages only; a bare number is not a valid weight.
const p0 = parts[0]!;
const p1 = parts[1]!;

const isP0Weight = p0.endsWith('%') || (!isNaN(Number(p0)) && p0 !== '');
const isP1Weight = p1.endsWith('%') || (!isNaN(Number(p1)) && p1 !== '');
const isP0Weight = p0.endsWith('%');
const isP1Weight = p1.endsWith('%');

if (isP0Weight && !isP1Weight) {
const w = p0.endsWith('%') ? parseFloat(p0.slice(0, -1)) : parseFloat(p0) * 100;
return { colorStr: p1, weight: w };
return { colorStr: p1, weight: parseFloat(p0.slice(0, -1)) };
} else if (isP1Weight && !isP0Weight) {
const w = p1.endsWith('%') ? parseFloat(p1.slice(0, -1)) : parseFloat(p1) * 100;
return { colorStr: p0, weight: w };
return { colorStr: p0, weight: parseFloat(p1.slice(0, -1)) };
}

return null;
Expand Down
19 changes: 19 additions & 0 deletions packages/cli/src/linter/model/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,25 @@ describe('ModelHandler', () => {
expect(mix2?.g).toBe(128);
expect(mix2?.b).toBe(128);
});

it('parses grad hue units correctly (100grad === 90deg)', () => {
const result = handler.execute(makeParsed({
colors: { grad: 'hsl(100grad 100% 50%)', deg: 'hsl(90deg 100% 50%)' },
}));
expect(result.findings.length).toBe(0);
const grad = result.designSystem.colors.get('grad');
expect(grad?.hex).toBe('#80ff00');
expect(grad?.hex).toBe(result.designSystem.colors.get('deg')?.hex);
});

it('rejects color-mix with bare-number (non-percentage) weights', () => {
const result = handler.execute(makeParsed({
colors: { bad: 'color-mix(in srgb, red 20, blue)' },
}));
// CSS color-mix weights are percentages only; a bare number is invalid.
expect(result.designSystem.colors.has('bad')).toBe(false);
expect(result.findings.some(f => f.path === 'colors.bad' && f.severity === 'error')).toBe(true);
});
});

// ── Cycle 10: Resolve single-level token reference ────────────────
Expand Down