Socket
Socket
Sign inDemoInstall

listr

Package Overview
Dependencies
30
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.3 to 0.5.0

lib/renderer/string-renderer.js

23

index.js

@@ -7,3 +7,8 @@ 'use strict';

constructor(tasks) {
constructor(tasks, opts) {
if (tasks && !Array.isArray(tasks) && typeof tasks === 'object') {
opts = tasks;
tasks = [];
}
if (tasks && !Array.isArray(tasks)) {

@@ -15,2 +20,7 @@ throw new TypeError('Expected an array of tasks');

this._tasks = [];
this._options = Object.assign({
showSubtasks: true,
concurrent: false
}, opts);
this.level = 0;

@@ -29,3 +39,3 @@

for (const task of tasks) {
this._tasks.push(new Task(this, task));
this._tasks.push(new Task(this, task, this._options));
}

@@ -47,3 +57,10 @@

return this._tasks.reduce((promise, task) => promise.then(() => task.run()), Promise.resolve())
let tasks;
if (this._options.concurrent === true) {
tasks = Promise.all(this._tasks.map(task => task.run()));
} else {
tasks = this._tasks.reduce((promise, task) => promise.then(() => task.run()), Promise.resolve());
}
return tasks
.then(() => {

@@ -50,0 +67,0 @@ this._renderer.end();

2

lib/renderer/index.js
'use strict';
exports.LocalRenderer = require('./local-renderer');
exports.StringRenderer = require('./string-renderer');
exports.CLIRenderer = require('./cli-renderer');

@@ -5,3 +5,4 @@ 'use strict';

COMPLETED: 1,
FAILED: 2
FAILED: 2,
SKIPPED: 3
};

@@ -8,5 +8,7 @@ 'use strict';

const isStream = require('is-stream');
const isPromise = require('is-promise');
const streamToObservable = require('stream-to-observable');
const stripAnsi = require('strip-ansi');
const LocalRenderer = require('./renderer').LocalRenderer;
const cliTruncate = require('cli-truncate');
const StringRenderer = require('./renderer').StringRenderer;
const state = require('./state');

@@ -16,4 +18,7 @@

const pointer = chalk[color](figures.pointer);
const skipped = chalk[color](figures.arrowDown);
const isListr = obj => obj.setRenderer && obj.add && obj.run;
const isListr = obj => obj && obj.setRenderer && obj.add && obj.run;
// https://github.com/sindresorhus/is-observable/issues/1
const isObservable = obj => obj && obj.subscribe && obj.forEach;

@@ -23,3 +28,3 @@ const getSymbol = task => {

case state.PENDING:
return task._result ? `${pointer} ` : task._spinner.frame();
return task.showSubtasks() ? `${pointer} ` : task._spinner.frame();
case state.COMPLETED:

@@ -29,2 +34,4 @@ return `${logSymbols.success} `;

return task._result ? `${pointer} ` : `${logSymbols.error} `;
case state.SKIPPED:
return `${skipped} `;
default:

@@ -35,5 +42,7 @@ return ' ';

const defaultSkipFn = () => false;
class Task {
constructor(listr, task) {
constructor(listr, task, options) {
if (!task) {

@@ -51,13 +60,24 @@ throw new TypeError('Expected a task');

if (task.skip && typeof task.skip !== 'function') {
throw new TypeError(`Expected property \`skip\` of type \`function\` but got \`${typeof task.skip}\``);
}
this._listr = listr;
this._options = options || {};
this._spinner = new Ora({color});
this.title = task.title;
this.skip = task.skip || defaultSkipFn;
this.task = task.task;
}
showSubtasks() {
return this._result && (this._options.showSubtasks !== false || this.state === state.FAILED);
}
render() {
let out = indentString(` ${getSymbol(this)}${this.title}`, ' ', this._listr.level);
const skipped = this.state === state.SKIPPED ? ` ${chalk.dim('[skipped]')}` : '';
let out = indentString(` ${getSymbol(this)}${this.title}${skipped}`, ' ', this._listr.level);
if (this._result) {
if (this.showSubtasks()) {
const output = this._result.render();

@@ -69,4 +89,8 @@ if (output !== null) {

if (this.state === state.PENDING && this._lastLine) {
out += `\n ${indentString(chalk.gray(`${figures.arrowRight} ${this._lastLine}`), ' ', this._listr.level)}`;
if ((this.state === state.PENDING || this.state === state.SKIPPED) && this._output) {
const lastLine = stripAnsi(this._output.trim().split('\n').pop().trim());
if (lastLine) {
const output = indentString(`${figures.arrowRight} ${lastLine}`, ' ', this._listr.level);
out += `\n ${chalk.gray(cliTruncate(output, process.stdout.columns - 3))}`;
}
}

@@ -78,38 +102,57 @@

run() {
const handleResult = result => {
// Detect the subtask
if (isListr(result)) {
result.level = this._listr.level + 1;
result.setRenderer(StringRenderer);
this._result = result;
return result.run();
}
// Detect stream
if (isStream(result)) {
result = streamToObservable(result);
}
// Detect Observable
if (isObservable(result)) {
result = new Promise((resolve, reject) => {
result.subscribe({
next: data => {
this._output = data;
},
error: reject,
complete: resolve
});
});
}
// Detect promise
if (isPromise(result)) {
return result.then(handleResult);
}
return result;
};
return Promise.resolve()
.then(() => {
this.state = state.PENDING;
let result = this.task();
// Detect the subtask
if (isListr(result)) {
result.level = this._listr.level + 1;
result.setRenderer(LocalRenderer);
this._result = result;
return result.run();
return this.skip();
})
.then(skipped => {
if (skipped) {
this.state = state.SKIPPED;
if (typeof skipped === 'string') {
this._output = skipped;
}
return;
}
// Detect stream
if (isStream(result)) {
result = streamToObservable(result);
}
// https://github.com/sindresorhus/is-observable/issues/1
// Detect Observable
if (result.subscribe && result.forEach) {
return new Promise((resolve, reject) => {
result.subscribe(
data => {
this._lastLine = stripAnsi(data.trim().split('\n').pop().trim());
},
reject,
resolve
);
});
}
return result;
return handleResult(this.task());
})
.then(() => {
this.state = state.COMPLETED;
if (this.state === state.PENDING) {
this.state = state.COMPLETED;
}
})

@@ -116,0 +159,0 @@ .catch(err => {

{
"name": "listr",
"version": "0.4.3",
"version": "0.5.0",
"description": "Terminal task list",

@@ -41,4 +41,6 @@ "license": "MIT",

"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",

@@ -54,2 +56,3 @@ "log-symbols": "^1.0.2",

"clinton": "*",
"delay": "^1.3.1",
"rxjs": "^5.0.0-beta.9",

@@ -56,0 +59,0 @@ "xo": "*"

@@ -41,3 +41,3 @@ # listr [![Build Status](https://travis-ci.org/SamVerschueren/listr.svg?branch=master)](https://travis-ci.org/SamVerschueren/listr)

}
]);
], {concurrent: true});
}

@@ -67,3 +67,3 @@ },

A `task` can return different values. If a `task` returns, it means the task was completed succesfully. If a task throws an error, the task failed.
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.

@@ -88,3 +88,3 @@ ```js

A `task` can also be async by returning a `Promise`. If the promise resolves, the task completed sucessfully, it it rejects, the task failed.
A `task` can also be async by returning a `Promise`. If the promise resolves, the task completed successfully, it it rejects, the task failed.

@@ -106,3 +106,3 @@ ```js

<img src="media/observable.gif" width="255" align="right">
<img src="media/observable.gif" width="250" align="right">

@@ -142,5 +142,40 @@ 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

#### 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')
}
]);
```
## API
### Listr([tasks])
### Listr([tasks], [options])

@@ -165,2 +200,25 @@ #### tasks

##### skip
Type: `Function`
Skip function. Read more about [skipping tasks](#skipping-tasks).
#### options
##### showSubtasks
Type: `boolean`<br>
Default: `true`
Set to `false` if you want to disable the rendering of the subtasks. Subtasks will be rendered if
an error occurred in one of them.
##### concurrent
Type: `boolean`<br>
Default: `false`
Set to `true` if you want tasks to run concurrently.
### Instance

@@ -167,0 +225,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc