From 2328c215291fd2a9a723ae85d2669ecb267cdb0e Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 11:56:11 +0000 Subject: [PATCH 1/9] Add support to prepend / append string to command --- bin/concurrently.js | 15 ++++++ src/command-parser/zz-expand-arguments.js | 17 +++++++ .../zz-expand-arguments.spec.js | 46 +++++++++++++++++++ src/concurrently.js | 5 +- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/command-parser/zz-expand-arguments.js create mode 100644 src/command-parser/zz-expand-arguments.spec.js diff --git a/bin/concurrently.js b/bin/concurrently.js index 6c558706..909fa7e5 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -133,6 +133,20 @@ const args = yargs 'Identifier for child process to which input on stdin ' + 'should be sent if not specified at start of input.\n' + 'Can be either the index or the name of the process.' + }, + + // shorten command + 'P': { + alias: 'prepend', + describe: 'prepend string to each command', + default: "", + type: 'string' + }, + 'A': { + alias: 'append', + describe: 'append string to each command', + default: "", + type: 'string' } }) .group(['m', 'n', 'name-separator', 'raw', 's', 'no-color'], 'General') @@ -153,6 +167,7 @@ concurrently(args._.map((command, index) => { lastColor = prefixColors[index] || lastColor; return { command, + argPend: { prepend:args.prepend, append:args.append }, prefixColor: lastColor, name: names[index] }; diff --git a/src/command-parser/zz-expand-arguments.js b/src/command-parser/zz-expand-arguments.js new file mode 100644 index 00000000..38fd885c --- /dev/null +++ b/src/command-parser/zz-expand-arguments.js @@ -0,0 +1,17 @@ +module.exports = class StripQuotes { + parse(commandInfo) { + let { command, argPend } = commandInfo; + if(!argPend) { + return commandInfo + } + + const argPrepend = argPend.prepend ? (argPend.prepend + " ") : "" + const argAppend = argPend.append ? (" " + argPend.append) : "" + if (argPrepend == "" && argAppend == "") { + return commandInfo + } + + command = argPrepend + command + argAppend + return Object.assign({}, commandInfo, { command }); + } +}; diff --git a/src/command-parser/zz-expand-arguments.spec.js b/src/command-parser/zz-expand-arguments.spec.js new file mode 100644 index 00000000..e0742771 --- /dev/null +++ b/src/command-parser/zz-expand-arguments.spec.js @@ -0,0 +1,46 @@ +const ZZ_ExpandArguments = require('./zz-expand-arguments'); +const parser = new ZZ_ExpandArguments(); + +it('noop if no argPend', () => { + const commandInfo = { + command: 'foo bar' + }; + expect(parser.parse(commandInfo).command) + .toEqual('foo bar'); +}); + +it('noop if empty argPend', () => { + const commandInfo = { + command: 'foo bar', + argPend: {} + }; + expect(parser.parse(commandInfo).command) + .toEqual('foo bar'); +}); + +it('argPend prepend', () => { + const commandInfo = { + command: 'foo bar', + argPend: { prepend: "echo" }, + }; + expect(parser.parse(commandInfo).command) + .toEqual('echo foo bar'); +}); + +it('argPend append', () => { + const commandInfo = { + command: 'foo bar', + argPend: { append: "--watch" }, + }; + expect(parser.parse(commandInfo).command) + .toEqual('foo bar --watch'); +}); + +it('argPend prepend + append', () => { + const commandInfo = { + command: 'foo bar', + argPend: { prepend: "echo", append: "--watch" }, + }; + expect(parser.parse(commandInfo).command) + .toEqual('echo foo bar --watch'); +}); diff --git a/src/concurrently.js b/src/concurrently.js index 31d97a72..daf7da9e 100644 --- a/src/concurrently.js +++ b/src/concurrently.js @@ -6,6 +6,7 @@ const treeKill = require('tree-kill'); const StripQuotes = require('./command-parser/strip-quotes'); const ExpandNpmShortcut = require('./command-parser/expand-npm-shortcut'); const ExpandNpmWildcard = require('./command-parser/expand-npm-wildcard'); +const ZZ_ExpandArguments = require('./command-parser/zz-expand-arguments') const CompletionListener = require('./completion-listener'); @@ -29,7 +30,8 @@ module.exports = (commands, options) => { const commandParsers = [ new StripQuotes(), new ExpandNpmShortcut(), - new ExpandNpmWildcard() + new ExpandNpmWildcard(), + new ZZ_ExpandArguments(), ]; commands = _(commands) @@ -66,6 +68,7 @@ module.exports = (commands, options) => { function mapToCommandInfo(command) { return { command: command.command || command, + argPend: command.argPend, name: command.name || '', prefixColor: command.prefixColor || '', env: command.env || {}, From 447023b984861b6315683683ed7b756906367279 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 12:45:19 +0000 Subject: [PATCH 2/9] Update document --- README.md | 15 +++++++++++++++ bin/concurrently.js | 8 ++++++-- bin/epilogue.txt | 9 +++++++++ package.json | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b116b67..34ce517e 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,12 @@ Restarting --restart-after Delay time to respawn the process, in milliseconds. [number] [default: 0] +shorten command + -P, --prepend prepend string to each command + [string] [default: ""] + -A, --append append string to each command + eg: pass arguments [string] [default: ""] + Options: -h, --help Show help [boolean] -v, -V, --version Show version number [boolean] @@ -193,6 +199,15 @@ Examples: $ concurrently --prefix "{time}-{pid}" "npm run watch" "http-server" + - Custom cmd prepend + + $ concurrently -P 'npm run' 'example:echo:A' 'example:echo:B' + + - Custom cmd append + + $ concurrently -A ' -- --watch' 'npm:example:echo*' + # Add one space to prevent yargs parse this string as an option + - Custom names and colored prefixes $ concurrently --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" diff --git a/bin/concurrently.js b/bin/concurrently.js index 909fa7e5..fbdf5f2c 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -138,13 +138,16 @@ const args = yargs // shorten command 'P': { alias: 'prepend', - describe: 'prepend string to each command', + describe: + 'prepend string to each command', default: "", type: 'string' }, 'A': { alias: 'append', - describe: 'append string to each command', + describe: + 'append string to each command\n' + + 'eg: pass arguments', default: "", type: 'string' } @@ -154,6 +157,7 @@ const args = yargs .group(['i', 'default-input-target'], 'Input handling') .group(['k', 'kill-others-on-fail'], 'Killing other processes') .group(['restart-tries', 'restart-after'], 'Restarting') + .group(['P', 'A'], 'shorten command') // Too much text to write as JS strings, .txt file is better .epilogue(fs.readFileSync(__dirname + '/epilogue.txt', { encoding: 'utf8' })) .argv; diff --git a/bin/epilogue.txt b/bin/epilogue.txt index 58c6a5be..3bf8f5b9 100644 --- a/bin/epilogue.txt +++ b/bin/epilogue.txt @@ -12,6 +12,15 @@ Examples: $ $0 --prefix "{time}-{pid}" "npm run watch" "http-server" + - Custom cmd prepend + + $ $0 -P 'npm run' 'example:echo:A' 'example:echo:B' + + - Custom cmd append + + $ $0 -A ' -- --watch' 'npm:example:echo*' + # Add one space to prevent yargs parse this string as an option + - Custom names and colored prefixes $ $0 --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "http-server" "npm run watch" diff --git a/package.json b/package.json index a7fe928b..65b78be7 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "node": ">=10.0.0" }, "scripts": { + "example:echo:A": "echo A", + "example:echo:B": "echo B", "lint": "eslint . --ignore-path .gitignore", "report-coverage": "cat coverage/lcov.info | coveralls", "test": "jest" From 0f1aa4126717b45e7cc91fc4ed3fcf10238c7145 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 13:15:00 +0000 Subject: [PATCH 3/9] Style Fix --- bin/concurrently.js | 4 ++-- src/command-parser/zz-expand-arguments.js | 17 +++++++++-------- src/command-parser/zz-expand-arguments.spec.js | 6 +++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/bin/concurrently.js b/bin/concurrently.js index fbdf5f2c..39b0dc61 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -140,7 +140,7 @@ const args = yargs alias: 'prepend', describe: 'prepend string to each command', - default: "", + default: '', type: 'string' }, 'A': { @@ -148,7 +148,7 @@ const args = yargs describe: 'append string to each command\n' + 'eg: pass arguments', - default: "", + default: '', type: 'string' } }) diff --git a/src/command-parser/zz-expand-arguments.js b/src/command-parser/zz-expand-arguments.js index 38fd885c..b5b8bd85 100644 --- a/src/command-parser/zz-expand-arguments.js +++ b/src/command-parser/zz-expand-arguments.js @@ -1,17 +1,18 @@ module.exports = class StripQuotes { parse(commandInfo) { - let { command, argPend } = commandInfo; - if(!argPend) { - return commandInfo + let { command } = commandInfo; + const { argPend } = commandInfo; + if (!argPend) { + return commandInfo; } - const argPrepend = argPend.prepend ? (argPend.prepend + " ") : "" - const argAppend = argPend.append ? (" " + argPend.append) : "" - if (argPrepend == "" && argAppend == "") { - return commandInfo + const argPrepend = argPend.prepend ? (argPend.prepend + ' ') : ''; + const argAppend = argPend.append ? (' ' + argPend.append) : ''; + if (argPrepend === '' && argAppend === '') { + return commandInfo; } - command = argPrepend + command + argAppend + command = argPrepend + command + argAppend; return Object.assign({}, commandInfo, { command }); } }; diff --git a/src/command-parser/zz-expand-arguments.spec.js b/src/command-parser/zz-expand-arguments.spec.js index e0742771..da3189ef 100644 --- a/src/command-parser/zz-expand-arguments.spec.js +++ b/src/command-parser/zz-expand-arguments.spec.js @@ -21,7 +21,7 @@ it('noop if empty argPend', () => { it('argPend prepend', () => { const commandInfo = { command: 'foo bar', - argPend: { prepend: "echo" }, + argPend: { prepend: 'echo' }, }; expect(parser.parse(commandInfo).command) .toEqual('echo foo bar'); @@ -30,7 +30,7 @@ it('argPend prepend', () => { it('argPend append', () => { const commandInfo = { command: 'foo bar', - argPend: { append: "--watch" }, + argPend: { append: '--watch' }, }; expect(parser.parse(commandInfo).command) .toEqual('foo bar --watch'); @@ -39,7 +39,7 @@ it('argPend append', () => { it('argPend prepend + append', () => { const commandInfo = { command: 'foo bar', - argPend: { prepend: "echo", append: "--watch" }, + argPend: { prepend: 'echo', append: '--watch' }, }; expect(parser.parse(commandInfo).command) .toEqual('echo foo bar --watch'); From 6faec2ccadda5c1b1fca670b12f7713482313f05 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 13:17:57 +0000 Subject: [PATCH 4/9] Style Fix --- src/concurrently.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concurrently.js b/src/concurrently.js index daf7da9e..a833554b 100644 --- a/src/concurrently.js +++ b/src/concurrently.js @@ -6,7 +6,7 @@ const treeKill = require('tree-kill'); const StripQuotes = require('./command-parser/strip-quotes'); const ExpandNpmShortcut = require('./command-parser/expand-npm-shortcut'); const ExpandNpmWildcard = require('./command-parser/expand-npm-wildcard'); -const ZZ_ExpandArguments = require('./command-parser/zz-expand-arguments') +const ZZ_ExpandArguments = require('./command-parser/zz-expand-arguments'); const CompletionListener = require('./completion-listener'); From 8e56f33e667a81a4cd818dd72bbc6f30d5fe8a18 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 15:17:24 +0000 Subject: [PATCH 5/9] Cli style Using `-D append='-- --watch'` style, instead of `--append ' -- --watch'` to prevent yargs miss parse dash. --- README.md | 9 ++++-- bin/concurrently.js | 28 +++++++++++++++++-- bin/epilogue.txt | 4 +++ src/command-parser/zz-expand-arguments.js | 6 ++-- .../zz-expand-arguments.spec.js | 8 +++--- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 34ce517e..4f57d0c5 100644 --- a/README.md +++ b/README.md @@ -176,10 +176,11 @@ Restarting [number] [default: 0] shorten command - -P, --prepend prepend string to each command - [string] [default: ""] + -P, --prepend prepend string to each command [string] [default: ""] -A, --append append string to each command eg: pass arguments [string] [default: ""] + -D, --define add definition to prepend / append each command, can be use + multiple times [string] [default: []] Options: -h, --help Show help [boolean] @@ -203,11 +204,15 @@ Examples: $ concurrently -P 'npm run' 'example:echo:A' 'example:echo:B' + $ concurrently -D prepend='npm run' 'example:echo:A' 'example:echo:B' + - Custom cmd append $ concurrently -A ' -- --watch' 'npm:example:echo*' # Add one space to prevent yargs parse this string as an option + $ concurrently -D append='-- --watch' 'npm:example:echo*' + - Custom names and colored prefixes $ concurrently --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" diff --git a/bin/concurrently.js b/bin/concurrently.js index 39b0dc61..39b13ac7 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -150,6 +150,16 @@ const args = yargs 'eg: pass arguments', default: '', type: 'string' + }, + + // force to use `-D A=B` style + // to prevent yargs mis-parsed dash, eg: `--append --watch` + 'D': { + alias: 'define', + describe: + 'add definition to prepend / append each command, can be use multiple times', + default: [], + type: 'string' } }) .group(['m', 'n', 'name-separator', 'raw', 's', 'no-color'], 'General') @@ -157,7 +167,7 @@ const args = yargs .group(['i', 'default-input-target'], 'Input handling') .group(['k', 'kill-others-on-fail'], 'Killing other processes') .group(['restart-tries', 'restart-after'], 'Restarting') - .group(['P', 'A'], 'shorten command') + .group(['P', 'A', 'D'], 'shorten command') // Too much text to write as JS strings, .txt file is better .epilogue(fs.readFileSync(__dirname + '/epilogue.txt', { encoding: 'utf8' })) .argv; @@ -165,13 +175,27 @@ const args = yargs const prefixColors = args.prefixColors.split(','); const names = (args.names || '').split(args.nameSeparator); +const _define = Array.isArray(args.define) ? args.define : [args.define]; +const definition = Object.assign( + {}, + { prepend: args.prepend, append: args.append }, + // desc: convert ["a=1","b=2"] into {"a":"1","b":"2"} + Object.fromEntries( + _define + .map(el=>el.split('=')) + .map(x=>[x[0],x.slice(1).join('=')]) + ) +); + let lastColor; concurrently(args._.map((command, index) => { // Use documented behaviour of repeating last colour when specifying more commands than colours lastColor = prefixColors[index] || lastColor; return { command, - argPend: { prepend:args.prepend, append:args.append }, + argPend: { + definition + }, prefixColor: lastColor, name: names[index] }; diff --git a/bin/epilogue.txt b/bin/epilogue.txt index 3bf8f5b9..fa7940ca 100644 --- a/bin/epilogue.txt +++ b/bin/epilogue.txt @@ -15,12 +15,16 @@ Examples: - Custom cmd prepend $ $0 -P 'npm run' 'example:echo:A' 'example:echo:B' + + $ $0 -D prepend='npm run' 'example:echo:A' 'example:echo:B' - Custom cmd append $ $0 -A ' -- --watch' 'npm:example:echo*' # Add one space to prevent yargs parse this string as an option + $ $0 -D append='-- --watch' 'npm:example:echo*' + - Custom names and colored prefixes $ $0 --names "HTTP,WATCH" -c "bgBlue.bold,bgMagenta.bold" "http-server" "npm run watch" diff --git a/src/command-parser/zz-expand-arguments.js b/src/command-parser/zz-expand-arguments.js index b5b8bd85..8c6a42d4 100644 --- a/src/command-parser/zz-expand-arguments.js +++ b/src/command-parser/zz-expand-arguments.js @@ -2,12 +2,12 @@ module.exports = class StripQuotes { parse(commandInfo) { let { command } = commandInfo; const { argPend } = commandInfo; - if (!argPend) { + if (!argPend || !argPend.definition) { return commandInfo; } - const argPrepend = argPend.prepend ? (argPend.prepend + ' ') : ''; - const argAppend = argPend.append ? (' ' + argPend.append) : ''; + const argPrepend = argPend.definition.prepend ? (argPend.definition.prepend + ' ') : ''; + const argAppend = argPend.definition.append ? (' ' + argPend.definition.append) : ''; if (argPrepend === '' && argAppend === '') { return commandInfo; } diff --git a/src/command-parser/zz-expand-arguments.spec.js b/src/command-parser/zz-expand-arguments.spec.js index da3189ef..4f84a2ea 100644 --- a/src/command-parser/zz-expand-arguments.spec.js +++ b/src/command-parser/zz-expand-arguments.spec.js @@ -12,7 +12,7 @@ it('noop if no argPend', () => { it('noop if empty argPend', () => { const commandInfo = { command: 'foo bar', - argPend: {} + argPend: { definition: {} } }; expect(parser.parse(commandInfo).command) .toEqual('foo bar'); @@ -21,7 +21,7 @@ it('noop if empty argPend', () => { it('argPend prepend', () => { const commandInfo = { command: 'foo bar', - argPend: { prepend: 'echo' }, + argPend: { definition: { prepend: 'echo' } }, }; expect(parser.parse(commandInfo).command) .toEqual('echo foo bar'); @@ -30,7 +30,7 @@ it('argPend prepend', () => { it('argPend append', () => { const commandInfo = { command: 'foo bar', - argPend: { append: '--watch' }, + argPend: { definition: { append: '--watch' } }, }; expect(parser.parse(commandInfo).command) .toEqual('foo bar --watch'); @@ -39,7 +39,7 @@ it('argPend append', () => { it('argPend prepend + append', () => { const commandInfo = { command: 'foo bar', - argPend: { prepend: 'echo', append: '--watch' }, + argPend: { definition: { prepend: 'echo', append: '--watch' } }, }; expect(parser.parse(commandInfo).command) .toEqual('echo foo bar --watch'); From b934bd8bc30b87c96b956aafb568ed0ea7c747d5 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 15:28:24 +0000 Subject: [PATCH 6/9] Update document --- bin/concurrently.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/concurrently.js b/bin/concurrently.js index 39b13ac7..68894552 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -157,7 +157,8 @@ const args = yargs 'D': { alias: 'define', describe: - 'add definition to prepend / append each command, can be use multiple times', + 'add definition to render \n' + + 'template `{{prepend}} {{append}}`', default: [], type: 'string' } From 30dc387927b293691b89907e75832f6c71be1ed3 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 15:32:58 +0000 Subject: [PATCH 7/9] Update document --- README.md | 13 +++++++++---- bin/concurrently.js | 8 ++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4f57d0c5..702f5ed2 100644 --- a/README.md +++ b/README.md @@ -176,11 +176,16 @@ Restarting [number] [default: 0] shorten command - -P, --prepend prepend string to each command [string] [default: ""] + -P, --prepend prepend string to each command + but make sure you not using dash, else use + `-D prepend="foobar"` [string] [default: ""] -A, --append append string to each command - eg: pass arguments [string] [default: ""] - -D, --define add definition to prepend / append each command, can be use - multiple times [string] [default: []] + eg: pass arguments + but make sure you not using dash, else use + `-D append="foobar"` [string] [default: ""] + -D, --define add definition to render + template `{{prepend}} {{append}}` + [string] [default: []] Options: -h, --help Show help [boolean] diff --git a/bin/concurrently.js b/bin/concurrently.js index 68894552..d214c050 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -139,7 +139,9 @@ const args = yargs 'P': { alias: 'prepend', describe: - 'prepend string to each command', + 'prepend string to each command\n' + + 'but make sure you not using dash, else use \n' + + '`-D prepend="foobar"`', default: '', type: 'string' }, @@ -147,7 +149,9 @@ const args = yargs alias: 'append', describe: 'append string to each command\n' + - 'eg: pass arguments', + 'eg: pass arguments\n' + + 'but make sure you not using dash, else use \n' + + '`-D append="foobar"`', default: '', type: 'string' }, From 385dd8d7756f1a530d9bed564c9642d8cce473ee Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 15:40:58 +0000 Subject: [PATCH 8/9] Style fix --- bin/concurrently.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/concurrently.js b/bin/concurrently.js index d214c050..92d44cbb 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -187,8 +187,8 @@ const definition = Object.assign( // desc: convert ["a=1","b=2"] into {"a":"1","b":"2"} Object.fromEntries( _define - .map(el=>el.split('=')) - .map(x=>[x[0],x.slice(1).join('=')]) + .map(el=>el.split('=')) + .map(x=>[x[0],x.slice(1).join('=')]) ) ); From 32e3a84c4d9566c8e161eb58497b6c615cef4390 Mon Sep 17 00:00:00 2001 From: loynoir Date: Fri, 4 Jun 2021 16:03:57 +0000 Subject: [PATCH 9/9] Object.fromEntries polyfiil --- bin/concurrently.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/concurrently.js b/bin/concurrently.js index 92d44cbb..a586fbfb 100755 --- a/bin/concurrently.js +++ b/bin/concurrently.js @@ -180,12 +180,17 @@ const args = yargs const prefixColors = args.prefixColors.split(','); const names = (args.names || '').split(args.nameSeparator); +const _ObjectFromEntries = (l) => { + const d = {}; + l.forEach(el=>d[el[0]] = el[1]); + return d; +}; const _define = Array.isArray(args.define) ? args.define : [args.define]; const definition = Object.assign( {}, { prepend: args.prepend, append: args.append }, // desc: convert ["a=1","b=2"] into {"a":"1","b":"2"} - Object.fromEntries( + _ObjectFromEntries( _define .map(el=>el.split('=')) .map(x=>[x[0],x.slice(1).join('=')])