You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					461 lines
				
				11 KiB
			
		
		
			
		
	
	
					461 lines
				
				11 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								# listr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[](https://travis-ci.org/SamVerschueren/listr) [](https://ci.appveyor.com/project/SamVerschueren/listr) [](https://codecov.io/gh/SamVerschueren/listr)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								> Terminal task list
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<img src="media/screenshot.gif">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Install
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								$ npm install --save listr
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Usage
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const execa = require('execa');
							 | 
						||
| 
								 | 
							
								const Listr = require('listr');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Git',
							 | 
						||
| 
								 | 
							
										task: () => {
							 | 
						||
| 
								 | 
							
											return new Listr([
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													title: 'Checking git status',
							 | 
						||
| 
								 | 
							
													task: () => execa.stdout('git', ['status', '--porcelain']).then(result => {
							 | 
						||
| 
								 | 
							
														if (result !== '') {
							 | 
						||
| 
								 | 
							
															throw new Error('Unclean working tree. Commit or stash changes first.');
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													})
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													title: 'Checking remote history',
							 | 
						||
| 
								 | 
							
													task: () => execa.stdout('git', ['rev-list', '--count', '--left-only', '@{u}...HEAD']).then(result => {
							 | 
						||
| 
								 | 
							
														if (result !== '0') {
							 | 
						||
| 
								 | 
							
															throw new Error('Remote history differ. Please pull changes.');
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													})
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											], {concurrent: true});
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Install package dependencies with Yarn',
							 | 
						||
| 
								 | 
							
										task: (ctx, task) => execa('yarn')
							 | 
						||
| 
								 | 
							
											.catch(() => {
							 | 
						||
| 
								 | 
							
												ctx.yarn = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												task.skip('Yarn not available, install it via `npm install -g yarn`');
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Install package dependencies with npm',
							 | 
						||
| 
								 | 
							
										enabled: ctx => ctx.yarn === false,
							 | 
						||
| 
								 | 
							
										task: () => execa('npm', ['install'])
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Run tests',
							 | 
						||
| 
								 | 
							
										task: () => execa('npm', ['test'])
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Publish package',
							 | 
						||
| 
								 | 
							
										task: () => execa('npm', ['publish'])
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								tasks.run().catch(err => {
							 | 
						||
| 
								 | 
							
									console.error(err);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Task
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A `task` can return different values. If a `task` returns, it means the task was completed successfully. If a task throws an error, the task failed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Success',
							 | 
						||
| 
								 | 
							
										task: () => 'Foo'
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Failure',
							 | 
						||
| 
								 | 
							
										task: () => {
							 | 
						||
| 
								 | 
							
											throw new Error('Bar')
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Promises
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A `task` can also be async by returning a `Promise`. If the promise resolves, the task completed successfully, if it rejects, the task failed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Success',
							 | 
						||
| 
								 | 
							
										task: () => Promise.resolve('Foo')
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Failure',
							 | 
						||
| 
								 | 
							
										task: () => Promise.reject(new Error('Bar'))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								> Tip: Always reject a promise with some kind of `Error` object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Observable
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<img src="media/observable.gif" width="250" align="right">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A `task` can also return an `Observable`. The thing about observables is that it can emit multiple values and can be used to show the output of the
							 | 
						||
| 
								 | 
							
								task. Please note that only the last line of the output is rendered.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const {Observable} = require('rxjs');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Success',
							 | 
						||
| 
								 | 
							
										task: () => {
							 | 
						||
| 
								 | 
							
											return new Observable(observer => {
							 | 
						||
| 
								 | 
							
												observer.next('Foo');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												setTimeout(() => {
							 | 
						||
| 
								 | 
							
													observer.next('Bar');
							 | 
						||
| 
								 | 
							
												}, 2000);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												setTimeout(() => {
							 | 
						||
| 
								 | 
							
													observer.complete();
							 | 
						||
| 
								 | 
							
												}, 4000);
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Failure',
							 | 
						||
| 
								 | 
							
										task: () => Promise.reject(new Error('Bar'))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can use the `Observable` package you feel most comfortable with, like [RxJS](https://www.npmjs.com/package/rxjs) or [zen-observable](https://www.npmjs.com/package/zen-observable).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Streams
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								It's also possible to return a [`ReadableStream`](https://nodejs.org/api/stream.html#stream_class_stream_readable). The stream will be converted to an `Observable` and handled as such.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const fs = require('fs');
							 | 
						||
| 
								 | 
							
								const split = require('split');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const list = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'File',
							 | 
						||
| 
								 | 
							
										task: () => fs.createReadStream('data.txt', 'utf8')
							 | 
						||
| 
								 | 
							
											.pipe(split(/\r?\n/, null, {trailing: false}))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Skipping tasks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<img src="media/skipped.png" width="250" align="right">
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Optionally specify a `skip` function to determine whether a task can be skipped.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- If the `skip` function returns a truthy value or a `Promise` that resolves to a truthy value then the task will be skipped.
							 | 
						||
| 
								 | 
							
								- If the returned value is a string it will be displayed as the reason for skipping the task.
							 | 
						||
| 
								 | 
							
								- If the `skip` function returns a falsey value or a `Promise` that resolves to a falsey value then the task will be executed as normal.
							 | 
						||
| 
								 | 
							
								- If the `skip` function throws or returns a `Promise` that rejects, the task (and the whole build) will fail.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Task 1',
							 | 
						||
| 
								 | 
							
										task: () => Promise.resolve('Foo')
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Can be skipped',
							 | 
						||
| 
								 | 
							
										skip: () => {
							 | 
						||
| 
								 | 
							
											if (Math.random() > 0.5) {
							 | 
						||
| 
								 | 
							
												return 'Reason for skipping';
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										task: () => 'Bar'
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Task 3',
							 | 
						||
| 
								 | 
							
										task: () => Promise.resolve('Bar')
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								> Tip: You can still skip a task while already executing the `task` function with the [task object](#task-object).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Enabling tasks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								By default, every task is enabled which means that every task will be executed. However, it's also possible to provide an `enabled` function that returns whether the task should be executed or not.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Install package dependencies with Yarn',
							 | 
						||
| 
								 | 
							
										task: (ctx, task) => execa('yarn')
							 | 
						||
| 
								 | 
							
											.catch(() => {
							 | 
						||
| 
								 | 
							
												ctx.yarn = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												task.skip('Yarn not available, install it via `npm install -g yarn`');
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Install package dependencies with npm',
							 | 
						||
| 
								 | 
							
										enabled: ctx => ctx.yarn === false,
							 | 
						||
| 
								 | 
							
										task: () => execa('npm', ['install'])
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In the above example, we try to run `yarn` first, if that fails we will fall back to `npm`. However, at first only the Yarn task will be visible. Because we set the `yarn` flag of the [context](https://github.com/SamVerschueren/listr#context) object to `false`, the second task will automatically be enabled and will be executed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								> Note: This does not work in combination with [concurrent](https://github.com/SamVerschueren/listr#concurrent) tasks.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Context
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A context object is passed as argument to every `skip` and `task` function. This allows you to create composable tasks and change the behaviour of your task depending on previous results.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Task 1',
							 | 
						||
| 
								 | 
							
										skip: ctx => ctx.foo === 'bar',
							 | 
						||
| 
								 | 
							
										task: () => Promise.resolve('Foo')
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Can be skipped',
							 | 
						||
| 
								 | 
							
										skip: () => {
							 | 
						||
| 
								 | 
							
											if (Math.random() > 0.5) {
							 | 
						||
| 
								 | 
							
												return 'Reason for skipping';
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										task: ctx => {
							 | 
						||
| 
								 | 
							
											ctx.unicorn = 'rainbow';
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Task 3',
							 | 
						||
| 
								 | 
							
										task: ctx => Promise.resolve(`${ctx.foo} ${ctx.bar}`)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								tasks.run({
							 | 
						||
| 
								 | 
							
									foo: 'bar'
							 | 
						||
| 
								 | 
							
								}).then(ctx => {
							 | 
						||
| 
								 | 
							
									console.log(ctx);
							 | 
						||
| 
								 | 
							
									//=> {foo: 'bar', unicorn: 'rainbow'}
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Task object
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A special task object is passed as second argument to the `task` function. This task object lets you change the title while running your task, you can skip it depending on some results or you can update the task's output.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const tasks = new Listr([
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Install package dependencies with Yarn',
							 | 
						||
| 
								 | 
							
										task: (ctx, task) => execa('yarn')
							 | 
						||
| 
								 | 
							
											.catch(() => {
							 | 
						||
| 
								 | 
							
												ctx.yarn = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												task.title = `${task.title} (or not)`;
							 | 
						||
| 
								 | 
							
												task.skip('Yarn not available');
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										title: 'Install package dependencies with npm',
							 | 
						||
| 
								 | 
							
										skip: ctx => ctx.yarn !== false && 'Dependencies already installed with Yarn',
							 | 
						||
| 
								 | 
							
										task: (ctx, task) => {
							 | 
						||
| 
								 | 
							
											task.output = 'Installing dependencies...';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return execa('npm', ['install'])
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								tasks.run();
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Custom renderers
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								It's possible to write custom renderers for Listr. A renderer is an ES6 class that accepts the tasks that it should render, and the Listr options object. It has two methods, the `render` method which is called when it should start rendering, and the `end` method. The `end` method is called when all the tasks are completed or if a task failed. If a task failed, the error object is passed in via an argument.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								class CustomRenderer {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor(tasks, options) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static get nonTTY() {
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									render() { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									end(err) { }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = CustomRenderer;
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								> Note: A renderer is not passed through to the subtasks, only to the main task. It is up to you to handle that case.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The `nonTTY` property returns a boolean indicating if the renderer supports non-TTY environments. The default for this property is `false` if you do not implement it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Observables
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Every task is an observable. The task emits three different events and every event is an object with a `type` property.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								1. The state of the task has changed (`STATE`).
							 | 
						||
| 
								 | 
							
								2. The task outputted data (`DATA`).
							 | 
						||
| 
								 | 
							
								3. The task returns a subtask list (`SUBTASKS`).
							 | 
						||
| 
								 | 
							
								4. The task's title changed (`TITLE`).
							 | 
						||
| 
								 | 
							
								5. The task became enabled or disabled (`ENABLED`).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This allows you to flexibly build your UI. Let's render every task that starts executing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								class CustomRenderer {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor(tasks, options) {
							 | 
						||
| 
								 | 
							
										this._tasks = tasks;
							 | 
						||
| 
								 | 
							
										this._options = Object.assign({}, options);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static get nonTTY() {
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									render() {
							 | 
						||
| 
								 | 
							
										for (const task of this._tasks) {
							 | 
						||
| 
								 | 
							
											task.subscribe(event => {
							 | 
						||
| 
								 | 
							
												if (event.type === 'STATE' && task.isPending()) {
							 | 
						||
| 
								 | 
							
													console.log(`${task.title} [started]`);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									end(err) { }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = CustomRenderer;
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you want more complex examples, take a look at the [update](https://github.com/SamVerschueren/listr-update-renderer) and [verbose](https://github.com/SamVerschueren/listr-verbose-renderer) renderers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## API
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Listr([tasks], [options])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### tasks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `object[]`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								List of tasks.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### title
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `string`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Title of the task.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### task
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `Function`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Task function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### skip
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `Function`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Skip function. Read more about [skipping tasks](#skipping-tasks).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### options
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Any renderer specific options. For instance, when using the `update-renderer`, you can pass in all of its [options](https://github.com/SamVerschueren/listr-update-renderer#options).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### concurrent
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `boolean` `number`<br>
							 | 
						||
| 
								 | 
							
								Default: `false`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Set to `true` if you want to run tasks in parallel, set to a number to control the concurrency. By default it runs tasks sequentially.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### exitOnError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `boolean`<br>
							 | 
						||
| 
								 | 
							
								Default: `true`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Set to `false` if you don't want to stop the execution of other tasks when one or more tasks fail.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### renderer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `string` `object`<br>
							 | 
						||
| 
								 | 
							
								Default: `default`<br>
							 | 
						||
| 
								 | 
							
								Options: `default` `verbose` `silent`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Renderer that should be used. You can either pass in the name of the known renderer, or a class of a custom renderer.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### nonTTYRenderer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `string` `object`<br>
							 | 
						||
| 
								 | 
							
								Default: `verbose`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The renderer that should be used if the main renderer does not support TTY environments. You can either pass in the name of the renderer, or a class of a custom renderer.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Instance
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### add(task)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Returns the instance.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### task
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `object` `object[]`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Task object or multiple task objects.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### run([context])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Start executing the tasks. Returns a `Promise` for the context object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								##### context
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Type: `object`<br>
							 | 
						||
| 
								 | 
							
								Default: `Object.create(null)`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Initial context object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Related
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- [ora](https://github.com/sindresorhus/ora) - Elegant terminal spinner
							 | 
						||
| 
								 | 
							
								- [cli-spinners](https://github.com/sindresorhus/cli-spinners) - Spinners for use in the terminal
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## License
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MIT © [Sam Verschueren](https://github.com/SamVerschueren)
							 |