diff --git a/packages/cli/src/linter/model/handler.test.ts b/packages/cli/src/linter/model/handler.test.ts index e402307..89ded11 100644 --- a/packages/cli/src/linter/model/handler.test.ts +++ b/packages/cli/src/linter/model/handler.test.ts @@ -465,6 +465,18 @@ describe('ModelHandler', () => { expect(result.findings[0]!.severity).toBe('error'); }); + it('keeps unquoted YAML numeric lineHeight as a unitless multiplier', () => { + const result = handler.execute(makeParsed({ + typography: { + 'body-md': { fontFamily: 'Inter', fontSize: '16px', fontWeight: 400, lineHeight: 1.6 }, + }, + })); + const body = result.designSystem.typography.get('body-md'); + expect(body?.lineHeight?.value).toBe(1.6); + expect(body?.lineHeight?.unit).toBe(''); + expect(result.findings.filter((f) => f.path?.includes('lineHeight') === true)).toHaveLength(0); + }); + it('accepts string representations of numbers for fontWeight', () => { const result = handler.execute(makeParsed({ typography: { diff --git a/packages/cli/src/linter/model/handler.ts b/packages/cli/src/linter/model/handler.ts index 9ea1193..1ac6b29 100644 --- a/packages/cli/src/linter/model/handler.ts +++ b/packages/cli/src/linter/model/handler.ts @@ -377,6 +377,25 @@ function parseTypography(props: Record, path: string, f const dimensionProps = ['fontSize', 'lineHeight', 'letterSpacing'] as const; for (const prop of dimensionProps) { const raw = props[prop]; + if (typeof raw === 'number' && Number.isFinite(raw)) { + // YAML parses unquoted unitless values as numbers. lineHeight is a + // unitless multiplier in both DESIGN.md and DTCG; other dimension + // properties still require an explicit unit. + if (prop === 'lineHeight') { + result[prop] = { + type: 'dimension', + value: raw, + unit: '', + }; + } else { + findings.push({ + severity: 'error', + path: `${path}.${prop}`, + message: `'${raw}' is not a valid dimension. Include a unit (px, rem, or em).`, + }); + } + continue; + } if (typeof raw === 'string') { if (isParseableDimension(raw)) { const parsed = parseDimension(raw);