Skip to main content

Commands

Configurator supports command-oriented applications using the Schema selector feature, which provides hierarchical command structures through schema options.

  • A property is marked as a selector to indicate it selects between alternatives.
  • Properties marked with selection are only evaluated when the selector matches a provided value (or the property name, if omitted).
  • You can define sub-commands within selection properties to build a command hierarchy.
  • The command line parser recognizes these patterns and produces appropriate parsing behavior.

For example, here's an app defining a command schema:

spm.js
import { Configurator, Schema } from '@versionzero/configurator';

const schema = new Schema('object')
.property('action', new Schema('string').selector())

.property('install', new Schema('object').selection()
.meta('description', 'install specified packages')
.property('packages', new Schema('array').meta('general')
.property('*', new Schema('string').meta('valueDescription', 'package-name'))
.required()
)
.property('save', new Schema('boolean'))
.property('save-dev', new Schema('boolean'))
.property('global', new Schema('boolean'))
)

.property('test', new Schema('object').selection()
.property('ignore-scripts', new Schema('boolean'))
)

.property('run', new Schema('object').selection()
.property('workspace', new Schema('string'))
.property('if-present', new Schema('boolean'))
.property('script', new Schema('string').required()
.meta('general')
.meta('valueDescription', 'script-name')
.meta('description', 'run script')
)
);

const context = {
appName: 'spm',
//argv: ['install', '-s', 'foo', 'bar']
//argv: ['--help']
}
const config = await new Configurator({schema}).configure(context);

console.log(config);

Running this with node spm.js --help produces:

Usage: spm [options] [install|run|test [options]]

--config (-C) [path|-] - load configuration from file (or -
for stdin)
--help (-h) [advanced] - display help information

install [options] <package-name...> - install specified packages
--global (-g) [true|false]
--save (-s) [true|false]
--save-dev (-S) [true|false]

test [options]
--ignore-scripts (-i) [true|false]

run [options] script-name
--if-present (-i) [true|false]
--workspace (-w) [string]

Running with node spm.js install -s foo bar yields

{
"action": "install",
"install": {
"packages": [ "foo", "bar" ],
"save": true
}
}

The selector pattern provides several benefits:

  • The command line parser automatically recognizes the structure and parses hierarchically
  • Environment variables work consistently: SPM_INSTALL_SAVE, SPM_TEST_IGNORE_SCRIPTS, etc.
  • Only the selected command's properties are evaluated (properties for other commands are suppressed)
  • The pattern naturally supports nested sub-commands

In other words, Configurator commands don't actually "do" anything on their own; they simply provide structured hints for the command line to hierarchically assemble the configuration in a friendly manner. The actual work of interpreting what a command "means" is up to the application.

See the API documentation for Schema for more information on using the selector pattern.

(For a higher-level abstraction that builds on Configurator to provide executable code modules, see ModuleManager).