[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"@babel/preset-env\", \"@babel/preset-typescript\"]\n}"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.vscode\n.DS_Store\nnode_modules\nnpm-debug.log\n/coverage\n/lib\n"
  },
  {
    "path": ".huskyrc.json",
    "content": "{\n  \"hooks\": {\n    \"pre-commit\": \"lint-staged\"\n  }\n}"
  },
  {
    "path": ".npmignore",
    "content": "*.spec.ts\n/src\n/test\n/.huskyrc.json\n/.travis.yml\n/.prettierrc.json\n/.vscode\n/.babelrc\n/test\n/jest.config.js\n/tslint.json\n/tsconfig.json\n"
  },
  {
    "path": ".npmrc",
    "content": "save-exact=true"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"semi\": false,\n  \"singleQuote\": true\n}"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"8.15.0\"\n  - \"10.15.0\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 5.1.0\n\n*API:*\n- `sh` function now accepts different set of options. Most importantly it does not accept\n`stdio` option anymore. By default it will be always in `stdio=pipe` mode for `stdout`\nand `stderr` process streams. It will also print out results to the terminal unless `silent=true`\noption given.\n\n- `sh` function accepts also `transform` option which allows to transform output of\nshell process. Usefull if we want to add prefixes to the output.\n\n- introducing `prefixTransform` function. It is dedicated for usage along with `sh`\nfunction as value for `transform` option.\n\n## 5.0.0\n\n*API:*\n\n- `help` function as second argument now accepts only `string`, for third argument\naccepts detailed help information about `options` and `params`\n- removing `option` and `options` helper, now `options` will be passed always as a first\nargument to the task\n- introducing `rawArgs` function, which returns raw, unparsed args which were provided\nto the task\n- renaming `run` function to `sh`\n- introducing `cli` function which exposes tasks functions to the cli\n\n\n*Mechanics:*\n\n- `options` are always passed as a first argument to the task function\n- calling tasks occurs through `npx task` not `npx run` script or by calling\n`tasksfile.js` directly (`node tasksfile.js`). Tasks file now behaves like a\nCLI script\n- to be able to call tasks from `tasksfile.js` they must be exposed by `cli`\nfunction. Exporting tasks functions won't do the job anymore.\n- to be able to call a task through `npx task`, entry to `npm scripts` must be added:\n`\"task\": \"node ./tasksfile.js\"`. `npx task` always try to execute `task` npm script,\nit's just an alias.\n- namespaces now can have `default` task\n- removing autocomplete feature, as it required too much configuration and it\nseems not used by the users\n- full support for `TypeScript`. Types files are included within the project. Using\n`TypeScript` for `tasksfile` is possible. It just require different entry in `npm scripts`:\n`\"task\": \"ts-node ./tasksfile.ts\"`\n\n\n*Other:*\n\n- renaming project from `runjs` to `tasksfile`\n\n\n## 4.4.0\n\n- source code migrated from `Flow/Babel` to `TypeScript`\n\n## 4.3.0\n\n- adding experimental bash autocompletion feature\n\n## 4.2.0\n\n*Changes:*\n\n- introducing `help` utility function\n- improving task docs generation by annotations\n\n*Dev env:*\n\n- improving e2e tests\n- using external module `microcli` as for cli args parsing and `--help` handling\n\n## 4.1.0\n\n- remove log option from `run` api command\n- upgrade dependent packages\n- introducing `options` helper, deprecating `option`\n- better printing of methods list when calling `run`\n\n*For development env:*\n\n- add tests coverage check\n- introducing `flow` types\n\n## 4.0.0\n\n**Changes:**\n\n- removing `ask` and `generate` helpers from api, to keep runjs codebase more focused about its main purpose\n- dropping support for `node` < 6.11.1\n- support for other than `Babel` transpilers, like `TypeScript`\n- log option to run function, when `false` it does not log the command\n- documentation updates\n- support for `async` / `await`\n- `option` helper\n\n**Migration from 3.x to 4.x procedure:**\n\n- make sure you have node version >=6.11.1\n- if you use Babel you need to add `\"runjs\": {requires: [\"./node_modules/babel-register\"]}` config to your package.json, otherwise Babel transpiler won't be picked up\n- find alternatives for ask and generate, those are not supported by runjs anymore\n\n## 3.4.1\n\n- changing documentation format for calling `run` without arguments (task documentation)\n- changing name of the prop for documentation from doc to help\n- when typing `--help` option with task run it will provide documentation only for that task (`run sometask --help`)\n\n## 3.3.0\n\n- migrating to `yarn`\n- removing task execution logging (decoration function) as it not working well with exporting pure functions\n- passing task options through `this.options` inside a task function\n\n## 3.2.1\n\n- fixes within handling dashed arguments when calling tasks, dashed arguments can be \"spaced\" by \"-\" or \".\" now, for example: `--some-argument` or `--some.argument` (#49)\n\n## 3.2.0\n\n- documenting tasks args when calling `run` without arguments\n- presenting list of available tasks from `runfile.js` in more readable way\n- passing `stdio` directly to `spawn` / `execSync`\n- changing run api where now it resolves/returns null by default and resolves/returns with value for option stdio: 'pipe'. This - allows to return colours to the terminal if provided by commands outcome.\n\n## 3.1.1\n\n- Bug fix: pass `process.env` by default to `spawn` and `execSync`\n\n## 3.1.0\n\n- fixes #43 `stderr` maxBuffer exceeded error (use `spawn` for `async` calls not `exec`)\n- `runfile.js` example update in README\n- drops support for `node` < 4.8.0\n\n## 3.0.0\n\n- task name spacing/nesting, better for scaling tasks into many files\n- task descriptions\n- `ask` function\n- handling dash arguments in tasks (for example `--test`, `-t`)\n- logging tasks arguments to console when executing tasks\n- fixing exit codes when task not found\n- `run` function returns an output of a command now\n- improving documentation\n- deep code refactor, more unit tests\n\n## 2.6.1\n\n- bugfix: streaming `stderr` also for `async` process\n\n## 2.6.0\n\n- streaming output of an `async` command by default (`run` api function)\n\n## 2.5.1\n\n- presenting straightforward message when no `runfile.js` found\n\n## 2.5.0\n\n- bringing backwards compatibility with `node` >= 4.0.0 (previously `node` >= 6.0.0 required)\n- `run` command in `async` mode now returns a `Promise`\n\n## 2.4.3\n\n- handling config from `package.json` to define a custom path to `babel-register`\n- executing async commands through `child_process.span` (better `stdio` handling)\n\n## 2.4.0\n\n- removing watch method from api\n- RunJS will fallback to pure node now if user `babel-register` not found (falling back to it's own `babel-register` before)\nadding information to README: Why RunJS ? and other README update\n\n## 2.3.0\n\n- dropping Babel 5 support\n- handling new `exports.default` after babel update\n\n## 2.2.0\n\n- more explicit exceptions\n- handling existing `babel-register` or `babel/register` require hooks from the user package\n\n## 2.1.0\n\n- new functions available as part of runjs api: `watch` and `generate`\n- broader README with extensive `runfile.js` example\n\n## 2.0.0\n\n- dropping `es5` and `coffeescript` support in favor of `es6` (handled by babel)\n- dropping support for `node` < 4.0"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Paweł Gałązka\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# tasksfile ![node version](https://img.shields.io/node/v/tasksfile.svg) [![Build Status](https://travis-ci.org/pawelgalazka/tasksfile.svg?branch=master)](https://travis-ci.org/pawelgalazka/tasksfile) [![npm version](https://badge.fury.io/js/tasksfile.svg)](https://badge.fury.io/js/tasksfile)\n\nMinimalistic building tool\n\n> From version >= 5 RunJS was renamed to Tasksfile.\n> Link to RunJS version: https://github.com/pawelgalazka/runjs/tree/runjs\n\n- [Get started](#get-started)\n- [Why tasksfile ?](#why-tasksfile-)\n- [Features](#features)\n    - [Executing shell commands](#executing-shell-commands)\n    - [Handling arguments](#handling-arguments)\n    - [Documenting tasks](#documenting-tasks)\n    - [Namespacing](#namespacing)\n    - [Sharing tasks](#sharing-tasks)\n    - [TypeScript support](#typescript-support)\n- [API](#api)\n    - [sh](#shcmd-options)\n    - [prefixTransform](#prefixTransformprefix)\n    - [help](#helpfunc-description-annotation)\n    - [rawArgs](#rawArgs)\n\n\n## Get started\n\nInstall tasksfile in your project\n\n    npm install tasksfile --save-dev\n    \nCreate `tasksfile.js` in your root project directory:\n\n```js\nconst { sh, cli } = require('tasksfile')\n\nfunction hello(options, name = 'Mysterious') {\n  console.log(`Hello ${name}!`)\n}\n\nfunction makedir() {\n  sh('mkdir somedir')\n}\n\ncli({\n  hello,\n  makedir\n})\n```\n\nCreate `task` entry in your `scripts` section in `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"task\": \"node ./tasksfile.js\"\n  }\n}\n```\n\nCall in your terminal through npm scripts:\n\n```bash\n$ npm run task -- hello Tommy\n$ npm run task -- makedir\n$ yarn task hello Tommy\n$ yarn task makedir\n```\n\nor through shorter `npx task` alias:\n\n```bash\n$ npx task hello Tommy\nHello Tommy!\n$ npx task makedir\nmkdir somedir\n```\n\n\n## Why tasksfile ?\n\nWe have Grunt, Gulp, npm scripts, Makefile. Why another building tool ?\n\nGulp or Grunt files seem overly complex for what they do and the plugin\necosystem adds a layer of complexity towards the simple command\nline tools underneath. The documentation is not always up to date\nand the plugin does not always use the latest version of the tool.\nAfter a while customizing the process even with simple things,\nreconfiguring it becomes time consuming.\n\nNpm scripts are simple but they get out of hand pretty quickly if\nwe need more complex process which make them quite hard to read\nand manage.\n\nMakefiles are simple, better for more complex processes\nbut they depend on bash scripting. Within `tasksfile` you can use\ncommand line calls as well as JavaScript code and npm\nlibraries which makes that approach much more flexible.\n\n[More](https://hackernoon.com/simple-build-tools-npm-scripts-vs-makefile-vs-runjs-31e578278162)\n\n\n## Features\n\n### Executing shell commands\n\nTasksfile gives an easy way to execute shell commands in your tasks by `sh` function\nin synchronous and asynchronous way:\n\n```js\nconst { sh, cli } = require('tasksfile')\n\nfunction command () {\n  sh('jest')\n  sh(`webpack-dev-server --config webpack.config.js`, {\n    async: true\n  })\n}\n\ncli({\n  command\n})\n```\n\n```bash\n$ npx task command\n```\n\nBecause `./node_modules/.bin` is included in `PATH` when calling shell commands\nby `sh` function, you can call \"bins\" from your local project in the same way as \nin npm scripts.\n\n### Handling arguments\n\nProvided arguments in the command line are passed to the function:\n\n\n```javascript\nfunction sayHello (options, who) {\n  console.log(`Hello ${who}!`)\n}\n\ncli({\n  sayHello\n})\n```\n\n```bash\n$ npx task sayHello world\nHello world!\n```\n    \nYou can also provide dash arguments like `-a` or `--test`. Order of them doesn't \nmatter after task name. They will be always available by `options` helper \nfrom inside a function.\n\n```javascript\nfunction sayHello (options, who) {\n  console.log(`Hello ${who}!`)\n  console.log('Given options:', options)\n}\n\ncli({\n  sayHello\n})\n```\n\n```bash\n$ npx task sayHello -a --test=something world\nHello world!\nGiven options: { a: true, test: 'something' }\n```\n    \n    \n### Documenting tasks\n\nTo display all available tasks for your `tasksfile.js` type `task` in your command line\nwithout any arguments:\n\n    $ npx task --help\n\n    Commands:\n    \n    echo                    - echo task description\n    buildjs                 - Compile JS files\n    \nUse `help` utility function for your task to get additional description:\n\n```javascript\nconst { cli, help } = require('tasksfile')\n\nfunction buildjs () {\n  \n}\n\nhelp(buildjs, 'Compile JS files')\n\ncli({\n  buildjs\n})\n```\n\n    $ npx task buildjs --help\n    Usage: buildjs\n    \n    Compile JS files\n    \nYou can provide detailed annotation to give even more info about the task:\n\n```javascript\nconst dedent = require('dedent')\nconst { sh, help } = require('tasksfile')\n\nfunction test (options, file) {\n  \n}\n\nhelp(test, 'Run unit tests', {\n  params: ['file'],\n  options: {\n    watch: 'run tests in a watch mode'\n  },\n  examples: dedent`\n    task test dummyComponent.js\n    task test dummyComponent.js --watch\n  `\n})\n\ncli({\n  test\n})\n```\n\n    $ npx task test --help\n    Usage: test [options] [file]\n    \n    Run unit tests\n    \n    Options:\n    \n      --watch       run tests in a watch mode\n      \n    Examples:\n    \n    task test dummyComponent.js\n    task test dummyComponent.js --watch\n\n\n### Namespacing\n\nTo better organise tasks, it is possible to call them from namespaces:\n```js\nconst test = {\n  unit () {\n    console.log('Doing unit testing!')\n  }\n}\n\ncli({\n  test\n})\n```\n\n```bash\n$ npx task test:unit\nDoing unit testing!\n```\n\nThis is especially useful if `tasksfile.js` gets too large. We can move some tasks\nto external modules and import them back to a namespace:\n\n`./tasks/test.js`:\n\n```javascript\nfunction unit () {\n  console.log('Doing unit testing!')\n}\n\nfunction integration () {\n  console.log('Doing unit testing!')\n}\n\nfunction default() {\n  unit()\n  integration()\n}\n\nmodule.exports = {\n  unit,\n  integration,\n  default\n}\n```\n\n`tasksfile.js`\n```js\nconst test = require('./tasks/test')\n\ncli({\n  test\n})\n```\n\n```bash\n$ npx task test:unit\nDoing unit testing!\n\n$ npx task test\nDoing unit testing!\nDoing integration testing!\n```\n\nIf we don't want to put imported tasks into a namespace, we can always use spread\noperator:\n\n```js\ncli({\n  ...test\n})\n```\n\n```bash\n$ npx task unit\nDoing unit testing!\n```\n\nWith ES6 modules import/export syntax this becomes even simpler:\n\n```js\n// export with no namespace\nexport * from './tasks/test' // no namespace\n\n// export with namespace\nimport * as test from './tasks/test'\nexport { test } // add namespace\n```\n\n```bash\n$ npx task unit\n$ npx task test:unit\n```\n\n### Sharing tasks\n\nBecause `tasksfile.js` is just a node.js module and `tasksfile` just calls exported\nfunctions from that module based on cli arguments, nothing stops you to move \nsome repetitive tasks across your projects to external npm package and \njust reuse it.\n\n`shared-tasksfile` module:\n```js\nfunction shared1 () {\n  console.log('This task is shared!')\n}\n\nfunction shared2 () {\n  console.log('This task is shared!')\n}\n\nmodule.exports = {\n  shared1,\n  shared2\n}\n```\n\nLocal `tasksfile.js`\n```js\nconst shared = require('shared-tasksfile')\n\nfunction local () {\n  console.log('This task is local!')\n}\n\ncli({\n  ...shared,\n  local\n})\n```\n\n```bash\n$ npx task shared1\n$ npx task shared2\n$ npx task local\n```\n\n### TypeScript support\n\nIt's very easy to run your tasks in `TypeScript` if you have `TypeScript` already\nin your project. Just:\n\n- change your `tasksfile.js` to `tasksfile.ts` and adjust the code\n- install `ts-node`: `npm install --save-dev ts-node`\n- change command in your `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"task\": \"ts-node ./tasksfile.ts\"\n  }\n}\n```\n\n`Tasksfile` project already has `TypeScript` declaration files in source files.\n\n## API\n\nFor inside `tasksfile.js` usage.\n\n#### sh(cmd, options)\n\nRun given command as a child process and log the call in the output. \n`./node_modules/.bin/` is included into `PATH` so you can call installed scripts directly.\n\nFunction will return output of executed command.\n\n```js\nconst { sh } = require('tasksfile')\n```\n\n*Options:*\n\n```ts\ninterface IShellOptions {\n  // current working directory\n  cwd?: string\n\n  // environment key-value pairs\n  env?: NodeJS.ProcessEnv\n\n  // timeout after which execution will be cancelled\n  timeout?: number\n\n  // default: false, if true it runs command asynchronously and returns a Promise\n  async?: boolean\n\n  // if true, it will send output directly to parent process (stdio=\"inherit\"), it won't return the output though\n  // usefull if default piping strips too much colours when printing to the terminal\n  // if enabled, transform option won't work\n  nopipe?: boolean\n\n  // if true, it won't print anything to the terminal but it will still return the output as a string\n  silent?: boolean\n\n  // function which allows to transform the output, line by line\n  // usefull for adding prefixes to async commands output\n  transform?: (output: string) => string\n}\n```\n\n#### prefixTransform(prefix)\n\nTransform function which can be used as `transform` option of `sh` function.\nIt allows to add prefixes to shell output.\n\n*Example:*\n\n```js\nconst { cli, sh, prefixTransform } = require('tasksfile')\n\nfunction test() {\n  sh('echo \"test\"', { \n    transform: prefixTransform('[prefix]')\n  })\n}\n\ncli({\n  test\n})\n```\n\n```sh\n$ npx task test\necho \"test\"\n[prefix] test\n```\n\n\n#### help(func, description, annotation)\n\nDefine help annotation for task function, so it will be printed out when calling task with `--help`\noption and when calling `run` without any arguments.\n\n```js\nconst { help } = require('tasksfile')\n```\n\n\n```javascript\nhelp(build, 'Generate JS bundle')\n\nhelp(test, 'Run unit tests', {\n  params: ['file'],\n  options: {\n    watch: 'run tests in a watch mode'\n  },\n  examples: `\n    task test dummyComponent.js\n    task test dummyComponent.js --watch\n  `\n})\n```\n\n    $ npx task build --help\n    $ npx task test --help\n\n\n#### rawArgs()\n\nReturns arguments / options passed to task in a raw, unparsed format.\n\n```javascript\nconst { cli, rawArgs } = require('tasksfile')\n\nfunction hello(options) {\n  console.log('RAW ARGS', rawArgs())\n}\n\ncli({\n  hello\n})\n```\n\n```sh\n$ npx task hello 1 2 3 --test\nRAW ARGS ['1', '2', '3', '--test']\n```"
  },
  {
    "path": "bin/task.js",
    "content": "#!/usr/bin/env node\nconst { execSync } = require('child_process')\nconst path = require('path')\nconst packageJson = require(path.resolve('./package.json'))\n\nconst taskScript = packageJson.scripts.task\n\ntry {\n  execSync(`${taskScript} ${process.argv.slice(2).join(' ')}`, {shell: true, stdio: 'inherit'})\n} catch (error) {\n  process.exit(1)\n}\n"
  },
  {
    "path": "jest.config.js",
    "content": "// For a detailed explanation regarding each configuration property, visit:\n// https://jestjs.io/docs/en/configuration.html\n\nmodule.exports = {\n  // A list of paths to directories that Jest should use to search for files in.\n  roots: [\"<rootDir>/src/\", \"<rootDir>/test/\"],\n  \n  // The test environment that will be used for testing\n  testEnvironment: \"node\",\n\n  // A list of reporter names that Jest uses when writing coverage reports\n  coverageReporters: [\n    \"text\",\n    \"text-summary\"\n  ],\n\n  // An object that configures minimum threshold enforcement for coverage results\n  coverageThreshold: {\n    \"global\": {\n      \"lines\": 30\n    }\n  }\n};"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"tasksfile\",\n  \"version\": \"5.1.1\",\n  \"description\": \"Minimalistic task runner for node.js\",\n  \"keywords\": [\n    \"build\",\n    \"system\",\n    \"make\",\n    \"tool\"\n  ],\n  \"main\": \"lib/index.js\",\n  \"types\": \"lib/index.d.ts\",\n  \"bin\": {\n    \"task\": \"bin/task.js\"\n  },\n  \"scripts\": {\n    \"lint\": \"tslint -c tslint.json 'src/*.ts' 'test/**/*.ts'\",\n    \"build\": \"tsc\",\n    \"test\": \"yarn lint && yarn build && yarn clean:sandbox && jest --coverage\",\n    \"test:unit\": \"jest ./src/\",\n    \"test:e2e\": \"jest ./test/\",\n    \"clean\": \"rm -rf node_modules && yarn clean:build && yarn clean:sandbox\",\n    \"clean:build\": \"rm -rf ./lib\",\n    \"clean:sandbox\": \"rm -rf ./test/e2e/sandbox/node_modules && mkdir -p ./test/sandbox/node_modules/.bin\",\n    \"sandbox:task\": \"cd ./test/sandbox && ../../bin/task.js\"\n  },\n  \"lint-staged\": {\n    \"src/*.{ts,tsx}\": [\n      \"tslint --fix\",\n      \"git add\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=6.11.1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/pawelgalazka/tasksfile.git\"\n  },\n  \"author\": \"Pawel Galazka\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/pawelgalazka/tasksfile/issues\"\n  },\n  \"homepage\": \"https://github.com/pawelgalazka/tasksfile#readme\",\n  \"dependencies\": {\n    \"@pawelgalazka/cli\": \"2.0.3\",\n    \"@pawelgalazka/shell\": \"2.0.0\",\n    \"chalk\": \"2.3.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.2.2\",\n    \"@babel/preset-env\": \"7.3.1\",\n    \"@babel/preset-typescript\": \"7.1.0\",\n    \"@types/jest\": \"24.0.0\",\n    \"@types/lodash.padend\": \"4.6.4\",\n    \"@types/node\": \"10.12.18\",\n    \"husky\": \"1.3.1\",\n    \"jest\": \"24.1.0\",\n    \"lint-staged\": \"8.1.0\",\n    \"prettier\": \"1.15.3\",\n    \"tslint\": \"5.12.1\",\n    \"tslint-config-prettier\": \"1.17.0\",\n    \"tslint-plugin-prettier\": \"2.0.1\",\n    \"typescript\": \"3.2.2\"\n  }\n}\n"
  },
  {
    "path": "src/index.spec.ts",
    "content": "import { shell } from '@pawelgalazka/shell'\nimport chalk from 'chalk'\n\nimport { sh } from './index'\n\nconst shellMock = shell as jest.Mock\n\njest.mock('@pawelgalazka/shell')\n\nprocess.env = { DEFAULT_ENV: 'default env' }\n\ndescribe('sh()', () => {\n  let logger: any\n\n  beforeEach(() => {\n    jest.resetAllMocks()\n    logger = {\n      error: jest.fn(),\n      log: jest.fn(),\n      title: jest.fn(),\n      warning: jest.fn()\n    }\n  })\n\n  it('calls original @pawelgalazka/shell function with the same command', () => {\n    sh('test command', undefined, logger)\n    expect(shellMock).toHaveBeenCalledTimes(1)\n    expect(shellMock).toHaveBeenCalledWith('test command', expect.anything())\n  })\n\n  it('logs executed command', () => {\n    sh('test command', undefined, logger)\n    expect(logger.log).toHaveBeenCalledTimes(1)\n    expect(logger.log).toHaveBeenCalledWith(chalk.bold('test command'))\n  })\n\n  it('calls original @pawelgalazka/shell with default options values', () => {\n    sh('test command', undefined, logger)\n    expect(shellMock).toHaveBeenCalledTimes(1)\n    expect(shellMock).toHaveBeenCalledWith(expect.anything(), {\n      env: {\n        DEFAULT_ENV: 'default env',\n        PATH: expect.anything()\n      }\n    })\n  })\n\n  it('calls original @pawelgalazka/shell with given options values', () => {\n    sh(\n      'test command',\n      {\n        async: true,\n        cwd: 'cwd-dir',\n        env: { CUSTOM_ENV: 'custom env' },\n        stdio: 'pipe',\n        timeout: 1000\n      },\n      logger\n    )\n    expect(shellMock).toHaveBeenCalledTimes(1)\n    expect(shellMock).toHaveBeenCalledWith(expect.anything(), {\n      async: true,\n      cwd: 'cwd-dir',\n      env: {\n        CUSTOM_ENV: 'custom env',\n        PATH: expect.anything()\n      },\n      stdio: 'pipe',\n      timeout: 1000\n    })\n  })\n\n  it('adds ./node_modules/.bin to $PATH', () => {\n    sh('test command', undefined, logger)\n    expect(shellMock).toHaveBeenCalledWith(\n      expect.anything(),\n      expect.objectContaining({\n        env: expect.objectContaining({\n          PATH: expect.stringContaining('node_modules/.bin:')\n        })\n      })\n    )\n  })\n})\n"
  },
  {
    "path": "src/index.ts",
    "content": "import {\n  cli as cliEngine,\n  CLIError,\n  CommandsModule,\n  Middleware,\n  useMiddlewares\n} from '@pawelgalazka/cli'\nimport { Logger } from '@pawelgalazka/cli/lib/utils/logger'\nimport {\n  IAsyncShellOptions,\n  IShellOptions,\n  ISyncShellOptions,\n  shell,\n  ShellError\n} from '@pawelgalazka/shell'\nimport chalk from 'chalk'\nimport path from 'path'\n\nexport { help, rawArgs } from '@pawelgalazka/cli'\nexport { prefixTransform } from '@pawelgalazka/shell'\n\nconst commandNotFoundHandler: Middleware = next => args => {\n  const { command } = args\n\n  if (!command) {\n    throw new CLIError(\n      'Command not found. Type \"npx task --help\" for more information.'\n    )\n  }\n\n  next(args)\n}\nconst shellErrorHandler: (\n  logger: Logger\n) => Middleware = logger => next => args => {\n  const { reject } = args\n  const nextReject = (error: Error) => {\n    if (error instanceof ShellError) {\n      logger.error(error.message)\n      process.exit(1)\n    } else {\n      reject(error)\n    }\n  }\n  try {\n    next({\n      ...args,\n      reject: nextReject\n    })\n  } catch (error) {\n    nextReject(error)\n  }\n}\n\nexport function sh(\n  command: string,\n  options: IAsyncShellOptions,\n  logger?: Logger\n): Promise<string | null>\n\nexport function sh(\n  command: string,\n  options?: ISyncShellOptions,\n  logger?: Logger\n): string | null\n\nexport function sh(\n  command: string,\n  options: IShellOptions = {},\n  logger: Logger = new Logger()\n) {\n  const binPath = path.resolve('./node_modules/.bin')\n  // Include in PATH node_modules bin path\n  const nextPath = [\n    binPath,\n    (options.env && options.env.PATH) || process.env.PATH\n  ].join(path.delimiter)\n\n  const nextOptions = {\n    ...options,\n    env: {\n      ...(options.env || process.env),\n      PATH: nextPath\n    }\n  }\n\n  logger.log(chalk.bold(command))\n\n  return shell(command, nextOptions)\n}\n\nexport function cli(definition: CommandsModule) {\n  return cliEngine(\n    definition,\n    useMiddlewares([commandNotFoundHandler, shellErrorHandler(new Logger())])\n  )\n}\n"
  },
  {
    "path": "test/__snapshots__/e2e.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`tasksfile displays commands list if only --help option provided and no task name 1`] = `\n\"\nCommands:\n\nasyncAwait\ncolor\necho                                     - Simple echo task\nerror\nerrorAsyncAwait\nnested\nnested:echo [p1 p2]                      - Description of nested task\nnpmBin\nshell\n\"\n`;\n"
  },
  {
    "path": "test/e2e.spec.ts",
    "content": "/* eslint-env jest */\nimport { execSync as orgExecSync } from 'child_process'\n\ndescribe('tasksfile', () => {\n  const scriptPath = '../../bin/task.js'\n  function execSync(cmd: string) {\n    return orgExecSync(cmd, {\n      cwd: './test/sandbox',\n      env: {\n        ...process.env,\n        FORCE_COLOR: '0'\n      },\n      stdio: 'pipe'\n    }).toString()\n  }\n\n  it('executes simple task', () => {\n    expect(execSync(`${scriptPath} echo 1 2 3 --foo --bar`)).toEqual(\n      \"echo [ { foo: true, bar: true }, '1', '2', '3' ]\\n\"\n    )\n  })\n\n  it('executes shell commands in a task', () => {\n    const output = execSync(`${scriptPath} shell`)\n    expect(output).toContain(\n      'echo \"sync terminal\"\\nsync terminal\\necho \"sync silent\"\\noutput sync silent'\n    )\n    expect(output).toContain('\\nasync terminal\\n')\n    expect(output).toContain('\\noutput async silent\\n')\n  })\n\n  it('executes task from a namespace', () => {\n    expect(execSync(`${scriptPath} nested:echo 1 2 3 --foo --bar`)).toEqual(\n      \"nested echo [ { foo: true, bar: true }, '1', '2', '3' ]\\n\"\n    )\n  })\n\n  it('executes default task from a namespace', () => {\n    expect(execSync(`${scriptPath} nested 1 2 3 --foo --bar`)).toEqual(\n      \"nested default [ { foo: true, bar: true }, '1', '2', '3' ]\\n\"\n    )\n  })\n\n  it('includes ./node_modules/.bin to PATH when executing bin scripts', () => {\n    execSync('cp -p ./scripts/hello.js ./node_modules/.bin/hello')\n    expect(execSync(`${scriptPath} npmBin`)).toEqual('hello\\nHello!\\n')\n  })\n\n  it('executes async/await task', () => {\n    expect(execSync(`${scriptPath} asyncAwait`)).toContain(\n      'echo \"async and await\"\\noutput async and await\\n\\nafter await\\n'\n    )\n  })\n\n  it('displays help for a task', () => {\n    expect(execSync(`${scriptPath} echo --help`)).toEqual(\n      'Usage: echo  \\n\\nSimple echo task\\n\\n'\n    )\n  })\n\n  it('displays detailed help', () => {\n    expect(execSync(`${scriptPath} nested:echo --help`)).toEqual(\n      'Usage: nested:echo [options] [p1 p2]\\n\\nDescription of nested task\\n\\n' +\n        'Options:\\n\\n  --foo       foo option description\\n' +\n        '  --bar       bar option description\\n'\n    )\n  })\n\n  it('displays error from executed task', () => {\n    expect(() => execSync(`${scriptPath} error`)).toThrow(\n      `Command failed: ${scriptPath} error`\n    )\n  })\n\n  it('displays error from executed async task', () => {\n    expect(() => execSync(`${scriptPath} errorAsyncAwait`)).toThrow(\n      `Command failed: ${scriptPath} errorAsyncAwait`\n    )\n  })\n\n  it('displays commands list if only --help option provided and no task name', () => {\n    expect(execSync(`${scriptPath} --help`)).toMatchSnapshot()\n  })\n})\n"
  },
  {
    "path": "test/sandbox/package.json",
    "content": "{\n  \"name\": \"sandbox\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"task\": \"node ./tasksfile.js\"\n  }\n}\n"
  },
  {
    "path": "test/sandbox/scripts/color.js",
    "content": "const chalk = require('chalk')\n\nconsole.log(chalk.yellow('This should be in yellow color'))\n"
  },
  {
    "path": "test/sandbox/scripts/error.js",
    "content": "throw new Error('error message')\n"
  },
  {
    "path": "test/sandbox/scripts/hello.js",
    "content": "#!/usr/bin/env node\n\nconsole.log('Hello!')\n"
  },
  {
    "path": "test/sandbox/tasksfile.js",
    "content": "const { sh, help, cli } = require('../../lib')\n\nhelp(echo, 'Simple echo task')\n\nfunction echo(...args) {\n  console.log('echo', args)\n}\n\nconst nested = {\n  echo(...args) {\n    console.log('nested echo', args)\n  },\n\n  default (...args) {\n    console.log('nested default', args)\n  }\n}\n\nhelp(nested.echo, 'Description of nested task', {\n  options: {\n    foo: 'foo option description',\n    bar: 'bar option description'\n  },\n  params: ['p1', 'p2']\n})\n\nfunction shell() {\n  sh('echo \"sync terminal\"')\n  console.log('output', sh('echo \"sync silent\"', {silent: true}))\n  sh('echo \"async terminal\"', { async: true })\n  sh('echo \"async silent\"', { async: true, silent: true}).then(output =>\n    console.log('output', output)\n  )\n}\n\nfunction npmBin() {\n  sh('hello')\n}\n\nasync function asyncAwait() {\n  const output = await sh('echo \"async and await\"', {\n    async: true,\n    silent: true\n  })\n  console.log('output', output)\n  console.log('after await')\n}\n\nfunction error() {\n  sh('node ./scripts/error.js', { async: true })\n  sh('node ./scripts/error.js')\n}\n\nasync function errorAsyncAwait() {\n  await Promise.reject(new Error('async await error'))\n}\n\nfunction color() {\n  sh('node ./scripts/color.js')\n  sh('node ./scripts/color.js', { async: true })\n}\n\n\ncli({\n  echo,\n  shell,\n  nested,\n  npmBin,\n  asyncAwait,\n  errorAsyncAwait,\n  error,\n  color\n})\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    /* Basic Options */\n    \"target\": \"es2015\",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */\n    \"module\": \"commonjs\",                        /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */\n    \"lib\": [\"es2017\"],                           /* Specify library files to be included in the compilation. */\n    \"declaration\": true,                         /* Generates corresponding '.d.ts' file. */\n    \"sourceMap\": true,                           /* Generates corresponding '.map' file. */\n    \"outDir\": \"./lib\",                           /* Redirect output structure to the directory. */\n\n    /* Strict Type-Checking Options */\n    \"strict\": true,                           /* Enable all strict type-checking options. */\n\n    /* Additional Checks */\n    \"noUnusedLocals\": true,                   /* Report errors on unused locals. */\n    \"noUnusedParameters\": true,               /* Report errors on unused parameters. */\n    \"noImplicitReturns\": true,                /* Report error when not all code paths in function return a value. */\n    \"noFallthroughCasesInSwitch\": true,       /* Report errors for fallthrough cases in switch statement. */\n\n    /* Module Resolution Options */\n    \"moduleResolution\": \"node\",               /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */\n    \"baseUrl\": \"./\",                          /* Base directory to resolve non-absolute module names. */\n    \"esModuleInterop\": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */\n  },\n  \"include\": [\n    \"src/**/*\"\n  ],\n  \"exclude\": [\n    \"**/*.spec.ts\"\n  ]\n}"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"extends\": [\n      \"tslint:latest\", \"tslint-config-prettier\"\n  ],\n  \"rules\": {\n      \"prettier\": true,\n      \"max-classes-per-file\": false,\n      \"no-console\": false,\n      \"no-empty\": false,\n      \"no-shadowed-variable\": false,\n      \"no-submodule-imports\": false\n  },\n  \"rulesDirectory\": [\"tslint-plugin-prettier\"]\n}"
  }
]