This page defines DSDS 0.22.0. The schema gives the exact shape of every field. This page says what those shapes mean together, and what a document, a validator and a consumer have to do. If the two ever seem to disagree, the schema is right and this page has a bug.
1. Conventions
1.1 Requirement words
MUST, MUST NOT, SHOULD, SHOULD NOT and MAY mean what RFC 2119 says, and only when written in capitals.
1.2 What enforces each requirement
Every MUST and MUST NOT on this page ends with what checks it, in parentheses:
- (schema: entries/entry): the JSON Schema file schema/entries/entry.schema.yaml. Any JSON Schema validator checks it.
- (DSDS-04): a rule in the rule catalog. A conforming validator checks it, on top of the schema.
- (vector: addresses): a consumer test vector whose expected answer depends on it.
- (suite): the conformance suite, which tests a validator.
- (consumer): a requirement on what a consumer does with a document. No check on the document itself can see it.
npm run check fails if a requirement on this page or in the processing model has nothing in parentheses. It also fails if one names a schema file, rule or vector that doesn't exist, or if a validator rule isn't named anywhere.
1.3 Terms
This page uses the words in the terms table:
- a document is one file;
- an entry is one documented thing;
- a section is one member of an entry's sections;
- an item is one member of a section's items;
- a field is a named slot on an object.
1.4 Conformance classes
The Conformance page defines four kinds of conforming thing: document, producer, consumer and validator. A conforming document meets every requirement in §2 to §7. A conforming validator meets §8. A conforming consumer meets §9 and the processing model.
2. Documents
2.1 Format
A document is one YAML 1.2 or JSON file, and its top level MUST be a single mapping (schema: base, entries/entry). By convention, YAML files end in .dsds.yaml and JSON files in .dsds.json.
2.2 Base documents
A document with a schemaVersion field is a base document. It MUST have schemaVersion, name and an entries list that isn't empty (schema: base). It MUST NOT have any field that base.schema.yaml doesn't declare (schema: base). schemaVersion SHOULD name the DSDS version the document was written for.
A base document's shared list holds content that no single entry owns, such as an accessibility rule many components follow. A shared entry MUST have an id, a name and a description (schema: shared). Entries and shared entries draw ids from the same pool, so one id MUST NOT name two of them in a document (DSDS-04).
2.3 Entry documents
A document with no schemaVersion is a single entry, written at the top level (schema: entries/entry). §4 applies to it in the same way as to an entry in entries.
2.4 Projects
A large system is usually split across several files. A base document lists the others in refs, with rel: file. A rel: file ref MUST point at another DSDS document (DSDS-25). A code file or a DTCG token file is rel: source instead.
A relative path MUST point at a file that exists (DSDS-11). That applies to the path in a rel: file or rel: source ref, in a component's sourceFiles, and in a token's or theme's source.
The code a system describes often lives somewhere other than its documents, such as in a separate repository. A system entry can say where with metadata.sourceRoot: a path relative to its own document, or a URL. When a project's system sets it, every relative sourceFiles path in the project MUST be read starting from there (DSDS-11). The processing model, §3 says how a consumer gathers a project's files.
3. Identifiers
3.1 Entry ids
An entry's id MUST be lowercase words joined by dashes, with dots allowed between parts, like button or color.action.primary (schema: entries/entry, common/id). A token's id MAY also use a design tool's own capitals and slashes, like Color/Action/Primary (schema: entries/token).
3.2 Item ids and addresses
A section item doesn't need an id. When it has none, a consumer MUST give it one made from its own text (vector: addresses). If an address points at two things on one entry, and neither one wins, that's an error (DSDS-05). The processing model, §2 has the full rules.
3.3 Trait ids
A trait's id, and an enum value's, copy a real API name in whatever case the API uses, like isDisabled. They MUST NOT contain a dot, because traitId.valueId is how one value is addressed (schema: entries/component, common/id).
3.4 Namespaced values
Some values can be custom: an entry kind, a section kind, a section's context, a rel, and every key in $extensions. A custom one MUST be namespaced: lowercase parts with at least one dot, like acme.icon-library (schema: common/id, common/extensions, entries/entry, sections/section, common/ref). The dot means a custom value can never clash with a built-in one.
4. Entries
4.1 Every entry
Every entry MUST have kind, id, name and description (schema: entries/entry). description says what the entry is and why it exists, starting with what it is.
kind MUST be system, token, theme, component or entry, or a namespaced custom kind (schema: entries/entry). Use entry for content like patterns, foundations, guides, or anything else that has no kind of its own.
A system, token, theme or component entry MUST NOT have any field its schema file doesn't declare (schema: entries/component, entries/token, entries/theme, entries/system). A generic entry and a custom kind accept extra fields. On a generic entry, a validator warns about a field no DSDS schema declares (DSDS-24). What fields a custom kind has is up to whoever made it.
4.2 Metadata
Every date in metadata MUST be written as YYYY-MM-DD (schema: metadata/metadata).
metadata.status is one status object, or a list with one for each platform. A status MUST have a status word (schema: metadata/entry-metadata). When the word is deprecated, the status MUST also have a deprecationNotice that says what to use instead (schema: metadata/entry-metadata). It can name the replacement in replacedBy, which MUST NOT appear in a status that isn't deprecated (schema: metadata/entry-metadata).
4.3 Components
A component's sourceFiles points at its real source code, with one entry for each platform. Each entry MUST have a platform and a file (schema: entries/component). Two entries MUST NOT name the same platform (DSDS-01).
Each of a component's traits MUST say whether it's a variant or a state with traitType, and whether it's a boolean or an enum with kind (schema: entries/component). Each trait MUST also have an id and a description (schema: entries/component). An enum trait MUST list its values, each with an id and a description (schema: entries/component). A trait or a value MAY have its own status, with the same shape as an entry's.
Whether the caller sets a trait as a prop is a fact about the component's API, so DSDS doesn't record it. A consumer reads it from sourceFiles or specs.
4.4 Combos
A component's or token's combos are rules about what can be paired with what. Each MUST have a subject, an items list that isn't empty, and a level (schema: common/combo). must and should allow the pairing. should-not and must-not forbid it.
Each subject or item MUST name one of three things (schema: common/combo; DSDS-09):
- a trait on the same entry, like size, or one of its values, like size.small;
- a token, in braces, like \{color.action.primary\};
- an entry.
4.5 Tokens, themes and systems
A token's tokenType names its DTCG type, and MUST be a camelCase word like color or fontFamily (schema: entries/token). A token's value lives in the DTCG file its source points at, never in the DSDS document.
A theme's colorScheme MUST be light or dark (schema: entries/theme).
A system's metadata.platforms lists the platforms it ships on. Once that list exists, every platform in the document MUST be one of them (DSDS-02). That covers a status, a sourceFiles entry and an imports entry.
5. Sections
5.1 Every section
Every section MUST have a kind and a for (schema: sections/section). It MUST also have items, freeform content, or both (schema: sections/section). kind is guidelines, definitions, steps, section, or a namespaced custom kind.
for says who the section is written for: all, human or agent. A tool showing documentation to people SHOULD NOT show a for: agent section. An agent SHOULD read every section, not only the for: agent ones.
A guidelines, definitions or steps section MUST NOT have any field that its schema file doesn't declare, on the section or on its items (schema: sections/guidelines, sections/definitions, sections/steps). A generic section is checked the same way as a generic entry (DSDS-24).
Each freeform entry MUST have a title (schema: sections/section).
5.2 Guidelines
A guideline item states one rule. It MUST have a statement, with two exceptions (schema: sections/guidelines):
- its refs reuse another item with same-as;
- its refs link to where the rule is tracked, with a relates-to href.
It MUST have a level unless it has refs (schema: sections/guidelines).
When an item that reuses another states its own level, the two MUST match (DSDS-10).
checkedBy says how the rule is checked: automated, assisted or manual. An automated rule MUST list at least one test, lint rule or agent eval in checks that runs it (DSDS-03).
5.3 Definitions and steps
A definitions item MUST have a term and a definition, unless it has refs (schema: sections/definitions). A steps item MUST have a title, unless it has refs (schema: sections/steps).
Use context on a definitions section to say what it's for: anatomy, terms, keyboard, events, or a namespaced value.
6. Pointers
6.1 Shape
A pointer has either to, which names something in the project, or href, which names something outside it. A pointer MUST NOT have both (schema: common/ref). A bare string is short for \{href: \}.
A to names an entry by its id, or one thing inside it as entryId#address. It MUST be shaped like an id (schema: common/ref). It MUST point at something that exists in the project (DSDS-08, DSDS-05).
6.2 Where each kind of pointer goes
There are fourteen kinds of pointer, and each one is a rel value. Eight have a field of their own. A pointer in one of those fields MUST NOT have a rel, because the field already says what kind it is (schema: common/ref, entries/entry, sections/guidelines, metadata/entry-metadata):
| Field | On | Kind |
|---|
| uses | entry, section item | uses |
| extends | entry | extends |
| alternatives | entry, guideline item | alternative-to |
| specs | component | contract |
| evidence | guideline item | cites |
| checks | guideline item | checked-by |
| refines | guideline item | refines |
| replacedBy | deprecated status | replaced-by |
The other six go in refs: same-as, file, source, design, demo and relates-to. A pointer in refs MUST have a rel (schema: common/ref). A rel MUST be one of the fourteen, or namespaced (schema: common/ref). When an object has a field for a kind of pointer, that kind MUST go in the field, not in refs (DSDS-25).
source belongs to both groups. Three fields each hold one source, with no rel: a token's source and a theme's source (their DTCG file), and the file in each of a component's sourceFiles (schema: entries/token, entries/theme, entries/component). Any other source, such as the package that ships the component, goes in refs as rel: source.
For what each kind means, which end it's written on, and what a consumer does with it, see the table in the processing model, §5.
6.3 Placement
A same-as pointer MUST sit on a section item, and MUST point at an item of the same section kind (DSDS-25). A successor named in replacedBy MUST sit in the status of a deprecated entry, trait or trait value (schema: metadata/entry-metadata, entries/component).
6.4 Direction and chains
A relationship is written once, on the thing it starts from. A consumer MUST NOT require it to be written on the other end too (vector: inverse).
Following uses, extends, same-as or replaced-by from one thing to the next MUST NOT lead back to where it started (DSDS-06).
7. Extensions
$extensions holds data for one particular tool. It can sit on a document, an entry, a section or an item. Each key MUST be namespaced, and each value MUST be a mapping (schema: common/extensions). What goes inside is up to the tool: DSDS doesn't read it.
There are three ways to extend DSDS: a custom kind, a profile that makes optional fields required for one project, and $extensions. See Extending.
8. Validators
A conforming validator MUST check a document against this version's schema, with format checks turned on (suite). It MUST also check every semantic rule in the rule catalog (suite). It MUST reject every example in the conformance suite, for the reason that example gives (suite).
DSDS-05, DSDS-08, DSDS-09, DSDS-11 and DSDS-24 report a warning, not an error. They can't always see every file a document depends on, or can't be sure a field is a mistake. A validator SHOULD offer a strict mode that treats them as errors.
The advisory rules (DSDS-13 and up) are suggestions. A finding from one never stops a document from conforming.
9. Consumers
A conforming consumer follows the processing model. It also has to do the following:
- It MUST NOT fail because a document has an optional field it doesn't recognize (consumer).
- When it writes a document back out, it MUST keep any $extensions content it doesn't understand (consumer).
- It SHOULD treat a document's must and must-not rules as binding only after deciding to trust whoever wrote the document. A document is data from its author, not instructions. See Security.
10. Versions
DSDS follows the version rules on the Stability page: what can change in a patch, a minor and a major release, and what has to be true before 1.0. Each release's schema is published at its own URL and never changes after the release.