@adobe/design-data-spec 0.0.1 → 0.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.
Files changed (124) hide show
  1. package/conformance/README.md +82 -10
  2. package/conformance/diff/cross-format/expected.json +27 -0
  3. package/conformance/diff/cross-format/new/tokens.tokens.json +8 -0
  4. package/conformance/diff/cross-format/old/tokens.json +7 -0
  5. package/conformance/diff/deprecated-new-token/expected.json +13 -0
  6. package/conformance/diff/deprecated-new-token/new/tokens.tokens.json +8 -0
  7. package/conformance/diff/deprecated-new-token/old/tokens.tokens.json +1 -0
  8. package/conformance/diff/deprecated-set-level/expected.json +13 -0
  9. package/conformance/diff/deprecated-set-level/new/tokens.tokens.json +10 -0
  10. package/conformance/diff/deprecated-set-level/old/tokens.tokens.json +1 -0
  11. package/conformance/diff/identical-tokens/expected.json +8 -0
  12. package/conformance/diff/identical-tokens/new/tokens.tokens.json +12 -0
  13. package/conformance/diff/identical-tokens/old/tokens.tokens.json +12 -0
  14. package/conformance/diff/matched-gaining-deprecated/expected.json +20 -0
  15. package/conformance/diff/matched-gaining-deprecated/new/tokens.tokens.json +8 -0
  16. package/conformance/diff/matched-gaining-deprecated/old/tokens.tokens.json +7 -0
  17. package/conformance/diff/property-nested-change/expected.json +27 -0
  18. package/conformance/diff/property-nested-change/new/tokens.tokens.json +10 -0
  19. package/conformance/diff/property-nested-change/old/tokens.tokens.json +10 -0
  20. package/conformance/diff/property-value-update/expected.json +21 -0
  21. package/conformance/diff/property-value-update/new/tokens.tokens.json +7 -0
  22. package/conformance/diff/property-value-update/old/tokens.tokens.json +7 -0
  23. package/conformance/diff/rename-by-uuid/expected.json +22 -0
  24. package/conformance/diff/rename-by-uuid/new/tokens.tokens.json +7 -0
  25. package/conformance/diff/rename-by-uuid/old/tokens.tokens.json +7 -0
  26. package/conformance/diff/rename-with-property-changes/expected.json +28 -0
  27. package/conformance/diff/rename-with-property-changes/new/tokens.tokens.json +7 -0
  28. package/conformance/diff/rename-with-property-changes/old/tokens.tokens.json +7 -0
  29. package/conformance/diff/replaced-by-pairing/expected.json +43 -0
  30. package/conformance/diff/replaced-by-pairing/new/tokens.tokens.json +7 -0
  31. package/conformance/diff/replaced-by-pairing/old/tokens.tokens.json +10 -0
  32. package/conformance/diff/reverted-token/expected.json +13 -0
  33. package/conformance/diff/reverted-token/new/tokens.tokens.json +7 -0
  34. package/conformance/diff/reverted-token/old/tokens.tokens.json +8 -0
  35. package/conformance/diff/simple-add-delete/expected.json +18 -0
  36. package/conformance/diff/simple-add-delete/new/tokens.tokens.json +7 -0
  37. package/conformance/diff/simple-add-delete/old/tokens.tokens.json +7 -0
  38. package/conformance/diff/uuid-backfill/expected.json +20 -0
  39. package/conformance/diff/uuid-backfill/new/tokens.tokens.json +7 -0
  40. package/conformance/diff/uuid-backfill/old/tokens.tokens.json +6 -0
  41. package/conformance/invalid/SPEC-008/dimension.json +5 -0
  42. package/conformance/invalid/SPEC-008/expected-errors.json +10 -0
  43. package/conformance/invalid/SPEC-008/tokens.tokens.json +15 -0
  44. package/conformance/invalid/SPEC-010/expected-errors.json +10 -0
  45. package/conformance/invalid/SPEC-010/tokens.tokens.json +9 -0
  46. package/conformance/invalid/SPEC-011/expected-errors.json +10 -0
  47. package/conformance/invalid/SPEC-011/tokens.tokens.json +22 -0
  48. package/conformance/invalid/SPEC-012/expected-errors.json +10 -0
  49. package/conformance/invalid/SPEC-012/tokens.tokens.json +13 -0
  50. package/conformance/invalid/SPEC-013/expected-errors.json +10 -0
  51. package/conformance/invalid/SPEC-013/tokens.tokens.json +8 -0
  52. package/conformance/query/and-conditions/expected.json +1 -0
  53. package/conformance/query/and-conditions/input/tokens.tokens.json +17 -0
  54. package/conformance/query/and-conditions/query.txt +1 -0
  55. package/conformance/query/and-or-precedence/expected.json +1 -0
  56. package/conformance/query/and-or-precedence/input/tokens.tokens.json +22 -0
  57. package/conformance/query/and-or-precedence/query.txt +1 -0
  58. package/conformance/query/empty-matches-all/expected.json +1 -0
  59. package/conformance/query/empty-matches-all/input/tokens.tokens.json +17 -0
  60. package/conformance/query/empty-matches-all/query.txt +1 -0
  61. package/conformance/query/negation/expected.json +1 -0
  62. package/conformance/query/negation/input/tokens.tokens.json +17 -0
  63. package/conformance/query/negation/query.txt +1 -0
  64. package/conformance/query/no-matches/expected.json +1 -0
  65. package/conformance/query/no-matches/input/tokens.tokens.json +7 -0
  66. package/conformance/query/no-matches/query.txt +1 -0
  67. package/conformance/query/or-conditions/expected.json +1 -0
  68. package/conformance/query/or-conditions/input/tokens.tokens.json +17 -0
  69. package/conformance/query/or-conditions/query.txt +1 -0
  70. package/conformance/query/schema-key/expected.json +1 -0
  71. package/conformance/query/schema-key/input/tokens.tokens.json +14 -0
  72. package/conformance/query/schema-key/query.txt +1 -0
  73. package/conformance/query/single-field/expected.json +1 -0
  74. package/conformance/query/single-field/input/tokens.tokens.json +17 -0
  75. package/conformance/query/single-field/query.txt +1 -0
  76. package/conformance/query/wildcard-prefix/expected.json +1 -0
  77. package/conformance/query/wildcard-prefix/input/tokens.tokens.json +17 -0
  78. package/conformance/query/wildcard-prefix/query.txt +1 -0
  79. package/conformance/query/wildcard-suffix/expected.json +1 -0
  80. package/conformance/query/wildcard-suffix/input/tokens.tokens.json +17 -0
  81. package/conformance/query/wildcard-suffix/query.txt +1 -0
  82. package/conformance/resolution/alias-resolved-after-cascade/dimensions/color-scheme.json +5 -0
  83. package/conformance/resolution/alias-resolved-after-cascade/expected.json +5 -0
  84. package/conformance/resolution/alias-resolved-after-cascade/input/tokens.tokens.json +12 -0
  85. package/conformance/resolution/alias-resolved-after-cascade/query.json +4 -0
  86. package/conformance/resolution/base-fallback/dimensions/color-scheme.json +5 -0
  87. package/conformance/resolution/base-fallback/expected.json +5 -0
  88. package/conformance/resolution/base-fallback/input/tokens.tokens.json +7 -0
  89. package/conformance/resolution/base-fallback/query.json +4 -0
  90. package/conformance/resolution/specificity-wins/dimensions/color-scheme.json +5 -0
  91. package/conformance/resolution/specificity-wins/expected.json +5 -0
  92. package/conformance/resolution/specificity-wins/input/tokens.tokens.json +12 -0
  93. package/conformance/resolution/specificity-wins/query.json +4 -0
  94. package/fields/anatomy.json +15 -0
  95. package/fields/color-scheme.json +15 -0
  96. package/fields/component.json +15 -0
  97. package/fields/contrast.json +15 -0
  98. package/fields/density.json +15 -0
  99. package/fields/object.json +15 -0
  100. package/fields/orientation.json +15 -0
  101. package/fields/position.json +15 -0
  102. package/fields/property.json +15 -0
  103. package/fields/scale.json +15 -0
  104. package/fields/shape.json +15 -0
  105. package/fields/size.json +15 -0
  106. package/fields/state.json +15 -0
  107. package/fields/structure.json +15 -0
  108. package/fields/substructure.json +15 -0
  109. package/fields/variant.json +15 -0
  110. package/package.json +3 -1
  111. package/rules/rules.yaml +56 -2
  112. package/schemas/cascade-file.schema.json +10 -0
  113. package/schemas/field.schema.json +85 -0
  114. package/schemas/manifest.schema.json +55 -1
  115. package/schemas/token.schema.json +89 -18
  116. package/spec/cascade.md +18 -2
  117. package/spec/diff.md +97 -0
  118. package/spec/dimensions.md +15 -6
  119. package/spec/evolution.md +98 -0
  120. package/spec/index.md +11 -8
  121. package/spec/manifest.md +15 -0
  122. package/spec/query.md +135 -0
  123. package/spec/taxonomy.md +173 -0
  124. package/spec/token-format.md +114 -19
