@adobe/design-data-spec 3.4.1 → 4.0.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 +22 -0
- package/conformance/invalid/SPEC-058/dataset.json +38 -0
- package/conformance/invalid/SPEC-058/expected-errors.json +10 -0
- 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/package.json +1 -1
- package/rules/rules.yaml +17 -0
- package/schemas/manifest.schema.json +43 -101
- package/spec/manifest-schema-override-spike.md +6 -3
- package/spec/manifest.md +108 -66
- package/spec/mode-sets.md +5 -5
- package/spec/taxonomy.md +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "relationships": { "absent": ["9c858f9c-1d90-4f1a-8c1a-1f1a1f1a1f1a"] } }
|
package/package.json
CHANGED
package/rules/rules.yaml
CHANGED
|
@@ -690,3 +690,20 @@ rules:
|
|
|
690
690
|
message: "Relationship '{relationship}' may need a legacyKey to round-trip through the legacy generator"
|
|
691
691
|
spec_ref: spec/relationship-format.md#legacy-fields-interim
|
|
692
692
|
introduced_in: "1.0.0-draft"
|
|
693
|
+
|
|
694
|
+
- id: SPEC-058
|
|
695
|
+
name: ctr-ref-not-deprecated
|
|
696
|
+
severity: warning
|
|
697
|
+
layer: 2
|
|
698
|
+
category: naming-consistency
|
|
699
|
+
note: >
|
|
700
|
+
Warning, not error: some deprecated targets have no `replacedBy` (or an ambiguous
|
|
701
|
+
array-form one) and can't be auto-corrected without manual triage, so this can't be
|
|
702
|
+
a hard gate yet.
|
|
703
|
+
assert: >
|
|
704
|
+
A relationship-only CTR's `$ref` (no `uuid`/`legacyKey`) SHOULD NOT resolve to a
|
|
705
|
+
token whose `lifecycle.deprecatedIn` is set. A value-owning CTR (`uuid`/`legacyKey`
|
|
706
|
+
present) is exempt — it legitimately *is* the deprecated token record.
|
|
707
|
+
message: "Relationship $ref {ref} resolves to a token deprecated in {deprecatedIn}"
|
|
708
|
+
spec_ref: spec/relationship-format.md#legacy-fields-interim
|
|
709
|
+
introduced_in: "1.0.0-draft"
|
|
@@ -83,122 +83,64 @@
|
|
|
83
83
|
"additionalProperties": false
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
|
-
"
|
|
86
|
+
"extensionsDir": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"minLength": 1,
|
|
89
|
+
"description": "Path (relative to the manifest) to the platform's extensions directory, holding platform-local tokens/components/fields/relationships/guidelines/platform-extensions as one file per artifact (see spec/manifest.md#extensions-directory). Default: \"extensions\"."
|
|
90
|
+
},
|
|
91
|
+
"namingExceptions": {
|
|
87
92
|
"type": "object",
|
|
88
|
-
"description": "Platform-local
|
|
93
|
+
"description": "Platform-local overlay on the base naming-exceptions set: names to add and/or remove for this platform's naming validation.",
|
|
89
94
|
"properties": {
|
|
90
|
-
"
|
|
91
|
-
"$ref": "cascade-file.schema.json",
|
|
92
|
-
"description": "Platform-local token definitions, in cascade-format (same shape as a cascade token file)."
|
|
93
|
-
},
|
|
94
|
-
"components": {
|
|
95
|
+
"add": {
|
|
95
96
|
"type": "array",
|
|
96
|
-
"items": { "
|
|
97
|
-
"description": "
|
|
97
|
+
"items": { "type": "string", "minLength": 1 },
|
|
98
|
+
"description": "Token names to add to the naming-exceptions set for this platform."
|
|
98
99
|
},
|
|
99
|
-
"
|
|
100
|
+
"remove": {
|
|
100
101
|
"type": "array",
|
|
101
|
-
"items": { "
|
|
102
|
-
"description": "
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"properties": {
|
|
113
|
-
"op": { "const": "override" },
|
|
114
|
-
"uuid": { "type": "string", "format": "uuid" },
|
|
115
|
-
"value": {
|
|
116
|
-
"$ref": "relationship.schema.json#/$defs/relationship"
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
"additionalProperties": false
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
"type": "object",
|
|
123
|
-
"required": ["op", "uuid"],
|
|
124
|
-
"properties": {
|
|
125
|
-
"op": { "const": "remove" },
|
|
126
|
-
"uuid": { "type": "string", "format": "uuid" }
|
|
127
|
-
},
|
|
128
|
-
"additionalProperties": false
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
},
|
|
132
|
-
"description": "Platform-local Component/Token Relationship (CTR) add/override/remove. Entries without \"op\" are added positionally; \"override\"/\"remove\" require a \"uuid\" to target an existing relationship."
|
|
133
|
-
},
|
|
134
|
-
"platformExtensions": {
|
|
102
|
+
"items": { "type": "string", "minLength": 1 },
|
|
103
|
+
"description": "Token names to remove from the base naming-exceptions set for this platform."
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"additionalProperties": false
|
|
107
|
+
},
|
|
108
|
+
"formatting": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"description": "Rules for serializing structured name objects into platform-specific token name strings.",
|
|
111
|
+
"properties": {
|
|
112
|
+
"conceptOrder": {
|
|
135
113
|
"type": "array",
|
|
136
114
|
"items": {
|
|
137
|
-
"
|
|
115
|
+
"type": "string"
|
|
138
116
|
},
|
|
139
|
-
"
|
|
117
|
+
"uniqueItems": true,
|
|
118
|
+
"description": "Ordered list of field names for serialization. Values must match declared field names from the design system's field catalog (field.schema.json declarations). Replaces the default serialization.position order from each field declaration."
|
|
140
119
|
},
|
|
141
|
-
"
|
|
142
|
-
"type": "
|
|
143
|
-
"
|
|
144
|
-
|
|
120
|
+
"casing": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"enum": [
|
|
123
|
+
"kebab-case",
|
|
124
|
+
"camelCase",
|
|
125
|
+
"PascalCase",
|
|
126
|
+
"SCREAMING_SNAKE_CASE"
|
|
127
|
+
],
|
|
128
|
+
"description": "Casing style for serialized token names. Default: kebab-case."
|
|
145
129
|
},
|
|
146
|
-
"
|
|
147
|
-
"type": "
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"add": {
|
|
151
|
-
"type": "array",
|
|
152
|
-
"items": { "type": "string", "minLength": 1 },
|
|
153
|
-
"description": "Token names to add to the naming-exceptions set for this platform."
|
|
154
|
-
},
|
|
155
|
-
"remove": {
|
|
156
|
-
"type": "array",
|
|
157
|
-
"items": { "type": "string", "minLength": 1 },
|
|
158
|
-
"description": "Token names to remove from the base naming-exceptions set for this platform."
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
"additionalProperties": false
|
|
130
|
+
"delimiter": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"minLength": 1,
|
|
133
|
+
"description": "Character(s) separating concepts in the serialized string. Default: -."
|
|
162
134
|
},
|
|
163
|
-
"
|
|
135
|
+
"abbreviations": {
|
|
164
136
|
"type": "object",
|
|
165
|
-
"
|
|
166
|
-
|
|
167
|
-
"conceptOrder": {
|
|
168
|
-
"type": "array",
|
|
169
|
-
"items": {
|
|
170
|
-
"type": "string"
|
|
171
|
-
},
|
|
172
|
-
"uniqueItems": true,
|
|
173
|
-
"description": "Ordered list of field names for serialization. Values must match declared field names from the design system's field catalog (field.schema.json declarations). Replaces the default serialization.position order from each field declaration."
|
|
174
|
-
},
|
|
175
|
-
"casing": {
|
|
176
|
-
"type": "string",
|
|
177
|
-
"enum": [
|
|
178
|
-
"kebab-case",
|
|
179
|
-
"camelCase",
|
|
180
|
-
"PascalCase",
|
|
181
|
-
"SCREAMING_SNAKE_CASE"
|
|
182
|
-
],
|
|
183
|
-
"description": "Casing style for serialized token names. Default: kebab-case."
|
|
184
|
-
},
|
|
185
|
-
"delimiter": {
|
|
186
|
-
"type": "string",
|
|
187
|
-
"minLength": 1,
|
|
188
|
-
"description": "Character(s) separating concepts in the serialized string. Default: -."
|
|
189
|
-
},
|
|
190
|
-
"abbreviations": {
|
|
191
|
-
"type": "object",
|
|
192
|
-
"additionalProperties": {
|
|
193
|
-
"type": "string"
|
|
194
|
-
},
|
|
195
|
-
"description": "Map of full term to abbreviated form, applied after ordering and before casing."
|
|
196
|
-
}
|
|
137
|
+
"additionalProperties": {
|
|
138
|
+
"type": "string"
|
|
197
139
|
},
|
|
198
|
-
"
|
|
140
|
+
"description": "Map of full term to abbreviated form, applied after ordering and before casing."
|
|
199
141
|
}
|
|
200
142
|
},
|
|
201
|
-
"additionalProperties":
|
|
143
|
+
"additionalProperties": false
|
|
202
144
|
}
|
|
203
145
|
},
|
|
204
146
|
"additionalProperties": false
|
|
@@ -24,9 +24,12 @@ schemas for its own data?
|
|
|
24
24
|
3. **No concrete need surfaced.** Nothing in the h890.22/h890.23 work (iOS
|
|
25
25
|
externalization, or the guidelines/fields/relationships/naming-exceptions cascade
|
|
26
26
|
additions) needed schema relaxation — every platform-local addition validates fine
|
|
27
|
-
against the existing schemas via
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
against the existing per-artifact schemas via the `extensions/` directory (see
|
|
28
|
+
[Manifest — `extensions/` directory](manifest.md#extensions-directory)). Each fragment
|
|
29
|
+
file there is checked against the same `component.schema.json` /
|
|
30
|
+
`field.schema.json` / `guideline.schema.json` / etc. as the foundation dataset, which
|
|
31
|
+
already covers "the platform wants to attach data the schema knows how to validate"
|
|
32
|
+
without touching the schema itself.
|
|
30
33
|
|
|
31
34
|
## Decision
|
|
32
35
|
|
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/mode-sets.md
CHANGED
|
@@ -27,11 +27,11 @@ A **mode set declaration** is a JSON object describing one axis of variation. It
|
|
|
27
27
|
|
|
28
28
|
These mode sets are declared in the `mode-sets/` catalog (see [Mode Set catalog](#mode-set-catalog)) and **SHOULD** be used consistently across Spectrum-compatible datasets:
|
|
29
29
|
|
|
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.
|
|
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. iOS platform data authors `increased` as a synonym for `high` — treat the two as the same crosswalk term, not distinct values. |
|
|
35
35
|
|
|
36
36
|
## Mode Set catalog
|
|
37
37
|
|
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
|