From af20de1dd93eaa10146d7018dbe1bd05a6f9f73f Mon Sep 17 00:00:00 2001 From: yudhi Date: Thu, 25 Jun 2026 22:33:41 +0700 Subject: [PATCH] feat(lint): flag unrecognized typography sub-properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A typography token's sub-properties outside the schema (fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, fontFeature, fontVariation) were silently dropped by the model — never resolved, never exported, and with no diagnostic, so a typo like `fontwight` or an unsupported property like `textTransform` vanished without a trace. Emit a warning for each, mirroring how unknown component sub-tokens are already reported. --- packages/cli/src/linter/model/handler.test.ts | 14 ++++++++++++++ packages/cli/src/linter/model/handler.ts | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/linter/model/handler.test.ts b/packages/cli/src/linter/model/handler.test.ts index 191e31ae..17e27a64 100644 --- a/packages/cli/src/linter/model/handler.test.ts +++ b/packages/cli/src/linter/model/handler.test.ts @@ -366,6 +366,20 @@ describe('ModelHandler', () => { const headline = result.designSystem.typography.get('headline'); expect(headline?.fontWeight).toBe(700); }); + + it('warns about unrecognized typography sub-properties that are silently dropped', () => { + const result = handler.execute(makeParsed({ + typography: { + 'headline': { fontFamily: 'Inter', textTransform: 'uppercase' }, + }, + })); + const warning = result.findings.find(f => f.path === 'typography.headline.textTransform'); + expect(warning).toBeDefined(); + expect(warning?.severity).toBe('warning'); + // The recognized property is still resolved, and known props never warn. + expect(result.designSystem.typography.get('headline')?.fontFamily).toBe('Inter'); + expect(result.findings.some(f => f.path === 'typography.headline.fontFamily')).toBe(false); + }); }); describe('rounded validation', () => { diff --git a/packages/cli/src/linter/model/handler.ts b/packages/cli/src/linter/model/handler.ts index bee269ff..d14cef85 100644 --- a/packages/cli/src/linter/model/handler.ts +++ b/packages/cli/src/linter/model/handler.ts @@ -25,7 +25,7 @@ import type { Finding, } from './spec.js'; -import { isValidColor, isParseableDimension, isTokenReference, parseDimensionParts } from './spec.js'; +import { isValidColor, isParseableDimension, isTokenReference, parseDimensionParts, VALID_TYPOGRAPHY_PROPS } from './spec.js'; import { parseCssColor } from './color-parser.js'; import { @@ -34,6 +34,7 @@ import { } from '../spec-config.js'; const SCHEMA_KEY_SET: ReadonlySet = new Set(SCHEMA_KEYS); +const TYPOGRAPHY_PROP_SET: ReadonlySet = new Set(VALID_TYPOGRAPHY_PROPS); /** * Builds a resolved DesignSystemState from parsed YAML tokens. @@ -367,6 +368,19 @@ function parseTypography(props: Record, path: string, f } } + // Surface typography sub-properties that aren't part of the schema: they are + // silently dropped (never resolved or emitted), so warn rather than ignore — + // mirroring how unknown component sub-tokens are reported. + for (const key of Object.keys(props)) { + if (!TYPOGRAPHY_PROP_SET.has(key)) { + findings.push({ + severity: 'warning', + path: `${path}.${key}`, + message: `'${key}' is not a recognized typography property. Valid properties: ${VALID_TYPOGRAPHY_PROPS.join(', ')}.`, + }); + } + } + return result; }