├── .github
└── workflows
│ └── node.js.yml
├── LICENSE
├── README.hbs
├── README.md
├── dist
└── index.cjs
├── example
├── advanced
│ ├── arg-data.js
│ └── git.js
├── minimist.js
├── screens
│ └── command-list.png
├── simple.js
├── synopsis.js
└── usage.js
├── index.js
├── option.js
├── package-lock.json
├── package.json
└── test.js
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
2 |
3 | name: Node.js CI
4 |
5 | on:
6 | push:
7 | branches: [ master ]
8 | pull_request:
9 | branches: [ master ]
10 |
11 | jobs:
12 | build:
13 |
14 | runs-on: ${{ matrix.os }}
15 |
16 | strategy:
17 | matrix:
18 | os: [ubuntu-latest]
19 | node-version: [12, 14, 16, 18, 20, 22]
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 | - name: Use Node.js ${{ matrix.node-version }}
24 | uses: actions/setup-node@v4
25 | with:
26 | node-version: ${{ matrix.node-version }}
27 | cache: 'npm'
28 | - run: npm install
29 | - run: npm i -g @75lb/nature
30 | - run: npm run test:ci
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-25 Lloyd Brookes <75pound@gmail.com>
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.hbs:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.org/package/command-line-commands)
2 | [](https://www.npmjs.org/package/command-line-commands)
3 | [](https://github.com/75lb/command-line-commands/network/dependents?dependent_type=REPOSITORY)
4 | [](https://github.com/75lb/command-line-commands/network/dependents?dependent_type=PACKAGE)
5 | [](https://github.com/75lb/command-line-commands/actions/workflows/node.js.yml)
6 | [](https://github.com/feross/standard)
7 |
8 | # command-line-commands
9 |
10 | A lightweight module to help build a git-like command interface for your app.
11 |
12 | Its job is to extract the command (the first argument, unless it's an option), check it's valid and either return it or throw. From there, you can parse the remaining args using your preferred option parser (e.g. [command-line-args](https://github.com/75lb/command-line-args), [minimist](https://github.com/substack/minimist) etc.).
13 |
14 | ## Synopsis
15 |
16 | Create a list of valid commands (`null` represents "no command"). Supply it to `commandLineCommands()`, receiving back an object with two properties: `command` (the supplied command) and `argv` (the remainder of the command line args):
17 | ```js
18 | const commandLineCommands = require('command-line-commands')
19 |
20 | const validCommands = [ null, 'clean', 'update', 'install' ]
21 | const { command, argv } = commandLineCommands(validCommands)
22 |
23 | /* print the command and remaining command-line args */
24 | console.log('command: %s', command)
25 | console.log('argv: %s', JSON.stringify(argv))
26 | ```
27 |
28 | We'll assume the above script is installed as `example`. Since the `validCommands` list includes `null`, running it without a command is valid:
29 | ```
30 | $ example
31 | command: null
32 | argv: []
33 | ```
34 |
35 | Running `example` with no command and one option:
36 | ```
37 | $ example --verbose
38 | command: null
39 | argv: ["--verbose"]
40 | ```
41 |
42 | Running `example` with both a command and an option:
43 | ```
44 | $ example install --save something
45 | command: install
46 | argv: ["--save","something"]
47 | ```
48 |
49 | Running `example` without a valid command will cause `commandLineCommands()` to throw.
50 |
51 | From here, you can make a decision how to proceed based on the `command` and `argv` received. For example, if no command (`null`) was passed, you could parse the remaining `argv` for general options (in this case using [command-line-args](https://github.com/75lb/command-line-args)):
52 |
53 | ```js
54 | if (command === null) {
55 | const commandLineArgs = require('command-line-args')
56 | const optionDefinitions = [
57 | { name: 'version', type: Boolean }
58 | ]
59 |
60 | // pass in the `argv` returned by `commandLineCommands()`
61 | const options = commandLineArgs(optionDefinitions, { argv })
62 |
63 | if (options.version) {
64 | console.log('version 1.0.1')
65 | }
66 | }
67 | ```
68 |
69 | The same example, using [minimist](https://github.com/substack/minimist):
70 |
71 | ```js
72 | if (command === null) {
73 | const minimist = require('minimist')
74 |
75 | // pass in the `argv` returned by `commandLineCommands()``
76 | const options = minimist(argv)
77 |
78 | if (options.version) {
79 | console.log('version 1.0.1')
80 | }
81 | }
82 | ```
83 |
84 | ## More examples
85 |
86 | Both examples use [command-line-args](https://github.com/75lb/command-line-args) for option-parsing.
87 |
88 | - [Simple](https://github.com/75lb/command-line-commands/blob/master/example/simple.js): A basic app with a couple of commands.
89 | - [Advanced](https://github.com/75lb/command-line-commands/blob/master/example/advanced/git.js): A more complete example, implementing part of the git command interface.
90 |
91 | ## Usage guides
92 |
93 | Usage guides can be generated by [command-line-usage](https://github.com/75lb/command-line-usage). Here is a simple example ([code](https://github.com/75lb/command-line-commands/blob/master/example/usage.js)):
94 |
95 | 
96 |
97 | # API Reference
98 | {{#module name="command-line-commands"}}
99 | {{>body~}}
100 | {{>member-index~}}
101 | {{>separator~}}
102 | {{>members~}}
103 | {{/module}}
104 |
105 | * * *
106 |
107 | © 2015-25 Lloyd Brookes \<75pound@gmail.com\>. Documented by [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown).
108 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.org/package/command-line-commands)
2 | [](https://www.npmjs.org/package/command-line-commands)
3 | [](https://github.com/75lb/command-line-commands/network/dependents?dependent_type=REPOSITORY)
4 | [](https://github.com/75lb/command-line-commands/network/dependents?dependent_type=PACKAGE)
5 | [](https://github.com/75lb/command-line-commands/actions/workflows/node.js.yml)
6 | [](https://github.com/feross/standard)
7 |
8 | # command-line-commands
9 |
10 | A lightweight module to help build a git-like command interface for your app.
11 |
12 | Its job is to extract the command (the first argument, unless it's an option), check it's valid and either return it or throw. From there, you can parse the remaining args using your preferred option parser (e.g. [command-line-args](https://github.com/75lb/command-line-args), [minimist](https://github.com/substack/minimist) etc.).
13 |
14 | ## Synopsis
15 |
16 | Create a list of valid commands (`null` represents "no command"). Supply it to `commandLineCommands()`, receiving back an object with two properties: `command` (the supplied command) and `argv` (the remainder of the command line args):
17 | ```js
18 | const commandLineCommands = require('command-line-commands')
19 |
20 | const validCommands = [ null, 'clean', 'update', 'install' ]
21 | const { command, argv } = commandLineCommands(validCommands)
22 |
23 | /* print the command and remaining command-line args */
24 | console.log('command: %s', command)
25 | console.log('argv: %s', JSON.stringify(argv))
26 | ```
27 |
28 | We'll assume the above script is installed as `example`. Since the `validCommands` list includes `null`, running it without a command is valid:
29 | ```
30 | $ example
31 | command: null
32 | argv: []
33 | ```
34 |
35 | Running `example` with no command and one option:
36 | ```
37 | $ example --verbose
38 | command: null
39 | argv: ["--verbose"]
40 | ```
41 |
42 | Running `example` with both a command and an option:
43 | ```
44 | $ example install --save something
45 | command: install
46 | argv: ["--save","something"]
47 | ```
48 |
49 | Running `example` without a valid command will cause `commandLineCommands()` to throw.
50 |
51 | From here, you can make a decision how to proceed based on the `command` and `argv` received. For example, if no command (`null`) was passed, you could parse the remaining `argv` for general options (in this case using [command-line-args](https://github.com/75lb/command-line-args)):
52 |
53 | ```js
54 | if (command === null) {
55 | const commandLineArgs = require('command-line-args')
56 | const optionDefinitions = [
57 | { name: 'version', type: Boolean }
58 | ]
59 |
60 | // pass in the `argv` returned by `commandLineCommands()`
61 | const options = commandLineArgs(optionDefinitions, { argv })
62 |
63 | if (options.version) {
64 | console.log('version 1.0.1')
65 | }
66 | }
67 | ```
68 |
69 | The same example, using [minimist](https://github.com/substack/minimist):
70 |
71 | ```js
72 | if (command === null) {
73 | const minimist = require('minimist')
74 |
75 | // pass in the `argv` returned by `commandLineCommands()``
76 | const options = minimist(argv)
77 |
78 | if (options.version) {
79 | console.log('version 1.0.1')
80 | }
81 | }
82 | ```
83 |
84 | ## More examples
85 |
86 | Both examples use [command-line-args](https://github.com/75lb/command-line-args) for option-parsing.
87 |
88 | - [Simple](https://github.com/75lb/command-line-commands/blob/master/example/simple.js): A basic app with a couple of commands.
89 | - [Advanced](https://github.com/75lb/command-line-commands/blob/master/example/advanced/git.js): A more complete example, implementing part of the git command interface.
90 |
91 | ## Usage guides
92 |
93 | Usage guides can be generated by [command-line-usage](https://github.com/75lb/command-line-usage). Here is a simple example ([code](https://github.com/75lb/command-line-commands/blob/master/example/usage.js)):
94 |
95 | 
96 |
97 | # API Reference
98 | **Example**
99 | ```js
100 | const commandLineCommands = require('command-line-commands')
101 | ```
102 |
103 |
104 | ### commandLineCommands(commands, [argv]) ⇒ Object
⏏
105 | Parses the `argv` value supplied (or `process.argv` by default), extracting and returning the `command` and remainder of `argv`. The command will be the first value in the `argv` array unless it is an option (e.g. `--help`).
106 |
107 | **Kind**: Exported function
108 | **Throws**:
109 |
110 | - `INVALID_COMMAND` - user supplied a command not specified in `commands`.
111 |
112 |
113 | | Param | Type | Description |
114 | | --- | --- | --- |
115 | | commands | string
\| Array.<string>
| One or more command strings, one of which the user must supply. Include `null` to represent "no command" (effectively making a command optional). |
116 | | [argv] | Array.<string>
| An argv array, defaults to the global `process.argv` if not supplied. |
117 |
118 |
119 | * * *
120 |
121 | © 2015-25 Lloyd Brookes \<75pound@gmail.com\>. Documented by [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown).
122 |
--------------------------------------------------------------------------------
/dist/index.cjs:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var arrayify = require('array-back');
4 |
5 | /**
6 | * A module for testing for and extracting names from options (e.g. `--one`, `-o`)
7 | */
8 |
9 | class Arg {
10 | constructor (re) {
11 | this.re = re;
12 | }
13 |
14 | test (arg) {
15 | return this.re.test(arg)
16 | }
17 | }
18 |
19 | const isShort = new Arg(/^-([^\d-])$/);
20 | const isLong = new Arg(/^--(\S+)/);
21 | const isCombined = new Arg(/^-([^\d-]{2,})$/);
22 | const isOption = function (arg) {
23 | return isShort.test(arg) || isLong.test(arg) || isCombined.test(arg)
24 | };
25 |
26 | /**
27 | * @module command-line-commands
28 | * @example
29 | * const commandLineCommands = require('command-line-commands')
30 | */
31 |
32 | /**
33 | * Parses the `argv` value supplied (or `process.argv` by default), extracting and returning the `command` and remainder of `argv`. The command will be the first value in the `argv` array unless it is an option (e.g. `--help`).
34 | *
35 | * @param {string|string[]} - One or more command strings, one of which the user must supply. Include `null` to represent "no command" (effectively making a command optional).
36 | * @param [argv] {string[]} - An argv array, defaults to the global `process.argv` if not supplied.
37 | * @returns {{ command: string, argv: string[] }}
38 | * @throws `INVALID_COMMAND` - user supplied a command not specified in `commands`.
39 | * @alias module:command-line-commands
40 | */
41 | function commandLineCommands (commands, argv) {
42 | if (!commands || (Array.isArray(commands) && !commands.length)) {
43 | throw new Error('Please supply one or more commands')
44 | }
45 | if (argv) {
46 | argv = arrayify(argv);
47 | } else {
48 | /* if no argv supplied, assume we are parsing process.argv. */
49 | /* never modify the global process.argv directly. */
50 | argv = process.argv.slice(0);
51 | argv.splice(0, 2);
52 | }
53 |
54 | /* the command is the first arg, unless it's an option (e.g. --help) */
55 | const command = (isOption(argv[0]) || !argv.length) ? null : argv.shift();
56 |
57 | if (arrayify(commands).indexOf(command) === -1) {
58 | const err = new Error('Command not recognised: ' + command);
59 | err.command = command;
60 | err.name = 'INVALID_COMMAND';
61 | throw err
62 | }
63 |
64 | return { command, argv }
65 | }
66 |
67 | module.exports = commandLineCommands;
68 |
--------------------------------------------------------------------------------
/example/advanced/arg-data.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | null: {
3 | definitions: [
4 | { name: 'version', alias: 'v', type: Boolean, description: 'Print the version number.' }
5 | ],
6 | usage: [
7 | {
8 | header: 'git',
9 | content: 'Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.'
10 | },
11 | {
12 | header: 'synopsis',
13 | content: '$ git '
14 | },
15 | {
16 | header: 'Command List',
17 | content: [
18 | { name: 'help', summary: 'Display help information about Git.' },
19 | { name: 'commit', summary: 'Record changes to the repository.' }
20 | ]
21 | }
22 | ]
23 | },
24 | help: {
25 | definitions: [
26 | { name: 'topic', type: String, description: 'the topic to display help on', defaultOption: true }
27 | ],
28 | usage: [
29 | {
30 | header: 'git help',
31 | content: 'Git help about a git command'
32 | },
33 | {
34 | header: 'synopsis',
35 | content: '$ git help '
36 | }
37 | ]
38 | },
39 | commit: {
40 | definitions: [
41 | { name: 'message', alias: 'm', type: String, description: 'Commit message.' }
42 | ],
43 | usage: [
44 | {
45 | header: 'git commit',
46 | content: 'Commit some work.'
47 | },
48 | {
49 | header: 'synopsis',
50 | content: '$ git commit [--message] '
51 | }
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/example/advanced/git.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict'
3 | const commandLineCommands = require('../../')
4 | const commandLineArgs = require('command-line-args')
5 | const commandLineUsage = require('command-line-usage')
6 | const argData = require('./arg-data')
7 |
8 | const { command, argv } = commandLineCommands([ null, 'help', 'commit' ])
9 |
10 | /* important: pass in the argv returned by `commandLineCommands()` */
11 | const options = commandLineArgs(argData[command].definitions, { argv })
12 | const usage = commandLineUsage(argData[command].usage)
13 |
14 | switch (command) {
15 | case null:
16 | if (options.version) {
17 | console.log('version 90')
18 | } else {
19 | console.log(usage)
20 | }
21 | break
22 |
23 | case 'help':
24 | if (options.topic) {
25 | console.log(commandLineUsage(argData[options.topic].usage))
26 | } else {
27 | console.log(commandLineUsage(argData.help.usage))
28 | }
29 | break
30 |
31 | case 'commit':
32 | if (options.message) {
33 | console.log('commit: ' + options.message)
34 | } else {
35 | console.log(usage)
36 | }
37 | break
38 | }
39 |
--------------------------------------------------------------------------------
/example/minimist.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const commandLineCommands = require('../')
3 | const minimist = require('minimist')
4 |
5 | const validCommands = [ 'load', 'print' ]
6 | const { command, argv } = commandLineCommands(validCommands)
7 |
8 | /* pass in the argv returned by `commandLineCommands()` */
9 | const options = minimist(argv)
10 |
11 | switch (command) {
12 | case 'load':
13 | if (options.file) {
14 | console.log(`Loading: ${options.file}`)
15 | } else {
16 | console.log('please supply a filename')
17 | }
18 | break
19 |
20 | case 'print':
21 | console.log('Printing %s', options.colour ? 'in colour' : 'in B&W' )
22 | break
23 | }
24 |
--------------------------------------------------------------------------------
/example/screens/command-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/75lb/command-line-commands/800b3b9111e7f6da6e1b647a5ef46ce77376fbc6/example/screens/command-list.png
--------------------------------------------------------------------------------
/example/simple.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const commandLineCommands = require('../')
3 | const commandLineArgs = require('command-line-args')
4 |
5 | const validCommands = [ 'load', 'print' ]
6 | const { command, argv } = commandLineCommands(validCommands)
7 |
8 | const optionDefinitions = {
9 | load: [
10 | { name: 'file', type: String }
11 | ],
12 | print: [
13 | { name: 'colour', type: Boolean }
14 | ]
15 | }
16 |
17 | /* important: pass in the argv returned by `commandLineCommands()` */
18 | const options = commandLineArgs(optionDefinitions[command], { argv })
19 |
20 | switch (command) {
21 | case 'load':
22 | if (options.file) {
23 | console.log(`Loading: ${options.file}`)
24 | } else {
25 | console.log('please supply a filename')
26 | }
27 | break
28 |
29 | case 'print':
30 | console.log('Printing %s', options.colour ? 'in colour' : 'in B&W' )
31 | break
32 | }
33 |
--------------------------------------------------------------------------------
/example/synopsis.js:
--------------------------------------------------------------------------------
1 | const commandLineCommands = require('../')
2 |
3 | const validCommands = [ null, 'clean', 'update', 'install' ]
4 | const { command, argv } = commandLineCommands(validCommands)
5 |
6 | console.log('command: %s', command)
7 | console.log('argv: %s', JSON.stringify(argv))
8 |
--------------------------------------------------------------------------------
/example/usage.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const commandLineUsage = require('command-line-usage')
3 |
4 | const sections = [
5 | {
6 | header: 'Example App',
7 | content: 'Generates something [italic]{very} important.'
8 | },
9 | {
10 | header: 'Synopsis',
11 | content: '$ app '
12 | },
13 | {
14 | header: 'Command List',
15 | content: [
16 | { name: 'help', summary: 'Display help information about Git.' },
17 | { name: 'commit', summary: 'Record changes to the repository.' },
18 | { name: 'Version', summary: 'Print the version.' },
19 | { name: 'etc', summary: 'Etc.' }
20 | ]
21 | }
22 | ]
23 |
24 | const usage = commandLineUsage(sections)
25 | console.log(usage)
26 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import arrayify from 'array-back'
2 | import { isOption } from './option.js'
3 |
4 | /**
5 | * @module command-line-commands
6 | * @example
7 | * const commandLineCommands = require('command-line-commands')
8 | */
9 |
10 | /**
11 | * Parses the `argv` value supplied (or `process.argv` by default), extracting and returning the `command` and remainder of `argv`. The command will be the first value in the `argv` array unless it is an option (e.g. `--help`).
12 | *
13 | * @param {string|string[]} - One or more command strings, one of which the user must supply. Include `null` to represent "no command" (effectively making a command optional).
14 | * @param [argv] {string[]} - An argv array, defaults to the global `process.argv` if not supplied.
15 | * @returns {{ command: string, argv: string[] }}
16 | * @throws `INVALID_COMMAND` - user supplied a command not specified in `commands`.
17 | * @alias module:command-line-commands
18 | */
19 | function commandLineCommands (commands, argv) {
20 | if (!commands || (Array.isArray(commands) && !commands.length)) {
21 | throw new Error('Please supply one or more commands')
22 | }
23 | if (argv) {
24 | argv = arrayify(argv)
25 | } else {
26 | /* if no argv supplied, assume we are parsing process.argv. */
27 | /* never modify the global process.argv directly. */
28 | argv = process.argv.slice(0)
29 | argv.splice(0, 2)
30 | }
31 |
32 | /* the command is the first arg, unless it's an option (e.g. --help) */
33 | const command = (isOption(argv[0]) || !argv.length) ? null : argv.shift()
34 |
35 | if (arrayify(commands).indexOf(command) === -1) {
36 | const err = new Error('Command not recognised: ' + command)
37 | err.command = command
38 | err.name = 'INVALID_COMMAND'
39 | throw err
40 | }
41 |
42 | return { command, argv }
43 | }
44 |
45 | export default commandLineCommands
46 |
--------------------------------------------------------------------------------
/option.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A module for testing for and extracting names from options (e.g. `--one`, `-o`)
3 | */
4 |
5 | class Arg {
6 | constructor (re) {
7 | this.re = re
8 | }
9 |
10 | test (arg) {
11 | return this.re.test(arg)
12 | }
13 | }
14 |
15 | const isShort = new Arg(/^-([^\d-])$/)
16 | const isLong = new Arg(/^--(\S+)/)
17 | const isCombined = new Arg(/^-([^\d-]{2,})$/)
18 | const isOption = function (arg) {
19 | return isShort.test(arg) || isLong.test(arg) || isCombined.test(arg)
20 | }
21 | const optEquals = new Arg(/^(--\S+)=(.*)/)
22 |
23 | export { isShort, isLong, isCombined, isOption, optEquals }
24 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "command-line-commands",
3 | "version": "4.0.1",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "command-line-commands",
9 | "version": "4.0.1",
10 | "license": "MIT",
11 | "dependencies": {
12 | "array-back": "^6.2.2"
13 | },
14 | "devDependencies": {
15 | "command-line-args": "^6.0.0",
16 | "command-line-usage": "^7.0.3",
17 | "minimist": "^1.2.8"
18 | },
19 | "engines": {
20 | "node": ">=12.17"
21 | }
22 | },
23 | "node_modules/ansi-styles": {
24 | "version": "4.3.0",
25 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
26 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
27 | "dev": true,
28 | "license": "MIT",
29 | "dependencies": {
30 | "color-convert": "^2.0.1"
31 | },
32 | "engines": {
33 | "node": ">=8"
34 | },
35 | "funding": {
36 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
37 | }
38 | },
39 | "node_modules/array-back": {
40 | "version": "6.2.2",
41 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
42 | "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==",
43 | "license": "MIT",
44 | "engines": {
45 | "node": ">=12.17"
46 | }
47 | },
48 | "node_modules/chalk": {
49 | "version": "4.1.2",
50 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
51 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
52 | "dev": true,
53 | "license": "MIT",
54 | "dependencies": {
55 | "ansi-styles": "^4.1.0",
56 | "supports-color": "^7.1.0"
57 | },
58 | "engines": {
59 | "node": ">=10"
60 | },
61 | "funding": {
62 | "url": "https://github.com/chalk/chalk?sponsor=1"
63 | }
64 | },
65 | "node_modules/chalk-template": {
66 | "version": "0.4.0",
67 | "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz",
68 | "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==",
69 | "dev": true,
70 | "license": "MIT",
71 | "dependencies": {
72 | "chalk": "^4.1.2"
73 | },
74 | "engines": {
75 | "node": ">=12"
76 | },
77 | "funding": {
78 | "url": "https://github.com/chalk/chalk-template?sponsor=1"
79 | }
80 | },
81 | "node_modules/color-convert": {
82 | "version": "2.0.1",
83 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
84 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
85 | "dev": true,
86 | "license": "MIT",
87 | "dependencies": {
88 | "color-name": "~1.1.4"
89 | },
90 | "engines": {
91 | "node": ">=7.0.0"
92 | }
93 | },
94 | "node_modules/color-name": {
95 | "version": "1.1.4",
96 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
97 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
98 | "dev": true,
99 | "license": "MIT"
100 | },
101 | "node_modules/command-line-args": {
102 | "version": "6.0.0",
103 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.0.tgz",
104 | "integrity": "sha512-zDdHxHzlCp/gA1gy0VtPK3YL0Aob3ijJdwZ7H3HSl55hh8EziLtRlyj/od8EGRJfX8IjussC/mQkScl2Ms5Suw==",
105 | "dev": true,
106 | "license": "MIT",
107 | "dependencies": {
108 | "array-back": "^6.2.2",
109 | "find-replace": "^5.0.1",
110 | "lodash.camelcase": "^4.3.0",
111 | "typical": "^7.1.1"
112 | },
113 | "engines": {
114 | "node": ">=12.20"
115 | }
116 | },
117 | "node_modules/command-line-usage": {
118 | "version": "7.0.3",
119 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz",
120 | "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==",
121 | "dev": true,
122 | "license": "MIT",
123 | "dependencies": {
124 | "array-back": "^6.2.2",
125 | "chalk-template": "^0.4.0",
126 | "table-layout": "^4.1.0",
127 | "typical": "^7.1.1"
128 | },
129 | "engines": {
130 | "node": ">=12.20.0"
131 | }
132 | },
133 | "node_modules/find-replace": {
134 | "version": "5.0.1",
135 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.1.tgz",
136 | "integrity": "sha512-o5/Y8HrCNRuFF5rdNTkX8Vhv6kTFTV0t1zIoigwlCdbkA9qaapRzxvWPND2VvlFa9LBI05Q1i8ml/saMqkOJUQ==",
137 | "dev": true,
138 | "license": "MIT",
139 | "dependencies": {
140 | "array-back": "^6.2.2"
141 | },
142 | "engines": {
143 | "node": ">=14"
144 | }
145 | },
146 | "node_modules/has-flag": {
147 | "version": "4.0.0",
148 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
149 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
150 | "dev": true,
151 | "license": "MIT",
152 | "engines": {
153 | "node": ">=8"
154 | }
155 | },
156 | "node_modules/lodash.camelcase": {
157 | "version": "4.3.0",
158 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
159 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
160 | "dev": true
161 | },
162 | "node_modules/minimist": {
163 | "version": "1.2.8",
164 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
165 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
166 | "dev": true,
167 | "license": "MIT",
168 | "funding": {
169 | "url": "https://github.com/sponsors/ljharb"
170 | }
171 | },
172 | "node_modules/supports-color": {
173 | "version": "7.2.0",
174 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
175 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
176 | "dev": true,
177 | "license": "MIT",
178 | "dependencies": {
179 | "has-flag": "^4.0.0"
180 | },
181 | "engines": {
182 | "node": ">=8"
183 | }
184 | },
185 | "node_modules/table-layout": {
186 | "version": "4.1.1",
187 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz",
188 | "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==",
189 | "dev": true,
190 | "license": "MIT",
191 | "dependencies": {
192 | "array-back": "^6.2.2",
193 | "wordwrapjs": "^5.1.0"
194 | },
195 | "engines": {
196 | "node": ">=12.17"
197 | }
198 | },
199 | "node_modules/typical": {
200 | "version": "7.1.1",
201 | "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz",
202 | "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==",
203 | "dev": true,
204 | "license": "MIT",
205 | "engines": {
206 | "node": ">=12.17"
207 | }
208 | },
209 | "node_modules/wordwrapjs": {
210 | "version": "5.1.0",
211 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz",
212 | "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==",
213 | "dev": true,
214 | "license": "MIT",
215 | "engines": {
216 | "node": ">=12.17"
217 | }
218 | }
219 | },
220 | "dependencies": {
221 | "ansi-styles": {
222 | "version": "4.3.0",
223 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
224 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
225 | "dev": true,
226 | "requires": {
227 | "color-convert": "^2.0.1"
228 | }
229 | },
230 | "array-back": {
231 | "version": "6.2.2",
232 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
233 | "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw=="
234 | },
235 | "chalk": {
236 | "version": "4.1.2",
237 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
238 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
239 | "dev": true,
240 | "requires": {
241 | "ansi-styles": "^4.1.0",
242 | "supports-color": "^7.1.0"
243 | }
244 | },
245 | "chalk-template": {
246 | "version": "0.4.0",
247 | "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz",
248 | "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==",
249 | "dev": true,
250 | "requires": {
251 | "chalk": "^4.1.2"
252 | }
253 | },
254 | "color-convert": {
255 | "version": "2.0.1",
256 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
257 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
258 | "dev": true,
259 | "requires": {
260 | "color-name": "~1.1.4"
261 | }
262 | },
263 | "color-name": {
264 | "version": "1.1.4",
265 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
266 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
267 | "dev": true
268 | },
269 | "command-line-args": {
270 | "version": "6.0.0",
271 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.0.tgz",
272 | "integrity": "sha512-zDdHxHzlCp/gA1gy0VtPK3YL0Aob3ijJdwZ7H3HSl55hh8EziLtRlyj/od8EGRJfX8IjussC/mQkScl2Ms5Suw==",
273 | "dev": true,
274 | "requires": {
275 | "array-back": "^6.2.2",
276 | "find-replace": "^5.0.1",
277 | "lodash.camelcase": "^4.3.0",
278 | "typical": "^7.1.1"
279 | }
280 | },
281 | "command-line-usage": {
282 | "version": "7.0.3",
283 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz",
284 | "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==",
285 | "dev": true,
286 | "requires": {
287 | "array-back": "^6.2.2",
288 | "chalk-template": "^0.4.0",
289 | "table-layout": "^4.1.0",
290 | "typical": "^7.1.1"
291 | }
292 | },
293 | "find-replace": {
294 | "version": "5.0.1",
295 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.1.tgz",
296 | "integrity": "sha512-o5/Y8HrCNRuFF5rdNTkX8Vhv6kTFTV0t1zIoigwlCdbkA9qaapRzxvWPND2VvlFa9LBI05Q1i8ml/saMqkOJUQ==",
297 | "dev": true,
298 | "requires": {
299 | "array-back": "^6.2.2"
300 | }
301 | },
302 | "has-flag": {
303 | "version": "4.0.0",
304 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
305 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
306 | "dev": true
307 | },
308 | "lodash.camelcase": {
309 | "version": "4.3.0",
310 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
311 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
312 | "dev": true
313 | },
314 | "minimist": {
315 | "version": "1.2.8",
316 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
317 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
318 | "dev": true
319 | },
320 | "supports-color": {
321 | "version": "7.2.0",
322 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
323 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
324 | "dev": true,
325 | "requires": {
326 | "has-flag": "^4.0.0"
327 | }
328 | },
329 | "table-layout": {
330 | "version": "4.1.1",
331 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz",
332 | "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==",
333 | "dev": true,
334 | "requires": {
335 | "array-back": "^6.2.2",
336 | "wordwrapjs": "^5.1.0"
337 | }
338 | },
339 | "typical": {
340 | "version": "7.1.1",
341 | "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz",
342 | "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==",
343 | "dev": true
344 | },
345 | "wordwrapjs": {
346 | "version": "5.1.0",
347 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz",
348 | "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==",
349 | "dev": true
350 | }
351 | }
352 | }
353 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "command-line-commands",
3 | "author": "Lloyd Brookes <75pound@gmail.com>",
4 | "version": "4.0.1",
5 | "description": "Add a git-like command interface to your app.",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/75lb/command-line-commands.git"
9 | },
10 | "license": "MIT",
11 | "files": [
12 | "index.js",
13 | "option.js",
14 | "dist"
15 | ],
16 | "type": "module",
17 | "exports": {
18 | "import": "./index.js",
19 | "require": "./dist/index.cjs"
20 | },
21 | "keywords": [
22 | "argv",
23 | "parse",
24 | "argument",
25 | "args",
26 | "option",
27 | "parser",
28 | "parsing",
29 | "cli",
30 | "command",
31 | "commands",
32 | "line"
33 | ],
34 | "engines": {
35 | "node": ">=12.17"
36 | },
37 | "scripts": {
38 | "test": "npm run dist && npm run test:ci",
39 | "test:ci": "75lb-nature test-runner test.js",
40 | "docs": "75lb-nature jsdoc2md -t README.hbs index.js > README.md",
41 | "dist": "75lb-nature cjs-build index.js"
42 | },
43 | "peerDependencies": {
44 | "@75lb/nature": "latest"
45 | },
46 | "peerDependenciesMeta": {
47 | "@75lb/nature": {
48 | "optional": true
49 | }
50 | },
51 | "dependencies": {
52 | "array-back": "^6.2.2"
53 | },
54 | "devDependencies": {
55 | "command-line-args": "^6.0.0",
56 | "command-line-usage": "^7.0.3",
57 | "minimist": "^1.2.8"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | import commandLineCommands from 'command-line-commands'
2 | import { strict as a } from 'assert'
3 |
4 | const [test, only, skip] = [new Map(), new Map(), new Map()]
5 |
6 | /* Tests which parse process.argv expect this array */
7 | process.argv = ['node', 'script', '--files', 'test.js']
8 |
9 | test.set('simple', function () {
10 | const commands = [ 'eat', 'sleep' ]
11 |
12 | let clc = commandLineCommands(commands, [ 'eat', '--food', 'peas' ])
13 | a.equal(clc.command, 'eat')
14 | a.deepEqual(clc.argv, [ '--food', 'peas' ])
15 |
16 | clc = commandLineCommands(commands, [ 'sleep', '--hours', '2' ])
17 | a.equal(clc.command, 'sleep')
18 | a.deepEqual(clc.argv, [ '--hours', '2' ])
19 | })
20 |
21 | test.set('no commands defined', function () {
22 | a.throws(function () {
23 | commandLineCommands([], [ 'eat' ])
24 | })
25 | a.throws(function () {
26 | commandLineCommands(undefined, [ 'eat' ])
27 | })
28 | a.throws(function () {
29 | commandLineCommands([])
30 | })
31 | a.throws(function () {
32 | commandLineCommands([], [ 'eat' ])
33 | })
34 | a.throws(function () {
35 | commandLineCommands()
36 | })
37 | })
38 |
39 | test.set('no command specified', function () {
40 | let clc
41 | let commands = [ ]
42 |
43 | /* throws if null not specified */
44 | a.throws(function () {
45 | clc = commandLineCommands(commands, [ ])
46 | })
47 |
48 | /* null specified */
49 | commands = [ null ]
50 | clc = commandLineCommands(commands, [ ])
51 | a.equal(clc.command, null)
52 | a.deepEqual(clc.argv, [ ])
53 |
54 | clc = commandLineCommands(commands, [ '--flag' ])
55 | a.equal(clc.command, null)
56 | a.deepEqual(clc.argv, [ '--flag' ])
57 | })
58 |
59 | test.set('invalid command', function () {
60 | const commands = [ 'eat', 'sleep' ]
61 | let clc
62 |
63 | a.throws(
64 | function () {
65 | clc = commandLineCommands(commands, [ 'cheese', '--food', 'peas' ])
66 | },
67 | function (err) {
68 | return err.name === 'INVALID_COMMAND' && err.command === 'cheese'
69 | }
70 | )
71 | })
72 |
73 | test.set('parse process.argv', function () {
74 | const commands = [ null ]
75 | const clc = commandLineCommands(commands)
76 | a.equal(clc.command, null)
77 | a.deepEqual(clc.argv, [ '--files', 'test.js' ])
78 | })
79 |
80 | test.set('different types of option as the first arg', function () {
81 | const commands = [ null ]
82 |
83 | let clc = commandLineCommands(commands, [ '--one' ])
84 | a.equal(clc.command, null)
85 | a.deepEqual(clc.argv, [ '--one' ])
86 |
87 | clc = commandLineCommands(commands, [ '--one=two' ])
88 | a.equal(clc.command, null)
89 | a.deepEqual(clc.argv, [ '--one=two' ])
90 |
91 | clc = commandLineCommands(commands, [ '-o' ])
92 | a.equal(clc.command, null)
93 | a.deepEqual(clc.argv, [ '-o' ])
94 |
95 | clc = commandLineCommands(commands, [ '-of' ])
96 | a.equal(clc.command, null)
97 | a.deepEqual(clc.argv, [ '-of' ])
98 | })
99 |
100 | export { test, only, skip }
101 |
--------------------------------------------------------------------------------