# composer [![NPM version](https://img.shields.io/npm/v/composer.svg?style=flat)](https://www.npmjs.com/package/composer) [![NPM monthly downloads](https://img.shields.io/npm/dm/composer.svg?style=flat)](https://npmjs.org/package/composer) [![NPM total downloads](https://img.shields.io/npm/dt/composer.svg?style=flat)](https://npmjs.org/package/composer) [![Linux Build Status](https://img.shields.io/travis/doowb/composer.svg?style=flat&label=Travis)](https://travis-ci.org/doowb/composer) [![Windows Build Status](https://img.shields.io/appveyor/ci/doowb/composer.svg?style=flat&label=AppVeyor)](https://ci.appveyor.com/project/doowb/composer)

> Run and compose async tasks. Easily define groups of tasks to run in series or parallel.

Please consider following this project's author, [Brian Woodward](https://github.com/doowb), and consider starring the project to show your :heart: and support.

- [Install](#install)
- [Usage](#usage)
- [API](#api)
  * [Tasks](#tasks)
  * [Generators](#generators)
- [Events](#events)
  * [task](#task)
  * [task-pending](#task-pending)
  * [task-preparing](#task-preparing)
- [Release history](#release-history)
- [About](#about)

_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_

## Install

Install with [npm](https://www.npmjs.com/):

```sh
$ npm install --save composer
```

## Usage

```js
// Create an instance of `Composer`
const Composer = require('composer');
const composer = new Composer();

// Define tasks with the .task() method
composer.task('foo', callback => {
  callback(); // do stuff
});
composer.task('bar', callback => {
  callback(); // do stuff
});

composer.task('baz', ['foo'. 'bar']);

// Run tasks with the .build() method
composer.build('baz')
  .then(() => console.log('done!'))
  .catch(console.error);
```

## API

### [.factory](lib/tasks.js#L27)

Factory for creating a custom `Tasks` class that extends the given `Emitter`. Or, simply call the factory function to use the built-in emitter.

**Params**

* `Emitter` **{function}**: Event emitter.
* `returns` **{Class}**: Returns a custom `Tasks` class.

**Example**

```js
// custom emitter
const Emitter = require('events');
const Tasks = require('composer/lib/tasks')(Emitter);
// built-in emitter
const Tasks = require('composer/lib/tasks')();
const composer = new Tasks();
```

### [Tasks](lib/tasks.js#L42)

Create an instance of `Tasks` with the given `options`.

**Params**

* `options` **{object}**

**Example**

```js
const Tasks = require('composer').Tasks;
const composer = new Tasks();
```

### [.task](lib/tasks.js#L86)

Define a task. Tasks run asynchronously, either in series (by default) or parallel (when `options.parallel` is true). In order for the build to determine when a task is complete, _one of the following_ things must happen: 1) the callback must be called, 2) a promise must be returned, or 3) a stream must be returned. Inside tasks, the "this" object is a composer Task instance created for each task with useful properties like the task name, options and timing information, which can be useful for logging, etc.

**Params**

* `name` **{String}**: The task name.
* `deps` **{Object|Array|String|Function}**: Any of the following: task dependencies, callback(s), or options object, defined in any order.
* `callback` **{Function}**: (optional) If the last argument is a function, it will be called after all of the task's dependencies have been run.
* `returns` **{undefined}**

**Example**

```js
// 1. callback
app.task('default', cb => {
  // do stuff
  cb();
});
// 2. promise
app.task('default', () => {
  return Promise.resolve(null);
});
// 3. stream (using vinyl-fs or your stream of choice)
app.task('default', function() {
  return vfs.src('foo/*.js');
});
```

### [.build](lib/tasks.js#L209)

Run one or more tasks.

**Params**

* `tasks` **{object|array|string|function}**: One or more tasks to run, options, or callback function. If no tasks are defined, the default task is automatically run.
* `callback` **{function}**: (optional)
* `returns` **{undefined}**

**Example**

```js
const build = app.series(['foo', 'bar', 'baz']);
// promise
build().then(console.log).catch(console.error);
// or callback
build(function() {
  if (err) return console.error(err);
});
```

### [.series](lib/tasks.js#L251)

Compose a function to run the given tasks in series.

**Params**

* `tasks` **{object|array|string|function}**: Tasks to run, options, or callback function. If no tasks are defined, the `default` task is automatically run, if one exists.
* `callback` **{function}**: (optional)
* `returns` **{promise|undefined}**: Returns a promise if no callback is passed.

**Example**

```js
const build = app.series(['foo', 'bar', 'baz']);
// promise
build().then(console.log).catch(console.error);
// or callback
build(function() {
  if (err) return console.error(err);
});
```

### [.parallel](lib/tasks.js#L304)

Compose a function to run the given tasks in parallel.

**Params**

* `tasks` **{object|array|string|function}**: Tasks to run, options, or callback function. If no tasks are defined, the `default` task is automatically run, if one exists.
* `callback` **{function}**: (optional)
* `returns` **{promise|undefined}**: Returns a promise if no callback is passed.

**Example**

```js
// call the returned function to start the build
const build = app.parallel(['foo', 'bar', 'baz']);
// promise
build().then(console.log).catch(console.error);
// callback
build(function() {
  if (err) return console.error(err);
});
// example task usage
app.task('default', build);
```

### [.create](lib/tasks.js#L388)

Static method for creating a custom Tasks class with the given `Emitter.

**Params**

* `Emitter` **{Function}**
* `returns` **{Class}**: Returns the custom class.

### [.create](lib/generator.js#L30)

Static factory method for creating a custom `Composer` class that extends the given `Emitter`.

**Params**

* `Emitter` **{Function}**: Event emitter.
* `returns` **{Class}**: Returns a custom `Composer` class.

**Example**

```js
// Composer extends a basic event emitter by default
const Composer = require('composer');
const composer = new Composer();

// Create a custom Composer class with your even emitter of choice
const Emitter = require('some-emitter');
const CustomComposer = Composer.create(Emitter);
const composer = new CustomComposer();
```

**Params**

* `name` **{String}**
* `options` **{Object}**
* `returns` **{Object}**: Returns an instance of Composer.

**Example**

```js
const composer = new Composer();
```

Create a wrapped generator function with the given `name`, `config`, and `fn`.

**Params**

* `name` **{String}**
* `config` **{Object}**: (optional)
* `fn` **{Function}**
* `returns` **{Function}**

Returns true if the given value is a Composer generator object.

**Params**

* `val` **{Object}**
* `returns` **{Boolean}**

### [.register](lib/generator.js#L167)

Alias to `.setGenerator`.

**Params**

* `name` **{String}**: The generator's name
* `options` **{Object|Function|String}**: or generator
* `generator` **{Object|Function|String}**: Generator function, instance or filepath.
* `returns` **{Object}**: Returns the generator instance.

**Example**

```js
app.register('foo', function(app, base) {
  // "app" is a private instance created for the generator
  // "base" is a shared instance
});
```

### [.generator](lib/generator.js#L190)

Get and invoke generator `name`, or register generator `name` with the given `val` and `options`, then invoke and return the generator instance. This method differs from `.register`, which lazily invokes generator functions when `.generate` is called.

**Params**

* `name` **{String}**
* `fn` **{Function|Object}**: Generator function, instance or filepath.
* `returns` **{Object}**: Returns the generator instance or undefined if not resolved.

**Example**

```js
app.generator('foo', function(app, options) {
  // "app" - private instance created for generator "foo"
  // "options" - options passed to the generator
});
```

### [.setGenerator](lib/generator.js#L222)

Store a generator by file path or instance with the given `name` and `options`.

**Params**

* `name` **{String}**: The generator's name
* `options` **{Object|Function|String}**: or generator
* `generator` **{Object|Function|String}**: Generator function, instance or filepath.
* `returns` **{Object}**: Returns the generator instance.

**Example**

```js
app.setGenerator('foo', function(app, options) {
  // "app" - new instance of Generator created for generator "foo"
  // "options" - options passed to the generator
});
```

### [.getGenerator](lib/generator.js#L247)

Get generator `name` from `app.generators`, same as [findGenerator], but also invokes the returned generator with the current instance. Dot-notation may be used for getting sub-generators.

**Params**

* `name` **{String}**: Generator name.
* `returns` **{Object|undefined}**: Returns the generator instance or undefined.

**Example**

```js
const foo = app.getGenerator('foo');

// get a sub-generator
const baz = app.getGenerator('foo.bar.baz');
```

### [.findGenerator](lib/generator.js#L280)

Find generator `name`, by first searching the cache, then searching the cache of the `base` generator. Use this to get a generator without invoking it.

**Params**

* `name` **{String}**
* `options` **{Function}**: Optionally supply a rename function on `options.toAlias`
* `returns` **{Object|undefined}**: Returns the generator instance if found, or undefined.

**Example**

```js
// search by "alias"
const foo = app.findGenerator('foo');

// search by "full name"
const foo = app.findGenerator('generate-foo');
```

**Params**

* `name` **{String}**
* `returns` **{Boolean}**

**Example**

```js
console.log(app.hasGenerator('foo'));
console.log(app.hasGenerator('foo.bar'));
```

### [.generate](lib/generator.js#L362)

Run one or more tasks or sub-generators and returns a promise.

**Params**

* `name` **{String}**
* `tasks` **{String|Array}**
* `returns` **{Promise}**

**Events**

* `emits`: `generate` with the generator `name` and the array of `tasks` that are queued to run.

**Example**

```js
// run tasks `bar` and `baz` on generator `foo`
app.generate('foo', ['bar', 'baz']);

// or use shorthand
app.generate('foo:bar,baz');

// run the `default` task on generator `foo`
app.generate('foo');

// run the `default` task on the `default` generator, if defined
app.generate();
```

### [.toAlias](lib/generator.js#L413)

Create a generator alias from the given `name`. By default, `generate-` is stripped from beginning of the generator name.

**Params**

* `name` **{String}**
* `options` **{Object}**
* `returns` **{String}**: Returns the alias.

**Example**

```js
// customize the alias
const app = new Generate({ toAlias: require('camel-case') });
```

### [.isGenerators](lib/generator.js#L434)

Returns true if every name in the given array is a registered generator.

**Params**

* `names` **{Array}**
* `returns` **{Boolean}**

### [.formatError](lib/generator.js#L446)

Format task and generator errors.

**Params**

* `name` **{String}**
* `returns` **{Error}**

### [.disableInspect](lib/generator.js#L466)

Disable inspect. Returns a function to re-enable inspect. Useful for debugging.

### [.base](lib/generator.js#L504)

Get the first ancestor instance of Composer. Only works if `generator.parent` is
defined on child instances.

### [.name](lib/generator.js#L517)

Get or set the generator name.

**Params**

* **{String}**

* `returns` **{String}**

### [.alias](lib/generator.js#L534)

Get or set the generator `alias`. By default, the generator alias is created
by passing the generator name to the [.toAlias](#toAlias) method.

**Params**

* **{String}**

* `returns` **{String}**

### [.namespace](lib/generator.js#L551)

Get the generator namespace. The namespace is created by joining the generator's `alias`
to the alias of each ancestor generator.

**Params**

* **{String}**

* `returns` **{String}**

### [.depth](lib/generator.js#L564)

Get the depth of a generator - useful for debugging. The root generator
has a depth of `0`, sub-generators add `1` for each level of nesting.

* `returns` **{Number}**

### [Composer#parse](lib/generator.js#L577)

Static method that returns a function for parsing task arguments.

**Params**

* `register` **{Function}**: Function that receives a name of a task or generator that cannot be found by the parse function. This allows the `register` function to dynamically register tasks or generators.
* `returns` **{Function}**: Returns a function for parsing task args.

### [Composer#isGenerator](lib/generator.js#L590)

Static method that returns true if the given `val` is an instance of Generate.

**Params**

* `val` **{Object}**
* `returns` **{Boolean}**

### [Composer#create](lib/generator.js#L603)

Static method for creating a custom Composer class with the given `Emitter.

**Params**

* `Emitter` **{Function}**
* `returns` **{Class}**: Returns the custom class.

### [Composer#Tasks](lib/generator.js#L617)

Static getter for getting the Tasks class with the same `Emitter` class as Composer.

**Params**

* `Emitter` **{Function}**
* `returns` **{Class}**: Returns the Tasks class.

### [Composer#Task](lib/generator.js#L633)

Static getter for getting the `Task` class.

**Example**

```js
const { Task } = require('composer');
```

## Events

### task

```js
app.on('task', function(task) {
  switch (task.status) {
    case 'starting':
      // Task is running
      break;
    case 'finished':
      // Task is finished running
      break;
  }
});
```

### task-pending

Emitted after a task is registered.

### task-preparing

Emitted when a task is preparing to run, right before it's called. You can use this event to dynamically skip tasks by updating `task.skip` to `true` or a function.

## Release history

See the [changelog](./CHANGELOG.md).

## About

<details>
<summary><strong>Contributing</strong></summary>

Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).

</details>

<details>
<summary><strong>Running Tests</strong></summary>

Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:

```sh
$ npm install && npm test
```

</details>

<details>
<summary><strong>Building docs</strong></summary>

_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_

To generate the readme, run the following command:

```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```

</details>

### Related projects

You might also be interested in these projects:

* [assemble](https://www.npmjs.com/package/assemble): Get the rocks out of your socks! Assemble makes you fast at creating web projects… [more](https://github.com/assemble/assemble) | [homepage](https://github.com/assemble/assemble "Get the rocks out of your socks! Assemble makes you fast at creating web projects. Assemble is used by thousands of projects for rapid prototyping, creating themes, scaffolds, boilerplates, e-books, UI components, API documentation, blogs, building websit")
* [enquirer](https://www.npmjs.com/package/enquirer): Stylish, intuitive and user-friendly prompt system. Fast and lightweight enough for small projects, powerful and… [more](https://github.com/enquirer/enquirer) | [homepage](https://github.com/enquirer/enquirer "Stylish, intuitive and user-friendly prompt system. Fast and lightweight enough for small projects, powerful and extensible enough for the most advanced use cases.")
* [generate](https://www.npmjs.com/package/generate): Command line tool and developer framework for scaffolding out new GitHub projects. Generate offers the… [more](https://github.com/generate/generate) | [homepage](https://github.com/generate/generate "Command line tool and developer framework for scaffolding out new GitHub projects. Generate offers the robustness and configurability of Yeoman, the expressiveness and simplicity of Slush, and more powerful flow control and composability than either.")
* [update](https://www.npmjs.com/package/update): Be scalable! Update is a new, open source developer framework and CLI for automating updates… [more](https://github.com/update/update) | [homepage](https://github.com/update/update "Be scalable! Update is a new, open source developer framework and CLI for automating updates of any kind in code projects.")
* [verb](https://www.npmjs.com/package/verb): Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used… [more](https://github.com/verbose/verb) | [homepage](https://github.com/verbose/verb "Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used on hundreds of projects of all sizes to generate everything from API docs to readmes.")

### Contributors

| **Commits** | **Contributor** |  
| --- | --- |  
| 227 | [doowb](https://github.com/doowb) |  
| 72  | [jonschlinkert](https://github.com/jonschlinkert) |  

### Author

**Brian Woodward**

* [GitHub Profile](https://github.com/doowb)
* [Twitter Profile](https://twitter.com/doowb)
* [LinkedIn Profile](https://linkedin.com/in/woodwardbrian)

### License

Copyright © 2018, [Brian Woodward](https://github.com/doowb).
Released under the [MIT License](LICENSE).

***

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on November 11, 2018._