Repository navigation
Référence de Syntaxe
English | Français
Version : 1.0
Dernière mise à jour : 2026-10-10
Format : YAML ou JSON
- Vue d'ensemble
- Format de fichier
- Structure racine
- Section metadata
- Options globales
- Section commands
- Définition de commande
- Arguments
- Options
- Options répétables
- Types d'arguments
- Règles de validation
- Exemple complet
- Bonnes pratiques
Voir aussi : Directives du REPL · Guide des plugins
Le fichier de configuration définit toutes les commandes CLI et le comportement REPL pour les applications construites avec dynamic-cli.
Fonctionnalités clés :
- Définir des commandes sans écrire de code
- Support des arguments positionnels et des options
- Validation et vérification de type automatiques
- Extensible avec des handlers personnalisés
Formats supportés :
- YAML (
.yaml,.yml) - Recommandé pour la lisibilité - JSON (
.json) - Compatible avec les outils existants
metadata:
version: "1.0.0"
prompt: "monapp"
prompt_suffix: " > "
global_options:
- name: "verbose"
# ...
commands:
- name: "init"
# ...{
"metadata": {
"version": "1.0.0",
"prompt": "monapp",
"prompt_suffix": " > "
},
"global_options": [
{
"name": "verbose"
}
],
"commands": [
{
"name": "init"
}
]
}Note : Les exemples YAML sont utilisés dans ce document pour la lisibilité.
Le fichier de configuration comporte trois sections principales :
metadata: # Métadonnées de l'application
# ...
global_options: # Options disponibles pour TOUTES les commandes
# ...
commands: # Liste des commandes disponibles
# ...
directives: # Facultatif : redéfinition des directives du REPL
# ...metadata et commands sont obligatoires. global_options est
facultative et vaut par défaut une liste vide. directives est
facultative : voir Directives du REPL.
Informations au niveau de l'application.
metadata:
version: string # Obligatoire - Version de la configuration
prompt: string # Obligatoire - Texte du prompt REPL
prompt_suffix: string # Facultatif - Suffixe après le prompt (défaut : " > ")| Champ | Type | Obligatoire | Description |
|---|---|---|---|
version |
string | ✅ Oui | Version du fichier de configuration (versioning sémantique recommandé) |
prompt |
string | ✅ Oui | Texte affiché en mode REPL (ex : "monapp", "rpn") |
prompt_suffix |
string | ❌ Non | Texte après le prompt (défaut : " > " ; typiquement " > " ou "$ "). Depuis la v0.9.0 (#67), c'est bien cette valeur que ReplInterface affiche réellement — une version antérieure ignorait ce champ et affichait toujours " > ". |
metadata:
version: "1.0.0"
prompt: "rpn"
prompt_suffix: " > "Affichage REPL :
rpn > _
Depuis la v0.9.0 (DD-027).
En mode REPL interactif, une ligne se terminant par un \ n'est pas
exécutée immédiatement : le marqueur est retiré, la ligne est mise en
tampon, le prompt bascule sur un prompt de continuation dérivé de
prompt/prompt_suffix ci-dessus, et une nouvelle ligne est lue. La
première ligne qui ne se termine pas par \ complète la commande
— chaque fragment mis en tampon et cette dernière ligne sont joints
par un unique espace puis exécutés une seule fois, à l'image de la
convention Unix classique du shell.
Ceci est indépendant du Chaînage de commandes (DD-026) : le chaînage enchaîne plusieurs commandes complètes en une seule invocation ; cette fonctionnalité permet aux options d'une seule commande de s'étaler sur plusieurs lignes du REPL. Les deux se combinent sans se gêner mutuellement.
rpn > push \
...> 0
- Seul un
\en fin de ligne déclenche l'accumulation — aucun autre terminateur explicite (ex :;) n'est reconnu. - La ligne reconstruite (fragments joints par un unique espace,
marqueurs
\retirés) est ce qui atteint l'historique du REPL — jamais un fragment brut partiel. - Un
Ctrl+Cpendant l'accumulation vide le tampon et revient au prompt normal, comme l'abandon d'une ligne continuée dans un shell.
Dérivation du prompt de continuation : le segment correspondant au
nom de l'application dans prompt est remplacé par ..., et
prompt_suffix est ajouté après avoir retiré ses espaces de tête —
pour se lire comme une marque continue accolée au séparateur plutôt
que de laisser un espace parasite :
prompt |
prompt_suffix |
Prompt principal | Prompt de continuation (défaut) |
|---|---|---|---|
rpn |
" > " (défaut) |
rpn > |
...> |
rpn |
" $ " |
rpn $ |
...$ |
Le segment de base (... ci-dessus) peut être remplacé côté Rust via
CliBuilder::prompt_multiline()
— il n'existe aucun champ YAML pour cela, car c'est un détail
d'affichage du REPL interactif, pas une partie du schéma de commandes.
Une surcharge ne remplace que la base ; prompt_suffix reste ajouté,
mais sans retirer ses espaces de tête cette fois — la surcharge
est le choix d'espacement de l'appelant :
CliBuilder::new()
.prompt("rpn")
.prompt_multiline("_ _ _")
// prompt_suffix == " $ " → prompt de continuation : "_ _ _ $ "Limitation connue — pas de politique abandon/continuation
configurable : une commande signalée comme complète (pas de \
final) mais à qui il manque encore un argument ou une option
obligatoire échoue immédiatement avec l'erreur exacte
MissingArgument/MissingOption d'aujourd'hui — il n'y a pas de
boucle de re-sollicitation. Délibéré, pas un oubli : le mode CLI en
une fois (CliInterface::run()), run_script() et :load n'ont
aucun opérateur en direct à qui redemander, donc ils abandonnent
toujours sur une commande incomplète ; le REPL garde le même
comportement d'abandon, pour une parité CLI/REPL. Non planifié pour
évoluer ; à revoir seulement si un besoin concret se présente.
Portée : s'applique uniquement à ReplInterface::run() (REPL
interactif). En mode CLI en une fois, le shell appelant a déjà fusionné
toute ligne continuée par \ avant que dynamic-cli ne voie son
argv — rien à implémenter dans ce cas. run_script() et la
directive :load du REPL ne sont pas concernés : chaque ligne
est exécutée indépendamment, et un \ en fin de ligne de script est
lu comme n'importe quel autre jeton.
Options qui sont disponibles pour TOUTES les commandes de l'application.
global_options:
- name: string # Obligatoire - Identifiant unique
short: string # Optionnel - Caractère unique (ex : "v")
long: string # Optionnel - Forme longue (ex : "verbose")
option_type: ArgumentType # Obligatoire - Type de données
required: boolean # Optionnel - Doit être fourni ? (défaut : false)
default: string # Optionnel - Valeur par défaut si non fourni
description: string # Obligatoire - Texte d'aide
choices: [string] # Optionnel - Liste des valeurs valides| Champ | Type | Obligatoire | Description |
|---|---|---|---|
name |
string | ✅ Oui | Identifiant interne (utilisé dans les handlers) |
short |
string | ⬜ Non | Forme courte du flag (caractère unique, ex : "v" pour -v) |
long |
string | ⬜ Non | Forme longue du flag (ex : "verbose" pour --verbose) |
option_type |
string | ✅ Oui | Un parmi : string, integer, float, bool, path
|
required |
boolean | ⬜ Non | Si true, doit être fourni par l'utilisateur (défaut : false) |
default |
string | ⬜ Non | Valeur par défaut (comme chaîne, sera parsée selon le type) |
description |
string | ✅ Oui | Texte d'aide pour l'utilisateur |
choices |
array | ⬜ Non | Restreindre les valeurs à une liste spécifique |
Flag verbose :
- name: "verbose"
short: "v"
long: "verbose"
option_type: "bool"
required: false
default: "false"
description: "Activer la sortie verbeuse"Utilisation :
monapp -v commande
monapp --verbose commandeRépertoire de sortie :
- name: "output"
short: "o"
long: "output"
option_type: "path"
required: false
description: "Répertoire de sortie pour les résultats"Utilisation :
monapp -o /tmp/resultats commande
monapp --output ./sortie commandeSélection de format :
- name: "format"
short: "f"
long: "format"
option_type: "string"
required: false
default: "text"
description: "Format de sortie"
choices: ["text", "json", "yaml"]Utilisation :
monapp --format json commande
monapp -f yaml commande- Au moins un de
shortoulongdoit être fourni - Les deux peuvent être fournis pour une flexibilité maximale
- Les options globales sont passées à tous les handlers de commandes
Liste des commandes disponibles dans l'application.
commands:
- name: string # Obligatoire - Nom de la commande
aliases: [string] # Optionnel - Noms alternatifs (défaut : [])
description: string # Obligatoire - Texte d'aide
required: boolean # Optionnel - Handler obligatoire ? (défaut : false)
arguments: [ArgumentDefinition] # Optionnel - Arguments positionnels (défaut : [])
options: [OptionDefinition] # Optionnel - Options spécifiques à la commande (défaut : [])
implementation: string # Obligatoire - Nom de la fonction handler| Champ | Type | Obligatoire | Description |
|---|---|---|---|
name |
string | ✅ Oui | Nom principal de la commande (pas d'espaces, minuscules recommandées) |
aliases |
array | ❌ Non | Noms alternatifs (ex : ["quitter", "q"] pour exit ; défaut : []) |
description |
string | ✅ Oui | Texte d'aide pour l'utilisateur |
required |
boolean | ❌ Non | Si true, un handler doit être enregistré pour cette commande, sinon la construction de l'application échoue (défaut : false) |
arguments |
array | ❌ Non | Liste des arguments positionnels (défaut : []) |
options |
array | ❌ Non | Options spécifiques à la commande (défaut : []) |
implementation |
string | ✅ Oui | Identifiant pour le handler de commande (référencé dans le code) |
commands:
- name: "input"
aliases: ["charger", "ouvrir"]
description: "Charger un fichier de configuration"
required: true
arguments:
- name: "fichier"
arg_type: "path"
required: true
description: "Chemin vers le fichier d'entrée"
validation:
- must_exist: true
- extensions: [".yaml", ".json"]
options: []
implementation: "load_config"Utilisation :
monapp input config.yaml
monapp charger config.yaml
monapp ouvrir config.jsonDétail complet d'une commande individuelle.
- name: "nom-commande"
aliases: ["alt1", "alt2"]
description: "Ce que fait cette commande"
required: false
arguments:
- name: "arg1"
arg_type: "string"
required: true
description: "Premier argument"
validation: []
- name: "arg2"
arg_type: "integer"
required: false
description: "Deuxième argument optionnel"
validation:
- min: 1
max: 100
options:
- name: "option1"
short: "o"
long: "option"
option_type: "bool"
required: false
default: "false"
description: "Activer l'option"
choices: []
implementation: "nom_handler"
continue_on_failure: false
requires_success: falsename (chaîne de caractères, obligatoire) :
- Identifiant principal de la commande
- Utilisé en CLI :
monapp <nom> - Convention : minuscules, pas d'espaces, utiliser des traits d'union pour les mots multiples (ex :
lancer-simulation) - Ne peut pas commencer par
:, qui signale les directives du REPL
aliases (liste de chaînes de caractères, optionnel, défaut []) :
- Noms alternatifs pour la même commande
- Exemple :
aliases: ["quitter", "q", "sortir"] - Tous les alias invoquent le même handler
- Comme
name, un alias ne peut pas commencer par:
description (chaîne de caractères, obligatoire) :
- Texte d'aide pour l'utilisateur
- Affiché dans la sortie de la commande
help - Devrait être concis mais clair (une phrase recommandée)
required (booléen, optionnel, défaut false) :
-
true: un handler doit être enregistré pour cette commande ; sinon, la construction de l'application échoue -
false: la commande est ignorée à la construction si aucun handler n'est enregistré pour elle - Ne dit rien de l'exécution de la commande : la lancer ou non revient à l'utilisateur
arguments (liste, optionnel, défaut []) :
- Liste des arguments positionnels
- L'ordre compte (parsés de gauche à droite)
- Voir section Arguments pour les détails
options (liste, optionnel, défaut []) :
- Flags/options spécifiques à la commande
- Indépendantes de
global_options - Voir section Options pour les détails
implementation (chaîne de caractères, obligatoire) :
- Identifiant utilisé dans le code Rust pour lier au handler
- Convention : snake_case
- Exemple :
"load_config"correspond àLoadConfigHandler
continue_on_failure (booléen, optionnel, défaut false) :
- Gouverne le chaînage de commandes (v0.8.0, DD-026) — sans effet quand cette commande n'appartient pas à une chaîne.
-
false(défaut) : si cette commande échoue, la chaîne s'arrête immédiatement — identique au comportement actuel d'une commande seule, appliqué par segment. -
true: si cette commande échoue, l'erreur avec position dans la chaîne est signalée et l'exécution se poursuit au segment suivant. Destiné aux étapes réellement optionnelles (ex : un export secondaire non critique).
requires_success (booléen, optionnel, défaut false) :
- Fait aussi partie du chaînage de commandes (DD-026).
Sans rapport avec
requiredci-dessus —requiredest un contrôle au démarrage (« un handler doit être enregistré »),requires_successest une garde de chaîne évaluée à chaque invocation, au moment du dispatch. -
false(défaut) : cette commande s'exécute indépendamment d'un échec antérieur dans la chaîne (sans effet sauf si une commande antérieure acontinue_on_failure: true). -
true: si une commande antérieure de la chaîne a déjà échoué (quelle que soit la valeur decontinue_on_failurede cet échec), cette commande est ignorée — non exécutée, non comptée comme un échec supplémentaire.
Sync vs async n'est pas une question de configuration (ref. #8). Ce champ est agnostique quant à la nature sync ou async du handler qui s'y rattache — il n'existe pas de drapeau
async: true, et il n'y en aura pas. Le choix entre exécution synchrone ou asynchrone se fait entièrement côté Rust, selon la méthode appelée lors du câblage du handler :// Handler synchrone .register_sync_handler("load_config", Box::new(LoadConfigHandler)) // Handler asynchrone — même convention de nom, même YAML .register_async_handler("fetch_remote", Box::new(FetchRemoteHandler))
CliBuilder::build()résout chaque nomimplementationselon le type effectivement enregistré. Ajouter un drapeau au niveau de la config créerait une seconde source de vérité susceptible de diverger de l'enregistrement Rust réel — seul le câblage Rust fait autorité, et c'est voulu.
Depuis la v0.8.0 (DD-026).
Une seule invocation CLI (ou une ligne de
run_script())
peut chaîner plusieurs commandes : une fois l'arité déclarée d'une
commande épuisée, le jeton nu suivant est vérifié auprès du registre
des commandes — s'il correspond à un nom de commande (ou un alias), il
démarre la commande suivante de la chaîne ; sinon, la ligne est rejetée
exactement comme une commande seule trop longue l'a toujours été. Il
n'existe aucun jeton séparateur (;, &&, |) — le chaînage résulte
uniquement de l'épuisement de l'arité, ce n'est pas une syntaxe
distincte à activer. continue_on_failure et requires_success,
décrits ci-dessus, gouvernent le comportement de chaque commande au
sein d'une chaîne.
Pour chaque commande de la séquence :
- Ses options (y compris les occurrences d'options répétables, DD-024) et ses arguments positionnels sont consommés jusqu'à son arité déclarée.
- Le jeton suivant est recherché dans le registre des commandes.
- S'il correspond à un nom de commande ou un alias → démarre le segment suivant.
- Sinon → la même erreur « trop d'arguments » qu'une commande seule non chaînée aurait levée — aucun changement de comportement pour une commande seule réellement trop longue.
Depuis la v0.9.0 (DD-028).
continue_on_failure est fixé en YAML, indépendamment du code du
handler — rien ne relie les deux par défaut, donc un handler écrit en
supposant que ses échecs arrêtent toujours la chaîne pourrait se
retrouver configuré silencieusement avec continue_on_failure: true
(ou l'inverse). Il n'y a aucun nouveau champ YAML pour cela : c'est un
contrôle de cohérence côté Rust, posé sur le champ existant, vérifié
une seule fois, à l'enregistrement, avant même que l'application ne
s'exécute.
L'auteur d'un handler peut déclarer une attente en surchargeant
expected_fault_tolerance() sur CommandHandler ou
AsyncCommandHandler (les deux valent None par défaut — aucune
opinion, aucun contrôle) :
impl CommandHandler for SolveCommand {
fn execute(&self, context: &mut dyn ExecutionContext, args: &ParsedArgs) -> Result<()> {
// ...
}
fn expected_fault_tolerance(&self) -> Option<bool> {
Some(false) // ce handler suppose qu'il arrête toujours la chaîne
}
}CommandRegistry::register_sync/register_async comparent cette
valeur (quand elle vaut Some) au continue_on_failure réellement
configuré pour la commande, et rejettent l'enregistrement avec
RegistryError::FaultToleranceMismatch en cas de contradiction —
détectant une mauvaise configuration YAML au démarrage plutôt qu'au
premier usage dans une chaîne. Un handler qui ne surcharge jamais la
méthode (le défaut, None) n'est absolument pas concerné, quelle que
soit la valeur de continue_on_failure.
Ceci ne vérifie pas la logique interne du handler — que son
execute() retourne bien Err(...) quand il le devrait. Cela reste
hors de portée de toute vérification au niveau de la signature,
couvert par les tests propres de l'application.
- Une commande en échec est signalée ainsi :
Error in command {n}/{total} ('{name}'): <sortie d'erreur habituelle>— la position dans la chaîne est ajoutée en préfixe ; le reste du message est inchangé par rapport à l'échec d'une commande seule. - Une commande ignorée (via
requires_success) est signalée ainsi :Skipped: command {n}/{total} ('{name}') — a preceding command failed. - Le code de sortie du processus reflète toujours le premier échec
rencontré dans la chaîne — l'échec « déclencheur » — même si une
commande ultérieure avec
continue_on_failure: trueéchoue aussi, ou qu'une commande en aval est ignorée en conséquence.
Si la ligne de commande fournit un jeton de plus que l'arité déclarée
d'une commande, et que ce jeton excédentaire correspond par ailleurs à
un nom de commande enregistré, il est silencieusement lu comme le
début du segment suivant plutôt que de lever une erreur — la
segmentation ne peut pas distinguer « une valeur excédentaire isolée »
de « la commande suivante » une fois l'arité épuisée. Aucun
échappement de type -- n'existe pour forcer une valeur à être
traitée comme positionnelle plutôt que comme une frontière de
commande. Non planifié pour correction ; à revoir seulement si un
besoin concret se présente.
-
CliInterface::run()(CLI en une fois) etrun_script()héritent automatiquement du chaînage — les deux passent par le même chemin de résolution interne. - La directive
:loaddu REPL ne chaîne pas : chaque ligne chargée passe toujours par le chemin mono-commande propre au REPL, inchangé.
commands:
- name: "configure"
description: "Enregistre une source d'entrée"
aliases: []
required: false
arguments:
- name: "path"
arg_type: "path"
required: true
description: "Fichier source"
validation: []
options: []
implementation: "configure_handler"
- name: "solve"
description: "Exécute une fois toutes les sources configurées"
aliases: []
required: false
arguments: []
options: []
implementation: "solve_handler"
requires_success: trueUtilisation :
monapp configure model.yml configure scenario.yml solve
# "configure" s'exécute deux fois, puis "solve" — seulement si les deux configure ont réussiArguments positionnels pour les commandes.
arguments:
- name: string # Obligatoire - Identifiant
arg_type: ArgumentType # Obligatoire - Type de données
required: boolean # Obligatoire - Doit être fourni ?
description: string # Obligatoire - Texte d'aide
validation: [Rule] # Optionnel - Règles de validation (défaut : [])| Champ | Type | Obligatoire | Description |
|---|---|---|---|
name |
chaîne | ✅ Oui | Identifiant interne de l'argument |
arg_type |
chaîne | ✅ Oui | Un parmi : string, integer, float, bool, path
|
required |
booléen | ✅ Oui | Si true, l'utilisateur doit fournir cet argument |
description |
chaîne | ✅ Oui | Texte d'aide pour l'utilisateur |
validation |
liste | ❌ Non | Règles de validation (défaut : []) |
Argument chemin de fichier :
- name: "fichier"
arg_type: "path"
required: true
description: "Chemin du fichier d'entrée"
validation:
- must_exist: true
- extensions: [".yaml", ".json", ".yml"]Utilisation : monapp charger config.yaml
Plage numérique :
- name: "iterations"
arg_type: "integer"
required: true
description: "Nombre d'itérations"
validation:
- min: 1
max: 10000Utilisation : monapp simuler 5000
Chaîne optionnelle :
- name: "nom-sortie"
arg_type: "string"
required: false
description: "Nom du fichier de sortie"
validation: []Utilisation :
monapp exporter resultat.csv # Fournit le nom
monapp exporter # Utilise la valeur par défautLes arguments sont parsés dans l'ordre de gauche à droite :
arguments:
- name: "source" # Premier positionnel
arg_type: "path"
required: true
- name: "destination" # Deuxième positionnel
arg_type: "path"
required: trueUtilisation : monapp copier source.txt dest.txt
Flags et options spécifiques aux commandes.
options:
- name: string # Obligatoire - Identifiant
short: string # Optionnel - Caractère unique
long: string # Optionnel - Forme longue
option_type: ArgumentType # Obligatoire - Type de données
required: boolean # Optionnel - Doit être fourni ? (défaut : false)
default: string # Optionnel - Valeur par défaut
description: string # Obligatoire - Texte d'aide
choices: [string] # Optionnel - Valeurs validesIdentiques aux champs des Options globales.
Flag booléen :
- name: "recursif"
short: "r"
long: "recursif"
option_type: "bool"
required: false
default: "false"
description: "Traiter les répertoires récursivement"Utilisation :
monapp traiter -r /chemin
monapp traiter --recursif /cheminOption entière :
- name: "threads"
short: "t"
long: "threads"
option_type: "integer"
required: false
default: "4"
description: "Nombre de threads parallèles"Utilisation :
monapp simuler --threads 8
monapp simuler -t 8
monapp simuler # Utilise la valeur par défaut : 4Restriction par choix :
- name: "niveau"
short: "n"
long: "niveau"
option_type: "string"
required: false
default: "info"
description: "Niveau de journalisation"
choices: ["debug", "info", "warn", "error"]Utilisation :
monapp lancer --niveau debug
monapp lancer -n warn
monapp lancer # Utilise la valeur par défaut : info
monapp lancer -n invalide # ERREUR : choix invalideDepuis la v0.6.0 (DD-024).
Une option répétable peut apparaître plusieurs fois sur la même ligne de
commande. Chaque occurrence commence par un discriminant — un jeton nu
immédiatement après le drapeau, tiré de choices — suivi de zéro ou
plusieurs sous-paramètres clé=valeur. dynamic-cli accumule chaque
occurrence dans l'ordre de la ligne de commande ; le handler les reçoit
toutes.
options:
- name: string # Requis
long: string # Optionnel
short: string # Optionnel
option_type: ArgumentType # Requis
required: boolean # Optionnel (défaut : false)
description: string # Requis
choices: [string] # Requis si repeatable — discriminants valides
repeatable: true # Requis pour activer ce comportement
option_parameters: # Requis — une entrée par discriminant
<discriminant>:
- name: string
arg_type: ArgumentType
required: boolean
description: string
validation: [] # Optionnel
secure: false # Optionnel-
choicesdoit être non vide et liste les discriminants valides. - Les clés de
option_parametersdoivent correspondre exactement àchoices— aucune clé orpheline, aucun discriminant non déclaré. Le chargement de la configuration échoue sinon. - Chaque entrée
option_parameters[discriminant]est uneArgumentDefinitionclassique (mêmes champs que lesarguments:positionnels), mais seulsname/arg_type/required/description/validation/secureont un sens — l'ordre n'a aucun effet puisque les sous-paramètres sont associés par clé, pas par position. -
defaultn'est pas autorisé quandrepeatable: true: l'absence de l'option signifie déjà zéro occurrence, une valeur par défaut implicite serait ambiguë. -
option_parameterssur une option avecrepeatable: false(ou absent) est une erreur de configuration. - Deux occurrences du même discriminant avec des paires
clé=valeurdifférentes sont toutes deux conservées. Deux occurrences strictement identiques (même discriminant, mêmes paires clé=valeur) sont rejetées — c'est le seul chevauchement que le framework peut détecter sans connaissance du domaine ; les occurrences partiellement chevauchantes (mêmefile,resolutiondifférente, par exemple) sont acceptées et laissées à la charge du handler.
- name: "output"
long: "output"
option_type: "string"
required: false
description: "Écrit les résultats sous une ou plusieurs formes de sortie"
choices: ["csv", "plot"]
repeatable: true
option_parameters:
csv:
- name: "file"
arg_type: "path"
required: true
description: "Fichier CSV de destination"
- name: "resolution"
arg_type: "integer"
required: false
description: "Résolution du pas de temps"
plot:
- name: "file"
arg_type: "path"
required: true
description: "Fichier image de destination"Utilisation :
monapp export --output csv file=resultats.csv resolution=100
monapp export --output csv file=resultats.csv --output plot file=graphe.png
monapp export --output csv file=a.csv --output csv file=b.csv # les deux conservées — `file` différent
monapp export --output csv file=a.csv --output csv file=a.csv # ERREUR : DuplicateOptionOccurrence
monapp export --output json file=out.json # ERREUR : UnknownDiscriminant
monapp export --output csv # ERREUR : MissingRequiredOptionParameter (file)
monapp export --output csv file=a.csv depth=3 # ERREUR : UnknownOptionParameter (depth)CommandHandler::execute (et validate) reçoivent désormais une valeur
ParsedArgs (voir la
documentation du module executor)
plutôt qu'une simple HashMap<String, String>, précisément pour pouvoir
représenter les occurrences d'une option répétable aux côtés des options
scalaires :
let occurrences = args.get_repeated("output").unwrap_or(&[]);
for occ in occurrences {
match occ.discriminant.as_str() {
"csv" => { /* occ.params.get("file"), occ.params.get("resolution") */ }
"plot" => { /* occ.params.get("file") */ }
_ => unreachable!(), // la validation de config a déjà rejeté les autres discriminants
}
}Voir CHANGELOG.md (v0.6.0) pour le chemin de migration complet
HashMap<String, String> → ParsedArgs des handlers existants.
Types de données supportés pour les arguments et options.
| Type | Description | Exemples de valeurs | Type Rust |
|---|---|---|---|
string |
Valeur texte |
"bonjour", "config.yaml"
|
String |
integer |
Nombre entier |
42, -10, 0
|
i64 |
float |
Nombre décimal |
3.14, -0.5, 1.0
|
f64 |
bool |
Flag booléen |
true, false
|
bool |
path |
Chemin fichier/répertoire |
"./fichier.txt", "/tmp"
|
PathBuf |
string :
- Accepte n'importe quel texte
- Pas de parsing requis
- Exemple :
nom: "Jean Dupont"
integer :
- Doit être un entier valide
- Support des valeurs négatives
- Plage :
-9,223,372,036,854,775,808à9,223,372,036,854,775,807 - Exemple :
compte: 42
float :
- Doit être un nombre décimal valide
- Support de la notation scientifique
- Exemple :
valeur: 3.14ouvaleur: 1.5e-3
bool :
- Pour les flags : présence =
true, absence =false - Pour les valeurs :
"true","false","yes","no","1","0" - Insensible à la casse
- Exemple :
--verbose(true) vs pas de flag (false)
path :
- Chemin de fichier ou répertoire
- Peut être relatif ou absolu
- La validation peut vérifier l'existence
- Exemple :
fichier: "./donnees/entree.csv"
Contraintes appliquées aux arguments et options.
validation:
- must_exist: trueS'applique à : type path
Effet : Vérifie si le fichier/répertoire existe avant l'exécution
Erreur si : Le chemin n'existe pas
validation:
- extensions: [".txt", ".csv", ".json"]S'applique à : type path (fichiers uniquement)
Effet : Valide que le fichier a l'une des extensions spécifiées
Erreur si : L'extension du fichier n'est pas dans la liste
validation:
- min: 1
max: 100S'applique à : types integer, float
Effet : La valeur doit être dans la plage (inclusive)
Champs :
-
min(optionnel) : Valeur minimale -
max(optionnel) : Valeur maximale - Les deux peuvent être omis pour des bornes unilatérales
Exemples :
# Seulement minimum
- min: 0
# Seulement maximum
- max: 100
# Les deux
- min: 1
max: 10Plusieurs règles peuvent être appliquées à un seul argument :
validation:
- must_exist: true
- extensions: [".yaml", ".json"]Effet : Le fichier doit exister ET avoir l'extension .yaml ou .json
Utiliser un tableau vide si aucune validation n'est nécessaire :
validation: []Fichier de configuration complet pour une application de traitement de données.
# ═══════════════════════════════════════════════════════════
# Configuration CLI - Traitement de Données
# ═══════════════════════════════════════════════════════════
metadata:
version: "1.0.0"
prompt: "dataproc"
prompt_suffix: " > "
# ───────────────────────────────────────────────────────────
# OPTIONS GLOBALES (disponibles pour toutes les commandes)
# ───────────────────────────────────────────────────────────
global_options:
- name: "verbose"
short: "v"
long: "verbose"
option_type: "bool"
required: false
default: "false"
description: "Activer la sortie verbeuse"
- name: "sortie-rep"
short: "o"
long: "sortie"
option_type: "path"
required: false
description: "Répertoire de sortie pour les résultats"
- name: "format"
short: "f"
long: "format"
option_type: "string"
required: false
default: "text"
description: "Format de sortie"
choices: ["text", "json", "yaml"]
# ───────────────────────────────────────────────────────────
# COMMANDES
# ───────────────────────────────────────────────────────────
commands:
# ═════════════════════════════════════════════════════════
# Commande : charger
# ═════════════════════════════════════════════════════════
- name: "charger"
aliases: ["ouvrir", "entree"]
description: "Charger un fichier de données"
required: true
arguments:
- name: "fichier"
arg_type: "path"
required: true
description: "Chemin vers le fichier de données"
validation:
- must_exist: true
- extensions: [".csv", ".json", ".yaml"]
options: []
implementation: "load_data"
# ═════════════════════════════════════════════════════════
# Commande : traiter
# ═════════════════════════════════════════════════════════
- name: "traiter"
aliases: ["lancer"]
description: "Traiter les données chargées"
required: false
arguments: []
options:
- name: "threads"
short: "t"
long: "threads"
option_type: "integer"
required: false
default: "4"
description: "Nombre de threads parallèles"
choices: []
- name: "taille-lot"
short: "b"
long: "lot"
option_type: "integer"
required: false
default: "1000"
description: "Taille du lot pour le traitement"
choices: []
implementation: "process_data"
# ═════════════════════════════════════════════════════════
# Commande : exporter
# ═════════════════════════════════════════════════════════
- name: "exporter"
aliases: ["sauver"]
description: "Exporter les résultats vers un fichier"
required: false
arguments:
- name: "fichier-sortie"
arg_type: "path"
required: true
description: "Chemin du fichier de sortie"
validation: []
options:
- name: "compresser"
short: "c"
long: "compresser"
option_type: "bool"
required: false
default: "false"
description: "Compresser le fichier de sortie"
choices: []
implementation: "export_results"
# ═════════════════════════════════════════════════════════
# Commande : aide
# ═════════════════════════════════════════════════════════
- name: "aide"
aliases: ["h", "?"]
description: "Afficher l'aide"
required: false
arguments:
- name: "commande"
arg_type: "string"
required: false
description: "Commande pour laquelle obtenir de l'aide"
validation: []
options: []
implementation: "show_help"
# ═════════════════════════════════════════════════════════
# Commande : quitter
# ═════════════════════════════════════════════════════════
- name: "quitter"
aliases: ["sortir", "q"]
description: "Quitter l'application"
required: false
arguments: []
options: []
implementation: "exit_app"Mode CLI :
# Avec options globales
dataproc --verbose charger donnees.csv
dataproc -v -o ./resultats traiter --threads 8
dataproc --format json exporter sortie.json
# Sans options globales
dataproc charger donnees.csv
dataproc traiter --threads 8 --lot 2000
dataproc exporter sortie.csv --compresserMode REPL :
dataproc > charger donnees.csv
Données chargées avec succès.
dataproc > traiter --threads 8
Traitement... Terminé.
dataproc > exporter resultats.csv
Résultats exportés vers resultats.csv
dataproc > aide exporter
Commande : exporter
Description : Exporter les résultats vers un fichier
...
dataproc > quitter
Au revoir !
Commandes :
- Utiliser les minuscules
- Utiliser des traits d'union pour les mots multiples :
lancer-simulation(paslancerSimulationoulancer_simulation) - Garder les noms concis mais descriptifs
- Fournir des alias significatifs :
["quitter", "q", "sortir"]
Arguments/Options :
- Utiliser les minuscules avec traits d'union :
rep-sortie(pasrepSortie) - Être cohérent dans toute l'application
- Utiliser judicieusement les formes courtes : caractère unique, couramment reconnu (
-vpour verbose)
Marquer comme required: true quand :
- La commande DOIT être exécutée pour le workflow de l'application
- L'argument DOIT être fourni pour que la commande fonctionne
- L'option est essentielle (rare - considérer si ce devrait être un argument à la place)
Marquer comme required: false quand :
- La commande est une fonctionnalité de commodité optionnelle
- L'argument a un comportement par défaut sensé
- L'option améliore mais ne bloque pas la fonctionnalité
Toujours valider quand :
- Acceptant des chemins de fichiers (vérifier l'existence, les extensions)
- Acceptant des valeurs numériques avec contraintes (utiliser des plages)
- Acceptant des énumérations (utiliser
choices)
Exemple :
# Bon : Validation complète
validation:
- must_exist: true
- extensions: [".csv", ".json"]# Mauvais : Pas de validation pour entrée fichier
validation: []Écrire des descriptions claires et concises :
- ✅ Bon : "Charger un fichier de configuration"
- ❌ Mauvais : "Charge des trucs"
- ✅ Bon : "Nombre de threads parallèles (1-16)"
- ❌ Mauvais : "threads"
Fournir des valeurs par défaut sensées pour les champs optionnels :
# Bon : Valeur par défaut sensée
- name: "threads"
default: "4"
# Mauvais : Requis mais devrait avoir une valeur par défaut
- name: "threads"
required: true # L'utilisateur doit toujours spécifierUtiliser global_options pour :
- Flags verbose/debug
- Sélection de format de sortie
- Chemins de fichiers de configuration
- Niveaux de journalisation
Utiliser options de commande pour :
- Comportement spécifique à la commande
- Paramètres qui n'ont de sens que pour une commande
Fournir des alias utiles :
# Bon : Raccourcis courants
aliases: ["quitter", "q", "sortir"]# Bon : Noms alternatifs
aliases: ["charger", "ouvrir", "entree"]# À éviter : Confus ou trop nombreux
aliases: ["a", "b", "c", "xyz123"]Utiliser un nommage clair et cohérent :
# Bon : Objectif clair
implementation: "load_config"implementation: "run_simulation"# Mauvais : Vague
implementation: "handler1"implementation: "do_stuff"Pour les grandes applications, considérer :
- Un fichier de configuration par mode (cli.yaml, repl.yaml)
- Commandes partagées dans un fichier inclus séparé
- Surcharges spécifiques à l'environnement (dev.yaml, prod.yaml)
Commenter les sections complexes :
# ═══════════════════════════════════════════════════════════
# COMMANDES DE SIMULATION
# Ces commandes contrôlent le moteur de simulation numérique
# ═══════════════════════════════════════════════════════════
commands:
- name: "simuler"
# Les utilisateurs avancés peuvent surcharger le pas de temps
options:
- name: "dt"
description: "Pas de temps en secondes (experts uniquement)"L'exemple complet ci-dessus au format JSON :
{
"metadata": {
"version": "1.0.0",
"prompt": "dataproc",
"prompt_suffix": " > "
},
"global_options": [
{
"name": "verbose",
"short": "v",
"long": "verbose",
"option_type": "bool",
"required": false,
"default": "false",
"description": "Activer la sortie verbeuse"
}
],
"commands": [
{
"name": "charger",
"aliases": ["ouvrir", "entree"],
"description": "Charger un fichier de données",
"required": true,
"arguments": [
{
"name": "fichier",
"arg_type": "path",
"required": true,
"description": "Chemin vers le fichier de données",
"validation": [
{"must_exist": true},
{"extensions": [".csv", ".json"]}
]
}
],
"options": [],
"implementation": "load_data"
}
]
}Cette référence couvre tous les éléments de syntaxe des fichiers de configuration dynamic-cli :
✅ Metadata - Informations sur l'application
✅ Options globales - Options pour toutes les commandes
✅ Commandes - Définitions de commandes individuelles
✅ Arguments - Paramètres positionnels
✅ Options - Flags et paramètres nommés
✅ Types - Spécifications de types de données
✅ Validation - Règles de contraintes
✅ Exemples - Utilisation réelle
✅ Bonnes pratiques - Recommandations
Pour les détails d'implémentation, voir la documentation de l'API dynamic-cli.
Version : 1.0
Framework : dynamic-cli
Date : 2026-01-11