@adobe/design-data-spec 3.5.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/README.md +3 -0
- package/conformance/README.md +24 -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/manifest-extensions/README.md +63 -0
- package/conformance/manifest-extensions/base/dataset.json +22 -0
- package/conformance/manifest-extensions/invalid/component-missing-name/expected-errors.json +7 -0
- package/conformance/manifest-extensions/invalid/component-missing-name/extensions/components/broken.json +1 -0
- package/conformance/manifest-extensions/invalid/component-missing-name/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/extensions-dir-absolute-path/expected-errors.json +1 -0
- package/conformance/manifest-extensions/invalid/extensions-dir-absolute-path/manifest.json +5 -0
- package/conformance/manifest-extensions/invalid/extensions-dir-parent-traversal/expected-errors.json +1 -0
- package/conformance/manifest-extensions/invalid/extensions-dir-parent-traversal/manifest.json +5 -0
- package/conformance/manifest-extensions/invalid/field-invalid-kind/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/field-invalid-kind/extensions/fields/broken.json +7 -0
- package/conformance/manifest-extensions/invalid/field-invalid-kind/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/guideline-invalid-category/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/guideline-invalid-category/extensions/guidelines/broken.json +7 -0
- package/conformance/manifest-extensions/invalid/guideline-invalid-category/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/override-missing-uuid/expected-errors.json +1 -0
- package/conformance/manifest-extensions/invalid/override-missing-uuid/extensions/relationships/bad-override.json +7 -0
- package/conformance/manifest-extensions/invalid/override-missing-uuid/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/platform-extension-missing-extends/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/platform-extension-missing-extends/extensions/platform-extensions/broken.json +4 -0
- package/conformance/manifest-extensions/invalid/platform-extension-missing-extends/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/relationship-missing-scope/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/relationship-missing-scope/extensions/relationships/broken.json +4 -0
- package/conformance/manifest-extensions/invalid/relationship-missing-scope/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/token-invalid-uuid/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/token-invalid-uuid/extensions/tokens/broken.tokens.json +7 -0
- package/conformance/manifest-extensions/invalid/token-invalid-uuid/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/unknown-subdir-name/expected-errors.json +6 -0
- package/conformance/manifest-extensions/invalid/unknown-subdir-name/extensions/bogus-subdir/whatever.json +1 -0
- package/conformance/manifest-extensions/invalid/unknown-subdir-name/manifest.json +4 -0
- package/conformance/manifest-extensions/invalid/unknown-term-id/expected-errors.json +1 -0
- package/conformance/manifest-extensions/invalid/unknown-term-id/extensions/platform-extensions/ios-states.json +5 -0
- package/conformance/manifest-extensions/invalid/unknown-term-id/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/custom-extensions-dir/expected.json +1 -0
- package/conformance/manifest-extensions/valid/custom-extensions-dir/manifest.json +5 -0
- package/conformance/manifest-extensions/valid/custom-extensions-dir/platform-extras/components/tab-bar-ios.json +9 -0
- package/conformance/manifest-extensions/valid/injects-component/expected.json +1 -0
- package/conformance/manifest-extensions/valid/injects-component/extensions/components/tab-bar-ios.json +9 -0
- package/conformance/manifest-extensions/valid/injects-component/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/injects-field/expected.json +1 -0
- package/conformance/manifest-extensions/valid/injects-field/extensions/fields/hapticStyle.json +8 -0
- package/conformance/manifest-extensions/valid/injects-field/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/injects-guideline/expected.json +1 -0
- package/conformance/manifest-extensions/valid/injects-guideline/extensions/guidelines/ios-haptics.json +9 -0
- package/conformance/manifest-extensions/valid/injects-guideline/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/injects-platform-extension/expected.json +12 -0
- package/conformance/manifest-extensions/valid/injects-platform-extension/extensions/platform-extensions/ios-states.json +5 -0
- package/conformance/manifest-extensions/valid/injects-platform-extension/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/injects-relationship/expected.json +7 -0
- package/conformance/manifest-extensions/valid/injects-relationship/extensions/relationships/button.json +5 -0
- package/conformance/manifest-extensions/valid/injects-relationship/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/later-file-wins/expected.json +1 -0
- package/conformance/manifest-extensions/valid/later-file-wins/extensions/components/a-tab-bar-ios.json +9 -0
- package/conformance/manifest-extensions/valid/later-file-wins/extensions/components/b-tab-bar-ios.json +9 -0
- package/conformance/manifest-extensions/valid/later-file-wins/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/override-entry-skips-schema-validation/expected.json +1 -0
- package/conformance/manifest-extensions/valid/override-entry-skips-schema-validation/extensions/relationships/a-override.json +9 -0
- package/conformance/manifest-extensions/valid/override-entry-skips-schema-validation/extensions/relationships/z-add.json +5 -0
- package/conformance/manifest-extensions/valid/override-entry-skips-schema-validation/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/override-relationship-by-uuid/expected.json +7 -0
- package/conformance/manifest-extensions/valid/override-relationship-by-uuid/extensions/relationships/a-override.json +9 -0
- package/conformance/manifest-extensions/valid/override-relationship-by-uuid/extensions/relationships/z-add.json +5 -0
- package/conformance/manifest-extensions/valid/override-relationship-by-uuid/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/plain-add-uuid-collision-append/expected.json +5 -0
- package/conformance/manifest-extensions/valid/plain-add-uuid-collision-append/extensions/relationships/button.json +5 -0
- package/conformance/manifest-extensions/valid/plain-add-uuid-collision-append/extensions/relationships/slider.json +5 -0
- package/conformance/manifest-extensions/valid/plain-add-uuid-collision-append/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/remove-relationship-by-uuid/expected.json +1 -0
- package/conformance/manifest-extensions/valid/remove-relationship-by-uuid/extensions/relationships/button.json +5 -0
- package/conformance/manifest-extensions/valid/remove-relationship-by-uuid/extensions/relationships/remove-button.json +4 -0
- package/conformance/manifest-extensions/valid/remove-relationship-by-uuid/manifest.json +4 -0
- package/conformance/manifest-extensions/valid/tokens-sorted-order/expected.json +8 -0
- package/conformance/manifest-extensions/valid/tokens-sorted-order/extensions/tokens/a.tokens.json +7 -0
- package/conformance/manifest-extensions/valid/tokens-sorted-order/extensions/tokens/b.tokens.json +7 -0
- package/conformance/manifest-extensions/valid/tokens-sorted-order/manifest.json +4 -0
- 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/schemas/manifest.schema.json +43 -101
- package/spec/cascade.md +3 -1
- package/spec/manifest-schema-override-spike.md +6 -3
- package/spec/manifest.md +108 -66
- package/spec/taxonomy.md +2 -2
- package/spec/token-format.md +28 -0
package/spec/manifest.md
CHANGED
|
@@ -8,23 +8,23 @@ This document defines the **platform manifest**: how a platform implementation r
|
|
|
8
8
|
|
|
9
9
|
The manifest supports a fixed, enumerated set of operations against the foundation — it does **not** allow overriding, aliasing, or removing arbitrary foundation artifacts. Support is concentrated on tokens; translations and schemas have no manifest-level override mechanism at all.
|
|
10
10
|
|
|
11
|
-
| Operation | Supported? | Field
|
|
12
|
-
| -------------------------------------------------- | ------------------------------------------------------------ |
|
|
13
|
-
| Remove / exclude | Yes | `exclude`
|
|
14
|
-
| Include / whitelist | Yes | `include`
|
|
15
|
-
| Override value (type-preserving) | Yes | `overrides[].value`
|
|
16
|
-
| Override → re-alias | Yes | `overrides[].$ref`
|
|
17
|
-
| Add new tokens (may alias via `$ref`) | Yes | `extensions
|
|
18
|
-
| Add / replace components | Yes | `extensions
|
|
19
|
-
| Add / replace field declarations | Yes | `extensions
|
|
20
|
-
| Add / replace guideline documents | Yes | `extensions
|
|
21
|
-
| Add relationships/CTRs; override/remove by `uuid` | Yes | `extensions
|
|
22
|
-
| Add / remove naming exceptions | Yes | `
|
|
23
|
-
| Annotate existing terminology (cannot add new ids) | Yes | `extensions
|
|
24
|
-
| Restrict allowed mode-set values | Yes | `modeSetRestrictions`
|
|
25
|
-
| Reformat name serialization | Schema-declared only, not yet applied by the reference SDK | `
|
|
26
|
-
| Override/remove/alias translations | No | —
|
|
27
|
-
| Override Layer-1 schemas | No (decided; see [spike](manifest-schema-override-spike.md)) | —
|
|
11
|
+
| Operation | Supported? | Field | Applies to |
|
|
12
|
+
| -------------------------------------------------- | ------------------------------------------------------------ | --------------------------------- | --------------------- |
|
|
13
|
+
| Remove / exclude | Yes | `exclude` | Tokens only |
|
|
14
|
+
| Include / whitelist | Yes | `include` | Tokens only |
|
|
15
|
+
| Override value (type-preserving) | Yes | `overrides[].value` | Tokens only |
|
|
16
|
+
| Override → re-alias | Yes | `overrides[].$ref` | Tokens only |
|
|
17
|
+
| Add new tokens (may alias via `$ref`) | Yes | `extensions/tokens/` | Tokens |
|
|
18
|
+
| Add / replace components | Yes | `extensions/components/` | Components |
|
|
19
|
+
| Add / replace field declarations | Yes | `extensions/fields/` | Fields |
|
|
20
|
+
| Add / replace guideline documents | Yes | `extensions/guidelines/` | Guidelines |
|
|
21
|
+
| Add relationships/CTRs; override/remove by `uuid` | Yes | `extensions/relationships/` | Relationships (CTRs) |
|
|
22
|
+
| Add / remove naming exceptions | Yes | `namingExceptions` | Naming validation |
|
|
23
|
+
| Annotate existing terminology (cannot add new ids) | Yes | `extensions/platform-extensions/` | Existing registry ids |
|
|
24
|
+
| Restrict allowed mode-set values | Yes | `modeSetRestrictions` | Mode sets |
|
|
25
|
+
| Reformat name serialization | Schema-declared only, not yet applied by the reference SDK | `formatting` | Token name strings |
|
|
26
|
+
| Override/remove/alias translations | No | — | — |
|
|
27
|
+
| Override Layer-1 schemas | No (decided; see [spike](manifest-schema-override-spike.md)) | — | — |
|
|
28
28
|
|
|
29
29
|
## Manifest document
|
|
30
30
|
|
|
@@ -39,13 +39,15 @@ A manifest **MUST** conform to [`manifest.schema.json`](../schemas/manifest.sche
|
|
|
39
39
|
|
|
40
40
|
## Optional fields
|
|
41
41
|
|
|
42
|
-
| Field | Type | Description
|
|
43
|
-
| --------------------- | --------------- |
|
|
44
|
-
| `include` | array of string | Semantic **queries** selecting subsets of foundation tokens to materialize.
|
|
45
|
-
| `exclude` | array of string | Queries removing tokens from the included set.
|
|
46
|
-
| `overrides` | array of object | Typed overrides; each entry **MUST** preserve the target token’s **value type**.
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
42
|
+
| Field | Type | Description |
|
|
43
|
+
| --------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `include` | array of string | Semantic **queries** selecting subsets of foundation tokens to materialize. |
|
|
45
|
+
| `exclude` | array of string | Queries removing tokens from the included set. |
|
|
46
|
+
| `overrides` | array of object | Typed overrides; each entry **MUST** preserve the target token’s **value type**. |
|
|
47
|
+
| `extensionsDir` | string | Path (relative to the manifest) to the platform's `extensions/` directory. Default: `"extensions"`. See [`extensions/` directory](#extensions-directory) below. |
|
|
48
|
+
| `namingExceptions` | object | Platform-local overlay on the base naming-exceptions set: names to add and/or remove for this platform's naming validation. |
|
|
49
|
+
| `formatting` | object | Rules for serializing structured name objects into platform-specific token name strings. |
|
|
50
|
+
| `modeSetRestrictions` | object | Mode set restrictions for this platform; see [Mode Sets — Platform restrictions](mode-sets.md#platform-restrictions). |
|
|
49
51
|
|
|
50
52
|
### `include` / `exclude`
|
|
51
53
|
|
|
@@ -71,41 +73,85 @@ apply `Foundation < Platform < Product` precedence to select a single winner. To
|
|
|
71
73
|
counts "tokens a platform ships" from `query` output should resolve first, or it will
|
|
72
74
|
double-count overridden tokens.
|
|
73
75
|
|
|
74
|
-
### `extensions
|
|
75
|
-
|
|
76
|
-
**
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
*
|
|
101
|
-
`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
76
|
+
### `extensions/` directory
|
|
77
|
+
|
|
78
|
+
**NORMATIVE:** Platform-local additions are declared as a sibling **directory** next to
|
|
79
|
+
`manifest.json` (default name `extensions/`; override with the top-level `extensionsDir`
|
|
80
|
+
field), not as an inline object in the manifest. This mirrors how the foundation dataset
|
|
81
|
+
(`packages/design-data/`) splits its own catalogs into one file per artifact, and lets a
|
|
82
|
+
platform's extension set grow without every addition colliding in one JSON object.
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
extensions/
|
|
86
|
+
tokens/ *.tokens.json cascade-format token files
|
|
87
|
+
components/ <component>.json one component per file
|
|
88
|
+
fields/ <field>.json one field declaration per file
|
|
89
|
+
relationships/ <component>.json one CTR set per file
|
|
90
|
+
guidelines/ <topic>.json one guideline per file
|
|
91
|
+
platform-extensions/ <platform>-<registry>.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**NORMATIVE:** Each subdirectory is discovered by a recursive glob for `*.json` files (for
|
|
95
|
+
`tokens/`, `**/*.tokens.json`), with no index file — the same convention used by
|
|
96
|
+
`discover_json_files` in `sdk/core/src/discovery.rs` for the foundation dataset. Matched files
|
|
97
|
+
are processed in **sorted path order**; this is the sole basis for precedence below. A missing
|
|
98
|
+
or empty subdirectory contributes nothing and is not an error.
|
|
99
|
+
|
|
100
|
+
**NORMATIVE:** Merge semantics by subdirectory:
|
|
101
|
+
|
|
102
|
+
* **`tokens/`** — every `*.tokens.json` file is cascade-format (same shape as a foundation
|
|
103
|
+
cascade token file) and **MUST** validate against `cascade-file.schema.json`. Files are
|
|
104
|
+
**deep-merged** into one tokens object, in sorted path order. Entries **MAY** carry a `$ref`
|
|
105
|
+
to alias an existing token instead of a literal value.
|
|
106
|
+
* **`components/`, `fields/`, `guidelines/`, `platform-extensions/`** — one artifact per file.
|
|
107
|
+
Entries across all files in the subdirectory are concatenated, in sorted path order, and
|
|
108
|
+
injected into the corresponding catalog **add-or-replace by name** (for
|
|
109
|
+
`platform-extensions/`, by `termId`; see below). When two files declare the same name,
|
|
110
|
+
**the entry from the later file (in sorted path order) wins.**
|
|
111
|
+
|
|
112
|
+
**NORMATIVE:** Each fragment file **MUST** validate against its category's real JSON schema at
|
|
113
|
+
load time — this is enforced reference-SDK behavior, not an aspirational goal:
|
|
114
|
+
|
|
115
|
+
* **`components/`** → `component.schema.json`
|
|
116
|
+
* **`fields/`** → `field.schema.json` (see [`extensions/fields/`](#extensionsfields) below)
|
|
117
|
+
* **`guidelines/`** → `guideline.schema.json`
|
|
118
|
+
* **`relationships/`** → `relationship.schema.json` (see the Add/Override/remove rules above)
|
|
119
|
+
* **`platform-extensions/`** → `platform-extension.json` (see
|
|
120
|
+
[`extensions/platform-extensions/`](#extensionsplatform-extensions) below)
|
|
121
|
+
* **`tokens/`** → `cascade-file.schema.json` (see above)
|
|
122
|
+
|
|
123
|
+
A fragment that fails validation against its category schema is a manifest error — the
|
|
124
|
+
reference SDK rejects the load rather than silently skipping the malformed file.
|
|
125
|
+
|
|
126
|
+
* **`relationships/`** — Component/Token Relationship (CTR) entries. Relationships have no
|
|
127
|
+
inherent stable key — only an optional `uuid` — so add and override/remove use different
|
|
128
|
+
identity rules:
|
|
129
|
+
* **Add:** an entry with no `op` field is a full relationship object (validated against
|
|
130
|
+
`relationship.schema.json`), appended at the platform layer, in sorted path order.
|
|
131
|
+
* **Override / remove:** targeting an existing relationship **MUST** carry a `uuid`.
|
|
132
|
+
**NORMATIVE:** an entry with `"op": "override"` or `"op": "remove"` that omits `uuid` is a
|
|
133
|
+
manifest error — the reference SDK rejects it rather than silently skipping it. `"op":
|
|
134
|
+
"override"` also carries a `value` (the replacement relationship object); `"op": "remove"`
|
|
135
|
+
drops the matching record. Override/remove ops apply, in sorted path order, against the
|
|
136
|
+
accumulated set of added relationships (across all files, foundation and platform-local).
|
|
137
|
+
|
|
138
|
+
#### `extensions/fields/`
|
|
139
|
+
|
|
140
|
+
Platform-local field declarations, injected into the field catalog. **NORMATIVE:** each file
|
|
141
|
+
**MUST** validate against `field.schema.json`. Note: a top-level `formatting.conceptOrder` (if
|
|
142
|
+
declared) references field names by string — a platform that renames or removes a field it
|
|
143
|
+
also references there is self-inconsistent; that is a manifest-authoring concern, not enforced
|
|
144
|
+
by the reference SDK.
|
|
145
|
+
|
|
146
|
+
#### `extensions/platform-extensions/`
|
|
147
|
+
|
|
148
|
+
Platform terminology annotations layered onto **existing** foundation registry entries (for
|
|
149
|
+
example, platform-specific state names). **NORMATIVE:** each file **MUST** validate against
|
|
150
|
+
`platform-extension.json`, and every `termId` **MUST** already exist in the referenced
|
|
151
|
+
foundation registry — this mechanism annotates existing ids, it does **NOT** introduce new
|
|
152
|
+
ones.
|
|
153
|
+
|
|
154
|
+
### `namingExceptions`
|
|
109
155
|
|
|
110
156
|
Platform-local overlay on the base naming-exceptions set used by naming validation.
|
|
111
157
|
**NORMATIVE:** the reference SDK applies `remove` before `add`, so a name listed in both
|
|
@@ -117,11 +163,7 @@ ends up present (add wins) rather than silently dropped. Absent this key, the ba
|
|
|
117
163
|
| `add` | array of string | Names to add to the naming-exceptions set for this platform. |
|
|
118
164
|
| `remove` | array of string | Names to remove from the base naming-exceptions set. |
|
|
119
165
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
Platform terminology annotations layered onto **existing** foundation registry entries (for example, platform-specific state names). **NORMATIVE:** every `termId` **MUST** already exist in the referenced foundation registry — this mechanism annotates existing ids, it does **NOT** introduce new ones.
|
|
123
|
-
|
|
124
|
-
#### `extensions.formatting`
|
|
166
|
+
### `formatting`
|
|
125
167
|
|
|
126
168
|
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.
|
|
127
169
|
|
|
@@ -132,9 +174,9 @@ A platform **MAY** declare formatting rules that control how structured name obj
|
|
|
132
174
|
| `delimiter` | string | Character(s) separating concepts in the serialized string (e.g. `-`, `_`, `.`, `/`). Default: `-`. |
|
|
133
175
|
| `abbreviations` | object | Map of full term → abbreviated form (e.g. `{ "background": "bg" }`). Abbreviations are applied after concept ordering and before casing. |
|
|
134
176
|
|
|
135
|
-
**NORMATIVE:** When `
|
|
177
|
+
**NORMATIVE:** When `formatting` is absent, the default serialization defined in [Taxonomy](taxonomy.md#default-serialization-legacy-format) is used.
|
|
136
178
|
|
|
137
|
-
**NORMATIVE:** A formatter applying `
|
|
179
|
+
**NORMATIVE:** A formatter applying `formatting` **MUST** produce deterministic output — the same name object and formatting configuration **MUST** always yield the same string.
|
|
138
180
|
|
|
139
181
|
## Validation
|
|
140
182
|
|
package/spec/taxonomy.md
CHANGED
|
@@ -282,7 +282,7 @@ This ordering is preserved for backward compatibility with the current `@adobe/s
|
|
|
282
282
|
|
|
283
283
|
## Platform formatting configuration
|
|
284
284
|
|
|
285
|
-
A platform [manifest](manifest.md) **MAY** declare formatting rules in its [`
|
|
285
|
+
A platform [manifest](manifest.md) **MAY** declare formatting rules in its top-level [`formatting`](manifest.md#formatting) field to control concept ordering, casing, delimiters, and abbreviations. The normative contract for these fields is defined in [Manifest — `formatting`](manifest.md#formatting).
|
|
286
286
|
|
|
287
287
|
When no platform formatting is declared, the default serialization above is used.
|
|
288
288
|
|
|
@@ -338,5 +338,5 @@ node tools/token-corpus-migrate/src/cli.js \
|
|
|
338
338
|
* [#806 — Token Taxonomy, Vocabulary, and Formatting](https://github.com/adobe/spectrum-design-data/discussions/806)
|
|
339
339
|
* [#661 — Spectrum Design System Glossary](https://github.com/adobe/spectrum-design-data/discussions/661)
|
|
340
340
|
* [#646 — Token Schema Structure and Validation System](https://github.com/adobe/spectrum-design-data/discussions/646)
|
|
341
|
-
* [Manifest — `
|
|
341
|
+
* [Manifest — `formatting`](manifest.md#formatting) — normative contract for platform formatting rules
|
|
342
342
|
* Nate Baldwin, "Naming conventions & shared taxonomy" — Design Data & Platforms onsite, April 1, 2026
|
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.
|