@taktikorg/accusantium-cum
is a library for generating terminal commands in a simple and straight-forward way.
It bundles many of your favorite terminal-based libraries together to give you a simple out-of-the-box experience when creating simple commands or full CLI utilities.
To install the Command class in an existing project, run the following:
npm i @taktikorg/accusantium-cum
Import or require the library:
// ESM
import { Command } from '@taktikorg/accusantium-cum'
// CommonJS
const { Command } = require('@taktikorg/accusantium-cum')
Now you're ready to create a Command:
const MyCommand = new Command({
name: 'my-command',
options: [],
action: async (data, details) => {
// do your thing
}
}).parse()
From here, you can run your script in 1 of 4 ways:
- Call the script directly (example:
./my-script.js
) - Call the script via
node
(example:node my-script.js
) - Add the script to your
package.json
intoscripts
and runnpm run <script>
- Add the script to your
package.json
intobin
and runnpm link
(or install globally) to run as an independent command
Property | Type | Req | Description |
---|---|---|---|
name |
string | Y | Command name |
command |
string | N | Terminal command to be called (used to enable subcommands) |
description |
string | N | Description to be used in help |
version |
string | N | Semver version of the command |
arguments |
object | N | Argument parsing definition |
options |
array | N | List of options to be parsed |
subcommands |
array,object | N | List of subcommands to be parsed |
prompts |
array | N | List of prompts to run |
promptTypes |
object | N | List of prompt types available to prompts
|
autoHelp |
boolean | N | Toggles automatic trigger of --help option |
helpTitle |
string | N | Title to use in --help
|
helpText |
string | N | Text to output in --help
|
addedHelp |
string | N | Additional text to output in --help
|
hidden |
boolean | N | Hides the command from --help if true
|
transform |
function | N | Method to transform response data from prompts |
action |
function | N | Action method to run when command is called |
new Command({
// required: name
name: 'create-foo',
// used as the command called when it's a subcommand
command: 'foo:create',
// used in help menu
description: 'Create a new Foo',
// application or command version
version: '1.4.7',
// argument handler
arguments: {
name: 'name'
},
// list of options to parse
options: [],
// list of subcommands
// if array, use the `command` property as the subcommand
// if object, use the key as the subcommand
subcommands: [],
// list of prompts to ask user
prompts: [],
// list of custom prompt types available to `prompts`
promptTypes: {},
// whether to automatically generate and display help menu on --help
autoHelp: true,
// used as the help menu title
helpTitle: 'Create Foo',
// replaces default help generated text
helptText: ``,
// additional help, like examples
addedHelp: ``,
// flag to be hidden from help menu
hidden: false,
// method to transform data before reaching action
transform: async (data) => {
data.type = 'based'
return data
},
action: async (data, details) => {
// perform your actions
}
})
(required) The identifying property of the Command.
Provides the default command to be called when imported, usually as a subcommand.
If not explicitly set, it defaults to name
. Can be overriden when importing via subcommands
by specifying a new command as the key.
Description of Command functionality.
This property displays in the --help
option, both on the Command's help page itself, as well as on the subcommand section of its parent Command.
The semver version of the Command.
The arguments
property allows you to add a catch-all for any arguments passed.
It is a single object that works similar to options
, so arguments can be passed in either directly or via parameter.
Key | Type | Req | Description |
---|---|---|---|
name | string | Y | Argument name |
type | function | N | Argument type (String , Number , Boolean ) or a function (default: String ) |
alias | string | N | getopt-style short option name (single character) |
multiple | boolean | N | Flag for declaring the possibility of multiple values (default: false ) |
lazyMultiple | boolean | N | Identical to multiple but with greedy parsing disabled (default: false ) |
defaultValue | any | N | Default value used when no value is passed |
group | string,array | N | Category name(s) to group by |
validate | function | N | Function to validate passed value against |
const MyCommand = new Command({
command: 'my-command',
arguments: {
name: 'value',
type: String,
multiple: true,
},
action: async (data, details) => {
console.log(data.value)
}
})
$ my-command foo bar
['foo', 'bar']
Notes:
- NO
arguments
property can be passed if usingsubcommands
. If both are used, it will throw an error. - In addition to any group(s) applied via
group
, all arguments will have theargs
group applied. - Arguments can also be passed in like options using
name
oralias
.
The options
property provides a list of any options that can be passed in, along with how to process them.
Key | Type | Req | Description |
---|---|---|---|
name | string | Y | Option name |
type | function | N | Option type as (String , Number , Boolean ) or a function (default: String ) |
alias | string | N | getopt-style short option name (single character) |
multiple | boolean | N | Flag for declaring the possibility of multiple values (default: false ) |
lazyMultiple | boolean | N | Identical to multiple but with greedy parsing disabled (default: false ) |
defaultOption | boolean | N | Flag to identify where unaccounted values go (default: false ) |
defaultValue | any | N | Initial option value |
group | string | array | N |
validate | function | N | Function to validate passed value against |
More details on option definitions can be found here
const MyCommand = new Command({
name: 'my-command',
options: [
{
name: 'file',
type: String,
alias: 'f',
multiple: true,
},
{
name: 'name',
type: String
},
{
name: 'force',
type: Boolean,
alias: 'F',
defaultValue: false
}
],
action: async (data, details) => {
console.log(data)
}
})
# single file passed
$ my-command --file src/file.txt
{ file: ['src/file.txt'], force: false }
# multiple files passed
$ my-command --file src/file.txt src/alt.txt
{ file: ['src/file', 'src/alt.txt'], force: false }
# `force` alias & name
$ my-command -F -name 'Hello World'
{ name: 'Hello World', force: true }
Notes:
- In addition to any group(s) applied via
group
, all options will have theopts
group applied.
The subcommands
property accepts a list of other Commands to be run as subcommands of the current command.
Subcommands can be added in as either an array or an object.
- When added as an array, it will use each subcommand's
command
property as the subcommand to use. - When added as an object, the key will represent the subcommand.
This provides for greater flexibility in importing commands from different places.
import { Command } from '@taktikorg/accusantium-cum'
const CreateCommand = new Command({
name: 'create',
action: () => {
console.log('Hello!')
}
})
export const ExampleCommand = new Command({
name: 'example',
subcommands: [
CreateCommand
]
}).parse()
export default ExampleCommand
$ example create
Hello!
Notes:
- NO
arguments
property can be passed if usingsubcommands
. If both are used, it will throw an error.
List of questions to prompt the user with.
Key | Type | Req | Description |
---|---|---|---|
name | string | Y | The name to apply in data |
type | string | N | Type of the prompt (possible values: input , number , confirm , list , rawlist , expand , checkbox , password , editor or custom type) (default: input ) |
message | string,function | N | The question to display (if defined as a function, the first parameter will be the current session answers) (default: ${name}: ) |
default | string,number,boolean,array,function | N | Default value(s) to use if nothing is entered, or a function that returns the default value(s) (if defined as a function, the first parameter will be the current session answers) |
choices | array,function | N | Choices array or a function returning a choices array (if defined as a function, the first parameter will be the current session answers; array values can be simple numbers, strings, or objects containing a name (to display in list), a value (to save in the answers hash), and a short (to display after selection) properties) |
validate | function | N | Validation function - receives the user input and answers hash (return true if the value is valid, or an error message (String) or false (default error message) otherwise) |
filter | function | N | Filtering function - receives the user input and answers hash (return the new filtered value) |
transformer | function | N | Transformer function - receives the user input, answers hash and option flags, and return a transformed value to display to the user (the transformation only impacts what is shown while editing, it does not modify the answers hash) |
when | function,boolean | N | When-to-display function - receives the current user answers hash and should return true or false depending on whether or not this question should be asked |
askAnswered | boolean | N | Force to prompt the question if the answer already exists |
Both arguments
and options
can be used to allow the end user to bypass specific prompts by providing a value in the command. The name
property must match between the options
or arguments
and the prompts
item.
Additionally, the promptTypes
property is used to add in custom prompt types and the transform
property is used to update values before it sent to action
.
More details on prompt types and how they work can be found in the Inquirer library.
const MyCommand = new Command({
name: 'my-command',
options: [
{
name: 'linter',
alias: 'l',
type: String,
}
],
prompts: [
// this prompt will always display
{
name: 'name',
message: 'Name',
},
// this prompt will only display if `--linter` or `-l` is not passed
{
name: 'linter',
type: 'list',
message: 'Select a linter',
choices: ['ESLint', 'JSLint', 'JSHint', 'StandardJS'],
default: 'StandardJS',
validate: async function(response) {
if (['ESLint', 'JSLint', 'JSHint', 'StandardJS'].includes(response)) return true
return false
}
}
]
})
Notes:
- Arguments and options used to provide a value for a prompt WILL NOT trigger the prompt validation if a value is passed, so option validation is recommended, especially in the case of a list
- If the prompt
name
contains periods, it will define a path in the data object.
List of prompt plugins that can be used in prompts.type
.
Prompt types can be created manually or by including existing implementations. The inquirer
library has a list of existing plugins that can be used here.
Additional Resources:
Flag to toggle auto-generation of the --help
option flag. Set to true
by default.
If set to false
, you can still add your own help option, but it will require a call to the renderHelp()
method to output.
A title to output in the --help
menu. Defaults to Command: ${command}
.
Text to output in the --help
menu instead of dynamically generating it.
Text to append to the --help
menu.
Use this if you want to auto-generate the help text, but you want to add additional information, such as examples.
hidden
Flag to hide the current Command from displaying in --help
menus of parent Command(s).
Transformation method to update data
before it is sent to action()
.
The lone parameter is data
, which is an object containing all processed values. Return the updated data to be sent to action()
as the data
parameter.
const MyCommand = new Command({
name: 'my-command',
options: [
{
name: 'linter',
alias: 'l',
type: String,
}
],
prompts: [
{
name: 'linter',
type: 'list',
message: 'Select a linter',
choices: ['ESLint', 'JSLint', 'JSHint', 'StandardJS'],
default: 'StandardJS',
validate: async function(response) {
if (['ESLint', 'JSLint', 'JSHint', 'StandardJS'].includes(response)) return true
return false
}
}
],
transform: async (data) => {
data._foo = 'bar'
return data
}
})
Method providing all data and information processed.
There are 2 variables passed:
-
data
- the final data object -
details
- an object with a full list of properties parsed:-
details.args
- data output for justarguments
-
details.opts
- data output for justoptions
-
details.unknown
- array of unknown parsed args -
details.tags
- object of data parsed by specific tags -
details.data
- output of full data
-
Key | Type | Req | Description |
---|---|---|---|
usage | string | N | Usage string to be parsed into Options |
Instead of manually adding options to the options
property, you can instead use the usage
property, which is a string that will be parsed to automatically generate your options.
Example:
const Test = new Command({
name: 'foo',
usage: `
Usage: foo <name> [OPTIONS]
Options:
--debug STRING Run debug mode
--log-level STRING Set the log level
--log-format STRING Set the logging output format
-v, --version BOOLEAN Show version
--help BOOLEAN Show this help
`
})
@taktikorg/accusantium-cum
provides a list of output methods to use instead of/in addition to using console
:
-
style (styles)
applies styles via an array (e.g.['green', 'bold']
) or string (e.g.green.bold
) -
log (msg, opts)
outputs themsg
string and conditionally applies styling viaopts
-
out (msg, opts)
similar tolog()
-
error (err, msg, exit)
outputs an error, a custom message, and conditionally stops the script -
spacer ()
outputs an empty spacer row -
rainbow (text)
returns the passed in text string as a rainbow -
heading (msg, opts)
outputs a heading, which is bolded and contains spacers
const MyCommand = new Command({
name: 'my-command',
action: async function (data, details) {
// will output a heading in bold with spacers
this.heading('Example command output')
// a simple output
this.out('normal text')
// text output bolded and in blue
this.out('colorful text', { styles: ['blue', 'bold'] })
// a spacer line in the console
this.spacer()
// outputs a line of text in rainbow
this.out(this.rainbow('Rainbow sentence that goes on and on'))
this.spacer()
try {
throw new Error('Example error')
} catch (e) {
// outputs an error and exits the console
this.error(e, 'Example error message')
}
}
})
By default, the --help
option will output content showing the user how to use the command, its arguments and options, and give a list of subcommands.
By using the helpText
property, you can override this to display whatever text you want. You can also use the addedHelp
property to display additional text after the default help text generation.
const MyCommand = new Command({
name: 'my-command',
argument: {
name: 'name'
},
options: [{
name: 'tags',
alias: 't',
type: String,
multiple: true
}, {
name: 'force',
alias: 'f',
type: Boolean
}, {
name: 'execute',
alias: 'x',
type: Boolean
}],
action: async function (data, details) {
this.heading('Example Command')
this.out({ data, details })
}
})
my-command foo --tags Universal Item "Item Ref" -fx
If you have set up your command as a script
in package.json
and are running it using npm run <command>
, you must add an additional --
before your options:
package.json
{
"name": "example-lib",
...
"scripts": {
"my-command": "node bin/my-command.js"
}
}
bin/my-command.js
npm run my-command -- --debug
When running a script directly (without using NPM or Node), be sure to include the following in your script:
#!/usr/bin/env node
-
build
npm run build
- Build from./src
to./dist
for ESM & CommonJS (with types) -
build:cjs
npm run build:cjs
- Build from./src
to./dist
for CommonJS (with types) -
build:esm
npm run build:esm
- Build from./src
to./dist
for ESM (with types) -
watch
npm run watch
- Watch./src
directory and build on file change to./dist
for ESM & CommonJS (with types)
-
lint
npm run lint
- Lint all files in./src
-
lint:fix
npm run lint:fix
- Lint and fix all files in./src
-
lint:prettier
npm run lint:prettier
- Fix styling for all files in./src
-
lint:prettier:ci
npm run lint:prettier:ci
- CI style check
-
test
npm test
- Run tests -
test:coverage
npm run test:coverage
- Run tests with coverage information
- Create scaffold to generate a brand new CLI project
- Apply automatic option for
--version
- Parse
usage
for additional information, likecommand
andarguments
- Create
CommandCenter
as a way to create a primary bin file
-
command-line-args
for parsing arguments -
command-line-usage
for generating help docs -
chalk
for terminal coloring -
inquirer
for prompts