@adobe/design-data-spec 0.3.0 → 0.5.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/components/accordion.json +517 -0
- package/components/action-bar.json +203 -0
- package/components/action-button.json +481 -0
- package/components/action-group.json +82 -0
- package/components/alert-banner.json +111 -0
- package/components/alert-dialog.json +152 -0
- package/components/avatar-group.json +140 -0
- package/components/avatar.json +184 -0
- package/components/badge.json +502 -0
- package/components/body.json +29 -0
- package/components/bottom-navigation-android.json +41 -0
- package/components/breadcrumbs.json +263 -0
- package/components/button-group.json +47 -0
- package/components/button.json +466 -8
- package/components/calendar.json +104 -0
- package/components/cards.json +512 -0
- package/components/checkbox-group.json +54 -0
- package/components/checkbox.json +303 -0
- package/components/close-button.json +170 -0
- package/components/coach-indicator.json +76 -0
- package/components/coach-mark.json +157 -0
- package/components/code.json +25 -0
- package/components/color-area.json +115 -0
- package/components/color-handle.json +85 -0
- package/components/color-loupe.json +74 -0
- package/components/color-slider.json +121 -0
- package/components/color-wheel.json +94 -0
- package/components/combo-box.json +480 -0
- package/components/contextual-help.json +162 -0
- package/components/date-picker.json +439 -0
- package/components/detail.json +30 -0
- package/components/divider.json +73 -0
- package/components/drop-zone.json +211 -0
- package/components/field-label.json +189 -0
- package/components/heading.json +33 -0
- package/components/help-text.json +186 -0
- package/components/illustrated-message.json +155 -0
- package/components/in-field-progress-button.json +44 -0
- package/components/in-field-progress-circle.json +80 -0
- package/components/in-line-alert.json +201 -0
- package/components/link.json +135 -0
- package/components/list-view.json +355 -0
- package/components/menu.json +542 -0
- package/components/meter.json +162 -0
- package/components/number-field.json +468 -0
- package/components/opacity-checkerboard.json +43 -0
- package/components/picker.json +522 -0
- package/components/popover.json +119 -0
- package/components/progress-bar.json +182 -0
- package/components/progress-circle.json +99 -0
- package/components/radio-button.json +285 -0
- package/components/radio-group.json +63 -0
- package/components/rating.json +145 -0
- package/components/scroll-zoom-bar.json +53 -0
- package/components/search-field.json +306 -0
- package/components/segmented-control.json +210 -0
- package/components/select-box.json +248 -0
- package/components/side-navigation.json +293 -0
- package/components/slider.json +370 -0
- package/components/standard-dialog.json +151 -0
- package/components/standard-panel.json +53 -0
- package/components/status-light.json +272 -0
- package/components/steplist.json +270 -0
- package/components/swatch-group.json +62 -0
- package/components/swatch.json +193 -0
- package/components/switch.json +305 -0
- package/components/tab-bar-ios.json +41 -0
- package/components/table.json +392 -0
- package/components/tabs.json +229 -0
- package/components/tag-field.json +203 -0
- package/components/tag-group.json +53 -0
- package/components/tag.json +376 -0
- package/components/takeover-dialog.json +92 -0
- package/components/text-area.json +485 -0
- package/components/text-field.json +501 -0
- package/components/thumbnail.json +109 -0
- package/components/title.json +39 -0
- package/components/toast.json +131 -0
- package/components/tooltip.json +140 -0
- package/components/tray.json +21 -0
- package/components/tree-view.json +341 -0
- package/conformance/invalid/SPEC-027/dataset.json +25 -0
- package/conformance/invalid/SPEC-027/expected-errors.json +10 -0
- package/conformance/valid/token-bindings.json +27 -0
- package/package.json +2 -1
- package/rules/rules.yaml +9 -0
- package/schemas/component.schema.json +24 -2
- package/schemas/token.schema.json +27 -0
- package/spec/agent-surface.md +39 -9
- package/spec/component-format.md +41 -16
- package/spec/token-format.md +18 -0
- package/src/validate.js +27 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/design-data-spec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Design Data Specification — prose, JSON Schemas, rule catalog, and conformance fixtures for Spectrum design data",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
"./package.json": "./package.json",
|
|
23
|
+
"./components/*.json": "./components/*.json",
|
|
23
24
|
"./schemas/token.schema.json": "./schemas/token.schema.json",
|
|
24
25
|
"./schemas/dimension.schema.json": "./schemas/dimension.schema.json",
|
|
25
26
|
"./schemas/field.schema.json": "./schemas/field.schema.json",
|
package/rules/rules.yaml
CHANGED
|
@@ -235,3 +235,12 @@ rules:
|
|
|
235
235
|
message: "Component '{component}' has custom state '{state}' with no description"
|
|
236
236
|
spec_ref: spec/state-model.md#canonical-state-vocabulary
|
|
237
237
|
introduced_in: "1.0.0-draft"
|
|
238
|
+
|
|
239
|
+
- id: SPEC-027
|
|
240
|
+
name: token-binding-token-exists
|
|
241
|
+
severity: error
|
|
242
|
+
category: reference-integrity
|
|
243
|
+
assert: Each tokenBindings[].token value in a component declaration MUST match the name of a declared token in the dataset.
|
|
244
|
+
message: "Component '{component}' tokenBindings references unknown token '{token}'"
|
|
245
|
+
spec_ref: spec/component-format.md#token-bindings
|
|
246
|
+
introduced_in: "1.0.0-draft"
|
|
@@ -63,6 +63,11 @@
|
|
|
63
63
|
},
|
|
64
64
|
"lifecycle": {
|
|
65
65
|
"$ref": "#/$defs/lifecycle"
|
|
66
|
+
},
|
|
67
|
+
"tokenBindings": {
|
|
68
|
+
"type": "array",
|
|
69
|
+
"items": { "$ref": "#/$defs/tokenBinding" },
|
|
70
|
+
"description": "Tokens this component uses, including foundation/structure tokens not scoped to the component in their name-object. See spec/component-format.md#token-bindings (Phase 6.7)."
|
|
66
71
|
}
|
|
67
72
|
},
|
|
68
73
|
"additionalProperties": false,
|
|
@@ -102,7 +107,7 @@
|
|
|
102
107
|
},
|
|
103
108
|
"optionDescriptor": {
|
|
104
109
|
"type": "object",
|
|
105
|
-
"description": "JSON Schema-compatible descriptor for a single component option.",
|
|
110
|
+
"description": "JSON Schema-compatible descriptor for a single component option. Standard JSON Schema keywords (type, enum, default, description, pattern, minimum, maximum, items, properties, etc.) are all permitted.",
|
|
106
111
|
"properties": {
|
|
107
112
|
"type": {
|
|
108
113
|
"oneOf": [
|
|
@@ -154,7 +159,7 @@
|
|
|
154
159
|
"description": "Reference to a shared type schema."
|
|
155
160
|
}
|
|
156
161
|
},
|
|
157
|
-
"additionalProperties":
|
|
162
|
+
"additionalProperties": true
|
|
158
163
|
},
|
|
159
164
|
"slotDeclaration": {
|
|
160
165
|
"type": "object",
|
|
@@ -233,6 +238,23 @@
|
|
|
233
238
|
},
|
|
234
239
|
"additionalProperties": false
|
|
235
240
|
},
|
|
241
|
+
"tokenBinding": {
|
|
242
|
+
"type": "object",
|
|
243
|
+
"required": ["token"],
|
|
244
|
+
"description": "A single token usage binding on a component declaration.",
|
|
245
|
+
"properties": {
|
|
246
|
+
"token": {
|
|
247
|
+
"type": "string",
|
|
248
|
+
"minLength": 1,
|
|
249
|
+
"description": "Token name string. MUST resolve to a known token in the dataset (rule SPEC-027)."
|
|
250
|
+
},
|
|
251
|
+
"context": {
|
|
252
|
+
"type": "string",
|
|
253
|
+
"description": "Human-readable label for how this token is used in the component (maps to Figma Token Group label)."
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
"additionalProperties": false
|
|
257
|
+
},
|
|
236
258
|
"lifecycle": {
|
|
237
259
|
"type": "object",
|
|
238
260
|
"description": "Version lifecycle metadata, mirroring the token lifecycle pattern.",
|
|
@@ -171,6 +171,11 @@
|
|
|
171
171
|
"description": {
|
|
172
172
|
"type": "string",
|
|
173
173
|
"description": "Plain text describing the token's purpose (aligns with DTCG $description)."
|
|
174
|
+
},
|
|
175
|
+
"componentBindings": {
|
|
176
|
+
"type": "array",
|
|
177
|
+
"items": { "$ref": "#/$defs/componentBinding" },
|
|
178
|
+
"description": "Reverse index: components that declare this token in their tokenBindings. Optional and derivable from component files."
|
|
174
179
|
}
|
|
175
180
|
},
|
|
176
181
|
"additionalProperties": false
|
|
@@ -240,6 +245,28 @@
|
|
|
240
245
|
"description": {
|
|
241
246
|
"type": "string",
|
|
242
247
|
"description": "Plain text describing the token's purpose (aligns with DTCG $description)."
|
|
248
|
+
},
|
|
249
|
+
"componentBindings": {
|
|
250
|
+
"type": "array",
|
|
251
|
+
"items": { "$ref": "#/$defs/componentBinding" },
|
|
252
|
+
"description": "Reverse index: components that declare this token in their tokenBindings. Optional and derivable from component files."
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
"additionalProperties": false
|
|
256
|
+
},
|
|
257
|
+
"componentBinding": {
|
|
258
|
+
"type": "object",
|
|
259
|
+
"required": ["component"],
|
|
260
|
+
"description": "A single component usage binding on a token — the reverse of tokenBindings on the component.",
|
|
261
|
+
"properties": {
|
|
262
|
+
"component": {
|
|
263
|
+
"type": "string",
|
|
264
|
+
"minLength": 1,
|
|
265
|
+
"description": "Component name (kebab-case). MUST match a declared component name."
|
|
266
|
+
},
|
|
267
|
+
"context": {
|
|
268
|
+
"type": "string",
|
|
269
|
+
"description": "Human-readable label for how this token is used in the component."
|
|
243
270
|
}
|
|
244
271
|
},
|
|
245
272
|
"additionalProperties": false
|
package/spec/agent-surface.md
CHANGED
|
@@ -25,15 +25,15 @@ The surface targets three consumer shapes:
|
|
|
25
25
|
|
|
26
26
|
**NORMATIVE:** A conforming implementation MUST expose the following operations. Transport-specific naming (CLI subcommand vs MCP tool name vs skill action) MAY differ; the semantics MUST NOT.
|
|
27
27
|
|
|
28
|
-
| Operation | Reads | Returns
|
|
29
|
-
| -------------------- | ------------------------------------------------------ |
|
|
30
|
-
| `resolve_token` | property + dimension context | winning token (literal or resolved alias) with file/UUID/specificity
|
|
31
|
-
| `query_tokens` | filter expression (see [Query](query.md)) | matching token list
|
|
32
|
-
| `validate_usage` | candidate token document or fragment | `ValidationReport` (Layer 1 + Layer 2 diagnostics)
|
|
33
|
-
| `describe_component` | component identifier | component contract (anatomy, options, states); see [#832](https://github.com/adobe/spectrum-design-data/discussions/832) | (Phase 6 contract) |
|
|
34
|
-
| `suggest_token` | natural-language intent + optional property hint | ranked candidate tokens with rationale (RECOMMENDED, not NORMATIVE in v1)
|
|
35
|
-
| `get_guidance` | token UUID, component identifier, or anatomy reference | attached document blocks (Phase 9 / RFC-D); falls back to empty list pre-RFC-D
|
|
36
|
-
| `diff_datasets` | two dataset roots | `DiffReport` per [Diff](diff.md)
|
|
28
|
+
| Operation | Reads | Returns | Backed by |
|
|
29
|
+
| -------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
|
|
30
|
+
| `resolve_token` | property + dimension context | winning token (literal or resolved alias) with file/UUID/specificity | `cascade::resolve` |
|
|
31
|
+
| `query_tokens` | filter expression (see [Query](query.md)) | matching token list | `query::filter` |
|
|
32
|
+
| `validate_usage` | candidate token document or fragment | `ValidationReport` (Layer 1 + Layer 2 diagnostics) | `validate::validate_*` |
|
|
33
|
+
| `describe_component` | component identifier | component contract (anatomy, options, states, tokenBindings); see [#832](https://github.com/adobe/spectrum-design-data/discussions/832) and [Phase 6.7](#describe_component-return-shape) | (Phase 6 contract) |
|
|
34
|
+
| `suggest_token` | natural-language intent + optional property hint | ranked candidate tokens with rationale (RECOMMENDED, not NORMATIVE in v1) | registry + query |
|
|
35
|
+
| `get_guidance` | token UUID, component identifier, or anatomy reference | attached document blocks (Phase 9 / RFC-D); falls back to empty list pre-RFC-D | document blocks |
|
|
36
|
+
| `diff_datasets` | two dataset roots | `DiffReport` per [Diff](diff.md) | `diff::semantic_diff` |
|
|
37
37
|
|
|
38
38
|
**NORMATIVE:** `validate_usage`, `resolve_token`, `query_tokens`, and `diff_datasets` MUST be implemented in a conforming agent surface. `suggest_token` and `get_guidance` are RECOMMENDED. `describe_component` becomes NORMATIVE once [#832](https://github.com/adobe/spectrum-design-data/discussions/832) reaches implemented status.
|
|
39
39
|
|
|
@@ -82,6 +82,36 @@ A reference Claude Code Agent Skill is RECOMMENDED at `tools/design-data-agent-m
|
|
|
82
82
|
|
|
83
83
|
**RECOMMENDED:** The skill SHOULD shell out to the CLI rather than embedding tool calls, so its description (the only persistent context cost) stays small and the heavy lifting happens out-of-band.
|
|
84
84
|
|
|
85
|
+
## `describe_component` return shape
|
|
86
|
+
|
|
87
|
+
The `describe_component` tool returns the component declaration object as stored in the dataset, extended with `tokenBindings` when Phase 6.7 data is present. A conforming implementation MUST include `tokenBindings` in the response when the component declaration contains that field.
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"name": "button",
|
|
92
|
+
"displayName": "Button",
|
|
93
|
+
"meta": { "category": "actions", "documentationUrl": "https://spectrum.adobe.com/page/button/" },
|
|
94
|
+
"options": {
|
|
95
|
+
"variant": { "type": "string", "enum": ["accent", "negative", "primary", "secondary"], "default": "accent" }
|
|
96
|
+
},
|
|
97
|
+
"anatomy": [
|
|
98
|
+
{ "name": "icon", "description": "Leading icon." },
|
|
99
|
+
{ "name": "label", "description": "Button text.", "required": true }
|
|
100
|
+
],
|
|
101
|
+
"states": [
|
|
102
|
+
{ "name": "hover", "trigger": "interaction", "precedence": 50 },
|
|
103
|
+
{ "name": "focus", "trigger": "interaction", "precedence": 60, "layered": true },
|
|
104
|
+
{ "name": "disabled", "trigger": "prop", "precedence": 100 }
|
|
105
|
+
],
|
|
106
|
+
"tokenBindings": [
|
|
107
|
+
{ "token": "component-height-100", "context": "Minimum height" },
|
|
108
|
+
{ "token": "corner-radius-full", "context": "Rounding" }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`tokenBindings` enables agents to retrieve a complete picture of a component's token usage — including shared structure and foundation tokens that do not carry the component name in their name-object — without issuing a second `query_tokens` call.
|
|
114
|
+
|
|
85
115
|
## Conformance
|
|
86
116
|
|
|
87
117
|
**NORMATIVE:** An agent surface implementation that claims conformance MUST:
|
package/spec/component-format.md
CHANGED
|
@@ -29,15 +29,16 @@ A component declaration **MUST** contain:
|
|
|
29
29
|
|
|
30
30
|
### Optional fields
|
|
31
31
|
|
|
32
|
-
| Field
|
|
33
|
-
|
|
|
34
|
-
| `specVersion`
|
|
35
|
-
| `description`
|
|
36
|
-
| `options`
|
|
37
|
-
| `slots`
|
|
38
|
-
| `anatomy`
|
|
39
|
-
| `states`
|
|
40
|
-
| `lifecycle`
|
|
32
|
+
| Field | Type | Description |
|
|
33
|
+
| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
34
|
+
| `specVersion` | string | Declares which spec version this document targets. Currently `"1.0.0-draft"`; future stable releases will accept their own version string. |
|
|
35
|
+
| `description` | string | Plain-text description of the component's purpose. |
|
|
36
|
+
| `options` | object | Component API options — see [Options](#options). |
|
|
37
|
+
| `slots` | array | Named content injection points — see [Slots](#slots). |
|
|
38
|
+
| `anatomy` | array | Named anatomy parts — see [Anatomy (stub)](#anatomy-stub). |
|
|
39
|
+
| `states` | array | Per-component state declarations — see [States (stub)](#states-stub). |
|
|
40
|
+
| `lifecycle` | object | Version lifecycle metadata — see [Lifecycle](#lifecycle). |
|
|
41
|
+
| `tokenBindings` | array | Tokens this component uses — see [Token bindings](#token-bindings) (Phase 6.7). |
|
|
41
42
|
|
|
42
43
|
**NORMATIVE:** No properties beyond those listed above are permitted at the top level of a component declaration. Additional fields **MUST** cause a Layer 1 schema error.
|
|
43
44
|
|
|
@@ -241,17 +242,41 @@ The `lifecycle` block tracks a component declaration's version history. It mirro
|
|
|
241
242
|
}
|
|
242
243
|
```
|
|
243
244
|
|
|
245
|
+
## Token bindings
|
|
246
|
+
|
|
247
|
+
The optional `tokenBindings` array declares which tokens a component uses, including foundation and structure tokens that do not carry the component name in their name-object. This is the *component-declares-usage* direction; the *token-declares-scope* direction is expressed via name-object `component`/`anatomy`/`state` fields and validated by SPEC-018–022.
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
"tokenBindings": [
|
|
251
|
+
{ "token": "component-height-100", "context": "Minimum height" },
|
|
252
|
+
{ "token": "corner-radius-full", "context": "Rounding" },
|
|
253
|
+
{ "token": "button-background-color-accent", "context": "Fill background" }
|
|
254
|
+
]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Each entry contains:
|
|
258
|
+
|
|
259
|
+
| Field | Required | Type | Description |
|
|
260
|
+
| --------- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
261
|
+
| `token` | yes | string | Token name. **MUST** resolve to a declared token in the dataset when the dataset is present (rule SPEC-027). May reference structure/foundation tokens. |
|
|
262
|
+
| `context` | no | string | Human-readable label for how this token is used (maps to the Figma Token Group label in the S2 Token Specs Figma file). |
|
|
263
|
+
|
|
264
|
+
**NORMATIVE:** When the dataset includes token declarations, each `tokenBindings[].token` value **MUST** match the name of a declared token (rule SPEC-027). A missing token reference is a validation error.
|
|
265
|
+
|
|
266
|
+
The `context` field is informative. It is used by `describe_component` (Phase 8 agent surface) to present token usage in grouped, human-readable form.
|
|
267
|
+
|
|
244
268
|
## SPEC rules
|
|
245
269
|
|
|
246
270
|
The following rules are added to the Layer 2 rule catalog (`rules/rules.yaml`) by this chapter. New component cross-reference rules start at SPEC-018 to avoid collision with existing token rules (SPEC-001–SPEC-017).
|
|
247
271
|
|
|
248
|
-
| Rule ID | Name
|
|
249
|
-
| -------- |
|
|
250
|
-
| SPEC-018 | `component-name-exists`
|
|
251
|
-
| SPEC-019 | `component-variant-valid`
|
|
252
|
-
| SPEC-020 | `component-anatomy-valid`
|
|
253
|
-
| SPEC-021 | `component-slot-vocabulary`
|
|
254
|
-
| SPEC-022 | `component-state-valid`
|
|
272
|
+
| Rule ID | Name | Severity | Assert |
|
|
273
|
+
| -------- | ---------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
274
|
+
| SPEC-018 | `component-name-exists` | error | Token `component` field value **MUST** match the `name` of a declared component in the dataset. |
|
|
275
|
+
| SPEC-019 | `component-variant-valid` | error | Token `variant` field value **MUST** match a value in the declared `variant` option enum for the referenced component (when that enum exists). |
|
|
276
|
+
| SPEC-020 | `component-anatomy-valid` | error | Token `anatomy` field value **MUST** match the `name` of a declared anatomy part on the referenced component. |
|
|
277
|
+
| SPEC-021 | `component-slot-vocabulary` | warning | Component `slots` entries with a `name` outside the canonical vocabulary **SHOULD** include a `description`. Custom slot names without descriptions are surfaced as warnings. |
|
|
278
|
+
| SPEC-022 | `component-state-valid` | error | Token `state` field value **MUST** match the `name` of a declared state on the referenced component (when state declarations are present). |
|
|
279
|
+
| SPEC-027 | `token-binding-token-exists` | error | Each `tokenBindings[].token` value **MUST** match the name of a declared token in the dataset (Phase 6.7). |
|
|
255
280
|
|
|
256
281
|
## Full example
|
|
257
282
|
|
package/spec/token-format.md
CHANGED
|
@@ -218,6 +218,24 @@ Within a composite value, a string sub-value **MAY** be an **inline alias**: a r
|
|
|
218
218
|
|
|
219
219
|
**NORMATIVE:** Inline aliases within composite values are subject to alias resolution rules. Validators **MUST** resolve inline aliases and report errors for missing targets (SPEC-014), type mismatches (SPEC-015), and circular references (SPEC-003, extended).
|
|
220
220
|
|
|
221
|
+
## Component bindings
|
|
222
|
+
|
|
223
|
+
The optional `componentBindings` array on a token is the **reverse index** of `tokenBindings` on a component declaration (Phase 6.7). It declares which components reference this token in their `tokenBindings` list.
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
"componentBindings": [
|
|
227
|
+
{ "component": "button", "context": "Minimum height" },
|
|
228
|
+
{ "component": "checkbox", "context": "Height" }
|
|
229
|
+
]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
| Field | Required | Type | Description |
|
|
233
|
+
| ----------- | -------- | ------ | -------------------------------------------------------------------- |
|
|
234
|
+
| `component` | yes | string | Component name (kebab-case). MUST match a declared component `name`. |
|
|
235
|
+
| `context` | no | string | Human-readable label for how this token is used in the component. |
|
|
236
|
+
|
|
237
|
+
`componentBindings` is **informative and optional**. It is fully derivable from the `tokenBindings` arrays on component declarations and does not need to be hand-maintained. Tooling that generates component files may populate `componentBindings` as a convenience for consumers that query token files directly.
|
|
238
|
+
|
|
221
239
|
## Relationship to legacy Spectrum tokens
|
|
222
240
|
|
|
223
241
|
The current `@adobe/spectrum-tokens` JSON uses **sets** (`color-set`, `scale-set`, …). This specification describes the **target** per-token model. Mapping from legacy to this format is out of scope for this document; see [#743](https://github.com/adobe/spectrum-design-data/issues/743).
|
package/src/validate.js
CHANGED
|
@@ -13,9 +13,9 @@ governing permissions and limitations under the License.
|
|
|
13
13
|
/**
|
|
14
14
|
* Layer 2 cross-reference validator for design-data-spec.
|
|
15
15
|
*
|
|
16
|
-
* Implements SPEC-018 through SPEC-
|
|
17
|
-
* name-object fields against component declarations,
|
|
18
|
-
* declarations internally.
|
|
16
|
+
* Implements SPEC-018 through SPEC-027: semantic rules that validate token
|
|
17
|
+
* name-object fields against component declarations, validate component
|
|
18
|
+
* declarations internally, and validate tokenBindings references.
|
|
19
19
|
*
|
|
20
20
|
* @see spec/component-format.md#spec-rules
|
|
21
21
|
* @see spec/anatomy-format.md#spec-rules
|
|
@@ -162,5 +162,29 @@ export function validateDataset(dataset) {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
// --- Token binding rules ---
|
|
166
|
+
|
|
167
|
+
// SPEC-027: each tokenBindings[].token must resolve to a known token name.
|
|
168
|
+
// String-named tokens are matched directly. Name-object tokens are skipped
|
|
169
|
+
// here because tokenBindings always reference tokens by their string name.
|
|
170
|
+
const tokenNameSet = new Set(
|
|
171
|
+
tokens
|
|
172
|
+
.map((t) => (typeof t.name === "string" ? t.name : null))
|
|
173
|
+
.filter(Boolean),
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
for (const component of components) {
|
|
177
|
+
for (const binding of component.tokenBindings ?? []) {
|
|
178
|
+
if (!tokenNameSet.has(binding.token)) {
|
|
179
|
+
diagnostics.push({
|
|
180
|
+
ruleId: "SPEC-027",
|
|
181
|
+
severity: "error",
|
|
182
|
+
message: `Component '${component.name}' tokenBindings references unknown token '${binding.token}'`,
|
|
183
|
+
componentName: component.name,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
165
189
|
return diagnostics;
|
|
166
190
|
}
|