ADR 019
StatutStatus ActifActive
DateDate 2026-05-29
DécideursDecision makers Design System Lead

ADR-019 — Résolution dynamique des tokens dans le build

Date : 2026-05-29 Statut : ✅ Actif Décideurs : Design System Lead Type: contract Chemin logique: decisions/ADR-019-resolution-dynamique-tokens-build.md Lecture avant: AGENTS.md, DESIGN.md, .claude/rules/tokens-system.md Relations: tokens/primitives.json, tokens/semantic.json, site/build.js, decisions/ADR-018-migration-references-primitives-radix.md


Contexte

ADR-018 avait documenté deux dettes techniques restantes :

1. site/build.js hardcodait toutes les valeurs sémantiques dans un objet SEM statique 2. Les tokens non-couleur de semantic.json ({space.4}, {fontSize.md}, etc.) référençaient des primitives inexistantes dans primitives.json

Ces deux dettes s'adressaient ensemble : l'une rendait l'autre inévitable.

La dette dans build.js

// Avant — 37 lignes hardcodées, source de dérive possible
const SEM = {
  'color-action-primary': '#0d74ce',
  'space-control-padding-x': '16px',
  // ...
};

Si une valeur changeait dans primitives.json ou semantic.json, elle ne se propageait pas automatiquement dans le CSS généré — un humain devait mettre à jour build.js manuellement.

Les références non-couleur non résolues

semantic.json utilisait {space.4}, {radius.sm}, {fontSize.md}, etc. Aucune de ces références n'existait dans primitives.json (qui ne contenait que des couleurs). build.js contournait silencieusement ce problème avec les valeurs hardcodées.


Décision

1. Ajout des primitives non-couleur dans primitives.json

Cinq nouvelles catégories ajoutées sous primitive (au même niveau que color) :

CatégorieStepsValeurs
space2, 4, 5, 88px, 16px, 20px, 32px
fontSizesm, md, xl14px, 16px, 24px
fontWeightregular, medium, bold400, 500, 700
lineHeighttight, normal1.25, 1.5
radiussm, md6px, 10px

2. Mise à jour des références dans semantic.json

Toutes les références non-couleur migrent vers {primitive.X.Y} :

"padding-x": { "value": "{primitive.space.4}" }
"control":   { "value": "{primitive.radius.sm}" }
"size":      { "value": "{primitive.fontSize.md}" }

L'ensemble des 35 tokens sémantiques (19 couleurs + 16 non-couleur) référencent maintenant des chemins résolvables dans primitives.json.

3. Résolveur dynamique dans build.js

L'objet SEM hardcodé (37 lignes) est remplacé par trois fonctions :

// Parcourt l'arbre de tokens par chemin pointé
function resolveRef(ref, data) {
  return ref.split('.').reduce((node, key) => node?.[key], data);
}

// Résout une valeur {primitive.X.Y} → valeur CSS finale
function resolveValue(val, data) { ... }

// Aplatit les tokens imbriqués en clés CSS 'category-sub-name'
function flattenTokens(obj, data, prefix = '') { ... }

const SEM = flattenTokens(semanticData.semantic, primitives);

La résolution est faite au moment du build — toute modification dans primitives.json ou semantic.json se propage automatiquement dans site/dist/tokens.css.

4. Correction de extractColorScales

Ajout d'un guard if (step === '_readme') continue dans la boucle interne, pour protéger contre les entrées de documentation dans les scales de couleur.


Invariant de sortie — zéro changement visuel

Les 35 valeurs résolues après migration sont strictement identiques à celles de l'objet SEM hardcodé qu'elles remplacent. Vérifiable par diff :

--sda-semantic-color-action-primary: #0d74ce    ← inchangé
--sda-semantic-space-control-padding-x: 16px    ← inchangé
--sda-semantic-typography-body-line-height: 1.5 ← inchangé

Alternatives rejetées

AlternativeRaison du rejet
Utiliser Style DictionaryDépendance externe pour un build qui n'en a pas. Style Dictionary ajoute une configuration non triviale et une abstraction pour un résolveur qui s'écrit en ~20 lignes. Choix cohérent avec la philosophie du projet : pas de dépendance sans justification.
Garder le SEM hardcodé + ajouter des primitivesRésout la dette dans semantic.json mais laisse build.js désynchronisé. Un changement de token nécessiterait toujours deux modifications manuelles.
Résolveur récursif multi-niveaux (tokens référençant des tokens)Non nécessaire : dans ce système, les tokens sémantiques référencent uniquement des primitives, jamais d'autres sémantiques. Le résolveur single-level est suffisant et plus simple à auditer.

Conséquences

Pour le pipeline de build :

se propage automatiquement dans site/dist/tokens.css au prochain build

Pour les agents IA :

semantic.json{primitive.X.Y}primitives.json → valeur CSS

Dette technique soldée :

← ADR-018 ADR-020 →