Le schéma est la seule autorité
Un type de step s'ajoute dans le schéma, et il apparaît dans la validation, dans l'autocomplétion et dans l'éditeur visuel sans qu'on écrive une ligne d'interface. Voilà ce que ça a demandé.
Un scénario Nexmesh est un fichier YAML, et ce qu’il accepte est décrit par un JSON Schema. Rien d’original jusque-là. Ce qui l’est un peu plus, c’est que trois consommateurs en dérivent, et qu’aucun ne redéclare quoi que ce soit.
- le processus principal valide avec Ajv avant l’exécution ;
- l’éditeur de texte le pousse dans monaco-yaml, qui s’en sert pour valider à la frappe et pour l’autocomplétion ;
- l’éditeur visuel génère ses formulaires depuis le schéma, chaque champ étant traduit en contrôle selon son type.
Le résultat est celui qu’on cherchait. Un type de step, un champ ou une condition s’ajoutent dans le schéma seul, et apparaissent aux trois endroits.
Pourquoi ça vaut le détour
L’autre approche est la plus naturelle : un schéma pour valider, et des formulaires écrits à la main pour l’éditeur. Elle marche parfaitement le jour où on l’écrit.
Ce qu’elle coûte arrive après. Un champ ajouté au schéma et oublié dans le formulaire est invisible. Rien n’échoue, le champ existe simplement pour qui écrit du YAML à la main et pas pour qui compose à la souris. On ne le voit pas en relisant le code, il faut ouvrir l’éditeur et chercher ce qui manque. Et un champ retiré du schéma mais laissé dans le formulaire est pire, puisqu’il écrit une clé que la validation refusera : le scénario ne part plus.
Trente-trois types de step, chacun avec ses champs propres et ses champs communs. Le décalage n’était pas une possibilité, c’était une certitude.
Les deux corollaires
Ajv compile le schéma au chargement du module. Toute modification du schéma demande donc un redémarrage complet, le rechargement à chaud ne suffit pas. C’est le genre de détail qui fait perdre une demi-heure une fois, puis plus jamais.
Tout champ doit porter une description. C’est le texte que l’éditeur affiche
sous le contrôle : un champ sans description arrive nu dans le formulaire, et
personne ne sait ce qu’on y attend. Subtilité au passage, un $ref fait
ignorer ses voisins à la validation, mais l’éditeur, lui, lit bien la
description qui l’accompagne. Il faut donc l’écrire même si Ajv ne la regardera
pas.
Et quand le format change
Un scénario porte le numéro du format qui l’a écrit. Ce numéro avance à chaque changement incompatible, et des migrations s’appliquent dans l’ordre depuis la génération du fichier.
Elles travaillent sur le document YAML et non sur un objet JavaScript reconstruit. Un fichier migré garde donc ses commentaires, ses lignes vides et l’ordre de ses clés. C’est la même règle que suit l’éditeur visuel : on ne réécrit jamais un fichier depuis zéro, on modifie l’arbre qu’on a lu.
Un changement incompatible demande trois gestes. Avancer le numéro, ajouter la migration qui l’atteint, et mettre à jour le modèle de nouveau scénario avec les exemples. Un test les réclame tous les trois, parce que trois gestes dont un seul est fait, c’est exactement ce qui arrive à six heures du soir.
Le format est publié à part
Le format et son analyse vivent dans un paquet npm à eux, sans Electron ni ADB. L’application le consomme par ses sources, le service l’installe depuis le registre.
C’est le même code des deux côtés, et c’est tout l’intérêt. Sinon un même fichier aurait deux verdicts selon l’endroit où on le juge : valide sur le poste qui l’a écrit, refusé par le service qui le reçoit, et personne pour dire lequel a raison.
Nexmesh