mixa v0.7.0
M.I.X.A.

Table of Contents generated with DocToc
- M.I.X.A.
M.I.X.A.
- M.I.X.A. is short for Meta—Internal/eXternal command—Arguments
- this is the generalized command line structure
- flags, a.k.a. 'options', 'settings', Boolean or not:
- Boolean flags have no srgument and are
truewhen given - flags of other types must be given a value as
-f value,--flag value, optionally with an equals sign between the flag name and the value
- Boolean flags have no srgument and are
- Internal commands must parse their specific flags and other arguments.
- External commands call a child process that is passed the remaing command line arguments, so those can be dealt with summarily.
M.I.X.A. for Command Line Argument Parsing
Command Line Structure
node cli.js │ --cd=some/other/place funge --verbose=true -gh 'foo'
│ │ │ │ │ │ │ │ │ └────────────┘ └─┘ └───┘
│ │ │ │ │ │ │ │ │ L S P
└──┘ └────┘ │ └───────────────────┘ └───┘ └──────────────────────┘
E S │ M I/X A- E—executable
- S—script
- M—meta flags (flags that pertain to MIXA)
- I/X—internal or external command
- A—arguments (flags that pertain to the command)
- L—long flag
verbosewith value - S—short Boolean flags
g,h - P—positional flag
A valid command line must either call for printing a application-specific help (using one of ... -h, ...
--help, or ... help), or application version (using one of ... -v, ... --version, or ... version),
or else spell out a configured application-specific command (including additional arguments where required).
Metaflags
Metaflags are command line arguments preceded by one (short form) or two (long form) dashes that are placed before the command line like so:
node cli.js --help # show help and exit
node cli.js -h # dto.
node cli.js --version # show version and exit
node cli.js -v # dto.
node cli.js --cd some/other/place/somewhere foo 42 # change into directory given, then run `foo 42`
node cli.js -d some/other/place/somewhere foo 42 # dto.The above are the preconfigured metaflags, but one can define additional ones in the Job Definition
(<jobdef>).
Job Definition (<jobdef>)
A Job definition (an object of type <jobdef>) specifies declaratively what additional metaflags and
commands are available for the application in question. A Job definition may contain the following fields
(question mark indicates optional value, angle brackets specifiy types; the default is given behind the
equals sign):
?exit_on_error <boolean> = true—When callingMIXA.run jobdef, input, determines whether to exit with an exit code in case an error in the jobdef or the input was detected.exit_on_errordoes not affect the behavior ofMIXA.parse jobdef, input.?meta <mixa_flagdefs>—An object that specifies (additional) metaflags to go before the command. See Flag Definitions (<flagdefs>,<flagdef>)?commands <mixa_cmddefs>—See Command Definitions (<cmddefs>,<cmddef>).
Example:
jobdef =
exit_on_error: true
commands:
foo: { ... definition for command `foo` ... }
bar: { ... definition for command `bar` ... }This job definition declares that there two commands foo and bar in the application.
Command Definitions (<cmddefs>, <cmddef>)
The keys of a cmddefs object are interpreted as command names; its values are <cmddef> objects:
?description <text>—A helpful one-liner to explain what the command does.?allow_extra <boolean> = false—Whether to allow unspecified arguments on the command line; these will be made available asverdict.extra.?flags <mixa_flagdefs>—An object detailing each command line argument to the command in question.?runner <_mixa_runnable>—A synchronous or asynchronous function to be called byMIXA.run jobdef, inputprovided no error occured during validation ofjobdefand parsing theinput?plus <any>—Any additional value or values that should be made accessible to the runner asverdict.plus.
Example (cont'd from above):
# file: cli.coffee
MIXA = require 'mixa'
jobdef =
exit_on_error: true
commands:
foo:
description: "Do something awesome"
allow_extra: true # allow unconfigured extra arguments
runner: run_foo # function to be called
listfiles:
runner: MIXA.runners.execSync # call convenience function for sync sub-process
plus: { executable: 'ls', } # `execSync` will use `plus.executable` as name of executable
allow_extra: true # `true` b/c we want to pass arguments to `ls`
console.log MIXA.run jobdef, process.argvWe can now call node cli.js --cd=somewhere listfiles -- -AlF from the command line to execute ls -AlF
and get back whatever that outputs.
Flag Definitions (<flagdefs>, <flagdef>)
The keys of a flagdefs object are interpreted as long flag names; its values are <flagdef> objects:
multiple <_mixa_mutliple>—false,'greedy','lazy'; defaults tofalse; if'greedy', multiple values may be set without repeating the flag name; if'lazy', flag name must be repeated for each value. Ensuing named values are honored in either case.fallback <any>—Used when flag is missing; note that when flag is mentioned without a value, then valuenonewill be assignedpositional <boolean>—trueorfalse(translated todefaultOption), indicates whether unnamed argument id allowed; interacts withallow_extra; only at most one flag can be markedpositional
Command Line Parsing: Example
parse jobdef, process.argvwill return object withjobdef—Thejobdefthat describes how to parse command line arguments into a command with flags (jobflags and metaflags)input—Theargvused as input, unchangedverdict—The result of parsing the inputargvagainst thejobdef; this is either a 'happy' result or, if an error was detected, a 'sad' result with indicators what the problem was.- A happy verdict will have the following attributes:
cmd—The matching command;argv—Remaining arguments, if any;parameters—Object with the named flags and their values;plus—Theplusattribute from the matching jobdef's command definition, if any;runner—Therunnerattribute from the matching jobdef's command definition, if any.
- A sad verdict will have the following attributes:
cmd—Invariably set tohelp, indicating that a helpful message should be displayed;error:tag—A short upper case textual code that identifies the error classcode—An integer error code in the range[ 1 .. 127 ]message—An error message
- A happy verdict will have the following attributes:
output:—What the runner returnedok:—The value of the computation, if any, depending on the runner callederror:—Details in case a runner encountered problems computing anokvalue; as above, will have fieldstag,code,messagewhere present
upcoming
Passing Options to Other Programs
- Sometimes one wants to pass options to another executable; e.g. say we want to use
node x.js search -iname 'whatever'to call the Linuxfindcommand in a subprocess and we wish to not analyze any options but just pass them through to the subprocess - Note that the
findutility uses long options with a single hyphen; problem is that the parser currently used bei MIXA will misinterpretinameas[ '-i', '-n', '-a', '-m', '-e', ] - As a workaround, use
--(a.k.a. 'the inhibitor') somewhere after the command (searchin this example) but before before the first single-dash flag to be left as-is (-inamein this case), that is, call your program asnode x.js search -- -iname 'whatever'. - A future version of MIXA might not require using
--. - Observe that
allow_extrashould be set totrueto allow extra arguments; otherwise, anEXTRA_FLAGSerror will be generated.
Passing Options to Run Methods
- set
runnerin the command definition to a synchronous or asynchronous function that will be called with the object that describes the parsing result; this will be called the 'run method' or the 'runner' - set
plusin the command definition to any value to be attached to the result object - the value of
plusis specific to the run method chosen
M.I.X.A. for TOML Configuration File Parsing
NOTE This functionality is pre-alpha; details are likely to change in upcoming releases
Configuration Sources
In the following list, later entries win over earlier ones; this is the same principle that CSS and
Object.assign() use.
- a file named
.$app_name.tomlin the user's home directory; - a file named
.$app_name.tomlin the directory of the parent project (i.e. the containing directory of thepackage.jsonfile for the package that hasmixaas direct dependency); - other file(s) identified by one or more paths passed to
read_cfg()(from the command line); - other settings passed to
read_cfg()(from the command line).
M.I.X.A. for Checking Pinned Versions of Dependencies
(forthcoming)
- Motivation
- Spec-ulation Keynote - Rich Hickey
- HN Discussion
- another HN Discussion
- devs like to forget they chose a particular version because of a particular feature that got removed or changed in a later version of a given dependency
- one example would be the now-popular move to ES Modules ('
import') when your own package still used CJS Modules ('require') - no way in
package.jsonto indicate reason for a particular version choice: was it the latest available at the time? would the software work with a newer version or is it known not to? - tools such as
npm-checkalways suggest to install the latest version which may not always be the right version for the project at hand
- How it works
- can configure SemVer matchers in file
pinned-package-versions.jsonwhich is not touched by tools - add
require( 'mixa/lib/pinned-package-versions.json' )close to your package entry point (index.js,main.js)
- can configure SemVer matchers in file
Also See
To Do
- – consider whether to replace
positionalflag configuration with a single option in command configuration - – implement mandatory flags
- – consider moving from
command-line-argstosade - – consider to offer sub-contexts as done by https://github.com/substack/subarg
- +/– implement 'default_command'
- – implement parsing of TOML configuration files
- – make checks for pinned dependency versions part of public API
- + in
check-package-versions.coffee, handle missing dependency gracefully - – rename
MIXA.configurator->MIXA.cfg - – implement
defaults,overridesforMIXA.cfg - – update all dependencies
- – update all dependency
intertype, then integrate MIXA flag type declaration withintertype - – allow parameters use both hypen-minus
-and underscores_transparently - – unify {
cmd,command,cmds,commands, } -> {cmd,cmds, } - – do not use runners, restrict functionality to extract (and normalize) command and parameters (i.e. 'flags')
– rename parameters -> flags
– accept an optional
types(anIntertypeinstance); naming convention is to prefix flag names withcli_(orflag_?); can then set thetypedeclaration inflagssection to any of these:- – nothing (or
null): to be filled out using the conventional prefix, the flag name, and thetypesargument - – any value that is legal for an InterType type declaration, including:
- – in any event, enforce at declaration time that
types.create[ type ].create()can be meaningfully called; this may entail an update tointertypeto avoid non-sensical auto-generatedcreatemethods
- – nothing (or
Is Done
- + in case of error, should still deliver all flags with values in
verdict.parametersan attributeverdict.extra_flagswill contain a list of extraneous flags