NodeJS et ses paquets permettent de créer énormément d'outils. Un de ses paquet, Caporal.js, permet de créer des applications cli (ligne de commande) très facilement et dont le résultat est très complet. Découvrons comment réaliser une application simple avec Caporal.

Caporal.js

Caporal.js est un script Javascript permettant donc de créer des applications cli (en ligne de commande) tout en prenant en compte les arguments, les options, les validateurs, les logs, l'aide auto-générée, etc...

Il n'est pas le seul sur ce segment, je pense notamment à l'excellent paquet Commander, mais voyons ce que Caporal.js propose.

Tout d'abord, un petit rappel de ce qu'est une commande, un argument et une option.

  • Commande : une commande est une partie d'un programme. Ce dernier peut en avoir plusieurs, faisant toutes une action différente.
  • Argument : une commande peut avoir plusieurs arguments. Ils permettent de spécifier une information.
  • Option : les options (ou paramètres) précisent une commande. Ils sont facultatifs.

Caporal.js utilise une syntaxe spécifique pour définir si un argument est obligatoire ou non.

  • Obligatoire : argument entouré des symboles inférieur et supérieur. Ex. : <search>
  • Facultatif : argument entouré de crochets. Ex. : [number]

Passons tout de suite à l'installation du paquet.

Installation

Caporal.js est un paquet NodeJS, donc qui s'installe facilement avec NPM ou Yarn :

npm install caporal --save

Ou avec Yarn :

yarn add caporal

Exemple simple

Je vais reprendre l'exemple disponible sur le README du projet :

#!/usr/bin/env node
const prog = require('caporal');
prog
  .version('1.0.0')
  .description('A simple program that says "biiiip"')
  .command('deploy', 'Deploy an application')
  .argument('<app>', 'App to deploy')
  .argument('[env]', 'Environment to deploy on', /^dev|staging|production$/, 'local')
  .action(function(args, options, logger) {
    logger.info("Deploy app " + args.app + " in " + args.env)
  });

prog.parse(process.argv);

Le script a une commande deploy qui a deux arguments. app est obligatoire et env facultatif. Par défaut, la valeur de ce dernier est local. Elle doit également être égale à dev, staging ou production.

Une fois la commande exécutée (node app.js deploy myapp production), le script affiche simplement un message "Deploy app myapp in production" par exemple.

Logging et validateurs

Plusieurs niveaux de logs existent :

  • logger.debug()
  • logger.info() ou logger.log()
  • logger.warn()
  • logger.error()

Lorsque vous lancer le script avec l'option -v ou --verbose, les logs de type debug seront affichés.
Avec l'option --quiet ou --silent, seuls les logs de type warn ou error seront affichés.

Les validateurs permettent de vérifier si la valeur donnée à un argument ou une option est correcte ou pas. Si nous reprenons l'exemple ci-dessus, l'argument env dispose d'un validateur sous forme d'expression régulière.

Plusieurs types de validateurs existent : flags, fonctions, tableau ou expression régulière.

Les validateurs flags sont :

  • INT ou INTEGER : permet de valider si la valeur est un entier (parseInt())
  • FLOAT : vérifie si la valeur est un décimal (parseFloat())
  • BOOL ou BOOLEAN : vérifie si la valeur est un booléen (0, 1, true, false, on, off)
  • LIST ou ARRAY : transforme une liste d'éléments séparés par une virgule en un tableau

Exemple pour le type INT :

.option('[number]', 'Number of lines', prog.INT, 1)

Le dernier paramètre correspond à la valeur par défaut.

Les autres types de validateurs sont très bien expliqués dans la documentation de Caporal.js, je vous laisse vous y rendre ;)

Suggestion orthographique

Si vous faites une erreur d'orthographe sur une option, Caporal.js va vous avertir et vous proposer l'argument que vous souhaitiez utiliser :

Création d'un script avec deux commandes

