jargon-parser

json schema driven argument parser


License
MIT
Install
npm install jargon-parser@0.0.2

Documentation

Jargon Parser

argument parsers from json schemas, using subarg syntax and the ajv validator

jargon-parser is designed to be a drop in cli builder that you don't have to manage or configure beyond the natural data schema for your application. This means you can easily use the same logic for your .json configurator, REST api, and cli, without losing power.

Example Usage

With the example/parser.js (rough equivalent in es6):

import newParser from 'jargon-parser'

const cli = newParser({ schema: __dirname + '/schema.json' })

console.log(JSON.stringify(cli()))

The invocation

node example/parser.js                              \
    --billing_address [                             \
        --street_address "1234 fake st" ]           \
    --shipping_address [                            \
        --street_address "2222 muddle drive"        \
        --city houston --type business ]            \
    --items [                                       \
        [ --name foo ]                              \
        [ --price 0.99 --name bar ] ]               \
    | python -mjson.tool # for pretty printing

yields

{
    "billing_address": {
        "city": "Austin",
        "state": "TX",
        "street_address": "1234 fake st"
    },
    "shipping_address": {
        "city": "houston",
        "state": "TX",
        "street_address": "2222 muddle drive",
        "type": "business"
    },
    "items": [
        {
            "name": "foo"
        },
        {
            "name": "bar",
            "price": 0.99
        }
    ]
}

given the sample schema in examples/schema.json (notice that defaults are applied).

Help statements

Note: Currently might not work with more complicated schemas
jargon-parser uses cliui for help formatting:

node example/parser.js --help

Usage: example/parser.js

A delivery order

Arguments:

  --billing_address [                                # address affiliated with credit card
    --street_address <string>   [required]           # street number and name
    --city <string>             [default: "Austin"]
    --state <string>            [default: "TX"]
  ]
  --items [                                          # array of items to purchase
    [
      --name <string>           [required]
      --price <number>          [optional]
    ],
    ...items
  ]
  --shipping_address [                               # address to which we will ship the package
    --street_address <string>   [optional]           # street number and name
    --city <string>             [default: "Austin"]
    --state <string>            [default: "TX"]
    --type <string>             [optional]
  ]

By default help is displayed with the flag --help or on error, both of which can be customized via helpOptions passed to newParser: { flag: 'help', catchErrors: true }

Caveat/technical details:
Currently, the only "schema intelligence" --help currently has is the ability to resolve references and merge allOf statments in objects. It is also as verbose as possible by default.

In depth usage / customization

The default export newParser({schema, schemaCaster, name, description, helpOptions}) returns a parser that takes an optional array of argv arguments, defaulting to process.argv.slice(2), and returns the validated/cast result.

schema and schemaCaster are mutually exclusive, and schemaCaster takes precedence. If schema is provided, either as as a relative path or object, it will be passed to newCaster with the default ajv compiler, which will construct Avj with the arguments { coerceTypes: true, useDefaults: true, v5: true }. The result of newParser

Notes

Aside from avj type coercion and default filling, jargon-parsers function mostly the same as subarg's, except that arrays and dictionaries are mutually exclusive in json. This means that cli command --sub [ args args -f ] is invalid, because the subarg result is

{
  "_": [ "command" ],
  "sub": {
    "_": [ "args" , "args" ],
    "f": true
  }
}

So [ "command" ] and { "sub": ... } would be in conflict, as would [ "args" , "args" ] and { "f": true }.
A valid alternative would be cli command [ --sub [ --list [ args args ] -f ] ], resulting in

{
  "command": {
    "sub": {
      "list": [ "args" , "args" ],
      "f": true
    }
  }
}