mirror of
https://github.com/morhetz/gruvbox.git
synced 2025-11-17 15:53:38 -05:00
chore(package): re-init package with commitizen and standard-release
This commit is contained in:
104
node_modules/listr/index.js
generated
vendored
Normal file
104
node_modules/listr/index.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
'use strict';
|
||||
const Task = require('./lib/task');
|
||||
const TaskWrapper = require('./lib/task-wrapper');
|
||||
const renderer = require('./lib/renderer');
|
||||
|
||||
const runTask = (task, context) => {
|
||||
if (!task.isEnabled()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new TaskWrapper(task).run(context);
|
||||
};
|
||||
|
||||
class Listr {
|
||||
|
||||
constructor(tasks, opts) {
|
||||
if (tasks && !Array.isArray(tasks) && typeof tasks === 'object') {
|
||||
opts = tasks;
|
||||
tasks = [];
|
||||
}
|
||||
|
||||
if (tasks && !Array.isArray(tasks)) {
|
||||
throw new TypeError('Expected an array of tasks');
|
||||
}
|
||||
|
||||
this._options = Object.assign({
|
||||
showSubtasks: true,
|
||||
concurrent: false,
|
||||
renderer: 'default',
|
||||
nonTTYRenderer: 'verbose'
|
||||
}, opts);
|
||||
this._tasks = [];
|
||||
this._RendererClass = renderer.getRenderer(this._options.renderer, this._options.nonTTYRenderer);
|
||||
|
||||
this.exitOnError = this._options.exitOnError;
|
||||
|
||||
this.add(tasks || []);
|
||||
}
|
||||
|
||||
_checkAll(context) {
|
||||
for (const task of this._tasks) {
|
||||
task.check(context);
|
||||
}
|
||||
}
|
||||
|
||||
get tasks() {
|
||||
return this._tasks;
|
||||
}
|
||||
|
||||
setRenderer(value) {
|
||||
this._RendererClass = renderer.getRenderer(value);
|
||||
}
|
||||
|
||||
add(task) {
|
||||
const tasks = Array.isArray(task) ? task : [task];
|
||||
|
||||
for (const task of tasks) {
|
||||
this._tasks.push(new Task(this, task, this._options));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this._renderer) {
|
||||
this._renderer = new this._RendererClass(this._tasks, this._options);
|
||||
}
|
||||
|
||||
return this._renderer.render();
|
||||
}
|
||||
|
||||
run(context) {
|
||||
this.render();
|
||||
|
||||
context = context || Object.create(null);
|
||||
|
||||
this._checkAll(context);
|
||||
|
||||
let tasks;
|
||||
if (this._options.concurrent === true) {
|
||||
tasks = Promise.all(this._tasks.map(task => runTask(task, context)));
|
||||
} else {
|
||||
tasks = this._tasks.reduce((promise, task) => promise.then(() => {
|
||||
this._checkAll(context);
|
||||
|
||||
return runTask(task, context);
|
||||
}), Promise.resolve());
|
||||
}
|
||||
|
||||
return tasks
|
||||
.then(() => {
|
||||
this._renderer.end();
|
||||
|
||||
return context;
|
||||
})
|
||||
.catch(err => {
|
||||
err.context = context;
|
||||
this._renderer.end(err);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Listr;
|
||||
30
node_modules/listr/lib/renderer.js
generated
vendored
Normal file
30
node_modules/listr/lib/renderer.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
const renderers = {
|
||||
silent: require('listr-silent-renderer'),
|
||||
verbose: require('listr-verbose-renderer'),
|
||||
default: require('listr-update-renderer')
|
||||
};
|
||||
|
||||
const isRendererSupported = renderer => process.stdout.isTTY === true || renderer.nonTTY === true;
|
||||
|
||||
const getRendererClass = renderer => {
|
||||
if (typeof renderer === 'string') {
|
||||
return renderers[renderer] || renderers.default;
|
||||
}
|
||||
|
||||
return typeof renderer === 'function' ? renderer : renderers.default;
|
||||
};
|
||||
|
||||
exports.getRenderer = (renderer, fallbackRenderer) => {
|
||||
let ret = getRendererClass(renderer);
|
||||
|
||||
if (!isRendererSupported(ret)) {
|
||||
ret = getRendererClass(fallbackRenderer);
|
||||
|
||||
if (!ret || !isRendererSupported(ret)) {
|
||||
ret = renderers.verbose;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
24
node_modules/listr/lib/state.js
generated
vendored
Normal file
24
node_modules/listr/lib/state.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
const state = {
|
||||
PENDING: 0,
|
||||
COMPLETED: 1,
|
||||
FAILED: 2,
|
||||
SKIPPED: 3
|
||||
};
|
||||
|
||||
state.toString = input => {
|
||||
switch (input) {
|
||||
case state.PENDING:
|
||||
return 'pending';
|
||||
case state.COMPLETED:
|
||||
return 'completed';
|
||||
case state.FAILED:
|
||||
return 'failed';
|
||||
case state.SKIPPED:
|
||||
return 'skipped';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = state;
|
||||
40
node_modules/listr/lib/task-wrapper.js
generated
vendored
Normal file
40
node_modules/listr/lib/task-wrapper.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
const state = require('./state');
|
||||
|
||||
class TaskWrapper {
|
||||
|
||||
constructor(task) {
|
||||
this._task = task;
|
||||
}
|
||||
|
||||
set title(title) {
|
||||
this._task.title = title;
|
||||
|
||||
this._task.next({
|
||||
type: 'TITLE',
|
||||
data: title
|
||||
});
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this._task.title;
|
||||
}
|
||||
|
||||
skip(message) {
|
||||
if (message && typeof message !== 'string') {
|
||||
throw new TypeError(`Expected \`message\` to be of type \`string\`, got \`${typeof message}\``);
|
||||
}
|
||||
|
||||
if (message) {
|
||||
this._task._output = message;
|
||||
}
|
||||
|
||||
this._task.state = state.SKIPPED;
|
||||
}
|
||||
|
||||
run(ctx) {
|
||||
return this._task.run(ctx, this);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TaskWrapper;
|
||||
201
node_modules/listr/lib/task.js
generated
vendored
Normal file
201
node_modules/listr/lib/task.js
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
'use strict';
|
||||
const isStream = require('is-stream');
|
||||
const isPromise = require('is-promise');
|
||||
const streamToObservable = require('stream-to-observable');
|
||||
const Subject = require('rxjs/Subject').Subject;
|
||||
const renderer = require('./renderer');
|
||||
const state = require('./state');
|
||||
const utils = require('./utils');
|
||||
|
||||
const defaultSkipFn = () => false;
|
||||
|
||||
class Task extends Subject {
|
||||
|
||||
constructor(listr, task, options) {
|
||||
super();
|
||||
|
||||
if (!task) {
|
||||
throw new TypeError('Expected a task');
|
||||
}
|
||||
|
||||
if (typeof task.title !== 'string') {
|
||||
throw new TypeError(`Expected property \`title\` to be of type \`string\`, got \`${typeof task.title}\``);
|
||||
}
|
||||
|
||||
if (typeof task.task !== 'function') {
|
||||
throw new TypeError(`Expected property \`task\` to be of type \`function\`, got \`${typeof task.task}\``);
|
||||
}
|
||||
|
||||
if (task.skip && typeof task.skip !== 'function') {
|
||||
throw new TypeError(`Expected property \`skip\` to be of type \`function\`, got \`${typeof task.skip}\``);
|
||||
}
|
||||
|
||||
if (task.enabled && typeof task.enabled !== 'function') {
|
||||
throw new TypeError(`Expected property \`enabled\` to be of type \`function\`, got \`${typeof task.enabled}\``);
|
||||
}
|
||||
|
||||
this._listr = listr;
|
||||
this._options = options || {};
|
||||
this._subtasks = [];
|
||||
this._output = undefined;
|
||||
this._enabledFn = task.enabled;
|
||||
this._isEnabled = true;
|
||||
|
||||
this.title = task.title;
|
||||
this.skip = task.skip || defaultSkipFn;
|
||||
this.task = task.task;
|
||||
}
|
||||
|
||||
get output() {
|
||||
return this._output;
|
||||
}
|
||||
|
||||
get subtasks() {
|
||||
return this._subtasks;
|
||||
}
|
||||
|
||||
set state(state) {
|
||||
this._state = state;
|
||||
|
||||
this.next({
|
||||
type: 'STATE'
|
||||
});
|
||||
}
|
||||
|
||||
get state() {
|
||||
return state.toString(this._state);
|
||||
}
|
||||
|
||||
check(ctx) {
|
||||
// Check if a task is enabled or disabled
|
||||
if (this._state === undefined && this._enabledFn) {
|
||||
const isEnabled = this._enabledFn(ctx);
|
||||
|
||||
if (this._isEnabled !== isEnabled) {
|
||||
this._isEnabled = isEnabled;
|
||||
|
||||
this.next({
|
||||
type: 'ENABLED',
|
||||
data: isEnabled
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasSubtasks() {
|
||||
return this._subtasks.length > 0;
|
||||
}
|
||||
|
||||
isPending() {
|
||||
return this._state === state.PENDING;
|
||||
}
|
||||
|
||||
isSkipped() {
|
||||
return this._state === state.SKIPPED;
|
||||
}
|
||||
|
||||
isCompleted() {
|
||||
return this._state === state.COMPLETED;
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
return this._isEnabled;
|
||||
}
|
||||
|
||||
hasFailed() {
|
||||
return this._state === state.FAILED;
|
||||
}
|
||||
|
||||
run(context, wrapper) {
|
||||
const handleResult = result => {
|
||||
// Detect the subtask
|
||||
if (utils.isListr(result)) {
|
||||
result._options = Object.assign(this._options, result._options);
|
||||
|
||||
result.exitOnError = result._options.exitOnError;
|
||||
|
||||
result.setRenderer(renderer.getRenderer('silent'));
|
||||
this._subtasks = result.tasks;
|
||||
|
||||
this.next({
|
||||
type: 'SUBTASKS'
|
||||
});
|
||||
|
||||
return result.run(context);
|
||||
}
|
||||
|
||||
// Detect stream
|
||||
if (isStream(result)) {
|
||||
result = streamToObservable(result);
|
||||
}
|
||||
|
||||
// Detect Observable
|
||||
if (utils.isObservable(result)) {
|
||||
result = new Promise((resolve, reject) => {
|
||||
result.subscribe({
|
||||
next: data => {
|
||||
this._output = data;
|
||||
|
||||
this.next({
|
||||
type: 'DATA',
|
||||
data
|
||||
});
|
||||
},
|
||||
error: reject,
|
||||
complete: resolve
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Detect promise
|
||||
if (isPromise(result)) {
|
||||
return result.then(handleResult);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
this.state = state.PENDING;
|
||||
return this.skip(context);
|
||||
})
|
||||
.then(skipped => {
|
||||
if (skipped) {
|
||||
if (typeof skipped === 'string') {
|
||||
this._output = skipped;
|
||||
}
|
||||
this.state = state.SKIPPED;
|
||||
return;
|
||||
}
|
||||
|
||||
return handleResult(this.task(context, wrapper));
|
||||
})
|
||||
.then(() => {
|
||||
if (this.isPending()) {
|
||||
this.state = state.COMPLETED;
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
this.state = state.FAILED;
|
||||
|
||||
this._output = err.message;
|
||||
|
||||
this.next({
|
||||
type: 'DATA',
|
||||
data: err.message
|
||||
});
|
||||
|
||||
if (this._listr.exitOnError !== false) {
|
||||
// Do not exit when explicitely set to `false`
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// Mark the Observable as completed
|
||||
this.complete();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Task;
|
||||
5
node_modules/listr/lib/utils.js
generated
vendored
Normal file
5
node_modules/listr/lib/utils.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
exports.isListr = obj => Boolean(obj && obj.setRenderer && obj.add && obj.run);
|
||||
// https://github.com/sindresorhus/is-observable/issues/1
|
||||
exports.isObservable = obj => Boolean(obj && typeof obj.subscribe === 'function' && obj.constructor.name === 'Observable');
|
||||
21
node_modules/listr/license
generated
vendored
Normal file
21
node_modules/listr/license
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Sam Verschueren <sam.verschueren@gmail.com> (github.com/SamVerschueren)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
70
node_modules/listr/package.json
generated
vendored
Normal file
70
node_modules/listr/package.json
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "listr",
|
||||
"version": "0.10.0",
|
||||
"description": "Terminal task list",
|
||||
"license": "MIT",
|
||||
"repository": "SamVerschueren/listr",
|
||||
"author": {
|
||||
"name": "Sam Verschueren",
|
||||
"email": "sam.verschueren@gmail.com",
|
||||
"url": "github.com/SamVerschueren"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "clinton && xo && nyc ava",
|
||||
"coveralls": "nyc report --reporter=text-lcov | coveralls"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib"
|
||||
],
|
||||
"keywords": [
|
||||
"cli",
|
||||
"task",
|
||||
"list",
|
||||
"tasklist",
|
||||
"terminal",
|
||||
"term",
|
||||
"console",
|
||||
"ascii",
|
||||
"unicode",
|
||||
"loading",
|
||||
"indicator",
|
||||
"progress",
|
||||
"busy",
|
||||
"wait",
|
||||
"idle"
|
||||
],
|
||||
"dependencies": {
|
||||
"chalk": "^1.1.3",
|
||||
"cli-truncate": "^0.2.1",
|
||||
"figures": "^1.7.0",
|
||||
"indent-string": "^2.1.0",
|
||||
"is-promise": "^2.1.0",
|
||||
"is-stream": "^1.1.0",
|
||||
"listr-silent-renderer": "^1.1.1",
|
||||
"listr-update-renderer": "^0.2.0",
|
||||
"listr-verbose-renderer": "^0.3.0",
|
||||
"log-symbols": "^1.0.2",
|
||||
"log-update": "^1.0.2",
|
||||
"ora": "^0.2.3",
|
||||
"rxjs": "^5.0.0-beta.11",
|
||||
"stream-to-observable": "^0.1.0",
|
||||
"strip-ansi": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "*",
|
||||
"clinton": "*",
|
||||
"coveralls": "^2.11.14",
|
||||
"delay": "^1.3.1",
|
||||
"hook-std": "^0.2.0",
|
||||
"nyc": "^8.3.2",
|
||||
"xo": "*",
|
||||
"zen-observable": "^0.3.0"
|
||||
},
|
||||
"xo": {
|
||||
"esnext": true
|
||||
}
|
||||
}
|
||||
440
node_modules/listr/readme.md
generated
vendored
Normal file
440
node_modules/listr/readme.md
generated
vendored
Normal file
@@ -0,0 +1,440 @@
|
||||
# listr
|
||||
|
||||
[](https://travis-ci.org/SamVerschueren/listr) [](https://ci.appveyor.com/project/SamVerschueren/listr) [](https://coveralls.io/github/SamVerschueren/listr?branch=master)
|
||||
|
||||
> 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, it 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 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'))
|
||||
}
|
||||
]);
|
||||
```
|
||||
|
||||
### Streams
|
||||
|
||||
It's also possible to return a `stream`. The stream will be converted to an `Observable` and handled as such.
|
||||
|
||||
|
||||
### 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 wheter 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 being passed as argument into 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 being passed as second argument into the `task` function. This task object lets you change the title while running your task or you can skip it depending on some results.
|
||||
|
||||
```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: () => 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 renderer, 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 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 up 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.
|
||||
|
||||
##### concurrent
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: `false`
|
||||
|
||||
Set to `true` if you want tasks to run concurrently.
|
||||
|
||||
##### 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)
|
||||
Reference in New Issue
Block a user