command-line-director 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG ADDED
@@ -0,0 +1,10 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+ This project adheres to [Semantic Versioning](http://semver.org/).
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [1.0.0] - 2021-21-09
8
+
9
+ ### Added
10
+ - Initial release
package/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ MIT License
2
+ Copyright (c) 2016 Marco Jonker
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5
+ and associated documentation files (the "Software"), to deal in the Software without restriction,
6
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
7
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial
11
+ portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # COMMAND LINE DIRECTOR #
2
+
3
+ The command line director give direction to you command line arguments. With the command line director you can configure, validate and direct the command line argument supported by your nodejs command line application.
4
+
5
+ # QUICKSTART #
6
+
7
+ **STEP 1:** Install
8
+ ```
9
+ npm install command-line-director
10
+ ```
11
+
12
+ **STEP 2:** Add the command line director to your application (see chapter 'sample')
13
+
14
+ **STEP 3:** Run your application
15
+
16
+ # CONFIGURATION #
17
+
18
+ The configuration the the command line director exists of 3 classes. The CommandLineDirector that contains a set of CommandLines. Each CommandLine exists of one or more CommandLineArguments.
19
+
20
+ ## Configuring the CommandLineDirector
21
+
22
+ The command line direction the class that contains all the application's command line and maps the input argument to a specific Command. It also contain a title and a description of the application, which is printed a the top of the generated help. For an example see the chapter 'sample'. The CommandLineDirector has 2 public functions:
23
+
24
+ * parse(verbose) - To parse the current command line arguments to a specific command. If verbose is true information about why a command is not found is printen at stdout
25
+ * generateHelp - To Generate a help text
26
+
27
+ ## Configuring a CommandLine
28
+
29
+ A command line the configuration of a set of arguments that defines a specific command. It also contains a title and a description of a CommandLine, which is printed in the generated Help. For an example see the chapter 'sample'.
30
+
31
+ ## Configuring a CommandLineArgument ##
32
+
33
+ The most used types of argument can be defined using the CommandLineArgument factory. The factory can be used to create a key value argument, a flag argument and a value argument.
34
+
35
+ ### Key value argument ###
36
+
37
+ A key value argument is a string argument with a key. The key value argument can be define with the following properties:
38
+
39
+ * propertyName - Name of the property that will contain the value when the command is parsed
40
+ * description - Description of the flag that is displayed in the command line help
41
+ * argumentName - Name of the argument in the command line (exmaple: '--test-flag')
42
+ * alias - Alias for the name of the argument (example: '-tf')
43
+ * required - Value is required or optional
44
+ * allowedValues - Array of allowed values
45
+ * regularExpression - regular expression for validating the value
46
+
47
+ Sample of creating a value argument:
48
+
49
+ ```
50
+ const argumentFactory = new CommandLineArgumentFactory()
51
+ argumentFactory.keyValueArgument('testValue', 'Used for testing', true, '--test-value', '-tv', ['test1', 'test2'], new RegEx('^A-Z*$'))
52
+ ```
53
+
54
+ ### Flag argument ###
55
+
56
+ A flag argument a boolean argument. If a flag is present in the command line argument the boolean value will be set to true. The flag argument can be define with the following properties:
57
+
58
+ * propertyName - Name of the property that will contain the value when the command is parsed
59
+ * description - Description of the flag that is displayed in the command line help
60
+ * argumentName - Name of the argument in the command line (exmaple: '--test-flag')
61
+ * alias - Alias for the name of the argument (example: '-tf')
62
+
63
+ Sample of creating a flag argument:
64
+
65
+ ```
66
+ const argumentFactory = new CommandLineArgumentFactory()
67
+ argumentFactory.flagArgument('testFlag', 'Used for testing', '--test-flag', '-tf')
68
+ ```
69
+
70
+ ### Value argument ###
71
+
72
+ A value argument is a string argument without a key. A value argument can be detected by allowed values, a regex or just by value. A usecase can be passing a file path a last argument. The value argument can be define with the following properties:
73
+
74
+ * propertyName - Name of the property that will contain the value when the command is parsed
75
+ * description - Description of the flag that is displayed in the command line help
76
+ * required - Value is required or optional
77
+ * allowedValues - Array of allowed values
78
+ * regularExpression - regular expression for validating the value
79
+
80
+ Sample of creating a value argument:
81
+
82
+ ```
83
+ const argumentFactory = new CommandLineArgumentFactory()
84
+ argumentFactory.valueArgument('testValue', 'Used for testing', true, ['test1', 'test2'], new RegEx('^A-Z*$'))
85
+ ```
86
+
87
+ # Sample #
88
+ This is an example that can handle the following commands:
89
+ * node ./samples/app ?
90
+ * node ./samples/app.js open "from-path"
91
+ * node ./samples/app.js cf --from="from-path" -to="to-path"
92
+ * node ./samples/app.js cf --remove-source --from="from-path" -to="to-path"
93
+ * node ./samples/app.js cf -rs -f="from-path" -t="to-path"
94
+
95
+ ```
96
+ const CommandLineDirector = require('../lib/command-line-director')
97
+ const CommandLine = require('../lib/command-line')
98
+ const CommandLineArgumentFactory = require('../lib/command-line-argument-factory')
99
+
100
+ class App {
101
+ constructor() {
102
+ const argumentFactory = new CommandLineArgumentFactory()
103
+
104
+ const commandLines = [
105
+ // node ./samples/app ?
106
+ new CommandLine('help-identifier', 'Help', 'Show help', [
107
+ argumentFactory.valueArgument('command', '?', true, ['?']),
108
+ ]),
109
+ // node ./samples/app.js open "from-path"
110
+ new CommandLine('open-identifier', 'Open', 'Open a file', [
111
+ argumentFactory.valueArgument('command', 'Open command', true, ['open']),
112
+ argumentFactory.valueArgument('fileName', 'Name of the file to open', true),
113
+ ]),
114
+ // node ./samples/app.js cf --from="from-path" -to="to-path"
115
+ // node ./samples/app.js cf --remove-source --from="from-path" -to="to-path"
116
+ // node ./samples/app.js cf -rs -f="from-path" -t="to-path"
117
+ new CommandLine('copy-file-identifier', 'Copy', 'Copy a file', [
118
+ argumentFactory.valueArgument('command', 'Copy file command', true, ['cf']),
119
+ argumentFactory.flagArgument('removeSource', 'Remove the source file', '--remove-source', '-rs'),
120
+ argumentFactory.keyValueArgument('from', 'From path', true, '--from', '-f'),
121
+ argumentFactory.keyValueArgument('to', 'To path', true, '--to', '-t'),
122
+ ]),
123
+ ]
124
+
125
+ this.commandLineDirector = new CommandLineDirector(
126
+ 'File functions',
127
+ 'A coomand line tool for special file operations',
128
+ commandLines)
129
+ }
130
+
131
+ run() {
132
+ const command = this.commandLineDirector.parse()
133
+
134
+ if(command) {
135
+ switch(command.identifier) {
136
+ case 'help-identifier':
137
+ console.log(this.commandLineDirector.generateHelp())
138
+ break
139
+ case 'open-identifier':
140
+ console.log(`Open a file with values: ${JSON.stringify(command.values)}`)
141
+ break
142
+ case 'copy-file-identifier':
143
+ console.log(`Copy a file with values: ${JSON.stringify(command.values)}`)
144
+ break
145
+ default:
146
+ console.error('unknown command')
147
+ break
148
+ }
149
+ } else {
150
+ console.error('unknown command')
151
+ }
152
+ }
153
+ }
154
+
155
+ const app = new App()
156
+ app.run()
157
+ ```
158
+
package/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,7 @@
1
+ const CommandLineArgumentDataType = {
2
+ Boolean: 'BOOLEAN',
3
+ Number: 'NUMBER',
4
+ String: 'STRING'
5
+ }
6
+
7
+ module.exports = CommandLineArgumentDataType
@@ -0,0 +1,86 @@
1
+ const CommandLineArgumentDataType = require('./command-line-argument-data-type')
2
+ const CommandLineArgumentType = require('./command-line-argument-type')
3
+ const CommandLineArgument = require('./command-line-argument')
4
+
5
+ class CommandLineArgumentFactory {
6
+ /**
7
+ * Create string argument
8
+ * Examples:
9
+ * --dir="/var/www/test"
10
+ * -d="/var/www/test"
11
+ *
12
+ * @param propertyName - string
13
+ * @param description - string
14
+ * @param required - boolean
15
+ * @param argumentName - string
16
+ * @param alias - string
17
+ * @param defaultValue - string
18
+ * @param allowedValues
19
+ * @param regularExpression
20
+ */
21
+ keyValueArgument(propertyName, description, required, argumentName, alias, defaultValue, allowedValues, regularExpression) {
22
+ return new CommandLineArgument(
23
+ propertyName,
24
+ required,
25
+ argumentName,
26
+ alias,
27
+ CommandLineArgumentDataType.String,
28
+ CommandLineArgumentType.KeyValue,
29
+ defaultValue,
30
+ allowedValues,
31
+ regularExpression,
32
+ description)
33
+ }
34
+
35
+ /**
36
+ * Create boolean argument
37
+ * Examples:
38
+ * --force
39
+ * -f
40
+ *
41
+ * @param propertyName - string
42
+ * @param description - string
43
+ * @param argumentName - string
44
+ * @param alias - string
45
+ */
46
+ flagArgument(propertyName, description, argumentName, alias) {
47
+ return new CommandLineArgument(
48
+ propertyName,
49
+ false,
50
+ argumentName,
51
+ alias,
52
+ CommandLineArgumentDataType.Boolean,
53
+ CommandLineArgumentType.KeyValue,
54
+ false,
55
+ null,
56
+ null,
57
+ description)
58
+ }
59
+
60
+ /**
61
+ * Create command
62
+ * Examples:
63
+ * init
64
+ *
65
+ * @param propertyName - string
66
+ * @param description
67
+ * @param required - boolean
68
+ * @param allowedValues
69
+ * @param regularExpression
70
+ */
71
+ valueArgument(propertyName, description, required, allowedValues, regularExpression) {
72
+ return new CommandLineArgument(
73
+ propertyName,
74
+ required,
75
+ null,
76
+ null,
77
+ CommandLineArgumentDataType.String,
78
+ CommandLineArgumentType.Value,
79
+ null,
80
+ allowedValues,
81
+ regularExpression,
82
+ description)
83
+ }
84
+ }
85
+
86
+ module.exports = CommandLineArgumentFactory
@@ -0,0 +1,6 @@
1
+ const CommandLineArgumentType = {
2
+ KeyValue: 'KEYVALUE',
3
+ Value: 'VALUE'
4
+ }
5
+
6
+ module.exports = CommandLineArgumentType
@@ -0,0 +1,84 @@
1
+ const CommandLineArgumentDataType = require('./command-line-argument-data-type')
2
+ const CommandLineArgumentType = require('./command-line-argument-type')
3
+
4
+ class CommandLineArgument {
5
+ /**
6
+ * CommandLineArgument Constructor
7
+ * @param propertyName - string
8
+ * @param required - boolean
9
+ * @param argumentName - string
10
+ * @param alias - string
11
+ * @param dataType - CommandLineArgumentDataType
12
+ * @param type - CommandLineArgumentType
13
+ * @param defaultValue
14
+ * @param allowedValues
15
+ * @param regularExpression
16
+ * @param description
17
+ */
18
+ constructor (propertyName, required, argumentName, alias, dataType, type, defaultValue, allowedValues, regularExpression, description) {
19
+ if (!propertyName) {
20
+ throw new Error("'propertyName' parameter not defined.")
21
+ }
22
+
23
+ if (required === undefined || required === null) {
24
+ throw new Error("'required' parameter not defined.")
25
+ }
26
+
27
+ if (type !== CommandLineArgumentType.KeyValue && type !== CommandLineArgumentType.Value) {
28
+ throw new Error("'type' parameter invalid.")
29
+ }
30
+
31
+ if (!argumentName && type === CommandLineArgumentType.KeyValue) {
32
+ throw new Error("'argumentName' parameter not defined.")
33
+ }
34
+
35
+ if (allowedValues && Array.isArray(allowedValues) === false) {
36
+ throw new Error("'allowedValues' parameter should be an array.")
37
+ }
38
+
39
+ this.propertyName = propertyName
40
+ this.required = Boolean(required)
41
+ this.argumentName = argumentName
42
+ this.alias = (alias !== undefined) ? alias : null
43
+ this.dataType = dataType || CommandLineArgumentDataType.String
44
+ this.type = type
45
+ this.defaultValue = defaultValue
46
+ this.allowedValues = allowedValues || null
47
+ this.regularExpression = regularExpression || null
48
+ this.description = description
49
+ }
50
+
51
+ toString () {
52
+ let help = ''
53
+ let title = ''
54
+
55
+ if (this.argumentName) {
56
+ title = ` ${this.argumentName},${this.alias}`
57
+ } else if (this.allowedValues) {
58
+ title = ` ${this.allowedValues}`
59
+ } else {
60
+ title = ' <string>'
61
+ }
62
+
63
+ help += title
64
+ for (let i = 0; i < 24 - title.length; i++) {
65
+ help += ' '
66
+ }
67
+
68
+ help += ` ${this.required ? 'R' : 'O'} | ${this.dataType}`
69
+
70
+ if (this.argumentName && this.allowedValues) {
71
+ help += ` | VALUES = ${this.allowedValues}`
72
+ }
73
+
74
+ if (this.regularExpression) {
75
+ help += ` | PATTERN = ${this.regularExpression.toString()}`
76
+ }
77
+
78
+ help += ` | ${this.description}`
79
+
80
+ return help
81
+ }
82
+ }
83
+
84
+ module.exports = CommandLineArgument
@@ -0,0 +1,83 @@
1
+ const Command = require('./command')
2
+
3
+ class CommandLineDirector {
4
+ constructor (title, description, commandLines) {
5
+ this.title = title
6
+ this.description = description
7
+ if (Array.isArray(commandLines)) {
8
+ this.commandLines = commandLines
9
+ } else {
10
+ throw new Error("Invalid argument 'commandLines', value should be of type 'array'")
11
+ }
12
+ }
13
+
14
+ _removeQuotes (text) {
15
+ return text.replace(/['"]+/g, '')
16
+ }
17
+
18
+ _createArgumentLookupFromProcessArguments (cmdArguments) {
19
+ const lookup = {
20
+ values: [],
21
+ keyValues: {}
22
+ }
23
+
24
+ cmdArguments.forEach((cmdArgument) => {
25
+ const keyValue = cmdArgument.split('=')
26
+ // Flag of key value type
27
+ if (typeof keyValue[0] === 'string' && keyValue[0].charAt(0) === '-') {
28
+ const value = keyValue.length === 2 ? this._removeQuotes(keyValue[1]) : true
29
+ const keyName = keyValue[0]
30
+ lookup.keyValues[keyName] = value
31
+ // Value type
32
+ } else {
33
+ lookup.values.push(this._removeQuotes(cmdArgument))
34
+ }
35
+ })
36
+
37
+ return lookup
38
+ }
39
+
40
+ parseArguments (cmdArguments, verbose) {
41
+ const lookup = this._createArgumentLookupFromProcessArguments(cmdArguments)
42
+ let command = null
43
+
44
+ for (let i = 0; i < this.commandLines.length; i++) {
45
+ const commandLine = this.commandLines[i]
46
+ try {
47
+ command = commandLine.commandFromLookup(lookup)
48
+ break
49
+ } catch (error) {
50
+ if (verbose) {
51
+ console.info(error.message)
52
+ }
53
+ command = null
54
+ }
55
+ };
56
+
57
+ return command
58
+ }
59
+
60
+ parse (verbose) {
61
+ return this.parseArguments(process.argv.slice(2), verbose)
62
+ }
63
+
64
+ generateHelp () {
65
+ let help = '\r\n=======================================================================\r\n'
66
+ help += `\r\n${this.title.toUpperCase()}\r\n${this.description}\r\n\r\n`
67
+
68
+ this.commandLines.forEach((commandLine) => {
69
+ help += '-----------------------------------------------------------------------\r\n'
70
+ help += `${commandLine.title.toUpperCase()} - ${commandLine.description}\r\n\r\n`
71
+
72
+ commandLine.commandLineArguments.forEach((argument) => {
73
+ help += `${argument.toString()}\r\n`
74
+ })
75
+ help += '\r\n'
76
+ })
77
+
78
+ help += '=======================================================================\r\n'
79
+ return help
80
+ }
81
+ }
82
+
83
+ module.exports = CommandLineDirector
@@ -0,0 +1,125 @@
1
+ const CommandLineArgumentDataType = require('./command-line-argument-data-type')
2
+ const CommandLineArgumentType = require('./command-line-argument-type')
3
+ const Command = require('./command')
4
+
5
+ class CommandLine {
6
+ /**
7
+ * CommandLine constructor
8
+ * @param identifier - string
9
+ * @param commandLineArguments - array
10
+ * @thows Error
11
+ */
12
+ constructor (identifier, title, description, commandLineArguments) {
13
+ this.identifier = identifier
14
+ this.title = title
15
+ this.description = description
16
+ this.commandLineArguments = []
17
+ if (Array.isArray(commandLineArguments)) {
18
+ this.commandLineArguments = commandLineArguments
19
+ } else {
20
+ throw new Error("Invalid argument 'commandLineArguments', value should be of type 'array'")
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Create lookup table for process arguments
26
+ * @result object
27
+ */
28
+
29
+ _parseDataType (value, dataType) {
30
+ let parsedValue = null
31
+
32
+ if (value !== undefined && value !== null) {
33
+ switch (dataType) {
34
+ case CommandLineArgumentDataType.Boolean:
35
+ parsedValue = Boolean(value)
36
+ break
37
+ case CommandLineArgumentDataType.Number:
38
+ parsedValue = Number(value)
39
+ if (isNaN(parsedValue)) {
40
+ parsedValue = null
41
+ }
42
+ break
43
+ case CommandLineArgumentDataType.String:
44
+ parsedValue = String(value)
45
+ break
46
+ default: {
47
+ throw new Error(`Unknown data type '${dataType}.`)
48
+ }
49
+ }
50
+
51
+ if (parsedValue === null) {
52
+ throw new Error(`Could not parse value '${value}' to data type '${dataType}.`)
53
+ }
54
+ }
55
+
56
+ return parsedValue
57
+ }
58
+
59
+ /**
60
+ * Create command from argument lookup
61
+ * @param argument lookup
62
+ * @result command
63
+ * @throws Error
64
+ */
65
+ commandFromLookup (argumentLookup) {
66
+ const result = {}
67
+ const values = argumentLookup.values
68
+ const keyValues = argumentLookup.keyValues
69
+ let valueIndex = 0
70
+
71
+ // Check all the arguments
72
+ this.commandLineArguments.forEach((arg) => {
73
+ if (arg.type === CommandLineArgumentType.KeyValue) {
74
+ if (keyValues[arg.argumentName] !== undefined) {
75
+ result[arg.propertyName] = keyValues[arg.argumentName]
76
+ } else if (keyValues[arg.alias] !== undefined) {
77
+ result[arg.propertyName] = keyValues[arg.alias]
78
+ }
79
+ } else if (arg.type === CommandLineArgumentType.Value) {
80
+ if (values.length > valueIndex) {
81
+ result[arg.propertyName] = values[valueIndex]
82
+ valueIndex++
83
+ }
84
+ } else {
85
+ throw new Error('Invalid command line argument type')
86
+ }
87
+
88
+ // Set the default value if avaiable
89
+ if (result[arg.propertyName] === undefined && arg.defaultValue !== undefined) {
90
+ result[arg.propertyName] = arg.defaultValue
91
+ }
92
+
93
+ // Parse data to the correct data type
94
+ if (result[arg.propertyName] !== undefined) {
95
+ result[arg.propertyName] = this._parseDataType(result[arg.propertyName], arg.dataType)
96
+ }
97
+ })
98
+
99
+ // Check all the arguments
100
+ this.commandLineArguments.forEach(function (arg) {
101
+ // Check if required field exists
102
+ if (arg.required === true && (result[arg.propertyName] === undefined || result[arg.propertyName] === null)) {
103
+ throw new Error(`Required field '${arg.propertyName}' is missing.`)
104
+ }
105
+
106
+ // Check if value is allowed
107
+ if (arg.allowedValues && (arg.required === true || (result[arg.propertyName] !== undefined && result[arg.propertyName] !== null))) {
108
+ if (arg.allowedValues.indexOf(result[arg.propertyName]) === -1) {
109
+ throw new Error(`Value for field '${arg.propertyName}' is not allowed.`)
110
+ }
111
+ };
112
+
113
+ // Check if value meets regex
114
+ if (arg.regularExpression && (arg.required === true || (result[arg.propertyName] !== undefined && result[arg.propertyName] !== null))) {
115
+ if (!arg.regularExpression.test(result[arg.propertyName])) {
116
+ throw new Error(`Value for field field '${arg.propertyName}' is invalid.`)
117
+ }
118
+ }
119
+ })
120
+
121
+ return new Command(this.identifier, this.commandLineArguments, result)
122
+ }
123
+ }
124
+
125
+ module.exports = CommandLine
package/lib/command.js ADDED
@@ -0,0 +1,9 @@
1
+ class Command {
2
+ constructor (identifier, commandLineArguments, values) {
3
+ this.identifier = identifier
4
+ this.commandLineArguments = commandLineArguments
5
+ this.values = values
6
+ }
7
+ }
8
+
9
+ module.exports = Command
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "command-line-director",
3
+ "version": "1.0.0",
4
+ "description": "Gives direction to you nodejs command line application",
5
+ "main": "./lib/command-line-director.js",
6
+ "keywords": [
7
+ "command line",
8
+ "command line parser",
9
+ "command line mapper",
10
+ "command line arguments",
11
+ "arguments"
12
+ ],
13
+ "bugs": "https://github.com/marcojonker/command-line-director/issues",
14
+ "license": "MIT",
15
+ "scripts": {
16
+ "test": "./node_modules/mocha/bin/mocha"
17
+ },
18
+ "author": "Marco Jonker",
19
+ "files": [
20
+ "package.json",
21
+ "README.md",
22
+ "LICENSE",
23
+ "CHANGELOG",
24
+ "lib",
25
+ "test"
26
+ ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/marcojonker/command-line-director.git"
30
+ },
31
+ "homepage": "http://www.cacadu.eu/opensource",
32
+ "dependencies": {},
33
+ "devDependencies": {
34
+ "eslint": "^7.32.0",
35
+ "eslint-config-standard": "^16.0.3",
36
+ "eslint-plugin-import": "^2.24.2",
37
+ "eslint-plugin-node": "^11.1.0",
38
+ "eslint-plugin-promise": "^5.1.0",
39
+ "mocha": "^9.1.1"
40
+ },
41
+ "engines": {
42
+ "node": ">=12.10.0"
43
+ }
44
+ }
package/test/.DS_Store ADDED
Binary file
@@ -0,0 +1,198 @@
1
+ var assert = require('assert');
2
+ const CommandLineDirector = require('../lib/command-line-director')
3
+ const CommandLine = require('../lib/command-line')
4
+ const CommandLineArgumentFactory = require('../lib/command-line-argument-factory')
5
+
6
+ describe('Integration test', function () {
7
+ const argumentFactory = new CommandLineArgumentFactory();
8
+
9
+ it('should handle string key value arguments correct', () => {
10
+ const commandLines = [
11
+ new CommandLine('test1', 'title1', 'title1 description', [
12
+ argumentFactory.keyValueArgument('param1', 'param1 description', true, '--param1', '-p1'),
13
+ argumentFactory.keyValueArgument('param2', 'param2 description', false, '--param2', '-p2', 'defaultParam2', ['defaultParam2', 'test']),
14
+ argumentFactory.keyValueArgument('param3', 'param3 description', false, '--param3', '-p3', '100', null, new RegExp('^[0-9]*$')),
15
+ argumentFactory.keyValueArgument('param4', 'param4 description', false, '--param4', '-p4')
16
+ ]),
17
+ ]
18
+
19
+ const commandLineDirector = new CommandLineDirector('title', 'description', commandLines)
20
+
21
+ let command = commandLineDirector.parseArguments([''], true)
22
+ assert.equal(command, null);
23
+
24
+ // required value set
25
+ command = commandLineDirector.parseArguments(['--param1=test'], true)
26
+ assert.equal(command.values['param1'], 'test');
27
+ assert.equal(command.values['param2'], 'defaultParam2');
28
+ assert.equal(command.values['param3'], '100');
29
+ assert.equal(command.values['param4'], undefined);
30
+
31
+ // allwed values invalid
32
+ command = commandLineDirector.parseArguments(['--param1=test', '--param2=invalid'], true)
33
+ assert.equal(command, null);
34
+
35
+ // allwed values valid
36
+ command = commandLineDirector.parseArguments(['--param1=test', '--param2=test'], true)
37
+ assert.equal(command.values['param1'], 'test');
38
+ assert.equal(command.values['param2'], 'test');
39
+
40
+ // regex invalid
41
+ command = commandLineDirector.parseArguments(['--param1=test', '--param3=test'], true)
42
+ assert.equal(command, null);
43
+
44
+ // regex valid
45
+ command = commandLineDirector.parseArguments(['--param1=test', '--param3=200'], true)
46
+ assert.equal(command.values['param1'], 'test');
47
+ assert.equal(command.values['param3'], '200');
48
+
49
+ // not required param
50
+ command = commandLineDirector.parseArguments(['--param1=test', '--param4=test'], true)
51
+ assert.equal(command.values['param1'], 'test');
52
+ assert.equal(command.values['param4'], 'test');
53
+
54
+ // alias
55
+ command = commandLineDirector.parseArguments(['-p1=test1', '-p2=test', '-p3=300', '-p4=test4'], true)
56
+ assert.equal(command.values['param1'], 'test1');
57
+ assert.equal(command.values['param2'], 'test');
58
+ assert.equal(command.values['param3'], '300');
59
+ assert.equal(command.values['param4'], 'test4');
60
+
61
+ // strip unknown param
62
+ command = commandLineDirector.parseArguments(['-p1=test1', '-p2=test', '-p3=300', '-p4=test4', '--param5=test5'], true)
63
+ assert.equal(command.values['param1'], 'test1');
64
+ assert.equal(command.values['param2'], 'test');
65
+ assert.equal(command.values['param3'], '300');
66
+ assert.equal(command.values['param4'], 'test4');
67
+ assert.equal(command.values['param5'], undefined);
68
+ });
69
+
70
+ it('should handle flag key value arguments correct', () => {
71
+ const commandLines = [
72
+ new CommandLine('test3', 'title3', 'title 3 description', [
73
+ argumentFactory.flagArgument('param1', 'param1 description', '--param1', '-p1')
74
+ ]),
75
+ ]
76
+
77
+ const commandLineDirector = new CommandLineDirector('title', 'description', commandLines)
78
+
79
+ let command = commandLineDirector.parseArguments([''], true)
80
+ assert.equal(command.values['param1'], false);
81
+
82
+ command = commandLineDirector.parseArguments(['--param1'], true)
83
+ assert.equal(command.values['param1'], true);
84
+
85
+ command = commandLineDirector.parseArguments(['-p1'], true)
86
+ assert.equal(command.values['param1'], true);
87
+ });
88
+
89
+ it('should handle string value arguments correct', () => {
90
+ const commandLines = [
91
+ new CommandLine('test4', 'title4', 'title 4 description', [
92
+ argumentFactory.valueArgument('param1', 'param1 description', true, ['value1', 'value2']),
93
+ argumentFactory.valueArgument('param2', 'param2 description', true, ['value3', 'value4']),
94
+ argumentFactory.valueArgument('param3', 'param3 description', false, ['value5', 'value6']),
95
+ argumentFactory.valueArgument('param4', 'param4 description', false),
96
+ ]),
97
+ ]
98
+
99
+ const commandLineDirector = new CommandLineDirector('title', 'description', commandLines)
100
+
101
+ let command = commandLineDirector.parseArguments([''], true)
102
+ assert.equal(command, null);
103
+
104
+ command = commandLineDirector.parseArguments(['value1'], true)
105
+ assert.equal(command, null);
106
+
107
+ command = commandLineDirector.parseArguments(['value1', 'value4'], true)
108
+ assert.equal(command.values['param1'], 'value1');
109
+ assert.equal(command.values['param2'], 'value4');
110
+
111
+ command = commandLineDirector.parseArguments(['value1', 'value3', 'value6'], true)
112
+ assert.equal(command.values['param1'], 'value1');
113
+ assert.equal(command.values['param2'], 'value3');
114
+ assert.equal(command.values['param3'], 'value6');
115
+
116
+ command = commandLineDirector.parseArguments(['value1', 'value3', 'value6', '"http://url.test"'], true)
117
+ assert.equal(command.values['param1'], 'value1');
118
+ assert.equal(command.values['param2'], 'value3');
119
+ assert.equal(command.values['param3'], 'value6');
120
+ assert.equal(command.values['param4'], 'http://url.test');
121
+ });
122
+
123
+ it('should generate a help text', () => {
124
+ const commandLines = [
125
+ new CommandLine('test1', 'title1', 'title 1 description', [
126
+ argumentFactory.keyValueArgument('param1', 'param1 description', true, '--param1', '-p1'),
127
+ argumentFactory.keyValueArgument('param2', 'param2 description', false, '--param2', '-p2', 'defaultParam2', ['defaultParam2', 'test']),
128
+ argumentFactory.keyValueArgument('param3', 'param3 description', false, '--param3', '-p3', '100', null, new RegExp('^[0-9]*$')),
129
+ argumentFactory.keyValueArgument('param4', 'param4 description', false, '--param4', '-p4')
130
+ ]),
131
+ new CommandLine('test2', 'title2', 'title 2 description', [
132
+ argumentFactory.keyValueArgument('param1', 'param1 description', true, '--param1', '-p1'),
133
+ argumentFactory.keyValueArgument('param2', 'param2 description', false, '--param2', '-p2', 200, [200, 201]),
134
+ argumentFactory.keyValueArgument('param3', 'param3 description', false, '--param3', '-p3')
135
+ ]),
136
+ new CommandLine('test3', 'title3', 'title 3 description', [
137
+ argumentFactory.flagArgument('param1', 'param1 description', '--param1', '-p1')
138
+ ]),
139
+ new CommandLine('test4', 'title4', 'title 4 description', [
140
+ argumentFactory.valueArgument('param1', 'param1 description', true, ['value1', 'value2']),
141
+ argumentFactory.valueArgument('param2', 'param2 description', true, ['value3', 'value4']),
142
+ argumentFactory.valueArgument('param3', 'param3 description', false, ['value5', 'value6']),
143
+ argumentFactory.valueArgument('param4', 'param4 description', false)
144
+ ]),
145
+ ]
146
+
147
+ const commandLineDirector = new CommandLineDirector('title', 'description', commandLines)
148
+ const helpText = commandLineDirector.generateHelp();
149
+
150
+ assert.equal(helpText.includes('TITLE1'), true)
151
+ assert.equal(helpText.includes('TITLE2'), true)
152
+ assert.equal(helpText.includes('TITLE3'), true)
153
+ assert.equal(helpText.includes('TITLE4'), true)
154
+ assert.equal(helpText.includes('title 1 description'), true)
155
+ assert.equal(helpText.includes('param1 descriptio'), true)
156
+ assert.equal(helpText.includes(' R '), true)
157
+ assert.equal(helpText.includes('--param1,-p1'), true)
158
+ });
159
+
160
+ it('should handle realworld example correct', () => {
161
+ const commandLines = [
162
+ new CommandLine('list-identifier', 'List', 'Create a list of items', [
163
+ argumentFactory.valueArgument('command', 'command', true, ['list']),
164
+ argumentFactory.flagArgument('delete', 'delete the list', '--delete', '-d'),
165
+ ]),
166
+ new CommandLine('open-identifier', 'Open', 'Open an item', [
167
+ argumentFactory.valueArgument('command', 'command', true, ['open', 'display']),
168
+ argumentFactory.flagArgument('all', 'Open all items', '--all', '-a'),
169
+ argumentFactory.keyValueArgument('id', 'id to open', false, '--identifier', '-id'),
170
+ ]),
171
+ new CommandLine('update-identifier', 'Update', 'Updat an item', [
172
+ argumentFactory.valueArgument('command', 'command', true, ['update']),
173
+ argumentFactory.flagArgument('all', 'Open all items', '--all', '-a'),
174
+ argumentFactory.keyValueArgument('id', 'id to open', false, '--identifier', '-id'),
175
+ ]),
176
+ ]
177
+
178
+ const commandLineDirector = new CommandLineDirector('File cli', 'file cli description', commandLines)
179
+ const helpText = commandLineDirector.generateHelp();
180
+
181
+ let command = commandLineDirector.parseArguments(['list', '-d'], true)
182
+ assert.equal(command.identifier, 'list-identifier');
183
+ assert.equal(command.values['command'], 'list');
184
+ assert.equal(command.values['delete'], true);
185
+
186
+ command = commandLineDirector.parseArguments(['display', '--all', '--identifier=12'], true)
187
+ assert.equal(command.identifier, 'open-identifier');
188
+ assert.equal(command.values['command'], 'display');
189
+ assert.equal(command.values['all'], true);
190
+ assert.equal(command.values['id'], 12);
191
+
192
+ command = commandLineDirector.parseArguments(['update', '-a', '-id=100'], true)
193
+ assert.equal(command.identifier, 'update-identifier');
194
+ assert.equal(command.values['command'], 'update');
195
+ assert.equal(command.values['all'], true);
196
+ assert.equal(command.values['id'], 100);
197
+ });
198
+ });