@adobe/design-data-spec 0.1.1 → 0.2.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 +26 -27
- package/conformance/invalid/SPEC-016/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-016/tokens.tokens.json +8 -0
- package/conformance/invalid/SPEC-017/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-017/tokens.tokens.json +7 -0
- package/conformance/valid/composite-drop-shadow.json +14 -0
- package/conformance/valid/composite-typography-scale.json +6 -0
- package/conformance/valid/composite-typography.json +12 -0
- package/conformance/valid/string-name-escape-hatch.json +7 -0
- package/fields/scaleIndex.json +15 -0
- package/package.json +1 -1
- package/rules/rules.yaml +32 -5
- package/schemas/field.schema.json +2 -2
- package/schemas/token.schema.json +26 -10
- package/schemas/value-types/drop-shadow.schema.json +20 -0
- package/schemas/value-types/typography-scale.schema.json +13 -0
- package/schemas/value-types/typography.schema.json +16 -0
- package/spec/evolution.md +32 -33
- package/spec/manifest.md +1 -3
- package/spec/taxonomy.md +1 -17
- package/spec/token-format.md +80 -15
- package/conformance/invalid/SPEC-014/expected-errors.json +0 -10
- package/conformance/invalid/SPEC-014/tokens.tokens.json +0 -9
- package/conformance/valid/lifecycle-with-last-modified.json +0 -12
package/conformance/README.md
CHANGED
|
@@ -16,7 +16,6 @@ Each **invalid** case lives under `invalid/<RULE_ID>/` with:
|
|
|
16
16
|
| `invalid/SPEC-005` | SPEC-005 | Dimension `default` not in `modes`. |
|
|
17
17
|
| `invalid/SPEC-006` | SPEC-006 | Ambiguous resolution / specificity tie (warning). |
|
|
18
18
|
| `invalid/SPEC-008` | SPEC-008 | Non-default mode variants with no base/default variant. |
|
|
19
|
-
| `invalid/SPEC-014` | SPEC-014 | `lastModified` semver precedes `introduced`. |
|
|
20
19
|
|
|
21
20
|
Implementors SHOULD run these fixtures once the Rust validator exposes rule IDs ([#724](https://github.com/adobe/spectrum-design-data/issues/724), [#725](https://github.com/adobe/spectrum-design-data/issues/725)).
|
|
22
21
|
|
|
@@ -49,20 +48,20 @@ Each **diff** case lives under `diff/<name>/` with:
|
|
|
49
48
|
* `new/` — new token dataset
|
|
50
49
|
* `expected.json` — full `DiffReport` structure (six category arrays: renamed, deprecated, reverted, added, deleted, updated)
|
|
51
50
|
|
|
52
|
-
| Folder
|
|
53
|
-
|
|
|
54
|
-
| `diff/identical-tokens`
|
|
55
|
-
| `diff/simple-add-delete`
|
|
56
|
-
| `diff/rename-by-uuid`
|
|
57
|
-
| `diff/deprecated-new-token`
|
|
58
|
-
| `diff/deprecated-set-level`
|
|
59
|
-
| `diff/reverted-token`
|
|
60
|
-
| `diff/matched-gaining-deprecated`
|
|
61
|
-
| `diff/property-value-update`
|
|
62
|
-
| `diff/property-nested-change`
|
|
63
|
-
| `diff/uuid-backfill`
|
|
64
|
-
| `diff/cross-format`
|
|
65
|
-
| `diff/rename-with-property-changes`
|
|
51
|
+
| Folder | Intent |
|
|
52
|
+
| ------------------------------------- | -------------------------------------------------------------------------------- |
|
|
53
|
+
| `diff/identical-tokens` | Two identical datasets MUST produce an empty diff (all arrays empty). |
|
|
54
|
+
| `diff/simple-add-delete` | One old-only token → deleted; one new-only token → added. |
|
|
55
|
+
| `diff/rename-by-uuid` | Same UUID, different name objects → renamed (not add + delete). |
|
|
56
|
+
| `diff/deprecated-new-token` | Unmatched new token with `deprecated: true` → deprecated (not added). |
|
|
57
|
+
| `diff/deprecated-set-level` | All set entries `deprecated: true` normalizes to token-level deprecated. |
|
|
58
|
+
| `diff/reverted-token` | Matched token that loses `deprecated` → reverted (not updated). |
|
|
59
|
+
| `diff/matched-gaining-deprecated` | Matched token that gains `deprecated` → updated (not deprecated). |
|
|
60
|
+
| `diff/property-value-update` | Matched token with changed `value` → updated with property change. |
|
|
61
|
+
| `diff/property-nested-change` | Nested object change reported at leaf path (e.g. `sets.light.value`). |
|
|
62
|
+
| `diff/uuid-backfill` | Old lacks UUID, new gains it with same name object → paired (not add + delete). |
|
|
63
|
+
| `diff/cross-format` | Legacy old + cascade new, paired by UUID across formats. |
|
|
64
|
+
| `diff/rename-with-property-changes` | Renamed token with additional value changes populates `property_changes`. |
|
|
66
65
|
|
|
67
66
|
The Rust SDK drives these fixtures in `sdk/core/src/lib.rs` (`diff_conformance` module, closes [#788](https://github.com/adobe/spectrum-design-data/issues/788)).
|
|
68
67
|
|
|
@@ -76,17 +75,17 @@ Each **query** case lives under `query/<name>/` with:
|
|
|
76
75
|
* `query.txt` — plain-text filter expression
|
|
77
76
|
* `expected.json` — sorted array of matched token UUIDs
|
|
78
77
|
|
|
79
|
-
| Folder
|
|
80
|
-
|
|
|
81
|
-
| `query/single-field`
|
|
82
|
-
| `query/and-conditions`
|
|
83
|
-
| `query/or-conditions`
|
|
84
|
-
| `query/negation`
|
|
85
|
-
| `query/wildcard-suffix`
|
|
86
|
-
| `query/wildcard-prefix`
|
|
87
|
-
| `query/empty-matches-all`
|
|
88
|
-
| `query/no-matches`
|
|
89
|
-
| `query/schema-key`
|
|
90
|
-
| `query/and-or-precedence`
|
|
78
|
+
| Folder | Intent |
|
|
79
|
+
| ----------------------------- | ------------------------------------------------------------------------- |
|
|
80
|
+
| `query/single-field` | Basic `key=value` equality filter. |
|
|
81
|
+
| `query/and-conditions` | `,` (AND) requires all conditions to match. |
|
|
82
|
+
| `query/or-conditions` | `\|` (OR) matches if any alternative matches. |
|
|
83
|
+
| `query/negation` | `!=` matches non-equal values and absent fields. |
|
|
84
|
+
| `query/wildcard-suffix` | Glob `*` at end of value matches prefix. |
|
|
85
|
+
| `query/wildcard-prefix` | Glob `*` at start of value matches suffix. |
|
|
86
|
+
| `query/empty-matches-all` | Empty filter expression is a universal match. |
|
|
87
|
+
| `query/no-matches` | Filter with no matching tokens returns empty result. |
|
|
88
|
+
| `query/schema-key` | `$schema` key queries the top-level `$schema` field. |
|
|
89
|
+
| `query/and-or-precedence` | AND binds tighter than OR: `a,b\|c` = `(a AND b) OR c`. |
|
|
91
90
|
|
|
92
91
|
The Rust SDK drives these fixtures in `sdk/core/src/lib.rs` (`query_conformance` module, closes [#788](https://github.com/adobe/spectrum-design-data/issues/788)).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": { "property": "drop-shadow-default" },
|
|
3
|
+
"$valueType": "value-types/drop-shadow.schema.json",
|
|
4
|
+
"value": [
|
|
5
|
+
{
|
|
6
|
+
"x": "0px",
|
|
7
|
+
"y": "1px",
|
|
8
|
+
"blur": "4px",
|
|
9
|
+
"spread": "0px",
|
|
10
|
+
"color": "rgba(0, 0, 0, 0.16)"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"uuid": "aaaaaaaa-0010-4000-8000-000000000002"
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": { "property": "component-m-regular" },
|
|
3
|
+
"$valueType": "value-types/typography.schema.json",
|
|
4
|
+
"value": {
|
|
5
|
+
"fontFamily": "{sans-serif-font-family}",
|
|
6
|
+
"fontSize": "{font-size-100}",
|
|
7
|
+
"fontWeight": "{regular-font-weight}",
|
|
8
|
+
"letterSpacing": "{letter-spacing}",
|
|
9
|
+
"lineHeight": "{line-height-font-size-100}"
|
|
10
|
+
},
|
|
11
|
+
"uuid": "aaaaaaaa-0010-4000-8000-000000000001"
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/field.schema.json",
|
|
3
|
+
"specVersion": "1.0.0-draft",
|
|
4
|
+
"name": "scaleIndex",
|
|
5
|
+
"description": "Numeric scale index appended at the end of the serialized name (e.g., 100, 200, 900). Used by foundational scale tokens for spacing, color palette, font sizes, border widths, corner radii, and drop-shadow values.",
|
|
6
|
+
"kind": "numeric",
|
|
7
|
+
"registry": null,
|
|
8
|
+
"validation": "none",
|
|
9
|
+
"serialization": {
|
|
10
|
+
"position": 16
|
|
11
|
+
},
|
|
12
|
+
"scope": null,
|
|
13
|
+
"required": false,
|
|
14
|
+
"valueType": "integer"
|
|
15
|
+
}
|
package/package.json
CHANGED
package/rules/rules.yaml
CHANGED
|
@@ -120,10 +120,37 @@ rules:
|
|
|
120
120
|
introduced_in: "1.0.0-draft"
|
|
121
121
|
|
|
122
122
|
- id: SPEC-014
|
|
123
|
-
name:
|
|
123
|
+
name: composite-inline-alias-exists
|
|
124
124
|
severity: error
|
|
125
|
-
category:
|
|
126
|
-
assert:
|
|
127
|
-
message: "
|
|
128
|
-
spec_ref: spec/token-format.md#
|
|
125
|
+
category: reference-integrity
|
|
126
|
+
assert: Inline alias references ({token-name}) within composite values MUST resolve to an existing token in the dataset.
|
|
127
|
+
message: "Inline alias target not found within composite value: {path}"
|
|
128
|
+
spec_ref: spec/token-format.md#inline-alias-references
|
|
129
|
+
introduced_in: "1.0.0-draft"
|
|
130
|
+
|
|
131
|
+
- id: SPEC-015
|
|
132
|
+
name: composite-inline-alias-type-compatible
|
|
133
|
+
severity: error
|
|
134
|
+
category: type-safety
|
|
135
|
+
assert: Resolved inline alias target within a composite value MUST have a value type compatible with the sub-value's expected type.
|
|
136
|
+
message: "Inline alias {path} within composite resolves to incompatible type"
|
|
137
|
+
spec_ref: spec/token-format.md#inline-alias-references
|
|
138
|
+
introduced_in: "1.0.0-draft"
|
|
139
|
+
|
|
140
|
+
- id: SPEC-016
|
|
141
|
+
name: value-type-match
|
|
142
|
+
severity: error
|
|
143
|
+
category: type-safety
|
|
144
|
+
assert: When $valueType is present on a token with a literal value, the value MUST validate against the referenced value-type schema.
|
|
145
|
+
message: "Token {token} value does not validate against declared $valueType schema {schema}"
|
|
146
|
+
spec_ref: spec/token-format.md#value-type-declaration-valuetype
|
|
147
|
+
introduced_in: "1.0.0-draft"
|
|
148
|
+
|
|
149
|
+
- id: SPEC-017
|
|
150
|
+
name: string-name-tech-debt
|
|
151
|
+
severity: warning
|
|
152
|
+
category: tech-debt
|
|
153
|
+
assert: Token names SHOULD be structured name objects. A plain string name is permitted as a temporary escape hatch but MUST be treated as tech debt and tracked for remediation.
|
|
154
|
+
message: 'Token "{name}" uses a string name instead of a name object — treat as tech debt and plan remediation'
|
|
155
|
+
spec_ref: spec/token-format.md#string-name-escape-hatch
|
|
129
156
|
introduced_in: "1.0.0-draft"
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"kind": {
|
|
25
25
|
"type": "string",
|
|
26
|
-
"enum": ["semantic", "dimension"],
|
|
27
|
-
"description": "Whether this field participates in cascade resolution. 'dimension' fields drive cascade specificity; '
|
|
26
|
+
"enum": ["semantic", "dimension", "numeric"],
|
|
27
|
+
"description": "Whether this field participates in serialization ordering or cascade resolution. 'semantic' fields describe identity and appear in the standard serialization order; 'dimension' fields drive cascade specificity; 'numeric' fields hold integer indices appended at the end of the serialized name."
|
|
28
28
|
},
|
|
29
29
|
"registry": {
|
|
30
30
|
"oneOf": [
|
|
@@ -99,7 +99,19 @@
|
|
|
99
99
|
"const": "1.0.0-draft"
|
|
100
100
|
},
|
|
101
101
|
"name": {
|
|
102
|
-
"
|
|
102
|
+
"oneOf": [
|
|
103
|
+
{ "$ref": "#/$defs/nameObject" },
|
|
104
|
+
{
|
|
105
|
+
"type": "string",
|
|
106
|
+
"minLength": 1,
|
|
107
|
+
"description": "String escape hatch for tokens that cannot be expressed as a name object. Valid but triggers SPEC-017 (tech-debt warning). See token-format.md#string-name-escape-hatch."
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"$valueType": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"format": "uri-reference",
|
|
114
|
+
"description": "URI reference to a value-type schema under schemas/value-types/. When present, value MUST validate against the referenced schema (rule SPEC-016)."
|
|
103
115
|
},
|
|
104
116
|
"value": {
|
|
105
117
|
"description": "Literal value; type narrowed by value-type schemas where applicable.",
|
|
@@ -131,10 +143,6 @@
|
|
|
131
143
|
"introduced": {
|
|
132
144
|
"type": "string"
|
|
133
145
|
},
|
|
134
|
-
"lastModified": {
|
|
135
|
-
"type": "string",
|
|
136
|
-
"description": "Spec version when token value or metadata last changed (e.g. \"2.1.0\"). MUST be >= introduced (see SPEC-014)."
|
|
137
|
-
},
|
|
138
146
|
"deprecated": {
|
|
139
147
|
"type": "string",
|
|
140
148
|
"description": "Spec version when token was deprecated (e.g. \"3.2.0\"). Truthy = deprecated."
|
|
@@ -178,7 +186,19 @@
|
|
|
178
186
|
"const": "1.0.0-draft"
|
|
179
187
|
},
|
|
180
188
|
"name": {
|
|
181
|
-
"
|
|
189
|
+
"oneOf": [
|
|
190
|
+
{ "$ref": "#/$defs/nameObject" },
|
|
191
|
+
{
|
|
192
|
+
"type": "string",
|
|
193
|
+
"minLength": 1,
|
|
194
|
+
"description": "String escape hatch for tokens that cannot be expressed as a name object. Valid but triggers SPEC-017 (tech-debt warning). See token-format.md#string-name-escape-hatch."
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
"$valueType": {
|
|
199
|
+
"type": "string",
|
|
200
|
+
"format": "uri-reference",
|
|
201
|
+
"description": "URI reference to a value-type schema under schemas/value-types/. When present, the alias resolution chain MUST terminate at a token whose value validates against this schema."
|
|
182
202
|
},
|
|
183
203
|
"$ref": {
|
|
184
204
|
"type": "string",
|
|
@@ -192,10 +212,6 @@
|
|
|
192
212
|
"introduced": {
|
|
193
213
|
"type": "string"
|
|
194
214
|
},
|
|
195
|
-
"lastModified": {
|
|
196
|
-
"type": "string",
|
|
197
|
-
"description": "Spec version when token value or metadata last changed (e.g. \"2.1.0\"). MUST be >= introduced (see SPEC-014)."
|
|
198
|
-
},
|
|
199
215
|
"deprecated": {
|
|
200
216
|
"type": "string",
|
|
201
217
|
"description": "Spec version when token was deprecated (e.g. \"3.2.0\"). Truthy = deprecated."
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/value-types/drop-shadow.schema.json",
|
|
4
|
+
"title": "Drop shadow composite value",
|
|
5
|
+
"description": "Array of shadow layers. Each layer defines offset, blur, spread, and color.",
|
|
6
|
+
"type": "array",
|
|
7
|
+
"items": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"x": { "type": "string" },
|
|
11
|
+
"y": { "type": "string" },
|
|
12
|
+
"blur": { "type": "string" },
|
|
13
|
+
"spread": { "type": "string" },
|
|
14
|
+
"color": { "type": "string" }
|
|
15
|
+
},
|
|
16
|
+
"required": ["x", "y", "blur", "spread", "color"],
|
|
17
|
+
"additionalProperties": false
|
|
18
|
+
},
|
|
19
|
+
"minItems": 1
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/value-types/typography-scale.schema.json",
|
|
4
|
+
"title": "Typography scale composite value",
|
|
5
|
+
"description": "Pairs a font size with its corresponding line height at a single typographic tier.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"fontSize": { "type": "string" },
|
|
9
|
+
"lineHeight": { "type": "string" }
|
|
10
|
+
},
|
|
11
|
+
"required": ["fontSize", "lineHeight"],
|
|
12
|
+
"additionalProperties": false
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://opensource.adobe.com/spectrum-design-data/schemas/v0/value-types/typography.schema.json",
|
|
4
|
+
"title": "Typography composite value",
|
|
5
|
+
"description": "Object bundling font properties for a typographic style. Sub-values may be literal strings or inline alias references ({token-name}).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"fontFamily": { "type": "string" },
|
|
9
|
+
"fontSize": { "type": "string" },
|
|
10
|
+
"fontWeight": { "type": "string" },
|
|
11
|
+
"letterSpacing": { "type": "string" },
|
|
12
|
+
"lineHeight": { "type": "string" }
|
|
13
|
+
},
|
|
14
|
+
"required": ["fontFamily", "fontSize", "fontWeight", "lineHeight"],
|
|
15
|
+
"additionalProperties": false
|
|
16
|
+
}
|
package/spec/evolution.md
CHANGED
|
@@ -12,13 +12,13 @@ Tokens progress through the following lifecycle stages:
|
|
|
12
12
|
introduced → active → deprecated → planned removal → removed
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
| Stage | Token state
|
|
16
|
-
| ------------------- |
|
|
17
|
-
| **Introduced** | Token first appears in the dataset. `introduced` field records the version.
|
|
18
|
-
| **Active** | Token is current and recommended for use. No `deprecated` field.
|
|
15
|
+
| Stage | Token state |
|
|
16
|
+
| ------------------- | ------------------------------------------------------------------------------- |
|
|
17
|
+
| **Introduced** | Token first appears in the dataset. `introduced` field records the version. |
|
|
18
|
+
| **Active** | Token is current and recommended for use. No `deprecated` field. |
|
|
19
19
|
| **Deprecated** | Token is no longer recommended. `deprecated` records the version. Consumers receive warnings. `replaced_by` points to the successor token(s) when a direct replacement exists. |
|
|
20
|
-
| **Planned removal** | `plannedRemoval` records the target version. The token remains in the dataset but consumers should complete migration.
|
|
21
|
-
| **Removed** | Token is deleted from the dataset. Consumers that still reference it will break.
|
|
20
|
+
| **Planned removal** | `plannedRemoval` records the target version. The token remains in the dataset but consumers should complete migration. |
|
|
21
|
+
| **Removed** | Token is deleted from the dataset. Consumers that still reference it will break. |
|
|
22
22
|
|
|
23
23
|
### Lifecycle fields
|
|
24
24
|
|
|
@@ -28,10 +28,10 @@ See [Token format — Lifecycle and metadata](token-format.md#lifecycle-and-meta
|
|
|
28
28
|
|
|
29
29
|
When a token carries `replaced_by`:
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
- Each target UUID **MUST** resolve to an existing token in the dataset (rule `SPEC-010`).
|
|
32
|
+
- The target token **SHOULD NOT** itself be deprecated. Chains of replacements (A replaced by B, B replaced by C) are discouraged; authors should point directly to the final replacement.
|
|
33
|
+
- For a single UUID (1:1 replacement), consumers can mechanically rewrite references.
|
|
34
|
+
- For an array of UUIDs (one-to-many split), the `deprecated_comment` **MUST** explain which replacement applies in which context.
|
|
35
35
|
|
|
36
36
|
## Migration windows
|
|
37
37
|
|
|
@@ -49,27 +49,27 @@ The specification follows [Semantic Versioning](https://semver.org/) for its pub
|
|
|
49
49
|
|
|
50
50
|
### Minor changes (backward compatible)
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
- New tokens added to the dataset
|
|
53
|
+
- New optional fields added to token schema
|
|
54
|
+
- New validation rules added to the rule catalog
|
|
55
|
+
- Tokens deprecated (with `deprecated` field)
|
|
56
|
+
- Rule severity relaxed (error → warning)
|
|
57
|
+
- New enum values added to registries
|
|
58
58
|
|
|
59
59
|
### Major changes (breaking)
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
- Tokens removed from the dataset
|
|
62
|
+
- Required fields added to token schema
|
|
63
|
+
- Existing fields removed or type-changed
|
|
64
|
+
- Rule severity tightened (warning → error)
|
|
65
|
+
- Enum values removed from registries
|
|
66
|
+
- Constraint tightening (e.g. stricter value validation)
|
|
67
67
|
|
|
68
68
|
### Patch changes (clarifications)
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
- Typo fixes in spec prose
|
|
71
|
+
- Clarifications to normative text that do not change conformance behavior
|
|
72
|
+
- Test fixture additions or corrections
|
|
73
73
|
|
|
74
74
|
## Legacy format contract
|
|
75
75
|
|
|
@@ -79,14 +79,13 @@ The `@adobe/spectrum-tokens` package continues to publish tokens in the **legacy
|
|
|
79
79
|
|
|
80
80
|
### Lifecycle field mapping
|
|
81
81
|
|
|
82
|
-
| Cascade format
|
|
83
|
-
|
|
|
84
|
-
| `deprecated: "3.2.0"` (version string) | `deprecated: true` (boolean)
|
|
85
|
-
| `replaced_by: "<uuid>"` | `renamed: "<target-token-name>"`
|
|
86
|
-
| `introduced`
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `deprecated_comment` | `deprecated_comment` (passed through) |
|
|
82
|
+
| Cascade format | Legacy format |
|
|
83
|
+
| --------------------------------------- | ------------------------------------ |
|
|
84
|
+
| `deprecated: "3.2.0"` (version string) | `deprecated: true` (boolean) |
|
|
85
|
+
| `replaced_by: "<uuid>"` | `renamed: "<target-token-name>"` |
|
|
86
|
+
| `introduced` | Not emitted |
|
|
87
|
+
| `plannedRemoval` | Not emitted |
|
|
88
|
+
| `deprecated_comment` | `deprecated_comment` (passed through)|
|
|
90
89
|
|
|
91
90
|
### Coexistence during migration
|
|
92
91
|
|
package/spec/manifest.md
CHANGED
|
@@ -26,9 +26,7 @@ A manifest **MUST** conform to [`manifest.schema.json`](../schemas/manifest.sche
|
|
|
26
26
|
|
|
27
27
|
### `include` / `exclude`
|
|
28
28
|
|
|
29
|
-
**NORMATIVE:** Entries **MUST** be non-empty strings.
|
|
30
|
-
|
|
31
|
-
> **Note:** Query notation syntax is fully defined in [Query](query.md) and is normative for programmatic use. Its normative use in manifest `include`/`exclude` is deferred to a post-`1.0.0-draft` revision pending conformance fixtures; until then, implementations **MUST** treat manifest query values as opaque identifiers.
|
|
29
|
+
**NORMATIVE:** Entries **MUST** be non-empty strings. The **query language** is **not** normative in `1.0.0-draft`; treat values as opaque identifiers for tooling until a future spec version defines syntax.
|
|
32
30
|
|
|
33
31
|
### `overrides`
|
|
34
32
|
|
package/spec/taxonomy.md
CHANGED
|
@@ -77,23 +77,7 @@ Additional categories for variant and state are inherited from the existing name
|
|
|
77
77
|
| Variant | `variant` | Variant within a component (e.g. accent, negative, primary). |
|
|
78
78
|
| State | `state` | Interactive or semantic state (e.g. hover, focus, disabled). |
|
|
79
79
|
|
|
80
|
-
**NOTE:** The categories above are filtered for semantic and layout token taxonomies. Additional
|
|
81
|
-
|
|
82
|
-
### Structure vs. component — when does the line move?
|
|
83
|
-
|
|
84
|
-
The `structure` and `component` fields both answer "What?" but apply at different scopes. A useful rule of thumb:
|
|
85
|
-
|
|
86
|
-
* Use `component` when the token belongs to a specific component's surface (e.g. `button-background-color` — the background color of the Button component).
|
|
87
|
-
* Use `structure` when the token belongs to a reusable visual pattern that recurs **across** components (e.g. `container-padding` — padding for any container-shaped surface, regardless of which component owns it).
|
|
88
|
-
|
|
89
|
-
**Worked example — `card`:**
|
|
90
|
-
|
|
91
|
-
* As a `structure`: when "card" describes a layout primitive used inside many components (e.g. `card-padding-medium` on a list item, a popover body, or a modal header), the token is structure-scoped.
|
|
92
|
-
* As a `component`: when "card" describes the dedicated Card component's own surfaces (e.g. `card-background-color` on the Card root), the token is component-scoped.
|
|
93
|
-
|
|
94
|
-
The same word can validly appear in both fields across the dataset; they are independent. Authors choose based on whether the token's *meaning* generalizes across many components (structure) or is specific to one component's identity (component).
|
|
95
|
-
|
|
96
|
-
Source: Nate Baldwin, "Naming conventions & shared taxonomy" — Design Data & Platforms onsite, April 1, 2026.
|
|
80
|
+
**NOTE:** The categories above are filtered for semantic and layout token taxonomies. Additional categories do and will exist for other token types (e.g. color, typography). The taxonomy is built to scale as new concepts and terms are identified.
|
|
97
81
|
|
|
98
82
|
## Component anatomy vs. token objects
|
|
99
83
|
|
package/spec/token-format.md
CHANGED
|
@@ -12,13 +12,33 @@ A **token** is a JSON object that satisfies the Layer 1 schema [`token.schema.js
|
|
|
12
12
|
|
|
13
13
|
A token **MUST** contain:
|
|
14
14
|
|
|
15
|
-
1. **`name`** — a JSON object (the **name object**) as defined below.
|
|
15
|
+
1. **`name`** — a JSON object (the **name object**) as defined below, or a non-empty plain string (escape hatch — see [String-name escape hatch](#string-name-escape-hatch)).
|
|
16
16
|
2. Exactly one of:
|
|
17
17
|
* **`value`** — a literal token value (type depends on value-type schema), or
|
|
18
18
|
* **`$ref`** — a string reference to another token (alias).
|
|
19
19
|
|
|
20
20
|
A token **MUST NOT** include both `value` and `$ref`.
|
|
21
21
|
|
|
22
|
+
### String-name escape hatch
|
|
23
|
+
|
|
24
|
+
A token's `name` field **MAY** be a non-empty plain string instead of a name object when the token's identity cannot be expressed using the structured taxonomy fields.
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"name": "focus-ring-color-key-focus",
|
|
29
|
+
"value": "#0265dc",
|
|
30
|
+
"uuid": "aaaaaaaa-0012-4000-8000-000000000001"
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**NORMATIVE:** String-named tokens are schema-valid. Validators **MUST** accept them without a structural error.
|
|
35
|
+
|
|
36
|
+
**NORMATIVE:** String-named tokens **MUST** trigger rule SPEC-017 (severity: `warning`, category: `tech-debt`). The warning surfaces the token as tracked debt requiring future remediation.
|
|
37
|
+
|
|
38
|
+
**NORMATIVE:** String-named tokens **MUST NOT** participate in name-object cascade dimension matching, specificity calculation, or registry vocabulary checks (SPEC-009 does not apply).
|
|
39
|
+
|
|
40
|
+
**RECOMMENDED:** Authors **SHOULD** treat string names as a temporary escape hatch and track a remediation plan. Each string-named token **SHOULD** eventually be given a structured name object, at which point SPEC-017 no longer fires.
|
|
41
|
+
|
|
22
42
|
### Name object
|
|
23
43
|
|
|
24
44
|
The **name object** identifies the token in a structured way. Implementations use it for cascade matching, specificity, and tooling.
|
|
@@ -72,16 +92,15 @@ When **`value`** is present, it **MUST** conform to the declared value type for
|
|
|
72
92
|
|
|
73
93
|
The following OPTIONAL fields implement the token lifecycle model described in [#623](https://github.com/adobe/spectrum-design-data/discussions/623) and the evolution policy in [Evolution](evolution.md). Inspired by Swift's `@available` attribute, Kotlin's `@Deprecated`, and OpenAPI 3.3's deprecation model.
|
|
74
94
|
|
|
75
|
-
| Field | Type | Description
|
|
76
|
-
| -------------------- | --------------------------------------- |
|
|
77
|
-
| `uuid` | string (UUID) | Stable unique id for rename tracking and diffs.
|
|
78
|
-
| `introduced` | string (version) | Spec version when the token was first added (e.g. `"1.0.0"`).
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `private` | boolean | Not part of public API surface. |
|
|
95
|
+
| Field | Type | Description |
|
|
96
|
+
| -------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
97
|
+
| `uuid` | string (UUID) | Stable unique id for rename tracking and diffs. |
|
|
98
|
+
| `introduced` | string (version) | Spec version when the token was first added (e.g. `"1.0.0"`). |
|
|
99
|
+
| `deprecated` | string (version) | Spec version when the token was deprecated (e.g. `"3.2.0"`). Truthy = deprecated. |
|
|
100
|
+
| `deprecated_comment` | string | Human-readable deprecation explanation and migration guidance. |
|
|
101
|
+
| `replaced_by` | string (UUID) or array of string (UUID) | UUID(s) of the replacement token(s). Single string for 1:1 replacement; array for one-to-many splits. |
|
|
102
|
+
| `plannedRemoval` | string (version) | Spec version when the token will be removed. If omitted, defaults to the next major version after `deprecated`. |
|
|
103
|
+
| `private` | boolean | Not part of public API surface. |
|
|
85
104
|
|
|
86
105
|
#### Lifecycle example
|
|
87
106
|
|
|
@@ -91,7 +110,6 @@ The following OPTIONAL fields implement the token lifecycle model described in [
|
|
|
91
110
|
"value": "#0265dc",
|
|
92
111
|
"uuid": "aaaaaaaa-0001-4000-8000-000000000001",
|
|
93
112
|
"introduced": "1.0.0",
|
|
94
|
-
"lastModified": "3.2.0",
|
|
95
113
|
"deprecated": "3.2.0",
|
|
96
114
|
"deprecated_comment": "Use action-background-default instead.",
|
|
97
115
|
"replaced_by": "bbbbbbbb-0002-4000-8000-000000000001",
|
|
@@ -111,15 +129,13 @@ The following OPTIONAL fields implement the token lifecycle model described in [
|
|
|
111
129
|
|
|
112
130
|
**NORMATIVE:** Each UUID in `replaced_by` **MUST** resolve to an existing token in the dataset (see rule `SPEC-010`).
|
|
113
131
|
|
|
114
|
-
**NORMATIVE:** If `lastModified` is present, its version **MUST NOT** precede `introduced` (see rule `SPEC-014`). Authors **SHOULD** bump `lastModified` whenever a token's `value`, alias `$ref`, or non-formatting metadata changes; pure formatting or comment-only edits do not require a bump.
|
|
115
|
-
|
|
116
132
|
#### Legacy format mapping
|
|
117
133
|
|
|
118
134
|
When generating legacy-format output from cascade tokens:
|
|
119
135
|
|
|
120
136
|
* `deprecated: "3.2.0"` maps to `deprecated: true`
|
|
121
137
|
* `replaced_by: "<uuid>"` maps to `renamed: "<target-token-name>"` (resolved via UUID lookup)
|
|
122
|
-
* `introduced
|
|
138
|
+
* `introduced` and `plannedRemoval` have no legacy equivalent and are not emitted
|
|
123
139
|
|
|
124
140
|
When migrating legacy-format tokens to cascade:
|
|
125
141
|
|
|
@@ -153,6 +169,55 @@ Example:
|
|
|
153
169
|
|
|
154
170
|
Individual types (color, dimension, opacity, etc.) **MUST** be defined as JSON Schemas under `schemas/value-types/` and **MUST** use `$id` under the same `v0` base path as [Overview — JSON Schema `$id`](index.md).
|
|
155
171
|
|
|
172
|
+
### Value-type declaration (`$valueType`)
|
|
173
|
+
|
|
174
|
+
A token **MAY** include a `$valueType` field: a URI reference pointing to a value-type schema under `schemas/value-types/`.
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"name": { "property": "typography-scale", "scale": "desktop" },
|
|
179
|
+
"$valueType": "value-types/typography-scale.schema.json",
|
|
180
|
+
"value": { "fontSize": "14px", "lineHeight": "18px" },
|
|
181
|
+
"uuid": "377145e8-079b-43fd-b522-8f16b1b8f883"
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**NORMATIVE:** When `$valueType` is present on a token with a literal `value`, the value **MUST** validate against the referenced schema (rule SPEC-016).
|
|
186
|
+
|
|
187
|
+
**NORMATIVE:** When `$valueType` is present on an alias token (`$ref`), the alias resolution chain **MUST** terminate at a token whose value validates against the same value-type schema (rule SPEC-002, extended).
|
|
188
|
+
|
|
189
|
+
**RECOMMENDED:** All tokens with composite values (see below) **SHOULD** include `$valueType` to enable tooling discovery and validation. Tokens without `$valueType` remain valid under the permissive `anyOf` union in `token.schema.json`.
|
|
190
|
+
|
|
191
|
+
### Composite value types
|
|
192
|
+
|
|
193
|
+
A **composite value type** is a value-type schema whose root type is `object` or `array`. Composite values bundle multiple sub-values into a single token.
|
|
194
|
+
|
|
195
|
+
**NORMATIVE:** Composite value types **MUST** be defined as JSON Schemas under `schemas/value-types/` following the same conventions as primitive value types.
|
|
196
|
+
|
|
197
|
+
**NORMATIVE:** A composite token participates in cascade resolution as an **atomic unit**. Sub-values within a composite **MUST NOT** independently match, override, or participate in specificity calculation.
|
|
198
|
+
|
|
199
|
+
### Inline alias references
|
|
200
|
+
|
|
201
|
+
Within a composite value, a string sub-value **MAY** be an **inline alias**: a reference to another token that is resolved to produce the final sub-value.
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"name": { "property": "component-m-regular" },
|
|
206
|
+
"$valueType": "value-types/typography.schema.json",
|
|
207
|
+
"value": {
|
|
208
|
+
"fontFamily": "{sans-serif-font-family}",
|
|
209
|
+
"fontSize": "{font-size-100}",
|
|
210
|
+
"fontWeight": "{regular-font-weight}",
|
|
211
|
+
"letterSpacing": "{letter-spacing}",
|
|
212
|
+
"lineHeight": "{line-height-font-size-100}"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**NORMATIVE:** In legacy format, inline aliases use the syntax `{token-name}` (curly-brace-wrapped token property name). In cascade format, the inline alias syntax is `{token-name}` for backward compatibility; UUID-based inline aliases are reserved for a future spec version.
|
|
218
|
+
|
|
219
|
+
**NORMATIVE:** Inline aliases within composite values are subject to alias resolution rules. Validators **MUST** resolve inline aliases and report errors for missing targets (SPEC-014), type mismatches (SPEC-015), and circular references (SPEC-003, extended).
|
|
220
|
+
|
|
156
221
|
## Relationship to legacy Spectrum tokens
|
|
157
222
|
|
|
158
223
|
The current `@adobe/spectrum-tokens` JSON uses **sets** (`color-set`, `scale-set`, …). This specification describes the **target** per-token model. Mapping from legacy to this format is out of scope for this document; see [#743](https://github.com/adobe/spectrum-design-data/issues/743).
|