[
  {
    "path": ".gitignore",
    "content": "node_modules/\n_private/\npackage-lock.json"
  },
  {
    "path": ".jshintrc",
    "content": "{\n\t\"esversion\": 6,\n\t\"node\": true\n}"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - 8\n  - 10"
  },
  {
    "path": "README.md",
    "content": "# MagiCLI\n\n[![Build Status](https://api.travis-ci.org/DiegoZoracKy/magicli.svg)](https://travis-ci.org/DiegoZoracKy/magicli) [![npm](https://img.shields.io/npm/v/magicli.svg)]() [![npm](https://img.shields.io/npm/l/magicli.svg)]()\n\nAutomagically generates command-line interfaces (CLI), for any module.\nJust `require('magicli')();` and your module is ready to be executed via CLI.\n\nThe main goal is to have any module prepared to be executed via CLI (installed globally with `-g`, or by using **npx**):\n\nTo see why I believe you should plug it on your module, even if you don't need a CLI (it probably will serve someone on the community), read here: [Introducing MagiCLI: Automagically generates a command-line interface (CLI) for any module\n](https://hackernoon.com/introducing-magicli-automagically-generates-a-command-line-interface-cli-for-any-module-49543e50f86d)\n\n**It can be installed globally, in order to *execute* any module or .js file via CLI.**\n\n## Goals\n\n * Minimal setup (*one line*)\n * Automatic options names based on functions parameters\n * Out of the box support to async functions (`Promises`, or any *thenable* lib)\n * A specific help section for each nested property (*\"subcommands\"*)\n * *Name*, *Description* and *Version* extracted from package.json\n * Simple API to hook into the execution flow (*stdin*, *before*, *after*)\n * Cover all possible cases of module.exports (*Function*, *Object* with nested properties, Destructuring parameters)\n * Provide a CLI to be used to execute any given module or .js file via CLI\n\n## Usage (the most simple and minimal way)\n\n * `npm install magicli`\n * Add the property **bin** to your package.json containing the value **./bin/magicli.js**\n * Create the file **./bin/magicli.js** with the following content:\n\n```javascript\n#!/usr/bin/env node\n\nrequire('magicli')();\n```\n\n**Done!** Install your module with `-g`, or use it via **[npx](http://blog.npmjs.org/post/162869356040/introducing-npx-an-npm-package-runner)**, and run it with `--help` to see the result. The `--version` option will show the same value found at *package.json*. In the same way you can just run `node ./bin/magicli.js --help` to test it quickly, without installing it.\n\nLet's suppose that **your-module** exports the function:\n\n```javascript\nmodule.exports = function(param1, param2) {\n    return param1 + param2;\n}\n```\n\nWhen calling it via CLI, with `--help`, you will get:\n\n```bash\nDescription:\n\n  Same description found at package.json\n\nUsage:\n\n  $ your-module [options]\n\nOptions:\n\n  --param1\n  --param2\n```\n\nThe program will be expecting options with the same name as the parameters declared at the exported function, and it doesn't need to follow the same order. Example:\n\n`$ your-module --param2=\"K\" --param1=\"Z\"` would result in: `ZK`.\n\nImportant: MagiCLI requires the module in order to analyse it, and provide the command-line interface for it. Keep that in mind in case your module does something just by being required.\n\n## Usage via CLI\n\nIn order to **execute** any module or .js file via CLI, install it globally:\n\n```bash\n$ npm install magicli -g\n```\n\nThen just pass in as the first argument, the path to a module or a .js file. Examples:\n * `$ magicli . --help`\n * `$ magicli ./path/to-some-module --help`\n * `$ magicli ./path/to-a-file.js --help`\n\nOr use it via **[npx](http://blog.npmjs.org/post/162869356040/introducing-npx-an-npm-package-runner)** without the need to install it.\n\nLet's suppose that you have a simple .js file as this one:\n\n```javascript\nmodule.exports = {\n\tsum: (n1, n2) => n1 + n2,\n\tec: {\n\t\tho: str => `${str} !!!`\n\t}\n}\n```\n\nJust execute **magicli** on it, as `$ magicli ./path/to-the-file-above.js --help` and you will get:\n\n```bash\nCommands:\n  sum\n  ec-ho\n```\n\n`$ magicli ./path/to-the-file-above.js sum --help` will give you:\n```bash\nUsage:\n  $ sum [options]\n\nOptions:\n  --n1\n  --n2\n```\nand `$ magicli ./path/to-the-file-above.js sum --n1=4 --n2=2` will result in `6`\n\n### How it works\n\nMagiCLI is capable of handling many styles of `exports`, like:\n\n * Functions\n * Object Literal\n * Nested properties\n * Class with static methods\n\nAnd also any kind of parameters declaration (*Destructuring Parameters*, *Rest Parameters*).\n\nIf **your-module** were like this:\n```javascript\n// An Arrow function with Destructuring assignment and Default values\nconst mainMethod = ([p1, [p2]] = ['p1Default', ['p2Default']], { p3 = 'p3Default' } = {}) => `${p1}-${p2}-${p3}`;\n\n// Object Literal containing a nested method\nmodule.exports = {\n\tmainMethod,\n\tnested: {\n\t\tmethod: param => `nested method param value is: \"${param}`\n\t}\n};\n```\n\n`$ your-module --help` would result in:\n\n```bash\nDescription:\n\n  Same description found at package.json\n\nUsage:\n\n  $ your-module <command>\n\nCommands:\n\n  mainMethod\n  nested-method\n```\n\n`$ your-module mainMethod --help` would be:\n\n```bash\nUsage:\n\n  $ your-module mainMethod [options]\n\nOptions:\n\n  --p1\n  --p2\n  --p3\n```\n\n`$ your-module nested-method --help` returns:\n\n```bash\nUsage:\n\n  $ your-module nested-method [options]\n\nOptions:\n\n  --param\n```\n\nCalling *mainMethod* without any parameter:\n`$ your-module mainMethod`\n\nresults in:\n` p1Default-p2Default-p3Default`\n\nWhile defining the parameter for *nested-method*:\n`$ your-module mainMethod nested-method --param=paramValue`\n\nwould return:\n` nested method param value is: \"paramValue\"`\n\nNote: Nested methods/properties will be turned into commands separated by `-`, and it can be configurable via options (`subcommandDelimiter`).\n\n## Usage Options\n`magicli({ commands = {}, validateRequiredParameters = false, help = {}, version = {}, pipe = {}, enumerability = 'enumerable', subcommandDelimiter = '-'})`\n\nOptions are provided to add more information about commands and its options, and also to support a better control of a command execution flow, without the need to change the source code of the module itself (for example, to `JSON.stringify` an `Object Literal` that is returned).\n\n\n\n### enumerability\n\nBy default, only the enumerable nested properties will be considered. The possible values are: `'enumerable'` (default), `'nonenumerable'` or `'all'`.\n\n### validateRequiredParameters\nMagiCLI can validate the required parameters for a command and show the help in case some of them are missing. The default value is `false`.\n\n### help\n\n**help.option**\nTo define a different option name to show the help section. For example, if `'modulehelp'` is chosen, `--modulehelp` must be used instead of `--help` to show the help section.\n\n**help.stripAnsi**\n\tSet to `true` to strip all ansi escape codes (colors, underline, etc.) and output just a raw text.\n\n\n\n### version\n**version.option**\nTo define a different option name to show the version. For example, if `'moduleversion'` is chosen, `--moduleversion` must be used instead of `--version` to show the version number.\n\n### pipe (stdin, before and after)\n\nThe pipeline of a command execution is:\n\n**stdin** (command.pipe.stdin || magicliOptions.pipe.stdin) =>\n\n**magicliOptions.pipe.before** =>\n\n**command.pipe.before** =>\n\n**command.action** (the method in case) =>\n\n**command.pipe.after** =>\n\n**magicliOptions.pipe.after** =>\n\n**stdout**\n\nWhere each of these steps can be handled if needed.\n\nAs it can be defined on *commands* option, for each command, **pipe** can also be defined in *options* to implement a common handler for all commands. The expected properties are:\n\n**pipe.stdin**\n`(stdinValue, args, positionalArgs, argsAfterEndOfOptions)`\n\nUseful to get a value from *stdin* and set it to one of the expected *args*.\n\n**pipe.before**\n`(args, positionalArgs, argsAfterEndOfOptions)`\n\nTo transform the data being input, before it is passed in to the main command action.\n\n**pipe.after**\n`(result, parsedArgs, positionalArgs, argsAfterEndOfOptions)`\n\nNote: **stdin** and **before** must always return *args*, and **after** must always return *result*, as these values will be passed in for the next function in the pipeline.\n\n### commands\nThe options are effortlessly extracted from the parameters names, however it is possible to give more information about a command and its options, and also give instructions to the options parser.\n\n**commands** expects an `Object Literal` where each key is the command name. It would be the module's name for the main function that is exported, and the command's name as it is shown at the *Commands:* section of `--help`. For example:\n```javascript\ncommands: {\n    'mainmodulename': {},\n    'some-nested-method': {}\n}\n```\n\nFor each command the following properties can be configurable:\n\n#### options\nIs an *Array* of *Objects*, where each contains:\n\n**name** (*required*)\nThe name of the parameter that will be described\n\n**required**\nTo tell if the parameter is required.\n\n**description**\nTo give hints or explain what the option is about.\n\n**type**\nTo define how the parser should treat the option (Array, Object, String, Number, etc.).  Check [yargs-parser](https://github.com/yargs/yargs-parser) for instructions about *type*, as it is the engine being used to parse the options.\n\n**alias**\nTo define an alias for the option.\n\n#### pipe (stdin, before and after)\n\nThe pipeline of a command execution is:\n\n**stdin** (command.pipe.stdin || magicliOptions.pipe.stdin) =>\n\n**magicliOptions.pipe.before** =>\n\n**command.pipe.before** =>\n\n**command.action** (the method in case) =>\n\n**command.pipe.after** =>\n\n**magicliOptions.pipe.after** =>\n\n**stdout**\n\nWhere each of these steps can be handled if needed.\n\nAs it can be defined on *options* to implement a common handler for all commands, **pipe** can also be defined for each command.\n\n**pipe.stdin**\n`(stdinValue, args, positionalArgs, argsAfterEndOfOptions)`\n\nUseful to get a value from *stdin* and set it to one of the expected *args*.\n\n**pipe.before**\n`(args, positionalArgs, argsAfterEndOfOptions)`\n\nTo transform the data being input, before it is passed in to the main command action.\n\n**pipe.after**\n`(result, parsedArgs, positionalArgs, argsAfterEndOfOptions)`\n\nNote: **stdin** and **before** must always return *args*, and **after** must always return *result*, as these values will be passed in for the next function in the pipeline.\n\nIf needed, a more thorough guide about this section can be found at [cliss](https://github.com/DiegoZoracKy/cliss) (as this is the module under the hood to handle that)\n\nA full featured use of the module would look like:\n\n```javascript\nmagicli({\n\tcommands,\n\tenumerability,\n\tsubcommandDelimiter,\n\tvalidateRequiredParameters,\n\thelp: {\n\t\toption,\n\t\tstripAnsi\n\t},\n\tversion: {\n\t\toption\n\t},\n\tpipe: {\n\t\tstdin: (stdinValue, args, positionalArgs, argsAfterEndOfOptions) => {},\n\t\tbefore: (args, positionalArgs, argsAfterEndOfOptions) => {},\n\t\tafter: (result, parsedArgs, positionalArgs, argsAfterEndOfOptions) => {}\n\t}\n});\n```\n\n## Example\n\nTo better explain with an example, let's get the following module and configure it with MagiCLI to:\n\n * Define **p1** as `String` (*mainMethod*)\n * Write a description for **p2** (*mainMethod*)\n * Define **p3** as required (*mainMethod*)\n * Get **p2** from stdin (*mainMethod*)\n * Use **before** (command) to upper case **param** (*nested-method*)\n * Use **after** (command) to JSON.stringify the result of (*nested-method*)\n * Use **after** (options) to decorate all outputs (*nested-method*)\n\n**module** (\"main\" property of package.json)\n```javascript\n'use strict';\n\nmodule.exports = {\n\tmainMethod: (p1, p2, { p3 = 'p3Default' } = {}) => `${p1}-${p2}-${p3}`,\n\tnested: {\n\t\tmethod: param => {\n\n\t\t\t// Example of a Promise being handled\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tresolve({ param });\n\t\t\t\t}, 2000);\n\t\t\t});\n\t\t}\n\t}\n};\n```\n\n**magicli.js** (\"bin\" property of package.json)\n```javascript\n#!/usr/bin/env node\n\n\nrequire('../magicli')({\n\tcommands: {\n\t\t'mainMethod': {\n\t\t\toptions: [{\n\t\t\t\tname: 'p1',\n\t\t\t\tdescription: 'Number will be converted to String',\n\t\t\t\ttype: 'String'\n\t\t\t}, {\n\t\t\t\tname: 'p2',\n\t\t\t\tdescription: 'This parameter can be defined via stdin'\n\t\t\t}, {\n\t\t\t\tname: 'p3',\n\t\t\t\trequired: true\n\t\t\t}],\n\t\t\tpipe: {\n\t\t\t\tstdin: (stdinValue, args, positionalArgs, argsAfterEndOfOptions) => {\n\t\t\t\t\targs.p2 = stdinValue;\n\t\t\t\t\treturn args;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t'nested-method': {\n\t\t\toptions: [{\n\t\t\t\tname: 'param',\n\t\t\t\tdescription: 'Wait for it...'\n\t\t\t}],\n\t\t\tpipe: {\n\t\t\t\tbefore: (args, positionalArgs, argsAfterEndOfOptions) => {\n\t\t\t\t\tif (args.param) {\n\t\t\t\t\t\targs.param = args.param.toUpperCase();\n\t\t\t\t\t}\n\t\t\t\t\treturn args;\n\t\t\t\t},\n\n\t\t\t\tafter: JSON.stringify\n\t\t\t}\n\t\t}\n\t},\n\tpipe: {\n\t\tafter: (result, positionalArgs, argsAfterEndOfOptions) => `======\\n${result}\\n======`\n\t}\n});\n```\n\n## Tests\n\nThere is another repository called [MagiCLI Test Machine](https://github.com/DiegoZoracKy/magicli-test-machine), where many real published modules are being successfully tested. As the idea is to keep increasing the number of real modules tested, it made more sense to maintain a separated repository for that, instead of being constantly increasing the size of MagiCLI itself over time. I ask you to contribute with the growing numbers of those tests by adding your own module there via a pull request.\n\nIf you find some case that isn't being handled properly, please open an *issue* or feel free to create a PR ;)\n"
  },
  {
    "path": "bin/cli.js",
    "content": "#!/usr/bin/env node\n\n'use strict'\n\nconst { name, description, version } = require('../package.json');\nconst path = require('path');\nconst fs = require('fs');\n\nif (!process.argv[2]) {\n\tconsole.error('The first argument must be the path to a module or to a .js file');\n\treturn;\n}\n\nconst modulePath = path.resolve(process.argv[2]);\nif (!fs.existsSync(modulePath)) {\n\tconsole.error('The first argument must be a valid path to a module or to a .js file');\n\treturn;\n}\n\nprocess.argv = [process.argv[0], ...process.argv.slice(2)];\nrequire('../')({ modulePath });"
  },
  {
    "path": "lib/magicli.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nconst fs = require('fs');\nconst path = require('path');\nconst forEachProperty = require('for-each-property');\nconst inspectProperty = require('inspect-property');\nconst cliss = require('cliss');\nconst findUp = require('find-up');\n\nfunction requireMainModule(currentPath) {\n\tlet packageJson = path.resolve(path.join(currentPath, '/package.json'));\n\n\tif (!fs.existsSync(packageJson)) {\n\t\tpackageJson = findUp.sync('package.json', {\n\t\t\tcwd: packageJson\n\t\t});\n\t}\n\n\tconst modulePath = path.dirname(packageJson);\n\treturn {\n\t\tmoduleRef: require(modulePath),\n\t\tpackageJson: require(packageJson)\n\t};\n}\n\nfunction requireJsFile(currentPath) {\n\treturn {\n\t\tmoduleRef: require(currentPath),\n\t\tpackageJson: {}\n\t};\n}\n\nfunction magicli({ commands = {}, validateRequiredParameters = false, help = {}, version = {}, pipe = {}, enumerability = 'enumerable', subcommandDelimiter = '-', modulePath } = {}) {\n\tconst { moduleRef, packageJson } = modulePath && path.extname(modulePath) === '.js' ? requireJsFile(modulePath) : requireMainModule(modulePath || require.main.filename);\n\tconst moduleName = packageJson.name;\n\tconst moduleVersion = packageJson.version;\n\tconst moduleDescription = packageJson.description;\n\tconst moduleApi = inspectProperty(moduleRef, null, { enumerability, delimiter: subcommandDelimiter, inspectProperties: true });\n\n\t// CLIss cliSpec\n\tconst cliSpec = { name: moduleName, version: moduleVersion, description: moduleDescription };\n\n\t// Main command\n\tif (moduleApi.type === 'function') {\n\t\tcliSpec.action = moduleApi.functionInspection.fn;\n\n\t\tif (commands[moduleName]) {\n\t\t\tObject.assign(cliSpec, commands[moduleName]);\n\t\t}\n\t}\n\n\t// Subcommands\n\tforEachProperty(moduleApi.properties, (value, key) => {\n\t\tif (value.type !== 'function' || value.isClass) {\n\t\t\treturn;\n\t\t}\n\n\t\tcliSpec.commands = cliSpec.commands || [];\n\t\tconst subcommand = {\n\t\t\tname: key,\n\t\t\taction: value.functionInspection.fn\n\t\t};\n\n\t\tif (commands[subcommand.name]) {\n\t\t\tObject.assign(subcommand, commands[subcommand.name]);\n\t\t}\n\n\t\tcliSpec.commands.push(subcommand);\n\t});\n\n\tcliss(cliSpec, { options: { validateRequiredParameters }, help, version, pipe });\n}\n\nmodule.exports = magicli;"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"magicli\",\n  \"version\": \"0.2.1\",\n  \"description\": \"Automagically generates command-line interfaces (CLI) for any module. Expected options and help sections are created automatically based on parameters names, with support to async. It can be installed globally, in order to *execute* any module, or .js file, via CLI.\",\n  \"main\": \"lib/magicli.js\",\n  \"bin\": \"bin/cli.js\",\n  \"scripts\": {\n    \"test\": \"mocha ./tests\",\n    \"test-main\": \"mocha ./tests/main.test.js\",\n    \"test-cli\": \"mocha ./tests/cli.test.js\"\n  },\n  \"author\": {\n    \"name\": \"Diego ZoracKy\",\n    \"email\": \"diego.zoracky@gmail.com\",\n    \"url\": \"https://github.com/DiegoZoracKy/\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/DiegoZoracKy/magicli\"\n  },\n  \"keywords\": [\n    \"bin\",\n    \"cli\",\n    \"async\",\n    \"simple\",\n    \"command-line\",\n    \"interface\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"cliss\": \"0.0.8\",\n    \"find-up\": \"^2.1.0\",\n    \"for-each-property\": \"0.0.4\",\n    \"inspect-property\": \"0.0.7\"\n  },\n  \"devDependencies\": {\n    \"mocha\": \"^4.0.1\"\n  }\n}\n"
  },
  {
    "path": "tests/cli.test.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst path = require('path');\nconst fs = require('fs');\nconst { exec } = require('child_process');\n\nconst testsPath = path.resolve(__dirname, './test-modules');\nconst tests = [\n\t'function-simple-concat',\n\t'object-flat'\n];\n\ntests.forEach(test => {\n\tdescribe(`CLI :: ${test}`, function() {\n\t\tconst modulePath = path.resolve(testsPath, test);\n\t\tconst moduleCliPath = path.resolve(__dirname, '../bin/cli.js') + ' ' + modulePath;\n\t\tconst specs = require(path.resolve(modulePath, 'specs.js'));\n\n\t\tspecs.forEach(spec => {\n\t\t\tconst { input, output, description, stdin } = spec;\n\n\t\t\tit(description || input, function() {\n\t\t\t\treturn execCli(moduleCliPath, input, stdin).then(result => assert.equal(result, output));\n\t\t\t});\n\t\t});\n\t});\n});\n\nfunction execCli(moduleCliPath, args, stdin = '') {\n\treturn new Promise((resolve, reject) => {\n\t\tconst cmd = `${stdin} node ${moduleCliPath} ${args}`;\n\t\texec(cmd, (err, stdout, stderr) => {\n\t\t\tif (err || stderr) {\n\t\t\t\treturn reject(err || stderr);\n\t\t\t}\n\n\t\t\tresolve(stdout.replace(/ +$/gm, '').replace(/\\n$/, ''));\n\t\t}).stdin.end();\n\t});\n}"
  },
  {
    "path": "tests/main.test.js",
    "content": "'use strict';\n\nconst assert = require('assert');\nconst path = require('path');\nconst fs = require('fs');\nconst { exec } = require('child_process');\n\nconst testsPath = path.resolve(__dirname, './test-modules');\nconst tests = fs.readdirSync(testsPath);\n\ntests.forEach(test => {\n\tdescribe(test, function() {\n\t\tconst modulePath = path.resolve(testsPath, test);\n\t\tconst packageJson = require(path.resolve(modulePath, 'package.json'));\n\t\tconst moduleCliPath = path.resolve(modulePath, packageJson.bin);\n\t\tconst specs = require(path.resolve(modulePath, 'specs.js'));\n\n\t\tspecs.forEach(spec => {\n\t\t\tconst { input, output, description, stdin } = spec;\n\n\t\t\tit(description || input, function() {\n\t\t\t\treturn execCli(moduleCliPath, input, stdin).then(result => assert.equal(result, output));\n\t\t\t});\n\t\t});\n\t});\n});\n\nfunction execCli(moduleCliPath, args, stdin = '') {\n\treturn new Promise((resolve, reject) => {\n\t\tconst cmd = `${stdin} node ${moduleCliPath} ${args}`;\n\t\texec(cmd, (err, stdout, stderr) => {\n\t\t\tif (err || stderr) {\n\t\t\t\treturn reject(err || stderr);\n\t\t\t}\n\n\t\t\tresolve(stdout.replace(/ +$/gm, '').replace(/\\n$/, ''));\n\t\t}).stdin.end();\n\t});\n}"
  },
  {
    "path": "tests/test-modules/function-simple-concat/bin/cli.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nrequire('../../../../')();"
  },
  {
    "path": "tests/test-modules/function-simple-concat/lib/index.js",
    "content": "`use strict`;\n\nmodule.exports = (p1, p2) => `${p1} ${p2}`;"
  },
  {
    "path": "tests/test-modules/function-simple-concat/package.json",
    "content": "{\n  \"name\": \"function-simple-concat\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"description\": \"Test function-simple-concat\",\n  \"main\": \"lib/index.js\",\n  \"bin\": \"bin/cli.js\"\n}\n"
  },
  {
    "path": "tests/test-modules/function-simple-concat/specs.js",
    "content": "'use strict';\n\nconst tests = [{\n\tdescription: 'Version --version',\n\tinput: '--version',\n\toutput: `1.0.0`\n}, {\n\tdescription: 'Help --help',\n\tinput: '--help',\n\toutput: `\n\u001b[4;1mDescription:\u001b[0m\n\n  Test function-simple-concat\n\n\u001b[4;1mUsage:\u001b[0m\n\n  $ function-simple-concat [options]\n\n\u001b[4;1mOptions:\u001b[0m\n\n  \u001b[1m--p1\u001b[0m\n  \u001b[1m--p2\u001b[0m\n`\n}, {\n\tdescription: '--p1=P1 --p2=P2',\n\tinput: '--p1=P1 --p2=2',\n\toutput: 'P1 2'\n}];\n\nmodule.exports = tests;"
  },
  {
    "path": "tests/test-modules/general-test-module/bin/cli.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nrequire('../../../../')({\n\tcommands: {\n\t\t'a-b-c-d-e-f': {\n\t\t\toptions: [{\n\t\t\t\tname: 'f1',\n\t\t\t\trequired: true\n\t\t\t}],\n\t\t\tpipe: {\n\t\t\t\tafter: JSON.stringify\n\t\t\t}\n\t\t},\n\t\t'general-test-module': {\n\t\t\tpipe: {\n\t\t\t\tstdin: (stdinValue, args) => {\n\t\t\t\t\targs.param2 = stdinValue;\n\t\t\t\t\treturn args;\n\t\t\t\t},\n\t\t\t\tafter: JSON.stringify\n\t\t\t}\n\t\t}\n\t},\n\tvalidateRequiredParameters: true,\n\tenumerability: 'all',\n\thelp: {\n\t\toption: 'modulehelp',\n\t\tstripAnsi: true\n\t},\n\tversion: {\n\t\toption: 'moduleversion'\n\t},\n\tpipe: {\n\t\tafter: result => `${result}\\n=========`\n\t}\n});"
  },
  {
    "path": "tests/test-modules/general-test-module/lib/index.js",
    "content": "'use strict';\n\nconst main = function(param1, param2) {\n\treturn new Promise((resolve, reject) => {\n\t\tsetTimeout(() => {\n\t\t\tresolve(`o/ ${param1} ${param2}`);\n\t\t}, 1500);\n\t});\n};\n\nmain.methodA = function(paramA1, paramA2) {\n\treturn `${paramA1}=${paramA2}`;\n};\n\nmain.methodB = function() {\n\treturn `${paramB1}-${paramB2}`;\n};\n\nObject.defineProperty(main, 'methodNonEnumerable', {\n\tvalue: function(paramC1, paramC2) {\n\t\treturn `${paramC1}-${paramC2}`;\n\t}\n});\n\nmain.a = {\n\tb: (b1, b2) => `main.a.b: ${b1} ${b2}`\n};\n\nmain.a.b.c = (c1, c2) => `main.a.b.c: ${c1} ${c2}`;\nmain.a.b.c['d-e'] = {};\nmain.a.b.c['d-e'].f = ({f1}, [[f2 = 'F2Default']] = [[]]) => ({ f1, f2 });\n\nmodule.exports = main;"
  },
  {
    "path": "tests/test-modules/general-test-module/package.json",
    "content": "{\n  \"name\": \"general-test-module\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"description\": \"general-test-module description\",\n  \"main\": \"./lib/index.js\",\n  \"bin\": \"./bin/cli.js\"\n}\n"
  },
  {
    "path": "tests/test-modules/general-test-module/specs.js",
    "content": "'use strict';\n\nconst tests = [{\n\tdescription: 'Version with different option --moduleversion',\n\tinput: '--moduleversion',\n\toutput: `0.0.1`\n}, {\n\tdescription: 'Help with different option --modulehelp + help.stripAnsi = true + non-enumerable method',\n\tinput: '--modulehelp',\n\toutput: `\nDescription:\n\n  general-test-module description\n\nUsage:\n\n  $ general-test-module [options]\n  $ general-test-module [command]\n\nOptions:\n\n  --param1\n  --param2\n\nCommands:\n\n  methodA\n  methodB\n  methodNonEnumerable\n  a-b\n  a-b-c\n  a-b-c-d-e-f\n`\n},{\n\tdescription: 'Async + STDIN',\n\tstdin: 'echo \"PARAM2\" | ',\n\tinput: '--param1=111',\n\toutput: `\"o/ 111 PARAM2\"\n=========`\n}, {\n\tdescription: 'Method non-enumerable --modulehelp',\n\tinput: 'methodNonEnumerable --modulehelp',\n\toutput: `\nUsage:\n\n  $ general-test-module methodNonEnumerable [options]\n\nOptions:\n\n  --paramC1\n  --paramC2\n`\n}, {\n\tdescription: 'Method non-enumerable call',\n\tinput: 'methodNonEnumerable --paramC1=val1 --paramC2=val2',\n\toutput: `val1-val2\n=========`\n}, {\n\tdescription: 'Nested method with no required options',\n\tinput: 'a-b-c --modulehelp',\n\toutput: `\nUsage:\n\n  $ general-test-module a-b-c [options]\n\nOptions:\n\n  --c1\n  --c2\n`\n}, {\n\tdescription: 'Nested method with required options',\n\tinput: 'a-b-c-d-e-f --modulehelp',\n\toutput: `\nUsage:\n\n  $ general-test-module a-b-c-d-e-f <options>\n\nOptions:\n\n  --f1    Required\n  --f2\n`\n}, {\n\tdescription: 'Nested method without one required options',\n\tinput: 'a-b-c-d-e-f --f2=2',\n\toutput: `\nUsage:\n\n  $ general-test-module a-b-c-d-e-f <options>\n\nOptions:\n\n  --f1    Required\n  --f2\n`\n}, {\n\tdescription: 'Nested method passing only the required option',\n\tinput: 'a-b-c-d-e-f --f1=2',\n\toutput: `{\"f1\":2,\"f2\":\"F2Default\"}\n=========`\n}];\n\nmodule.exports = tests;"
  },
  {
    "path": "tests/test-modules/general-test-module-async/bin/cli.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nrequire('../../../../')({\n\tcommands: {\n\t\t'a-b-c-d-e-f': {\n\t\t\toptions: [{\n\t\t\t\tname: 'f1',\n\t\t\t\trequired: true\n\t\t\t}],\n\t\t\tpipe: {\n\t\t\t\tafter: JSON.stringify\n\t\t\t}\n\t\t},\n\t\t'general-test-module-async': {\n\t\t\tpipe: {\n\t\t\t\tstdin: (stdinValue, args) => {\n\t\t\t\t\targs.param2 = stdinValue;\n\t\t\t\t\treturn args;\n\t\t\t\t},\n\t\t\t\tafter: JSON.stringify\n\t\t\t}\n\t\t}\n\t},\n\tvalidateRequiredParameters: true,\n\tenumerability: 'all',\n\thelp: {\n\t\toption: 'modulehelp',\n\t\tstripAnsi: true\n\t},\n\tversion: {\n\t\toption: 'moduleversion'\n\t},\n\tpipe: {\n\t\tafter: result => `${result}\\n=========`\n\t}\n});"
  },
  {
    "path": "tests/test-modules/general-test-module-async/lib/index.js",
    "content": "'use strict';\n\nconst main = async function(param1, param2) {\n\treturn new Promise((resolve, reject) => {\n\t\tsetTimeout(() => {\n\t\t\tresolve(`o/ ${param1} ${param2}`);\n\t\t}, 1500);\n\t});\n};\n\nmain.methodA = async function(paramA1, paramA2) {\n\treturn `${paramA1}=${paramA2}`;\n};\n\nmain.methodB = async function() {\n\treturn `${paramB1}-${paramB2}`;\n};\n\nObject.defineProperty(main, 'methodNonEnumerable', {\n\tvalue: async function(paramC1, paramC2) {\n\t\treturn `${paramC1}-${paramC2}`;\n\t}\n});\n\nmain.a = {\n\tb: async (b1, b2) => `main.a.b: ${b1} ${b2}`\n};\n\nmain.a.b.c = async (c1, c2) => `main.a.b.c: ${c1} ${c2}`;\nmain.a.b.c['d-e'] = {};\nmain.a.b.c['d-e'].f = async ({f1}, [[f2 = 'F2Default']] = [[]]) => ({ f1, f2 });\n\nmodule.exports = main;"
  },
  {
    "path": "tests/test-modules/general-test-module-async/package.json",
    "content": "{\n  \"name\": \"general-test-module-async\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"description\": \"general-test-module-async description\",\n  \"main\": \"./lib/index.js\",\n  \"bin\": \"./bin/cli.js\"\n}\n"
  },
  {
    "path": "tests/test-modules/general-test-module-async/specs.js",
    "content": "'use strict';\n\nconst tests = [{\n\tdescription: 'Version with different option --moduleversion',\n\tinput: '--moduleversion',\n\toutput: `0.0.1`\n}, {\n\tdescription: 'Help with different option --modulehelp + help.stripAnsi = true + non-enumerable method',\n\tinput: '--modulehelp',\n\toutput: `\nDescription:\n\n  general-test-module-async description\n\nUsage:\n\n  $ general-test-module-async [options]\n  $ general-test-module-async [command]\n\nOptions:\n\n  --param1\n  --param2\n\nCommands:\n\n  methodA\n  methodB\n  methodNonEnumerable\n  a-b\n  a-b-c\n  a-b-c-d-e-f\n`\n},{\n\tdescription: 'Async + STDIN',\n\tstdin: 'echo \"PARAM2\" | ',\n\tinput: '--param1=111',\n\toutput: `\"o/ 111 PARAM2\"\n=========`\n}, {\n\tdescription: 'Method non-enumerable --modulehelp',\n\tinput: 'methodNonEnumerable --modulehelp',\n\toutput: `\nUsage:\n\n  $ general-test-module-async methodNonEnumerable [options]\n\nOptions:\n\n  --paramC1\n  --paramC2\n`\n}, {\n\tdescription: 'Method non-enumerable call',\n\tinput: 'methodNonEnumerable --paramC1=val1 --paramC2=val2',\n\toutput: `val1-val2\n=========`\n}, {\n\tdescription: 'Nested method with no required options',\n\tinput: 'a-b-c --modulehelp',\n\toutput: `\nUsage:\n\n  $ general-test-module-async a-b-c [options]\n\nOptions:\n\n  --c1\n  --c2\n`\n}, {\n\tdescription: 'Nested method with required options',\n\tinput: 'a-b-c-d-e-f --modulehelp',\n\toutput: `\nUsage:\n\n  $ general-test-module-async a-b-c-d-e-f <options>\n\nOptions:\n\n  --f1    Required\n  --f2\n`\n}, {\n\tdescription: 'Nested method without one required options',\n\tinput: 'a-b-c-d-e-f --f2=2',\n\toutput: `\nUsage:\n\n  $ general-test-module-async a-b-c-d-e-f <options>\n\nOptions:\n\n  --f1    Required\n  --f2\n`\n}, {\n\tdescription: 'Nested method passing only the required option',\n\tinput: 'a-b-c-d-e-f --f1=2',\n\toutput: `{\"f1\":2,\"f2\":\"F2Default\"}\n=========`\n}];\n\nmodule.exports = tests;"
  },
  {
    "path": "tests/test-modules/object-flat/bin/cli.js",
    "content": "#!/usr/bin/env node\n\n'use strict';\n\nrequire('../../../../')();"
  },
  {
    "path": "tests/test-modules/object-flat/lib/index.js",
    "content": "`use strict`;\n\nmodule.exports = {\n\tmethodA: function(param1, param2) {\n\t\treturn `${param1}-${param2}`;\n\t},\n\n\tmethodB: (param1, param2) => `${param1-param2}`\n}"
  },
  {
    "path": "tests/test-modules/object-flat/package.json",
    "content": "{\n  \"name\": \"object-flat\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"description\": \"Test object-flat\",\n  \"main\": \"./lib/index.js\",\n  \"bin\": \"./bin/cli.js\"\n}\n"
  },
  {
    "path": "tests/test-modules/object-flat/specs.js",
    "content": "'use strict';\n\nconst tests = [{\n\tdescription: 'Version --version',\n\tinput: '--version',\n\toutput: `0.0.0`\n},{\n\tdescription: 'Help --help',\n\tinput: '--help',\n\toutput: `\n\u001b[4;1mDescription:\u001b[0m\n\n  Test object-flat\n\n\u001b[4;1mUsage:\u001b[0m\n\n  $ object-flat <command>\n\n\u001b[4;1mCommands:\u001b[0m\n\n  methodA\n  methodB\n`\n}, {\n\tdescription: 'methodA --help',\n\tinput: 'methodA --help',\n\toutput: `\n\u001b[4;1mUsage:\u001b[0m\n\n  $ object-flat methodA [options]\n\n\u001b[4;1mOptions:\u001b[0m\n\n  \u001b[1m--param1\u001b[0m\n  \u001b[1m--param2\u001b[0m\n`\n}, {\n\tdescription: 'methodB --help',\n\tinput: 'methodB --help',\n\toutput: `\n\u001b[4;1mUsage:\u001b[0m\n\n  $ object-flat methodB [options]\n\n\u001b[4;1mOptions:\u001b[0m\n\n  \u001b[1m--param1\u001b[0m\n  \u001b[1m--param2\u001b[0m\n`\n}, {\n\tdescription: 'methodA --param2=\"Z\" --param1=\"K\"',\n\tinput: 'methodA --param2=\"Z\" --param1=\"K\"',\n\toutput: `K-Z`\n}, {\n\tdescription: 'methodB --param1=3 --param2=2',\n\tinput: 'methodB --param1=3 --param2=2',\n\toutput: `1`\n}];\n\nmodule.exports = tests;"
  }
]