@adobe/design-data-spec 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/conformance/README.md +2 -2
- package/conformance/generation/README.md +6 -6
- package/conformance/generation/mode-set-edit/input/tokens.tokens.json +3 -3
- package/conformance/generation/mode-set-token/input/tokens.tokens.json +2 -2
- package/conformance/reference/set-alias-dark/expected.json +1 -1
- package/conformance/reference/set-alias-dark/input/tokens.tokens.json +2 -2
- package/conformance/reference/set-alias-light/expected.json +1 -1
- package/conformance/reference/set-alias-light/input/tokens.tokens.json +2 -2
- package/package.json +1 -1
- package/rules/rules.yaml +17 -0
- package/spec/cascade.md +3 -1
- package/spec/token-format.md +28 -0
package/conformance/README.md
CHANGED
|
@@ -79,14 +79,14 @@ These fixtures verify the field-mapping contract in [Evolution — Legacy format
|
|
|
79
79
|
| Folder | Intent |
|
|
80
80
|
| --------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
81
81
|
| `generation/flat-token` | A single cascade token with no mode sets maps to a single keyed entry `{ slug: { value, uuid } }`. |
|
|
82
|
-
| `generation/mode-set-token` | Multiple cascade tokens sharing a `
|
|
82
|
+
| `generation/mode-set-token` | Multiple cascade tokens sharing a `conceptId` merge into a single `sets`-keyed entry. |
|
|
83
83
|
|
|
84
84
|
The Rust SDK drives these fixtures via `design-data migrate legacy-output` (see `sdk/core/src/legacy.rs`).
|
|
85
85
|
Consumer implementations MUST regenerate each `input/` and diff against `expected/` to claim conformance
|
|
86
86
|
with the output-generator determinism contract.
|
|
87
87
|
|
|
88
88
|
See [`generation/README.md`](generation/README.md) for the fixture format, the run command, and
|
|
89
|
-
documentation of the `
|
|
89
|
+
documentation of the `conceptId`/`set_schema` cascade grouping fields used in `mode-set-token`.
|
|
90
90
|
|
|
91
91
|
***
|
|
92
92
|
|
|
@@ -38,20 +38,20 @@ design-data migrate legacy-output <case>/input --output <case>/expected
|
|
|
38
38
|
| Case | What it exercises |
|
|
39
39
|
| ------------------ | ----------------------------------------------------------------------------------------------------------- |
|
|
40
40
|
| `flat-token` | Basic flat token conversion (property key derivation, field passthrough) |
|
|
41
|
-
| `mode-set-token` | Color-set reconstruction from per-mode cascade records (`
|
|
41
|
+
| `mode-set-token` | Color-set reconstruction from per-mode cascade records (`conceptId`/`set_schema`) |
|
|
42
42
|
| `deprecated-token` | `deprecated: "version"` string → `true` boolean; `deprecated_comment` passthrough; `plannedRemoval` dropped |
|
|
43
43
|
| `renamed-token` | `replaced_by: "<uuid>"` → `renamed: "<property-name>"` via global UUID→name map |
|
|
44
44
|
| `alias-rewire` | `$ref: "<uuid>"` → `value: "{<property-name>}"` (alias denormalization with UUID resolution) |
|
|
45
45
|
| `mode-set-edit` | `deprecated`/`renamed` hoisted to outer set level when consistent across all mode entries |
|
|
46
46
|
|
|
47
|
-
## Cascade grouping fields (`
|
|
47
|
+
## Cascade grouping fields (`conceptId` / `set_schema`)
|
|
48
48
|
|
|
49
49
|
The `mode-set-token` and `mode-set-edit` fixtures use two cascade-internal grouping fields:
|
|
50
50
|
|
|
51
|
-
| Field | Type | Role
|
|
52
|
-
| ------------ | ------ |
|
|
53
|
-
| `
|
|
54
|
-
| `set_schema` | string | The `$schema` URI of the aggregate set token emitted at the outer (non-mode-keyed) level in the legacy output (e.g. `color-set.json`).
|
|
51
|
+
| Field | Type | Role |
|
|
52
|
+
| ------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| `conceptId` | string | Canonical concept-level UUID shared by every mode row of a design concept. The SDK registers this as `conceptId → child-key list` in `sdk/core/src/graph.rs` and the legacy generator collapses all records sharing a `conceptId` into a single `sets`-keyed output object. |
|
|
54
|
+
| `set_schema` | string | The `$schema` URI of the aggregate set token emitted at the outer (non-mode-keyed) level in the legacy output (e.g. `color-set.json`). |
|
|
55
55
|
|
|
56
56
|
These fields are not yet in the normative token-format field table — they are Rust SDK
|
|
57
57
|
implementation fields defined in `sdk/core/src/graph.rs` and emitted by the cascade ingest
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
10
10
|
"value": "rgb(20, 115, 230)",
|
|
11
11
|
"uuid": "11111111-0001-4000-8000-000000000001",
|
|
12
|
-
"
|
|
12
|
+
"conceptId": "11111111-0003-4000-8000-000000000003",
|
|
13
13
|
"set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
|
|
14
14
|
"lifecycle": {
|
|
15
15
|
"deprecatedIn": true,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
27
27
|
"value": "rgb(56, 145, 254)",
|
|
28
28
|
"uuid": "11111111-0002-4000-8000-000000000002",
|
|
29
|
-
"
|
|
29
|
+
"conceptId": "11111111-0003-4000-8000-000000000003",
|
|
30
30
|
"set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
|
|
31
31
|
"lifecycle": {
|
|
32
32
|
"deprecatedIn": true,
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
39
39
|
"value": "rgb(20, 115, 230)",
|
|
40
40
|
"uuid": "11111111-0004-4000-8000-000000000004",
|
|
41
|
-
"
|
|
41
|
+
"conceptId": "11111111-0005-4000-8000-000000000005",
|
|
42
42
|
"set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json"
|
|
43
43
|
}
|
|
44
44
|
]
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
10
10
|
"value": "rgb(245, 249, 255)",
|
|
11
11
|
"uuid": "bbbbbbbb-0001-4000-8000-000000000001",
|
|
12
|
-
"
|
|
12
|
+
"conceptId": "cccccccc-0001-4000-8000-000000000001",
|
|
13
13
|
"set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
|
|
14
14
|
"private": true
|
|
15
15
|
},
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
24
24
|
"value": "rgb(14, 23, 63)",
|
|
25
25
|
"uuid": "bbbbbbbb-0002-4000-8000-000000000002",
|
|
26
|
-
"
|
|
26
|
+
"conceptId": "cccccccc-0001-4000-8000-000000000001",
|
|
27
27
|
"set_schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color-set.json",
|
|
28
28
|
"private": true
|
|
29
29
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "A set-level alias ($ref targeting a
|
|
2
|
+
"description": "A set-level alias ($ref targeting a conceptId) MUST resolve to the mode-appropriate child. Under colorScheme=dark, accent-color-900 → blue-900 dark (different value from light).",
|
|
3
3
|
"resolved": true,
|
|
4
4
|
"expected_value": "rgb(75, 117, 255)",
|
|
5
5
|
"expected_chain_length": 3,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
10
10
|
"value": "rgb(59, 99, 251)",
|
|
11
11
|
"uuid": "ref-blue900-light-0000-000000000002",
|
|
12
|
-
"
|
|
12
|
+
"conceptId": "ref-blue900-set-000-0000-000000000002"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
22
22
|
"value": "rgb(75, 117, 255)",
|
|
23
23
|
"uuid": "ref-blue900-dark-0000-000000000002",
|
|
24
|
-
"
|
|
24
|
+
"conceptId": "ref-blue900-set-000-0000-000000000002"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"name": { "property": "accent-color-900" },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "A set-level alias ($ref targeting a
|
|
2
|
+
"description": "A set-level alias ($ref targeting a conceptId) MUST resolve to the mode-appropriate child. Under colorScheme=light, accent-color-900 → blue-900 light.",
|
|
3
3
|
"resolved": true,
|
|
4
4
|
"expected_value": "rgb(59, 99, 251)",
|
|
5
5
|
"expected_chain_length": 3,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
10
10
|
"value": "rgb(59, 99, 251)",
|
|
11
11
|
"uuid": "ref-blue900-light-0000-000000000001",
|
|
12
|
-
"
|
|
12
|
+
"conceptId": "ref-blue900-set-000-0000-000000000001"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/token-types/color.json",
|
|
22
22
|
"value": "rgb(75, 117, 255)",
|
|
23
23
|
"uuid": "ref-blue900-dark-0000-000000000001",
|
|
24
|
-
"
|
|
24
|
+
"conceptId": "ref-blue900-set-000-0000-000000000001"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"name": { "property": "accent-color-900" },
|
package/package.json
CHANGED
package/rules/rules.yaml
CHANGED
|
@@ -707,3 +707,20 @@ rules:
|
|
|
707
707
|
message: "Relationship $ref {ref} resolves to a token deprecated in {deprecatedIn}"
|
|
708
708
|
spec_ref: spec/relationship-format.md#legacy-fields-interim
|
|
709
709
|
introduced_in: "1.0.0-draft"
|
|
710
|
+
|
|
711
|
+
- id: SPEC-059
|
|
712
|
+
name: alias-mode-context-compatibility
|
|
713
|
+
severity: warning
|
|
714
|
+
layer: 2
|
|
715
|
+
category: reference-integrity
|
|
716
|
+
note: >
|
|
717
|
+
Mode analogue of SPEC-002. A `$ref` target that is a `conceptId` (see
|
|
718
|
+
token-format.md#concept-identity-conceptid) is context-resolved elsewhere and exempt
|
|
719
|
+
here; only a direct per-value target is checked.
|
|
720
|
+
assert: >
|
|
721
|
+
An alias whose name object sets a mode-set field (e.g. `colorScheme: dark`) SHOULD NOT
|
|
722
|
+
resolve, via its `$ref` chain, to a per-value token that sets the same field to a
|
|
723
|
+
different value. Tokens whose name object omits the field (mode-agnostic) are exempt.
|
|
724
|
+
message: "Alias {token} sets {field}={ownValue} but its $ref chain resolves to a token with {field}={leafValue}"
|
|
725
|
+
spec_ref: spec/cascade.md#alias-resolution
|
|
726
|
+
introduced_in: "1.0.0-draft"
|
package/spec/cascade.md
CHANGED
|
@@ -57,7 +57,9 @@ Exact matching rules for omitted mode sets are defined alongside mode set declar
|
|
|
57
57
|
|
|
58
58
|
**NORMATIVE:** If the winning candidate is an alias, its `$ref` chain **MUST** be resolved to a literal value using the standard alias-resolution rules (SPEC-001 through SPEC-003 in `rules/rules.yaml`). The alias target is resolved within the same dataset (i.e. the same merged layer stack), not relative to any single layer. In cascade format, `$ref` holds the **UUID** of the target token (see [`token-format.md` §Alias](token-format.md#alias-ref)); resolution proceeds UUID-first, then direct graph key (legacy slug), then serialised name.
|
|
59
59
|
|
|
60
|
-
**
|
|
60
|
+
**NORMATIVE:** When a `$ref` target is a **`conceptId`** (see [`token-format.md` §Concept identity](token-format.md#concept-identity-conceptid)) rather than a per-row `uuid`, resolution **MUST** pick the mode row registered under that `conceptId` whose name-object fields best match the referencing token's own resolution context (greatest count of matching mode-set key/value pairs). Ties **MUST** be broken by the lexicographically smallest `uuid` among equally-scoring rows, so repeated resolution of the same alias always returns the same token. This context-aware step runs in place of, not in addition to, the UUID-first/direct-key/name fallback above — a `conceptId` target either resolves to its best-matching row or (when no rows are registered under it) falls through to the standard chain.
|
|
61
|
+
|
|
62
|
+
**RATIONALE:** Aliases participate in cascade as opaque references — their target values are not examined during specificity calculation or layer comparison. This keeps resolution deterministic and allows aliases to be valid candidates at any specificity level. Resolving a `conceptId` target against the *referencing* token's own context (rather than always the first or an arbitrary row) is what lets one alias correctly track a multi-mode concept (e.g. a semantic color that must stay light/dark-aligned with whatever aliases to it) without one alias per mode.
|
|
61
63
|
|
|
62
64
|
## Cross-mode-set overrides
|
|
63
65
|
|
package/spec/token-format.md
CHANGED
|
@@ -128,6 +128,34 @@ When **`$ref`** is present, the token is an **alias**. The value **MUST** be a n
|
|
|
128
128
|
"uuid": "f24eb871-6419-4cef-88a2-cca8548ae31e" }
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
### Concept identity (`conceptId`)
|
|
132
|
+
|
|
133
|
+
**`conceptId`** is a UUID shared by every mode row of the same design concept — e.g. the light,
|
|
134
|
+
dark, and wireframe rows of one color, or the mobile/desktop rows of one scale. It is additive to
|
|
135
|
+
the per-value `uuid` (which remains the `$ref`/diff/`replacedBy`/sync anchor for one specific mode
|
|
136
|
+
row) and, unlike `uuid`, is stable across the whole concept rather than one row.
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
// Two mode rows of the same concept share one conceptId, each with its own uuid.
|
|
140
|
+
{ "name": { "property": "accent-color", "colorScheme": "light" },
|
|
141
|
+
"value": "rgb(59, 99, 251)",
|
|
142
|
+
"uuid": "aaaaaaaa-0000-4000-8000-000000000001",
|
|
143
|
+
"conceptId": "cccccccc-0000-4000-8000-000000000099" }
|
|
144
|
+
{ "name": { "property": "accent-color", "colorScheme": "dark" },
|
|
145
|
+
"value": "rgb(75, 117, 255)",
|
|
146
|
+
"uuid": "aaaaaaaa-0000-4000-8000-000000000002",
|
|
147
|
+
"conceptId": "cccccccc-0000-4000-8000-000000000099" }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**NORMATIVE:** All mode rows of the same design concept **MUST** carry the same `conceptId`.
|
|
151
|
+
|
|
152
|
+
**NORMATIVE:** A `$ref` target **MAY** be a `conceptId` instead of a per-row `uuid`. When it is,
|
|
153
|
+
resolution **MUST** pick the mode row registered under that `conceptId` whose name-object fields
|
|
154
|
+
best match the referencing token's own resolution context (see
|
|
155
|
+
[Cascade resolution — Alias resolution](cascade.md#alias-resolution)), rather than an arbitrary
|
|
156
|
+
row — this is what makes a single alias correctly track light/dark or mobile/desktop without one
|
|
157
|
+
alias per mode.
|
|
158
|
+
|
|
131
159
|
### Literal `value`
|
|
132
160
|
|
|
133
161
|
When **`value`** is present, it **MUST** conform to the declared value type for that token. Value types are defined under `schemas/value-types/` and referenced from the token schema.
|