Poursuivons avec un script un peu plus concret. On va créer deux commandes (qui n'ont rien à voir, mais c'est pour l'exemple) qui vont permettre de récupérer :

  • la température d'une ville, avec la possibilité d'avoir le taux d'humidité et la vitesse du vent
  • n citations de la série TV Breaking Bad

Pour la première commande, nous allons utiliser l'API de OpenWeatherMap. Pour les citations de Breaking Bad, j'ai fait un petit projet NodeJS qui retourne les phrases cultes de la série. D'ailleurs, il faut que je vous présente ce projet plus en détails dans un autre article !

Voici le code final du script (disponible également sur ce Gist) :

#!/usr/bin/env node

var http = require('http');
var https = require('https');

var retreiveDatas = function(url){
    return new Promise((resolve, reject) => {
        var proto = https;
        if (url.indexOf("http://") == 0)
            proto = http;

        var request = proto.get(url, function(response){
            response.setEncoding('utf8');

            var body = '';
            response.on('data', function(d){
                body += d;
            });

            response.on('end', function(){
                var parsed = JSON.parse(body);
                resolve(parsed);
            });
        });
    })
}

const prog = require('caporal');
prog
    .version('1.0.0')
    .description('Simple program to display city weather and some Breaking Bad quotes')
    .command('weather', 'Get weather') 
    .argument('<city>', 'Search query')
    .option('--humidity', 'Allow to prints humidity value') 
    .option('--wind', 'Allow to prints wind speed') 
    .action(function(args, options, logger) {

        // Récupération des données via l'API OpenWeatherMap
        retreiveDatas('http://api.openweathermap.org/data/2.5/weather?APPID=9ffc8e8d9b6cdf53f8bf6b2168b7d7b5&q='+args.city+'&mode=json&units=metric').then(function(datas){

            var weather = {
                city: datas.name,
                temp: datas.main.temp + '°C',
                humidity: datas.main.humidity + '%',
                wind_speed: datas.wind.speed + ' km/h'
            };

            var content = "\n";
            content += "City: " + weather.city + "\n";
            content += "Temperature: " + weather.temp + "\n";

            if (options.humidity)
                content += "Humidity: " + weather.humidity + "\n";

            if (options.wind)
                content += "Wind: " + weather.wind_speed + "\n";

            logger.info(content);

        })

    })

    .command('breaking-bad', 'Get Breaking Bad quotes')
    .option('--nb <num>', 'Number of quotes', prog.INT, 1)
    .action(function(args, options, logger){

        // Récupération des citations via https://github.com/shevabam/breaking-bad-quotes
        retreiveDatas('https://breaking-bad-quotes.herokuapp.com/v1/quotes/'+options.nb).then(function(datas){

            var content = "\n";

            for (var i = 0; i < datas.length; i++) {
                content += '"'+datas[i].quote+'"';
                content += "\n";
                content += "- "+datas[i].author;
                content += "\n\n";
            }

            logger.info(content);

        })

    });

prog.parse(process.argv);

Le script dispose donc de deux commandes : weather et breaking-bad.

La première nécessite l'argument obligatoire city, suivi du nom de la ville que l'on recherche. Deux options sont disponibles : --humidity et --wind qui permettent respectivement d'afficher le taux d'humidité et la vitesse du vent.

La deuxième commande, breaking-bad, n'a pas d'argument mais une option nb qui défini le nombre de citations à retourner. Elle doit être un entier et a comme valeur par défaut "1".

Lors de l'exécution du script sans commande (node app.js), Caporal.js nous affiche l'aide auto générée :

On retrouve donc le nom des commandes disponibles et plusieurs options génériques.

En exécutant le script avec la commande weather suivie de help, Caporal.js nous retourne la liste des arguments et options disponibles pour la commande weather :

Pour avoir la température d'une ville : node app.js weather ajaccio

Avec l'humidité et la vitesse du vente :

Au tour de la deuxième commande, les citations Breaking Bad.

Avec l'option nb pour récupérer 5 citations :

Conclusion

Caporal.js est un script très pratique qui permet de faire des applications ligne de commande très rapidement. Les possibilités sont énormes et les multiples fonctionnalités du script sont très intéressantes.