package/spec/diff.md ADDED
@@ -0,0 +1,97 @@
1
+ # Semantic diff
2
+
3
+ **Spec version:** `1.0.0-draft` (see [Overview](index.md))
4
+
5
+ This document defines the **semantic diff model**: how two versions of a design data dataset are compared to produce a structured change report with awareness of renames, deprecations, and property-level changes.
6
+
7
+ ## Token identity
8
+
9
+ A **token identity** determines whether a token in the old dataset and a token in the new dataset refer to the same logical token.
10
+
11
+ **NORMATIVE:** Implementations **MUST** use the following matching rules, in order:
12
+
13
+ 1. **UUID match** — If a token in the old dataset and a token in the new dataset share the same `uuid` value, they are the **same token** regardless of name.
14
+ 2. **Name-object equivalence** — When a UUID match is not found for a token — because the old token, the new token, or both lack a `uuid`, or because no counterpart with the matching `uuid` exists in the other dataset — two tokens are the same if their `name` objects are deeply equal (all fields present with identical values).
15
+ 3. **Replacement link** — When passes 1 and 2 leave an old token unpaired and it carries a `replaced_by` field whose UUID matches an unpaired new token, the pair is established. This enables diff classification as **renamed** for tokens that were deprecated with a machine-readable replacement pointer.
16
+
17
+ **NORMATIVE:** UUID matching **MUST** take precedence over name-object equivalence, which **MUST** take precedence over replacement link matching. A UUID match always identifies the token pair, even if name objects differ (which constitutes a rename).
18
+
19
+ **RATIONALE:** UUID-based identity allows tokens to be renamed without breaking continuity tracking. Name-object equivalence is a fallback for legacy datasets that predate UUID adoption. Replacement link matching is a tertiary fallback for deprecated tokens that carry an explicit `replaced_by` UUID pointing to their successor.
20
+
21
+ ## Change taxonomy
22
+
23
+ A semantic diff classifies every token into exactly one of six categories:
24
+
25
+ | Category | Definition |
26
+ | -------------- | ------------------------------------------------------------------------------------------------ |
27
+ | **renamed** | Token exists in both datasets (matched by identity) but the name has changed. |
28
+ | **deprecated** | Token exists only in the new dataset (unmatched) and carries a `deprecated` field. |
29
+ | **reverted** | Token existed with `deprecated` in the old dataset and no longer carries it in the new dataset. |
30
+ | **added** | Token exists only in the new dataset and is not renamed, deprecated, or pre-existing. |
31
+ | **deleted** | Token exists only in the old dataset and is not the source of a rename. |
32
+ | **updated** | Token exists in both datasets (matched by identity) with the same name but changed properties. |
33
+
34
+ **NORMATIVE:** Every token that appears in the old dataset, the new dataset, or both **MUST** be classified into exactly one category. Categories are mutually exclusive.
35
+
36
+ ## Category partitioning
37
+
38
+ **NORMATIVE:** Implementations **MUST** resolve categories in the following order to ensure mutual exclusivity:
39
+
40
+ 1. **Renamed** — Identify all identity-matched pairs where the name has changed. These tokens are removed from further classification as added or deleted.
41
+ 2. **Deprecated** — Among remaining unmatched new tokens, identify those carrying a `deprecated` field. These are removed from the "added" pool.
42
+ 3. **Reverted** — Among identity-matched pairs, identify tokens where `deprecated` was present in the old version and absent in the new. These are removed from the "updated" pool.
43
+ 4. **Added** — Remaining unmatched new tokens that are not renamed, deprecated, or pre-existing in the old dataset.
44
+ 5. **Deleted** — Remaining unmatched old tokens that are not the source of a rename.
45
+ 6. **Updated** — Remaining identity-matched pairs with unchanged names but differing properties.
46
+
47
+ **RATIONALE:** This ordering mirrors the pipeline in existing tooling and ensures that a renamed token does not also appear as "added" + "deleted", a deprecated token does not appear as "added", and so forth. A matched token that newly gains a `deprecated` field is classified as **updated** — the deprecation surfaces as a property-level change in the updated sub-categories, not as a new-token deprecation.
48
+
49
+ ## Deprecation normalization
50
+
51
+ **NORMATIVE:** When a token uses the legacy `sets` structure and **all** set entries carry `deprecated: true`, the token **MUST** be treated as deprecated at the token level for diff classification purposes, even if the top-level token object does not carry `deprecated`.
52
+
53
+ **RATIONALE:** Set-level deprecation that covers all variants is semantically equivalent to token-level deprecation. Normalizing this prevents diff noise from implementation-level differences in where the `deprecated` flag is placed.
54
+
55
+ ## Property-level changes
56
+
57
+ For tokens classified as **updated** (or **renamed** with additional property changes), a semantic diff **SHOULD** produce property-level change records.
58
+
59
+ ### Change record format
60
+
61
+ Each property-level change is described by:
62
+
63
+ | Field | Type | Description |
64
+ | ---------------- | ------ | ------------------------------------------------------- |
65
+ | `path` | string | Dot-separated path from the token root (e.g. `value`, `name.colorScheme`, `sets.light.value`). |
66
+ | `new_value` | any | The value in the new dataset. Present for additions and updates. |
67
+ | `original_value` | any | The value in the old dataset. Present for deletions and updates. |
68
+
69
+ ### Property change sub-categories
70
+
71
+ | Sub-category | Condition |
72
+ | --------------------- | ------------------------------------------------- |
73
+ | **added-properties** | Property exists in new but not in old. |
74
+ | **deleted-properties**| Property exists in old but not in new. |
75
+ | **updated-properties**| Property exists in both but with different values. |
76
+
77
+ **NORMATIVE:** Property comparison **MUST** be recursive: nested objects are traversed and changes reported at the leaf level with full dot-separated paths.
78
+
79
+ **NORMATIVE:** Property comparison **MUST** use deep equality for values. Two values are equal if their JSON serializations are identical.
80
+
81
+ ## Output ordering
82
+
83
+ **RECOMMENDED:** Diff output **SHOULD** be deterministic. Within each category, tokens **SHOULD** be sorted by their canonical name (or new name for renames) in lexicographic order.
84
+
85
+ **RATIONALE:** Deterministic output makes diff reports suitable for snapshot testing and human review.
86
+
87
+ ## Cross-format compatibility
88
+
89
+ **NORMATIVE:** A conforming diff engine **MUST** accept both legacy format (JSON object maps) and cascade format (JSON arrays with `.tokens.json` extension) as inputs for either the old or new dataset, including mixed-format comparisons (e.g. legacy old, cascade new).
90
+
91
+ **RATIONALE:** The diff operates on the token graph abstraction, which normalizes both formats into the same `TokenRecord` structure. This enables diffing across format migrations without special-case handling.
92
+
93
+ ## References
94
+
95
+ * [#623 — Token Lifecycle Metadata](https://github.com/adobe/spectrum-design-data/discussions/623)
96
+ * [#714 — Design Data Specification](https://github.com/adobe/spectrum-design-data/discussions/714)
97
+ * [#776 — Phase 3: Diff change taxonomy and token identity rules](https://github.com/adobe/spectrum-design-data/issues/776)
@@ -25,13 +25,21 @@ A **dimension declaration** is a JSON object describing one axis of variation. I
25
25
 
26
26
  ## Built-in dimensions
27
27
 
28
- These dimensions **SHOULD** be used consistently across Spectrum-compatible datasets:
28
+ These dimensions are declared in the `dimensions/` catalog (see [Dimension catalog](#dimension-catalog)) and **SHOULD** be used consistently across Spectrum-compatible datasets:
29
29
 
30
- | `name` | Typical `modes` | Notes |
31
- | ------------- | ------------------------------- | ----------------------------- |
32
- | `colorScheme` | `light`, `dark`, `wireframe`, | Theme / appearance. |
33
- | `scale` | `medium`, `large`, | Density / t-shirt scale. |
34
- | `contrast` | `regular`, `high`, … | Accessibility contrast level. |
30
+ | `name` | `modes` | `default` | Notes |
31
+ | ------------- | ---------------------------- | --------- | --------------------------------------------------------------------------------- |
32
+ | `colorScheme` | `light`, `dark`, `wireframe` | `light` | Theme / appearance. |
33
+ | `scale` | `desktop`, `mobile` | `desktop` | Density scale. Legacy names; desktop = medium, mobile = large in W3C terminology. |
34
+ | `contrast` | `regular`, `high` | `regular` | Accessibility contrast level. |
35
+
36
+ ## Dimension catalog
37
+
38
+ The Spectrum foundation publishes dimension declarations as JSON files under `packages/design-data-spec/dimensions/`. Each file conforms to [`dimension.schema.json`](../schemas/dimension.schema.json).
39
+
40
+ **NORMATIVE:** Tooling (validators, resolution engine) **MUST** load dimension declarations from the dataset’s dimension catalog before performing specificity calculations or coverage validation.
41
+
42
+ **RECOMMENDED:** The catalog directory is named `dimensions/` and is co-located with the dataset’s spec package or manifest.
35
43
 
36
44
  ## Optional dimensions
37
45
 
@@ -53,3 +61,4 @@ Additional dimensions (e.g. `language`, `motion`) **MAY** be declared in a datas
53
61
 
54
62
  * [#646 — Token Schema Structure and Validation System](https://github.com/adobe/spectrum-design-data/discussions/646)
55
63
  * [#714 — Design Data Specification](https://github.com/adobe/spectrum-design-data/discussions/714)
64
+ * [#746 — Phase 2: Dimension declarations (machine-readable)](https://github.com/adobe/spectrum-design-data/issues/746)
@@ -0,0 +1,98 @@
1
+ # Evolution
2
+
3
+ **Spec version:** `1.0.0-draft` (see [Overview](index.md))
4
+
5
+ This document defines the **evolution policy** for the Design Data Specification: how the spec, schemas, and token data change over time, with a focus on the token deprecation lifecycle and backward compatibility.
6
+
7
+ ## Token deprecation lifecycle
8
+
9
+ Tokens progress through the following lifecycle stages:
10
+
11
+ ```
12
+ introduced → active → deprecated → planned removal → removed
13
+ ```
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. |
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. |
22
+
23
+ ### Lifecycle fields
24
+
25
+ See [Token format — Lifecycle and metadata](token-format.md#lifecycle-and-metadata) for the full field definitions and normative rules.
26
+
27
+ ### What `replaced_by` guarantees
28
+
29
+ When a token carries `replaced_by`:
30
+
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
+
36
+ ## Migration windows
37
+
38
+ **NORMATIVE:** A deprecated token **MUST** remain in the published dataset for at least **two minor versions** after the version recorded in `deprecated` before it may be removed.
39
+
40
+ **EXAMPLE:** A token deprecated in `3.2.0` may not be removed until `3.4.0` at the earliest. Removal in a major version (e.g. `4.0.0`) is always permitted regardless of how recently the token was deprecated.
41
+
42
+ **RATIONALE:** Two minor versions gives consumers at least two release cycles to migrate. The major-version escape hatch allows accumulated deprecations to be cleaned up in a coordinated breaking release.
43
+
44
+ If `plannedRemoval` is set, it overrides the default window — the token will be removed in the specified version (which must not precede the `deprecated` version).
45
+
46
+ ## Change classification
47
+
48
+ The specification follows [Semantic Versioning](https://semver.org/) for its published artifacts (schemas, rule catalog, spec documents).
49
+
50
+ ### Minor changes (backward compatible)
51
+
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
+
59
+ ### Major changes (breaking)
60
+
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
+
68
+ ### Patch changes (clarifications)
69
+
70
+ - Typo fixes in spec prose
71
+ - Clarifications to normative text that do not change conformance behavior
72
+ - Test fixture additions or corrections
73
+
74
+ ## Legacy format contract
75
+
76
+ The `@adobe/spectrum-tokens` package continues to publish tokens in the **legacy format** (JSON object maps with `color-set`, `scale-set`, etc.) for backward compatibility with existing consumers.
77
+
78
+ **NORMATIVE:** The legacy format output **MUST** be generated from the cascade-format authoritative source. It is a **derived artifact**, not independently authored.
79
+
80
+ ### Lifecycle field mapping
81
+
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)|
89
+
90
+ ### Coexistence during migration
91
+
92
+ Both formats are published simultaneously. The cascade format is the source of truth; the legacy format is generated from it. This dual-format period continues until platform consumers have migrated to the cascade format or to platform SDKs that consume it.
93
+
94
+ ## References
95
+
96
+ * [#623 — Token Lifecycle Metadata](https://github.com/adobe/spectrum-design-data/discussions/623)
97
+ * [#735 — RFC: Versioning and Evolution](https://github.com/adobe/spectrum-design-data/discussions/735)
98
+ * [#736 — Define spec evolution policy and migration contract](https://github.com/adobe/spectrum-design-data/issues/736)
package/spec/index.md CHANGED
@@ -10,14 +10,13 @@ This document is the top-level overview for the **Design Data Specification**: a
10
10
  The specification defines:
11
11
 
12
12
  1. **Token format** — structured token identity (`name`), literal `value` or alias `$ref`, and lifecycle metadata ([Token format](token-format.md)).
13
- 2. **Cascade and resolution** — layered data (foundation, platform, product), specificity, and how a context picks a winning value ([Cascade](cascade.md)).
14
- 3. **Dimensions** — declared modes, defaults, and coverage expectations ([Dimensions](dimensions.md)).
15
- 4. **Platform manifest** — how a platform repo pins foundation data, filters tokens, and applies typed overrides ([Manifest](manifest.md)).
16
-
17
- Out of scope for this draft (tracked elsewhere):
18
-
19
- * Exact query syntax for `include` / `exclude` in manifests (placeholder fields only).
20
- * Full evolution, migration windows, and SDK version negotiation — see [discussion #735](https://github.com/adobe/spectrum-design-data/discussions/735).
13
+ 2. **Taxonomy** — concept categories, token term vocabulary, formatting style, and the distinction between component anatomy and token objects ([Taxonomy](taxonomy.md)).
14
+ 3. **Cascade and resolution** — layered data (foundation, platform, product), specificity, and how a context picks a winning value ([Cascade](cascade.md)).
15
+ 4. **Dimensions** — declared modes, defaults, and coverage expectations ([Dimensions](dimensions.md)).
16
+ 5. **Platform manifest** — how a platform repo pins foundation data, filters tokens, and applies typed overrides ([Manifest](manifest.md)).
17
+ 6. **Semantic diff** — change taxonomy, token identity rules, and property-level change tracking for comparing dataset versions ([Diff](diff.md)).
18
+ 7. **Query notation** — filter syntax for selecting tokens by structured fields ([Query](query.md)).
19
+ 8. **Evolution** deprecation lifecycle, migration windows, change classification, and legacy format contract ([Evolution](evolution.md)).
21
20
 
22
21
  ## Conformance
23
22
 
@@ -54,9 +53,13 @@ Full governance (compatibility tiers, migration, CLI `--spec-version`) is discus
54
53
  | Document | Role |
55
54
  | ------------------------------- | ---------------------------------------------------------------- |
56
55
  | [Token format](token-format.md) | Token `name`, `value` / `$ref`, value types, lifecycle metadata. |
56
+ | [Taxonomy](taxonomy.md) | Concept categories, vocabulary, formatting, anatomy vs objects. |
57
57
  | [Cascade](cascade.md) | Layers, specificity, resolution algorithm. |
58
58
  | [Dimensions](dimensions.md) | Dimension declarations, built-in dimensions, coverage. |
59
59
  | [Manifest](manifest.md) | Platform manifest fields and validation expectations. |
60
+ | [Diff](diff.md) | Semantic diff change taxonomy, token identity, property changes. |
61
+ | [Query](query.md) | Filter notation for selecting tokens by structured fields. |
62
+ | [Evolution](evolution.md) | Deprecation lifecycle, migration windows, change classification. |
60
63
 
61
64
  ## JSON Schema `$id` and versioning
62
65
 
package/spec/manifest.md CHANGED
@@ -38,6 +38,21 @@ Each override object **MUST** include enough information to identify a target to
38
38
 
39
39
  **RECOMMENDED:** `extensions` follows the same structural conventions as foundation token files (tokens, dimensions) and **SHOULD** be validated with the same Layer 1 and Layer 2 rules.
40
40
 
41
+ #### `extensions.formatting`
42
+
43
+ A platform **MAY** declare formatting rules that control how structured name objects are serialized into flat token name strings for that platform. See [Taxonomy — Platform formatting configuration](taxonomy.md#platform-formatting-configuration) for motivation and examples.
44
+
45
+ | Field | Type | Description |
46
+ | --------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
47
+ | `conceptOrder` | array of string | Ordered list of name object field names for serialization. Each entry **MUST** be a declared field name from the design system's [field catalog](../fields/) (see [Token format — Name object](token-format.md#name-object)). Omitted fields are appended in the default order defined by each field declaration's `serialization.position` (see [Taxonomy — Default serialization](taxonomy.md#default-serialization-legacy-format)). |
48
+ | `casing` | string | One of: `kebab-case`, `camelCase`, `PascalCase`, `SCREAMING_SNAKE_CASE`. Default: `kebab-case`. |
49
+ | `delimiter` | string | Character(s) separating concepts in the serialized string (e.g. `-`, `_`, `.`, `/`). Default: `-`. |
50
+ | `abbreviations` | object | Map of full term → abbreviated form (e.g. `{ "background": "bg" }`). Abbreviations are applied after concept ordering and before casing. |
51
+
52
+ **NORMATIVE:** When `extensions.formatting` is absent, the default serialization defined in [Taxonomy](taxonomy.md#default-serialization-legacy-format) is used.
53
+
54
+ **NORMATIVE:** A formatter applying `extensions.formatting` **MUST** produce deterministic output — the same name object and formatting configuration **MUST** always yield the same string.
55
+
41
56
  ## Validation
42
57
 
43
58
  **NORMATIVE:** Manifests **MUST** pass Layer 1 JSON Schema validation.
package/spec/query.md ADDED
@@ -0,0 +1,135 @@
1
+ # Query notation
2
+
3
+ **Spec version:** `1.0.0-draft` (see [Overview](index.md))
4
+
5
+ This document defines the **query filter notation**: a concise syntax for selecting tokens from a dataset by matching against structured token fields.
6
+
7
+ ## Filter notation
8
+
9
+ A **filter expression** is a string that describes a set of conditions a token must satisfy to be included in the result. The notation uses `key=value` pairs combined with logical operators.
10
+
11
+ | Operator | Syntax | Meaning |
12
+ | -------- | ---------------- | ------------------------------------------------------- |
13
+ | `=` | `key=value` | Field `key` equals `value`. |
14
+ | `!=` | `key!=value` | Field `key` does not equal `value`. |
15
+ | `,` | `a=x,b=y` | Logical AND — both conditions must match. |
16
+ | `\|` | `a=x\|b=y` | Logical OR — at least one condition must match. |
17
+ | `*` | `key=patt*ern` | Glob wildcard — `*` matches zero or more characters. |
18
+
19
+ ## Supported keys
20
+
21
+ **NORMATIVE:** Implementations **MUST** support the following keys:
22
+
23
+ | Key | Source | Description |
24
+ | ---------------- | --------------------------- | ------------------------------------------------ |
25
+ | `property` | `name.property` | Token property identifier. |
26
+ | `component` | `name.component` | Associated component name. |
27
+ | `variant` | `name.variant` | Component variant. |
28
+ | `state` | `name.state` | Component or interaction state. |
29
+ | `colorScheme` | `name.colorScheme` | Color scheme dimension value. |
30
+ | `scale` | `name.scale` | Scale dimension value. |
31
+ | `contrast` | `name.contrast` | Contrast dimension value. |
32
+ | `uuid` | `uuid` | Token UUID (top-level field). |
33
+ | `$schema` | `$schema` | Token schema URL (top-level field). |
34
+
35
+ **NORMATIVE:** Implementations **MUST** reject filter expressions containing keys not listed above with a parse error. Future spec versions MAY add keys.
36
+
37
+ **RATIONALE:** Restricting keys to a known set ensures that typos are caught early and that all implementations agree on which fields are queryable. This also enables implementations to build indexes for supported keys.
38
+
39
+ ## Formal grammar
40
+
41
+ The following EBNF defines the filter expression syntax:
42
+
43
+ ```ebnf
44
+ filter-expr = or-expr ;
45
+ or-expr = and-expr { "|" and-expr } ;
46
+ and-expr = condition { "," condition } ;
47
+ condition = key operator value ;
48
+ key = (letter | "$") { letter | digit | "$" | "_" } ;
49
+ operator = "=" | "!=" ;
50
+ value = { value-char } ;
51
+ value-char = letter | digit | "-" | "_" | "." | "/" | ":" | "*" ;
52
+ letter = "A"-"Z" | "a"-"z" ;
53
+ digit = "0"-"9" ;
54
+ ```
55
+
56
+ **NORMATIVE:** Whitespace around operators and delimiters is **NOT** significant and **MUST** be trimmed by the parser.
57
+
58
+ **NORMATIVE:** An empty filter expression **MUST** match all tokens (universal match).
59
+
60
+ ## Operator precedence
61
+
62
+ **NORMATIVE:** The `,` (AND) operator binds more tightly than `|` (OR).
63
+
64
+ The expression `a=x,b=y|c=z` is equivalent to `(a=x AND b=y) OR (c=z)`.
65
+
66
+ **NORMATIVE:** Parentheses for grouping are **NOT** supported in `1.0.0-draft`. Implementations **MUST** reject parentheses with a parse error.
67
+
68
+ **RATIONALE:** Avoiding parentheses keeps the notation simple and shell-friendly. Most practical queries are either pure AND or pure OR; mixed expressions with the defined precedence cover the remaining common cases.
69
+
70
+ ## Evaluation semantics
71
+
72
+ **NORMATIVE:** A filter expression is evaluated independently against each token in the dataset. A token is included in the result if and only if the expression evaluates to `true` for that token.
73
+
74
+ **NORMATIVE:** For equality (`=`), a condition matches when the token's field value equals the specified value. If the token does not have the field, the condition does **NOT** match.
75
+
76
+ **NORMATIVE:** For negation (`!=`), a condition matches when the token's field value does not equal the specified value **OR** the field is absent. A missing field satisfies `!=`.
77
+
78
+ **RATIONALE:** Negation matching absent fields follows the convention that "not equal to X" includes "does not exist" — the same semantics as label selectors in Kubernetes and CSS attribute selectors.
79
+
80
+ ## Glob matching
81
+
82
+ **NORMATIVE:** The `*` character in a value is a **glob wildcard** matching zero or more characters.
83
+
84
+ **NORMATIVE:** Glob matching is **case-sensitive**.
85
+
86
+ **NORMATIVE:** Multiple `*` characters in a single value are permitted and each independently matches zero or more characters.
87
+
88
+ **NORMATIVE:** To match a literal `*` character, there is no escape mechanism in `1.0.0-draft`. Future versions MAY define one.
89
+
90
+ ## Examples
91
+
92
+ ### Select all tokens for a specific component
93
+
94
+ ```
95
+ component=button
96
+ ```
97
+
98
+ Matches tokens whose `name.component` is `"button"`.
99
+
100
+ ### Select tokens matching multiple criteria
101
+
102
+ ```
103
+ component=button,state=hover
104
+ ```
105
+
106
+ Matches tokens where `name.component` is `"button"` **AND** `name.state` is `"hover"`.
107
+
108
+ ### Select tokens for either of two properties
109
+
110
+ ```
111
+ property=background-color|property=border-color
112
+ ```
113
+
114
+ Matches tokens whose `name.property` is `"background-color"` **OR** `"border-color"`.
115
+
116
+ ### Select color tokens using wildcard
117
+
118
+ ```
119
+ property=color-*
120
+ ```
121
+
122
+ Matches tokens whose `name.property` starts with `"color-"` (e.g. `color-default`, `color-hover`).
123
+
124
+ ### Exclude a specific color scheme
125
+
126
+ ```
127
+ component=button,colorScheme!=light
128
+ ```
129
+
130
+ Matches button tokens that are **not** in the `light` color scheme. Tokens without a `colorScheme` field also match (absent field satisfies `!=`).
131
+
132
+ ## References
133
+
134
+ * [#714 — Design Data Specification](https://github.com/adobe/spectrum-design-data/discussions/714)
135
+ * [#777 — Phase 3: Query notation definition](https://github.com/adobe/spectrum-design-data/issues/777)
@@ -0,0 +1,173 @@
1
+ # Taxonomy
2
+
3
+ **Spec version:** `1.0.0-draft` (see [Overview](index.md))
4
+
5
+ This document defines the **token taxonomy**: a hierarchical system of concept categories that classify design tokens, the **token term vocabulary** of allowed words within each category, and the **formatting style** rules that control serialization of structured token names into platform-consumable strings.
6
+
7
+ ## Motivation
8
+
9
+ "Naming convention" is too broad a term when discussing malleability across platform teams. A token name like `accent-background-color-hover` embeds multiple independent decisions:
10
+
11
+ 1. **Which concepts** are represented and in what hierarchy (taxonomy).
12
+ 2. **Which words** describe each concept (vocabulary).
13
+ 3. **How the words are rendered** — casing, delimiters, abbreviations, concept order (formatting).
14
+
15
+ Each layer has a different malleability profile: the taxonomy is shared across all platforms; the vocabulary is shared with platform-aware compromises; the formatting is platform-malleable.
16
+
17
+ ## Three layers of naming
18
+
19
+ ### Layer 1: Token taxonomy
20
+
21
+ A **token taxonomy** is a hierarchical set of concept categories for classifying design ideas and use cases. It creates a clear, consistent, and predictable shared language across disciplines and teams.
22
+
23
+ The taxonomy is **NORMATIVE** and **shared** — all platforms use the same concept categories in the same hierarchy. Changing the taxonomy changes the meaning of token names across the entire ecosystem.
24
+
25
+ Taxonomies are **scoped to specific token types** for clarity. The semantic/layout taxonomy defined in this document is one such scope; additional taxonomies (e.g. for color tokens) will be defined in future spec versions.
26
+
27
+ ### Layer 2: Token term vocabulary
28
+
29
+ The **token term vocabulary** is the set of specific words used to describe each conceptual option within the taxonomy. The vocabulary creates a shared language across disciplines and teams.
30
+
31
+ The vocabulary is **NORMATIVE at the foundation level** — the foundation defines canonical terms. Platforms **MAY** declare vocabulary mappings (e.g. `hover` → `highlighted` for iOS) in their [manifest](manifest.md) for platform-specific consumption.
32
+
33
+ ### Layer 3: Formatting style
34
+
35
+ **Formatting style** defines rules for altering the appearance of a token's name for platform-specific consumption and usability needs. This includes concept ordering, casing, delimiters, and abbreviations.
36
+
37
+ Formatting is **platform-malleable** — each platform manifest **MAY** declare its own formatting rules. The foundation defines a default formatting style for legacy compatibility.
38
+
39
+ **NORMATIVE:** The name object defined in [Token format](token-format.md) is unordered structured data. Concept ordering is purely a serialization concern and **MUST NOT** affect cascade resolution, specificity, or validation.
40
+
41
+ ## Principles
42
+
43
+ The taxonomy is designed with three guiding principles:
44
+
45
+ 1. **Object-oriented** — Designers and developers think in terms of how they would construct components, rather than abstract semantic ideas.
46
+ 2. **Agnostic (with compromises)** — Platform-agnostic terms are used except when platforms have specific terms for the same concept. In those cases, the most common or clear term is used.
47
+ 3. **Verified** — Multiple existing components must be rebuildable using the taxonomy system, and consumers must find them reasonably understandable or learnable.
48
+
49
+ ## Semantic / layout token taxonomy
50
+
51
+ Concept categories for name-object fields are declared in the design system's **field catalog** — a set of field declarations in the `fields/` directory, each conforming to [`field.schema.json`](../schemas/field.schema.json). Each declaration specifies the field name, vocabulary registry, validation severity, and default serialization position.
52
+
53
+ **NORMATIVE:** The field catalog is the authoritative source for what fields exist on the name object. Tools, validators, and serializers **SHOULD** read the catalog rather than hardcoding field knowledge.
54
+
55
+ The following concept categories are defined in Spectrum's foundation field catalog for semantic and layout tokens, ordered by default serialization position. This ordering is the **default serialization order** for legacy format output; it is not a conformance requirement for stored name objects.
56
+
57
+ **NORMATIVE:** Each category listed below corresponds to an OPTIONAL field on the token [name object](token-format.md). Tokens **MAY** use any subset of these fields.
58
+
59
+ | Category | Name object field | Answers | Description |
60
+ | ------------- | ----------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
61
+ | Structure | `structure` | What? | Individual objects or object categories that have shared styling. Distinctly different from "components" in that they represent structures and visual patterns that can or do occur across many varieties of components. |
62
+ | Sub-structure | `substructure` | What? | A structure within an element that should only exist within the context of its parent structure. |
63
+ | Component | `component` | What? | Component scope when the token is component-scoped. |
64
+ | Anatomy | `anatomy` | What? | A visible, named part of a component as defined by designers. |
65
+ | Object | `object` | Where? | The styling surface to which a visual property is applied (e.g. background, border, edge). |
66
+ | Property | `property` | Where? | The stylistic attribute being defined (e.g. color, width, padding, gap). |
67
+ | Orientation | `orientation` | When/Why? | The direction or order of structures and elements within a component or pattern. |
68
+ | Position | `position` | When/Why? | The location of an object relative to another, with or without respect to directional order. |
69
+ | Size | `size` | When/Why? | Relative terms used to create relationships and patterns of usage across multiple tokens and token types. |
70
+ | Density | `density` | When/Why? | Options that create more or less space within or around the parts of a component. |
71
+ | Shape | `shape` | When/Why? | Relative to the overall shape of a component (e.g. "uniform" creates a 1:1 padding ratio between horizontal and vertical padding). |
72
+
73
+ Additional categories for variant and state are inherited from the existing name object:
74
+
75
+ | Category | Name object field | Description |
76
+ | -------- | ----------------- | ------------------------------------------------------------ |
77
+ | Variant | `variant` | Variant within a component (e.g. accent, negative, primary). |
78
+ | State | `state` | Interactive or semantic state (e.g. hover, focus, disabled). |
79
+
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.
81
+
82
+ ## Component anatomy vs. token objects
83
+
84
+ Two concepts that are often conflated but serve different purposes:
85
+
86
+ ### Component anatomy
87
+
88
+ **Component anatomy** refers to the visible, named parts of a component as defined by designers. These are the parts called out in component specification diagrams (e.g. icon, label, track, handle, hold icon).
89
+
90
+ Component anatomy is declared per component in [component schemas](../../component-schemas/) and validated against the anatomy registry. A token referencing a component's anatomy part (e.g. `slider` + `handle`) can be validated as a legitimate combination.
91
+
92
+ Anatomy parts fall into three tiers:
93
+
94
+ | Tier | Description | Examples |
95
+ | ------------------ | -------------------------------------- | ------------------------------------------------------------- |
96
+ | Primitive | Reusable across many components | icon, label, track, handle, fill, divider, title, description |
97
+ | Composite | Another component used as a named part | checkbox, close button, popover, avatar |
98
+ | Component-specific | Unique to one component | loupe, gripper, opacity checkerboard |
99
+
100
+ ### Token objects (styling surfaces)
101
+
102
+ **Token objects** (or styling surfaces) describe *where* a visual property is applied on a UI element. These are NOT anatomy — they are abstract styling targets that exist on any element regardless of its component type.
103
+
104
+ | Object | Description |
105
+ | ------------ | ----------------------------------------------------- |
106
+ | `background` | Background surface or fill |
107
+ | `border` | Border or outline |
108
+ | `edge` | Outer boundary of component (used in spacing tokens) |
109
+ | `visual` | Visible graphic element area (may be inset from edge) |
110
+ | `content` | Main content area |
111
+
112
+ Token objects are stored in a separate registry from anatomy parts. Both may appear in the same token name — e.g. a token for the background color of a slider's handle would reference anatomy `handle` and object `background`.
113
+
114
+ ## Name object field categories
115
+
116
+ Name object fields fall into two categories with different validation behavior:
117
+
118
+ ### Semantic fields
119
+
120
+ Semantic fields describe identity, structure, and intent. They are used for querying and organization but do **not** participate in cascade resolution or specificity calculation.
121
+
122
+ **NORMATIVE:** Semantic field values are validated against their declared vocabulary registry with the severity specified in the field declaration (typically **advisory** — warning, not error). Values not in the registry are permitted but flagged.
123
+
124
+ Semantic fields are those declared with `kind: "semantic"` in the field catalog. In Spectrum's foundation catalog, these are: `structure`, `substructure`, `component`, `anatomy`, `object`, `property`, `variant`, `state`, `orientation`, `position`, `size`, `density`, `shape`.
125
+
126
+ ### Dimension fields
127
+
128
+ Dimension fields represent axes of variation that drive the [cascade](cascade.md) resolution algorithm and [specificity](cascade.md#semantic-specificity) calculation.
129
+
130
+ **NORMATIVE:** Dimension field values are validated against declared [dimension](dimensions.md) modes with **strict** severity (error). An invalid mode value would silently fail to match any context during cascade resolution.
131
+
132
+ Dimension fields are those declared with `kind: "dimension"` in the field catalog, plus any additional dimension keys from the dataset's [dimension declarations](dimensions.md). In Spectrum's foundation catalog, the standard dimension fields are: `colorScheme`, `scale`, `contrast`.
133
+
134
+ See [Dimensions](dimensions.md) for dimension declarations, modes, and defaults.
135
+
136
+ ## Default serialization (legacy format)
137
+
138
+ The **default serialization** produces a kebab-case string from the name object by ordering fields according to their `serialization.position` values (ascending) as declared in the field catalog. Omitted fields are skipped.
139
+
140
+ For Spectrum's foundation catalog, this produces the following concept order:
141
+
142
+ ```
143
+ {variant}-{component}-{structure}-{substructure}-{anatomy}-{object}-{property}-{orientation}-{position}-{size}-{density}-{shape}-{state}
144
+ ```
145
+
146
+ All fields are independent — `variant` and `component` **MAY** both appear in the same token name (e.g. a token with `component: "button"` and `variant: "accent"` serializes as `accent-button-...`).
147
+
148
+ This ordering is preserved for backward compatibility with the current `@adobe/spectrum-tokens` package. It is a serialization convention, not a structural requirement.
149
+
150
+ **NORMATIVE:** A conforming formatter **MUST** produce deterministic output for a given name object and formatting configuration. Two name objects that differ only in field ordering **MUST** produce identical serialized strings.
151
+
152
+ ## Platform formatting configuration
153
+
154
+ A platform [manifest](manifest.md) **MAY** declare formatting rules in its [`extensions.formatting`](manifest.md#extensionsformatting) section to control concept ordering, casing, delimiters, and abbreviations. The normative contract for these fields is defined in [Manifest — `extensions.formatting`](manifest.md#extensionsformatting).
155
+
156
+ When no platform formatting is declared, the default serialization above is used.
157
+
158
+ ## Scalability
159
+
160
+ The taxonomy and terms are built to scale as new concepts and terms are identified:
161
+
162
+ * New concept categories **MAY** be added by creating a new field declaration file in the field catalog — no spec version change is required for the mechanism itself.
163
+ * New terms **MAY** be added to the vocabulary registry without spec version changes.
164
+ * New token type taxonomies (beyond semantic/layout) **MAY** be defined in future spec versions.
165
+ * Platform manifests **MAY** extend the vocabulary with platform-specific terms and formatting.
166
+
167
+ ## References
168
+
169
+ * [#806 — Token Taxonomy, Vocabulary, and Formatting](https://github.com/adobe/spectrum-design-data/discussions/806)
170
+ * [#661 — Spectrum Design System Glossary](https://github.com/adobe/spectrum-design-data/discussions/661)
171
+ * [#646 — Token Schema Structure and Validation System](https://github.com/adobe/spectrum-design-data/discussions/646)
172
+ * [Manifest — `extensions.formatting`](manifest.md#extensionsformatting) — normative contract for platform formatting rules
173
+ * Nate Baldwin, "Naming conventions & shared taxonomy" — Design Data & Platforms onsite, April 1, 2026