fix(dtcg): emit required typography lineHeight and letterSpacing - #1
Closed
Arshgill01 wants to merge 37 commits into
Closed
Arshgill01 wants to merge 37 commits into
Arshgill01 wants to merge 37 commits into
Conversation
…sue google-labs-code#75 tests (google-labs-code#94) The component property loop only checked for typeof 'number' before passing values to string-only helpers (isTokenReference, isValidColor, isParseableDimension). Boolean YAML values (e.g. visible: true) fell through to those helpers and only survived by accident due to the typeof guards added in PR google-labs-code#79. This change handles booleans explicitly alongside numbers so the intent is clear. Adds three tests covering the exact reproducer from Issue google-labs-code#75 (opacity: 0.9), boolean properties (visible: true), and a mixed case with numbers, booleans, and strings in the same component.
…google-labs-code#95) formatAsMarkdown template-literaled obj.summary directly, which coerced the lint summary object { errors, warnings, infos } to its toString representation '[object Object]'. Detect the lint output shape (findings array + numeric summary) and render a proper markdown report with severity counts and a bulleted findings list. The legacy string-summary path for fixer/diff shapes is preserved. Adds 6 tests covering the regression, findings with and without paths, empty findings, the --format md alias, and the legacy fixer shape. Fixes the bug originally reported in PR google-labs-code#56.
…-labs-code#84) * feat(linter): add unknown-key rule for unknown top-level keys * refactor(linter): narrow unknown-key to typo detection via Levenshtein DESIGN.md is intentionally extensible, so warning on every unknown top-level key flags legitimate custom fields. Restrict the rule to likely typos of known schema keys (edit distance ≤ 2, case-insensitive) and stay silent for unrelated extension keys. Per @davideast review feedback on google-labs-code#84: - Add SCHEMA_KEYS / SchemaKey in parser/spec.ts as the single source of truth and reference it from the model handler. - Add a zero-dependency Levenshtein helper. - Suggest the closest known key in the warning message. * test(linter): add unit tests for levenshtein helper Cover empty strings, single edit operations (insert/delete/substitute), symmetry, the classic kitten/sitting case, and the exact distances used by the unknown-key typo threshold.
…oogle-labs-code#96) The linter already supports oklch, oklab, lab, lch, rgb, hsl, hwb, named colors, color-mix, and 8-digit hex alpha. But the spec, README, and error messages all said only hex was accepted. This was blocking adoption for teams using modern CSS color spaces (Issue google-labs-code#53). Update the Color type definition in the spec, the token types table in the README, the spec.mdx source, and the linter error message to reflect the full range of supported formats. Closes google-labs-code#53
…abs-code#98) - Remove dead runtime dependencies with zero imports: ink, react, @json-render/core, @json-render/ink, mdast (type-only import, covered by @types/mdast) - Remove @types/react from devDependencies - Add package-level lint script (tsc --noEmit --skipLibCheck) so turbo lint actually runs - Fix 10 pre-existing type errors in handler.test.ts where properties.get() returns ResolvedValue but tests compared against raw primitives - Pin CI bun version to 1.3.9 to match root packageManager field instead of floating on latest - Use root-level turbo commands in CI instead of cd-ing into packages/cli - Add lint step to CI pipeline - Regenerate bun.lock after dependency removal bun install now completes with no peer warnings. bun run build, bun run test, and bun run lint all pass at the root. Closes google-labs-code#30
google-labs-code#104) Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
…de#103) * fix: support nested token declarations in frontmatter (google-labs-code#102) * fix: support numeric/boolean properties and limit nesting depth --------- Co-authored-by: vikks <imvikks@gmail.com>
* release: 0.3.0 * fix: remove hardcoded local path from DTCG conformance test * test: skip DTCG conformance test (upstream @terrazzo/token-types removed from npm)
…er keys (google-labs-code#105) Closes google-labs-code#100 Add a new `token-like-ignored` lint rule that warns when a top-level YAML key is not part of the recognized export schema and its value looks like a design-token map (hex colors, CSS dimensions, or typography property names). These keys are silently dropped by `design.md export`, misleading users into thinking their color palette or type scale was exported. - Extend `ParsedDesignSystem` with `rawValues` so the parser carries all raw YAML values through to the model layer - Extend `DesignSystemState` with `unknownKeyValues` populated by `ModelHandler` - New rule `token-like-ignored` in `linter/rules/token-like-ignored.ts` - 10 tests covering hex color maps, font maps, dimension maps, flat scalars, non-token objects, nested maps, and multi-key scenarios - Register rule in `DEFAULT_RULE_DESCRIPTORS` and re-export from public API - Update hardcoded rule-count assertions in `types.test.ts` and `spec.test.ts` Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
…-labs-code#118) `npx @google/design.md spec` failed with "Failed to load spec.md" in installed/published packages. The bundler emits the CLI to dist/index.js, so getSpecContent() resolves spec.md alongside it at dist/spec.md, but the build only copied docs/spec.md to dist/linter/. The dev-path fallback then resolves outside the package, so the command threw. Copy spec.md to dist/ as well, mirroring how spec-config.yaml is already copied to both dist/ and dist/linter/. Add a `spec` invocation to the tarball smoke test so the bundled-spec.md resolution is exercised in CI.
…ogle-labs-code#151) serializeTailwindV4() already appends a trailing newline to the @theme block. Using console.log() adds a second trailing newline, making checked-in generated CSS fail strict whitespace gates like git diff --check. Fixes google-labs-code#139 Change-Id: I3a0150b2c0f8e6a7b9d4c3e2f1a0b9c8d7e6f5a4
…mix weights (google-labs-code#120) parseHue tested `endsWith('rad')` before `endsWith('grad')`, so a gradian angle matched the radians branch first: `100grad` resolved to ~329.58deg instead of 90deg, silently producing the wrong color, luminance, contrast result, and exports. Test `grad` before `rad`; deg/rad/turn/unitless behavior is unchanged. parseColorWithWeight treated any bare number as a weight and multiplied it by 100, so `color-mix(in srgb, red 20, blue)` produced a wildly wrong blend instead of being rejected. CSS color-mix weights are percentages only; require a `%` suffix and otherwise return null (invalid color).
…ode#121) Three small guards so a hostile DESIGN.md cannot pin CPU or exhaust the call stack. All inputs are at the documented untrusted boundary (arbitrary file/stdin), and none of the changes alter results for legitimate input. - parseDimensionParts (and token-like-ignored's CSS_DIMENSION_RE) backtrack quadratically on long all-digit strings. Cap value length to 64 chars before matching; real CSS dimensions are far shorter. - unknown-key runs an O(n*m) Levenshtein DP against every schema key for each unknown key. Skip a schema key whose length differs by more than the typo threshold — edit distance is at least the length difference, so the set of suggestions is unchanged. - parseCssColor recurses for nested color-mix() with no depth bound. Thread a depth counter and stop at 32, so an over-deep value resolves to an invalid color (a precise error finding) instead of a RangeError that collapses the whole model build.
…de#132) (google-labs-code#145) * fix: replace ENOENT stack trace with FileReadError and human-readable stderr (google-labs-code#132) Introduce a typed `FileReadError` class in `readInput` so the function throws instead of calling `process.exit` directly. Each command handler catches it and writes a plain-text error to stderr: Error: "DESIGN.md" not found. Create a DESIGN.md file or pass "-" to read from stdin. This replaces the unhandled Node.js stack trace dump reported in google-labs-code#132. `readInput` is now unit-testable without mocking `process.exit`, and `FileReadError.filePath` identifies the specific missing file (important for `diff`, which reads two files). * fix: use error code to generate accurate FileReadError message Replace the hardcoded "not found" string in all command handlers with a friendlyMessage getter on FileReadError that checks the OS error code: - ENOENT → "not found. Create a DESIGN.md file or pass '-' for stdin." - EACCES → "could not be read: permission denied." - other → "could not be read: <raw message>" This prevents a misleading "not found" message when the file exists but cannot be read due to permissions or other I/O errors.
…bs-code#146) When a user runs a command with "-" as the file path from an interactive terminal (e.g. design.md lint -), the process blocks silently waiting for EOF with no indication of what to do. Add a TTY check before the stdin read loop. If stdin is attached to a terminal, write to stderr: Reading from stdin… Press Ctrl+D when done. The stdin stream is accepted as an optional second parameter on readInput (defaulting to process.stdin), making the TTY path fully testable via dependency injection without touching process.stdin directly. Also exports StdinStream so callers can type mock streams without duplicating the definition.
…on input failure (google-labs-code#123) On a missing or unreadable input file, readInput printed a structured FILE_READ_ERROR JSON to stderr and then re-threw. The throw let the CLI framework print a second, stack-trace error on top of the JSON and override the exit code with 1 instead of the intended 2. Exit cleanly with code 2 right after the JSON, matching the function's documented "exits with error JSON" contract. Also unify the export command's stderr error envelope with readInput's `{ error: <CODE>, message }` shape: an unknown --format now reports `INVALID_FORMAT` (the human text moves to `message`), and emitter failures forward the emitter's structured code (e.g. INVALID_TOKEN_NAME) instead of discarding it.
…findings (google-labs-code#126) The export command derived its exit code from the source's lint summary, so exporting a file that had any lint *error* exited 1 even though the export produced correct output. That conflates "the source has lint findings" (which `lint` already reports by exiting 1) with "the export failed." Decouple them: a successful export exits 0; only an invalid --format or an emitter failure exits 1 (and an unreadable input exits 2, via readInput). Document the export exit codes in the README.
…ogle-labs-code#109) Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
…#152) The success branches (css-tailwind, json-tailwind, dtcg, css-vars) write their output but never assign process.exitCode, so a successful export left the code at its incoming value instead of an explicit 0. That is the success-path counterpart to google-labs-code#126, which decoupled the exit code from source lint findings; the subprocess test there only exercises json-tailwind and a real process happens to exit 0 when exitCode is unset, so the gap went unnoticed. Set process.exitCode = 0 after the format branches (every error branch already returns first). The in-process export.test.ts added in google-labs-code#109 asserts process.exitCode === 0 after a css-vars export, so it was failing on main. Also fix a companion assertion in that file: it read error.error for the human message, but the error envelope is { error: CODE, message: TEXT }, so the text lives on error.message. Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
…google-labs-code#122) cssStringLiteral escaped only backslash and double-quote. A font-family value containing a raw newline, carriage return, or form feed (legal via a YAML quoted or block scalar) was emitted verbatim inside the CSS string literal, where raw line terminators are illegal and can break the value out of the @theme token. Emit them as CSS hex escapes (e.g. `\a `).
* fix: render primitive types from spec config * chore: retrigger cla check --------- Co-authored-by: Julio César Suástegui <juliosuas@users.noreply.github.com>
* fix(cli): add defensive type guard to parseDimension to prevent runtime crashes * fix(cli): resolve spec.md path resolution issue in compiled CLI
Adds duplicate and collision detection to the model builder for nested and flat token keys, preventing silent overwrites in the symbol table.
…code#125) 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.
…labs-code#97) (google-labs-code#117) * feat: data-driven Color and Dimension type definitions (fixes google-labs-code#97) * fix(export): align export test expectations with structured error formats * fix(ts): eliminate duplicate typeDefinitions identifiers and properties for clean CI compilation --------- Co-authored-by: David East <deast@google.com>
…4 serializer (google-labs-code#140) Use stdout.write because serializeTailwindV4 already ends with one newline; console.log added a second byte that broke git diff --check. Also exit cleanly on missing DESIGN.md with a friendly message instead of dumping a Node stack trace after the JSON error. Fixes google-labs-code#139 Fixes google-labs-code#132 Co-authored-by: David East <deast@google.com>
…ing newline (google-labs-code#144) * fix: avoid extra css-tailwind newline * chore: retrigger cla check --------- Co-authored-by: David East <deast@google.com>
…arnings (google-labs-code#155) Implement support for an optional omitted frontmatter configuration key in DESIGN.md, allowing design system authors to explicitly declare token categories that are intentionally skipped or absent (Issue google-labs-code#78). * Update Parser: Add 'omitted' to the known schema keys and types. Implement frontmatter parsing supporting both bare strings (e.g. - spacing) and object mappings with reasons (e.g. section: rounded, reason: "No rounded corners"). * Update Model: Forward the parsed omitted sections to the compiled DesignSystemState. Add optional rule property to linter Findings. * Implement Omission Validation & Suppression: - Create omittedRule to validate the omitted configuration, warning on unknown or redundant sections (if tokens exist for a section listed in omitted). - Update missing-sections and missing-typography rules to skip warnings if the targets are explicitly listed as omitted. - Register the new rule in the default linter list. * Test Coverage: Add test suites verifying frontmatter parsing, model mapping, linter warnings (declared-omission, redundant-omission, unknown-omission), and rule suppressions. * Docs: Document the omitted frontmatter key in README.md and spec.mdx, update active rule counts, and regenerate docs/spec.md. --------- Co-authored-by: David East <deast@google.com> Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Sudarshan sunil hadmode <sudarshan.deve@gmail.com>
…gle-labs-code#119) - lint `summary` uses the key `infos`, not `info` - the `diff` JSON includes all token categories plus a `findings` block (before/after/delta) and `regression`; the example previously showed only two token categories and omitted `findings` - the linter runs ten rules — add the missing `token-like-ignored` row Co-authored-by: David East <deast@google.com>
YAML unquoted lineHeight values were dropped because the typography
model only accepted string dimensions. Keep numeric lineHeight as a
unitless multiplier, and emit letterSpacing {value: 0, unit: "px"}
when DESIGN.md omits it so DTCG export satisfies the 2025.10 schema.
Fixes google-labs-code#172
Co-authored-by: Arshdeep singh <arshgill6120@gmail.com>
|
Opened against this fork by mistake. The upstream PR is google-labs-code#177 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes google-labs-code#172.
What changed
export --format dtcgadvertised the 2025.10 DTCG schema but omitted two of the five required typography properties (lineHeightandletterSpacing), so every typography token failed validation.Two separate gaps:
lineHeightwas in the source but dropped. YAML parses unquotedlineHeight: 1.6as a number. The typography model only accepted string dimensions, so the value never reached the DTCG emitter. Quoted strings ("1.6") already worked. Finite numericlineHeightis now kept as a unitless multiplier (the DTCG meaning). Bare numbers onfontSize/letterSpacingstill error because those properties require an explicit unit.letterSpacinghas no DESIGN.md source. The DTCG 2025.10 typography value schema requiresletterSpacing. When the role omits it, the exporter now emits{ "value": 0, "unit": "px" }so the token validates. Explicit source values are unchanged.How this differs from closed google-labs-code#174
google-labs-code#174 (unmerged) only kept YAML numeric
lineHeightand explicitly did not invent aletterSpacingdefault. That left the schema-required field missing, so DTCG output still would not validate.This PR includes that lineHeight model fix and emits the letterSpacing default so option 1 from google-labs-code#172 is complete.
Verification
bun install bun run lint bun run test bun run buildTargeted:
bun test src/linter/model/handler.test.ts src/linter/dtcg/handler.test.tsAI assistance
Cursor Grok assisted with investigation, TDD, and drafting this PR. I reviewed the change and ran the tests above.