Commit a467ca3
feat(sdk,spec): Phase 2 cascade token format, resolution engine, migration tooling (#770)
* docs(spec): resolve Wave 0 decisions for Phase 2 cascade work
- spec/cascade.md: replace implementation-defined tie-breaking with
normative document-order rule (earlier in array wins; lexicographically
earlier file path wins across files); closes #757
- spec/cascade.md: add Alias resolution section specifying that $ref
chains MUST resolve after cascade selection; closes #758
- rules/rules.yaml: update SPEC-006 message and assert to reference
the deterministic tie-breaking algorithm
- spec/token-format.md: add RFC #646 relationship section documenting
that the flat name object is canonical, and how it differs from the
RFC's name.structure / name.original shape; closes #759
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(spec): cascade file schema, dimension declarations, document shape
- schemas/cascade-file.schema.json: new Layer 1 schema for cascade token
files; ordered array of token objects with document-order tie-breaking
semantics; closes #756
- spec/token-format.md: add document shape section specifying array
envelope, .tokens.json extension recommendation, and example
- dimensions/color-scheme.json: declare colorScheme dimension (light,
dark, wireframe; default: light)
- dimensions/scale.json: declare scale dimension (desktop, mobile;
default: desktop; keeps legacy mode names per phase 2 decisions)
- dimensions/contrast.json: declare contrast dimension (regular, high;
default: regular)
- spec/dimensions.md: update built-in dimensions table with actual modes
and defaults; add dimension catalog section with discovery convention;
closes #746
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk): cascade resolution engine, dimension loader, CLI resolve command
graph.rs:
- add index field to TokenRecord for document-order tie-breaking
- extend from_json_dir to handle cascade-format array files
- add load_spec_dimensions() to load from spec dimensions/ catalog
cascade.rs (new):
- ResolutionContext builder for dimension → mode pairs
- specificity(): count non-default dimension fields; closes #745
- matches_context(): wildcard matching for absent dimensions; closes #761
- resolve(): full cascade algorithm (filter → specificity → tie-break)
with 8 unit tests; closes #744
cli/src/main.rs:
- add --dimensions-path flag to validate command; closes #760
- add resolve subcommand with --color-scheme, --scale, --contrast flags
and pretty/json output formats; closes #764
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk): set-to-cascade migration converter and CLI convert command
Implements Wave 3 of Phase 2:
- sdk/core/src/migrate.rs: convert_token() splits color-set/scale-set
entries into individual cascade tokens; convert_dir() processes a
directory of legacy files and writes .tokens.json output files.
Alias syntax `value: "{foo}"` → `$ref: "foo"`, outer lifecycle fields
propagate to all mode tokens, entry-level values override outer.
8 unit tests covering all conversion paths.
- sdk/core/src/lib.rs: exports pub mod migrate
- sdk/cli/src/main.rs: adds `design-data migrate convert <INPUT>
--output <OUTPUT>` subcommand (closes #765)
- sdk/core/src/validate/structural.rs: structural validator now accepts
cascade-format files (top-level JSON arrays) in addition to legacy
object maps — validates each element against its individual $schema
(closes #767)
Closes #743, #765, #767
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk): add SPEC-008 cascade-completeness and SPEC-009 name-field-enum-sync rules
Wave 4 of Phase 2:
- packages/design-data-spec/rules/rules.yaml: adds SPEC-008 and SPEC-009
rule definitions to the normative catalog
- sdk/core/src/validate/rules/spec008.rs: warns when a cascade token
property has non-default dimension mode variants but no base/default
variant, which would cause resolution gaps (closes #762)
- sdk/core/src/validate/rules/spec009.rs: stub for registry/enum sync
validation; emits no diagnostics until design-system-registry data is
threaded into ValidationContext (closes #763 — structure in place)
- sdk/core/src/validate/rules/mod.rs: wires SPEC-008 and SPEC-009 into
the default rule set
4 new tests covering spec008 base/default/no-dim-declarations behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk,spec): resolution conformance and migration roundtrip test suites
Wave 5 of Phase 2:
- packages/design-data-spec/conformance/resolution/: three fixture cases
covering base-fallback (wildcard), specificity-wins, and
alias-resolved-after-cascade scenarios (closes #768)
- sdk/core/src/lib.rs: resolution_conformance module drives all three
fixtures against the real cascade::resolve() engine; migration_roundtrip
module verifies color-set and scale-set conversion outputs are loadable
and resolve correctly (closes #769)
- relational_conformance: adds spec008 conformance test
- packages/design-data-spec/conformance/README.md: documents resolution
fixture format and table
46 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk,spec): dimensions in validate pipeline, SPEC-008 fixture, legacy output generator
Three gap-fills for the Phase 2 PR:
- sdk/core/src/validate/mod.rs: adds validate_all_with_options() that
accepts an optional dimensions_path; loads spec-format dimension
declarations into the graph before running relational rules so that
SPEC-008 can fire during 'design-data validate'. Previous
validate_all_with_exceptions() now delegates to this function.
- sdk/cli/src/main.rs: wires --dimensions-path into run_validate() via
validate_all_with_options(); adds 'design-data migrate legacy-output
<INPUT> --output <OUTPUT>' subcommand (closes #766)
- packages/design-data-spec/conformance/invalid/SPEC-008/: portable
fixture files (cascade tokens + dimension declaration + expected-errors)
that any implementation can use to verify SPEC-008 enforcement
- sdk/core/src/legacy.rs: inverse of migrate.rs — converts cascade
.tokens.json arrays back to legacy set-format JSON objects; groups
tokens by property, reconstructs color-set/scale-set wrappers, hoists
consistent lifecycle fields to outer level, denormalizes $ref back to
value: "{foo}" alias syntax; 7 unit tests (closes #766)
53 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sdk): p1 cascade duplicate uuid/name dropped before validation, multi-dim lossy output
- graph: key cascade tokens by file:index (always unique) instead of uuid/serialized-name
so SPEC-004 and SPEC-006 see all duplicates before deduplication
- graph: add uuid_index (uuid -> primary key) for alias $ref resolution in resolve_leaf
- legacy: collect_dimension_keys replaces detect_dimension_key; returns BTreeSet of all
recognized dimension keys in a property group
- legacy: convert_array now returns Result; errors with MultiDimensionalToken when a
property group spans more than one dimension (colorScheme x scale etc.) instead of
silently emitting a lossy legacy file
- lib: add MultiDimensionalToken CoreError variant
- lib: add TempDir-isolated regression tests for SPEC-004 and SPEC-006 cascade paths
- core: add tempfile dev-dependency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent b0a7864 commit a467ca3
41 files changed
Lines changed: 2632 additions & 43 deletions
File tree
- packages/design-data-spec
- conformance
- invalid/SPEC-008
- resolution
- alias-resolved-after-cascade
- dimensions
- input
- base-fallback
- dimensions
- input
- specificity-wins
- dimensions
- input
- dimensions
- rules
- schemas
- spec
- sdk
- cli
- src
- tests
- core
- src
- validate
- rules
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
6 | | - | |
| 5 | + | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
Lines changed: 10 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
Lines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
Lines changed: 12 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
0 commit comments