Comparing version 3.0.0-alpha.1 to 3.0.0-alpha.2
@@ -1,3 +0,1 @@ | ||
import deps from '../deps'; | ||
export declare function getSpinner(): ActionBase; | ||
export interface ITask { | ||
@@ -9,5 +7,10 @@ action: string; | ||
export declare type ActionType = 'spinner' | 'simple' | 'debug'; | ||
export declare class ActionBase extends deps.Base { | ||
export interface Options { | ||
stderr?: boolean; | ||
} | ||
export declare class ActionBase { | ||
type: ActionType; | ||
start(action: string, status?: string): void; | ||
std: 'stdout' | 'stderr'; | ||
protected stdmocks?: ['stdout' | 'stderr', string[]][]; | ||
start(action: string, status?: string, opts?: Options): void; | ||
stop(msg?: string): void; | ||
@@ -21,11 +24,19 @@ private readonly globals; | ||
pause(fn: () => any, icon?: string): any; | ||
protected log({action, status}: { | ||
action: string; | ||
status?: string; | ||
}): void; | ||
protected _start(): void; | ||
protected _stop(status: string): void; | ||
protected _stop(_: string): void; | ||
protected _resume(): void; | ||
protected _pause(icon?: string): void; | ||
protected _updateStatus(status: string | undefined, prevStatus?: string): void; | ||
protected _pause(_?: string): void; | ||
protected _updateStatus(_: string | undefined, __?: string): void; | ||
/** | ||
* mock out stdout/stderr so it doesn't screw up the rendering | ||
*/ | ||
protected _stdout(toggle: boolean): void; | ||
/** | ||
* flush mocked stdout/stderr | ||
*/ | ||
protected _flushStdout(): void; | ||
/** | ||
* write to the real stdout/stderr | ||
*/ | ||
protected _write(std: 'stdout' | 'stderr', s: string | string[]): void; | ||
} |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const _ = require("lodash"); | ||
const util_1 = require("util"); | ||
const stdmockWrite = { | ||
stdout: process.stdout.write, | ||
stderr: process.stderr.write, | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const deps_1 = require("../deps"); | ||
function getSpinner() { | ||
let Action; | ||
if (deps_1.default.Config.debug) | ||
Action = require('./debug').DebugAction; | ||
else if (!deps_1.default.Config.mock && | ||
!!process.stdin.isTTY && | ||
!!process.stderr.isTTY && | ||
!process.env.CI && | ||
process.env.TERM !== 'dumb') | ||
Action = require('./spinner').SpinnerAction; | ||
else | ||
Action = require('./simple').SimpleAction; | ||
return new Action(); | ||
} | ||
exports.getSpinner = getSpinner; | ||
class ActionBase extends deps_1.default.Base { | ||
start(action, status) { | ||
class ActionBase { | ||
constructor() { | ||
this.std = 'stdout'; | ||
} | ||
start(action, status, opts = {}) { | ||
this.std = opts.stderr ? 'stderr' : 'stdout'; | ||
const task = (this.task = { action, status, active: !!(this.task && this.task.active) }); | ||
this._start(); | ||
task.active = true; | ||
this.log(task); | ||
this._stdout(true); | ||
} | ||
@@ -42,2 +28,3 @@ stop(msg = 'done') { | ||
this.task = undefined; | ||
this._stdout(false); | ||
} | ||
@@ -77,18 +64,16 @@ get globals() { | ||
task.status = status; | ||
this.log(task); | ||
} | ||
pauseAsync(fn, icon) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const task = this.task; | ||
const active = task && task.active; | ||
if (task && active) { | ||
this._pause(icon); | ||
task.active = false; | ||
} | ||
const ret = yield fn(); | ||
if (task && active) { | ||
this._resume(); | ||
} | ||
return ret; | ||
}); | ||
async pauseAsync(fn, icon) { | ||
const task = this.task; | ||
const active = task && task.active; | ||
if (task && active) { | ||
this._pause(icon); | ||
this._stdout(false); | ||
task.active = false; | ||
} | ||
const ret = await fn(); | ||
if (task && active) { | ||
this._resume(); | ||
} | ||
return ret; | ||
} | ||
@@ -100,2 +85,3 @@ pause(fn, icon) { | ||
this._pause(icon); | ||
this._stdout(false); | ||
task.active = false; | ||
@@ -109,10 +95,6 @@ } | ||
} | ||
log({ action, status }) { | ||
const msg = status ? `${action}... ${status}\n` : `${action}...\n`; | ||
this.stderr.writeLogFile(msg, true); | ||
} | ||
_start() { | ||
throw new Error('not implemented'); | ||
} | ||
_stop(status) { | ||
_stop(_) { | ||
throw new Error('not implemented'); | ||
@@ -124,7 +106,65 @@ } | ||
} | ||
_pause(icon) { | ||
_pause(_) { | ||
throw new Error('not implemented'); | ||
} | ||
_updateStatus(status, prevStatus) { } | ||
_updateStatus(_, __) { } | ||
/** | ||
* mock out stdout/stderr so it doesn't screw up the rendering | ||
*/ | ||
_stdout(toggle) { | ||
try { | ||
const outputs = ['stdout', 'stderr']; | ||
if (toggle) { | ||
if (this.stdmocks) | ||
return; | ||
this.stdmocks = []; | ||
for (let std of outputs) { | ||
process[std].write = (...args) => { | ||
this.stdmocks.push([std, args]); | ||
}; | ||
} | ||
} | ||
else { | ||
if (!this.stdmocks) | ||
return; | ||
// this._write('stderr', '\nresetstdmock\n\n\n') | ||
delete this.stdmocks; | ||
for (let std of outputs) | ||
process[std].write = stdmockWrite[std]; | ||
} | ||
} | ||
catch (err) { | ||
this._write('stderr', util_1.inspect(err)); | ||
} | ||
} | ||
/** | ||
* flush mocked stdout/stderr | ||
*/ | ||
_flushStdout() { | ||
try { | ||
let output = ''; | ||
let std; | ||
while (this.stdmocks && this.stdmocks.length) { | ||
let cur = this.stdmocks.shift(); | ||
std = cur[0]; | ||
this._write(std, cur[1]); | ||
output += cur[1].map((a) => a.toString('utf8')).join(''); | ||
} | ||
// add newline if there isn't one already | ||
// otherwise we'll just overwrite it when we render | ||
if (output && std && output[output.length - 1] !== '\n') { | ||
this._write(std, '\n'); | ||
} | ||
} | ||
catch (err) { | ||
this._write('stderr', util_1.inspect(err)); | ||
} | ||
} | ||
/** | ||
* write to the real stdout/stderr | ||
*/ | ||
_write(std, s) { | ||
stdmockWrite[std].apply(process[std], _.castArray(s)); | ||
} | ||
} | ||
exports.ActionBase = ActionBase; |
import { ActionBase, ActionType } from './base'; | ||
export declare class SimpleAction extends ActionBase { | ||
export default class SimpleAction extends ActionBase { | ||
type: ActionType; | ||
_start(): void; | ||
_pause(icon?: string): void; | ||
_resume(): void; | ||
_updateStatus(status: string, prevStatus?: string, newline?: boolean): void; | ||
_stop(status: string): void; | ||
_render(action: string, status?: string): void; | ||
_write(s: string): void; | ||
protected _start(): void; | ||
protected _pause(icon?: string): void; | ||
protected _resume(): void; | ||
protected _updateStatus(status: string, prevStatus?: string, newline?: boolean): void; | ||
protected _stop(status: string): void; | ||
private _render(action, status?); | ||
private _flush(); | ||
} |
@@ -19,3 +19,3 @@ "use strict"; | ||
else | ||
this._write('\n'); | ||
this._flush(); | ||
} | ||
@@ -28,7 +28,7 @@ _resume() { } | ||
if (task.active && !prevStatus) | ||
this._write(` ${status}`); | ||
this._write(this.std, ` ${status}`); | ||
else | ||
this._write(`${task.action}... ${status}`); | ||
this._write(this.std, `${task.action}... ${status}`); | ||
if (newline || !prevStatus) | ||
this._write('\n'); | ||
this._flush(); | ||
} | ||
@@ -46,9 +46,10 @@ _stop(status) { | ||
if (task.active) | ||
this._write('\n'); | ||
this._write(status ? `${action}... ${status}` : `${action}...`); | ||
this._flush(); | ||
this._write(this.std, status ? `${action}... ${status}` : `${action}...`); | ||
} | ||
_write(s) { | ||
this.stderr.write(s, { log: false }); | ||
_flush() { | ||
this._write(this.std, '\n'); | ||
this._flushStdout(); | ||
} | ||
} | ||
exports.SimpleAction = SimpleAction; | ||
exports.default = SimpleAction; |
@@ -1,4 +0,3 @@ | ||
import deps from '../deps'; | ||
import { ActionType } from './base'; | ||
export declare class SpinnerAction extends deps.ActionBase.ActionBase { | ||
import { ActionBase, ActionType } from './base'; | ||
export default class SpinnerAction extends ActionBase { | ||
type: ActionType; | ||
@@ -9,10 +8,9 @@ spinner: number; | ||
constructor(); | ||
_start(): void; | ||
_stop(status: string): void; | ||
_pause(icon?: string): void; | ||
_render(icon?: string): void; | ||
_reset(): void; | ||
_frame(): string; | ||
_lines(s: string): number; | ||
_write(s: string): void; | ||
protected _start(): void; | ||
protected _stop(status: string): void; | ||
protected _pause(icon?: string): void; | ||
private _render(icon?); | ||
private _reset(); | ||
private _frame(); | ||
private _lines(s); | ||
} |
"use strict"; | ||
// tslint:disable restrict-plus-operands | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const supportsColor = require("supports-color"); | ||
const deps_1 = require("../deps"); | ||
const supportsColor = require("supports-color"); | ||
const base_1 = require("./base"); | ||
const spinners = require('./spinners'); | ||
@@ -10,9 +12,9 @@ function color(s) { | ||
let has256 = supportsColor.has256 || (process.env.TERM || '').indexOf('256') !== -1; | ||
return has256 ? '\u001b[38;5;104m' + s + deps_1.default.ansiStyles.reset.open : deps_1.default.chalk.magenta(s); | ||
return has256 ? `\u001b[38;5;104m${s}${deps_1.default.ansiStyles.reset.open}` : deps_1.default.chalk.magenta(s); | ||
} | ||
class SpinnerAction extends deps_1.default.ActionBase.ActionBase { | ||
class SpinnerAction extends base_1.ActionBase { | ||
constructor() { | ||
super(); | ||
this.type = 'spinner'; | ||
this.frames = spinners[deps_1.default.Config.windows ? 'line' : 'dots2'].frames; | ||
this.frames = spinners[process.platform === 'win32' ? 'line' : 'dots2'].frames; | ||
this.frameIndex = 0; | ||
@@ -25,3 +27,3 @@ } | ||
this._render(); | ||
let interval = (this.spinner = setInterval(this._render.bind(this), deps_1.default.Config.windows ? 500 : 100, 'spinner')); | ||
let interval = (this.spinner = setInterval(this._render.bind(this), process.platform === 'win32' ? 500 : 100, 'spinner')); | ||
interval.unref(); | ||
@@ -48,6 +50,7 @@ } | ||
this._reset(); | ||
this._flushStdout(); | ||
let frame = icon === 'spinner' ? ` ${this._frame()}` : icon || ''; | ||
let status = task.status ? ` ${task.status}` : ''; | ||
this.output = `${task.action}...${frame}${status}\n`; | ||
this._write(this.output); | ||
this._write(this.std, this.output); | ||
} | ||
@@ -58,3 +61,3 @@ _reset() { | ||
let lines = this._lines(this.output); | ||
this._write(deps_1.default.ansiEscapes.cursorLeft + deps_1.default.ansiEscapes.cursorUp(lines) + deps_1.default.ansiEscapes.eraseDown); | ||
this._write(this.std, deps_1.default.ansiEscapes.cursorLeft + deps_1.default.ansiEscapes.cursorUp(lines) + deps_1.default.ansiEscapes.eraseDown); | ||
this.output = undefined; | ||
@@ -74,6 +77,3 @@ } | ||
} | ||
_write(s) { | ||
this.stderr.write(s, { log: false }); | ||
} | ||
} | ||
exports.SpinnerAction = SpinnerAction; | ||
exports.default = SpinnerAction; |
@@ -161,3 +161,3 @@ "use strict"; | ||
interval: 70, | ||
frames: ['_', '_', '_', '-', '`', '`', "'", '´', '-', '_', '_', '_'], | ||
frames: ['_', '_', '_', '-', '`', '`', '\'', '´', '-', '_', '_', '_'], | ||
}, | ||
@@ -164,0 +164,0 @@ hamburger: { |
@@ -1,10 +0,12 @@ | ||
export default class Config { | ||
static debug: boolean; | ||
static mock: boolean; | ||
static displayTimestamps: boolean; | ||
static errlog: string | undefined; | ||
static stdout: string; | ||
static stderr: string; | ||
static readonly windows: boolean; | ||
static readonly _globals: any; | ||
import Rx = require('rxjs/Rx'); | ||
import { ActionBase } from './action/base'; | ||
import { ConfigMessage } from './message'; | ||
export declare type Levels = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'; | ||
export declare class Config extends Rx.Subject<ConfigMessage> { | ||
logLevel: Levels; | ||
outputLevel: Levels; | ||
debug: boolean; | ||
action: ActionBase; | ||
errlog: string | undefined; | ||
} | ||
export declare const config: Config; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const deps_1 = require("./deps"); | ||
class Config { | ||
static get debug() { | ||
return !!Config._globals.debug; | ||
const Rx = require("rxjs/Rx"); | ||
const semver = require("semver"); | ||
const version = semver.parse(require('../package.json').version); | ||
const globals = global['cli-ux'] || (global['cli-ux'] = {}); | ||
const actionType = (!!process.stdin.isTTY && | ||
!!process.stderr.isTTY && | ||
!process.env.CI && | ||
process.env.TERM !== 'dumb' && | ||
'spinner') || 'simple'; | ||
const Action = actionType === 'spinner' ? require('./action/spinner').default : require('./action/simple').default; | ||
class Config extends Rx.Subject { | ||
constructor() { | ||
super(...arguments); | ||
this.logLevel = 'warn'; | ||
this.outputLevel = 'info'; | ||
this.debug = process.env.DEBUG === '*'; | ||
this.action = new Action(); | ||
} | ||
static set debug(debug) { | ||
Config._globals.debug = debug; | ||
get errlog() { return globals.errlog; } | ||
set errlog(errlog) { | ||
globals.errlog = errlog; | ||
this.next({ type: 'config', prop: 'errlog', value: errlog }); | ||
} | ||
static get mock() { | ||
return !!Config._globals.mock; | ||
} | ||
static set mock(mock) { | ||
if (mock) { | ||
deps_1.default.chalk.enabled = false; | ||
Config.stdout = ''; | ||
Config.stderr = ''; | ||
} | ||
Config._globals.mock = mock; | ||
} | ||
static get displayTimestamps() { | ||
return !!Config._globals.displayTimestamps; | ||
} | ||
static set displayTimestamps(displayTimestamps) { | ||
Config._globals.displayTimestamps = displayTimestamps; | ||
} | ||
static get errlog() { | ||
return Config._globals.errlog; | ||
} | ||
static set errlog(errlog) { | ||
Config._globals.errlog = errlog; | ||
} | ||
static get stdout() { | ||
return Config._globals.stdout || ''; | ||
} | ||
static set stdout(stdout) { | ||
Config._globals.stdout = stdout; | ||
} | ||
static get stderr() { | ||
return Config._globals.stderr || ''; | ||
} | ||
static set stderr(stderr) { | ||
Config._globals.stderr = stderr; | ||
} | ||
static get windows() { | ||
return process.platform === 'win32'; | ||
} | ||
static get _globals() { | ||
const globals = (global['cli-ux'] = global['cli-ux'] || {}); | ||
globals.action = globals.action || {}; | ||
return globals; | ||
} | ||
} | ||
exports.default = Config; | ||
exports.Config = Config; | ||
function current() { | ||
if (!globals[version.major] || globals[version.major].closed) | ||
return; | ||
return globals[version.major]; | ||
} | ||
function fetch() { | ||
let subject = current(); | ||
if (subject) | ||
return subject; | ||
return globals[version.major] = new Config(); | ||
} | ||
exports.config = fetch(); |
@@ -0,15 +1,7 @@ | ||
import screen = require('@dxcli/screen'); | ||
import ansiStyles = require('ansi-styles'); | ||
import { Chalk } from 'chalk'; | ||
import moment = require('moment'); | ||
import ansiStyles = require('ansi-styles'); | ||
import screen = require('@cli-engine/screen'); | ||
import Prompt from './prompt'; | ||
import { Errors } from './errors'; | ||
import ActionBase = require('./action/base'); | ||
import Base from './base'; | ||
import StreamOutput from './stream'; | ||
import Config from './config'; | ||
import exitError = require('./exit_error'); | ||
import Prompt = require('./prompt'); | ||
export declare const deps: { | ||
readonly chalk: Chalk; | ||
readonly moment: typeof moment; | ||
readonly stripAnsi: (str: string) => string; | ||
@@ -20,10 +12,4 @@ readonly ansiStyles: typeof ansiStyles; | ||
readonly screen: typeof screen; | ||
readonly Prompt: typeof Prompt; | ||
readonly Errors: typeof Errors; | ||
readonly ActionBase: typeof ActionBase; | ||
readonly Base: typeof Base; | ||
readonly StreamOutput: typeof StreamOutput; | ||
readonly Config: typeof Config; | ||
readonly ExitError: typeof exitError.ExitError; | ||
readonly prompt: typeof Prompt; | ||
}; | ||
export default deps; |
@@ -5,3 +5,2 @@ "use strict"; | ||
get chalk() { return fetch('chalk'); }, | ||
get moment() { return fetch('moment'); }, | ||
get stripAnsi() { return fetch('strip-ansi'); }, | ||
@@ -11,10 +10,4 @@ get ansiStyles() { return fetch('ansi-styles'); }, | ||
get passwordPrompt() { return fetch('password-prompt'); }, | ||
get screen() { return fetch('@cli-engine/screen'); }, | ||
get Prompt() { return fetch('./prompt').default; }, | ||
get Errors() { return fetch('./errors').Errors; }, | ||
get ActionBase() { return fetch('./action/base'); }, | ||
get Base() { return fetch('./base').default; }, | ||
get StreamOutput() { return fetch('./stream').default; }, | ||
get Config() { return fetch('./config').default; }, | ||
get ExitError() { return fetch('./exit_error').ExitError; }, | ||
get screen() { return fetch('@dxcli/screen'); }, | ||
get prompt() { return fetch('./prompt'); }, | ||
}; | ||
@@ -21,0 +14,0 @@ const cache = {}; |
@@ -1,17 +0,3 @@ | ||
import deps from './deps'; | ||
export interface IErrorOptions { | ||
exitCode?: number | false; | ||
severity: 'warn' | 'fatal' | 'error'; | ||
context?: string; | ||
} | ||
export declare class Errors extends deps.Base { | ||
handleUnhandleds(): void; | ||
error(err: Error | string, options: Partial<IErrorOptions> & { | ||
exitCode: false; | ||
}): void; | ||
error(err: Error | string, options?: Partial<IErrorOptions>): never; | ||
fatal(err: Error | string, options?: Partial<IErrorOptions>): void; | ||
warn(err: Error | string, options?: Partial<IErrorOptions>): void; | ||
exit(code?: number): void; | ||
private logError(err); | ||
} | ||
import Rx = require('rxjs/Rx'); | ||
import { Message } from './message'; | ||
export default function (o: Rx.Subject<Message>): Rx.Observable<any>; |
"use strict"; | ||
// tslint:disable no-console | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util_1 = require("util"); | ||
const _1 = require("."); | ||
const config_1 = require("./config"); | ||
const deps_1 = require("./deps"); | ||
const util = require("util"); | ||
const arrow = process.platform === 'win32' ? ' !' : ' ▸'; | ||
@@ -19,6 +22,6 @@ function bangify(msg, c) { | ||
if (err.body.message) { | ||
message = util.inspect(err.body.message); | ||
message = util_1.inspect(err.body.message); | ||
} | ||
else if (err.body.error) { | ||
message = util.inspect(err.body.error); | ||
message = util_1.inspect(err.body.error); | ||
} | ||
@@ -28,3 +31,3 @@ } | ||
if (err.message && err.code) { | ||
message = `${util.inspect(err.code)}: ${err.message}`; | ||
message = `${util_1.inspect(err.code)}: ${message}`; | ||
} | ||
@@ -34,3 +37,3 @@ else if (err.message) { | ||
} | ||
return message || util.inspect(err); | ||
return message || util_1.inspect(err); | ||
} | ||
@@ -44,75 +47,69 @@ function wrap(msg) { | ||
} | ||
class Errors extends deps_1.default.Base { | ||
handleUnhandleds() { | ||
process.on('unhandledRejection', (reason, p) => { | ||
this.fatal(reason, { context: 'Promise unhandledRejection' }); | ||
}); | ||
process.on('uncaughtException', error => { | ||
this.fatal(error, { context: 'Error uncaughtException' }); | ||
}); | ||
function default_1(o) { | ||
function renderError(message) { | ||
let bang = deps_1.default.chalk.red(arrow); | ||
if (message.severity === 'fatal') | ||
bang = deps_1.default.chalk.bgRed.bold.white(' FATAL '); | ||
if (message.severity === 'warn') | ||
bang = deps_1.default.chalk.yellow(arrow); | ||
const msg = message.scope ? `${message.scope}: ${getErrorMessage(message.error)}` : getErrorMessage(message.error); | ||
return bangify(wrap(msg), bang); | ||
} | ||
error(err, options) { | ||
if (typeof options === 'string') | ||
options = { context: options }; | ||
options = options || {}; | ||
if (!options.severity) | ||
options.severity = 'error'; | ||
if (options.exitCode === undefined) | ||
options.exitCode = 1; | ||
if (options.severity !== 'warn' && deps_1.default.Config.mock && typeof err !== 'string' && options.exitCode !== false) | ||
throw err; | ||
const handleError = (scope) => async (err) => { | ||
// ignore EPIPE errors | ||
// these come from using | head and | tail | ||
// and can be ignored | ||
try { | ||
if (typeof err === 'string') | ||
err = new Error(err); | ||
const prefix = options.context ? `${options.context}: ` : ''; | ||
this.logError(err); | ||
if (deps_1.default.Config.debug) { | ||
this.stderr.write(`${options.severity.toUpperCase()}: ${prefix}`); | ||
this.stderr.log(err.stack || util.inspect(err)); | ||
if (err.code === 'EPIPE') | ||
return; | ||
if (err.code === 'EEXIT' && typeof err.status === 'number') { | ||
process.exit(err.status); | ||
} | ||
else { | ||
let bang = deps_1.default.chalk.red(arrow); | ||
if (options.severity === 'fatal') | ||
bang = deps_1.default.chalk.bgRed.bold.white(' FATAL '); | ||
if (options.severity === 'warn') | ||
bang = deps_1.default.chalk.yellow(arrow); | ||
this.stderr.log(bangify(wrap(prefix + getErrorMessage(err)), bang)); | ||
const cli = new _1.CLI(scope); | ||
cli.fatal(err, { exit: false }); | ||
await cli.done(); | ||
process.exit(100); | ||
} | ||
} | ||
catch (e) { | ||
console.error('error displaying error'); | ||
console.error(e); | ||
catch (err) { | ||
console.error(err); | ||
process.exit(101); | ||
} | ||
if (options.exitCode !== false) | ||
this.exit(options.exitCode); | ||
}; | ||
function handleUnhandleds() { | ||
process.once('SIGINT', () => { | ||
const cli = new _1.CLI('SIGINT'); | ||
const err = new Error(); | ||
err.code = 'ESIGINT'; | ||
cli.error(err); | ||
}); | ||
process.once('unhandledRejection', handleError('unhandledRejection')); | ||
process.once('uncaughtException', handleError('uncaughtException')); | ||
process.stdout.on('error', handleError); | ||
process.stderr.on('error', handleError); | ||
} | ||
fatal(err, options = {}) { | ||
options.severity = 'fatal'; | ||
this.error(err, options); | ||
} | ||
warn(err, options = {}) { | ||
if (typeof options === 'string') | ||
options = { context: options }; | ||
options.exitCode = false; | ||
options.severity = 'warn'; | ||
this.error(err, options); | ||
} | ||
exit(code = 0) { | ||
if (deps_1.default.Config.debug) { | ||
console.error(`Exiting with code: ${code}`); | ||
handleUnhandleds(); | ||
return o | ||
.takeUntil(o.filter(m => m.type === 'done')) | ||
.filter((m) => m.type === 'error') | ||
.do(m => { | ||
o.next({ type: 'logger', scope: m.scope, severity: m.severity, message: getErrorMessage(m.error) }); | ||
const bang = (m.severity === 'warn' && deps_1.default.chalk.yellowBright('!')) | ||
|| (m.severity === 'fatal' && deps_1.default.chalk.bold.bgRedBright('!!!')) | ||
|| deps_1.default.chalk.bold.redBright('!'); | ||
try { | ||
config_1.config.action.pause(() => { | ||
process.stderr.write(config_1.config.debug ? util_1.inspect(m.error) : renderError(m) + '\n'); | ||
if (m.severity === 'fatal') | ||
process.stderr.write(util_1.inspect(m.error) + '\n'); | ||
}, bang); | ||
} | ||
if (deps_1.default.Config.mock) { | ||
throw new deps_1.default.ExitError(code, this.stdout.output, this.stderr.output); | ||
catch (newErr) { | ||
console.error(newErr); | ||
console.error(m.error); | ||
process.exit(1); | ||
} | ||
else { | ||
process.exit(code); | ||
} | ||
} | ||
logError(err) { | ||
if (!deps_1.default.Config.errlog) | ||
return; | ||
deps_1.default.StreamOutput.logToFile(util.inspect(err) + '\n', deps_1.default.Config.errlog); | ||
} | ||
}); | ||
} | ||
exports.Errors = Errors; | ||
exports.default = default_1; |
@@ -1,37 +0,28 @@ | ||
import StreamOutput from './stream'; | ||
import Prompt, { IPromptOptions } from './prompt'; | ||
import { Errors, IErrorOptions } from './errors'; | ||
import { ActionBase } from './action/base'; | ||
import { TableOptions } from './table'; | ||
import deps from './deps'; | ||
export declare class CLI extends deps.Base { | ||
stdout: StreamOutput; | ||
stderr: StreamOutput; | ||
private _prompt; | ||
readonly Prompt: Prompt; | ||
private _errors; | ||
readonly Errors: Errors; | ||
private _action; | ||
import { IPromptOptions } from './prompt'; | ||
import { Config } from './config'; | ||
export interface IErrorOptions { | ||
exit?: number | false; | ||
severity?: 'fatal' | 'error' | 'warn'; | ||
} | ||
export declare class CLI { | ||
scope: string | undefined; | ||
config: Config; | ||
readonly action: ActionBase; | ||
constructor(scope?: string | undefined); | ||
error(input: Error | string, options?: IErrorOptions): void; | ||
fatal(input: Error | string, options?: IErrorOptions): void; | ||
warn(input: Error | string): void; | ||
log(...input: any[]): void; | ||
info(...input: any[]): void; | ||
debug(...input: any[]): void; | ||
trace(...input: any[]): void; | ||
exit(code?: number, error?: Error): void; | ||
done(): Promise<void>; | ||
styledObject(...args: any[]): void; | ||
table(...args: any[]): void; | ||
prompt(name: string, options?: IPromptOptions): Promise<any>; | ||
confirm(message: string): Promise<boolean>; | ||
log(data?: string, ...args: any[]): void; | ||
warn(err: Error | string, options?: Partial<IErrorOptions>): void; | ||
error(err: Error | string, options?: Partial<IErrorOptions>): void; | ||
exit(code?: number): void; | ||
table(data: any[], options: Partial<TableOptions>): any; | ||
styledJSON(obj: any): void; | ||
styledHeader(header: string): void; | ||
styledObject(obj: any, keys: string[]): void; | ||
readonly color: any; | ||
/** | ||
* puts in a handler for process.on('uncaughtException') and process.on('unhandledRejection') | ||
*/ | ||
handleUnhandleds(): void; | ||
/** | ||
* cleanup any outstanding output like actions that need to be stopped | ||
*/ | ||
done(): void; | ||
} | ||
export declare const cli: CLI; | ||
export default cli; |
187
lib/index.js
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
// tslint:disable no-console | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const Rx = require("rxjs/Rx"); | ||
const deps_1 = require("./deps"); | ||
// import { deprecate } from 'util' | ||
const deprecate = process.env.DEBUG ? require('util').deprecate : (fn) => () => fn(); | ||
const deprecatedColor = deprecate(() => require('@heroku-cli/color').default, "cli.color is deprecated. Please use `import color from '@heroku-cli/color'` instead."); | ||
class CLI extends deps_1.default.Base { | ||
get Prompt() { | ||
if (!this._prompt) { | ||
this._prompt = new deps_1.default.Prompt(); | ||
} | ||
return this._prompt; | ||
const errors_1 = require("./errors"); | ||
const exit_1 = require("./exit"); | ||
const logger_1 = require("./logger"); | ||
const output_1 = require("./output"); | ||
const config_1 = require("./config"); | ||
let subject = new Rx.Subject(); | ||
let children; | ||
config_1.config.subscribe(subject); | ||
class CLI { | ||
constructor(scope) { | ||
this.scope = scope; | ||
this.config = config_1.config; | ||
} | ||
get Errors() { | ||
if (!this._errors) { | ||
this._errors = new deps_1.default.Errors(); | ||
} | ||
return this._errors; | ||
get action() { return config_1.config.action; } | ||
error(input, options = {}) { | ||
const error = input instanceof Error ? input : new Error(input); | ||
subject.next({ type: 'error', scope: this.scope, severity: options.severity || 'error', error }); | ||
const code = getExitCode(options); | ||
if (code !== false) | ||
this.exit(code, error); | ||
} | ||
get action() { | ||
if (!this._action) | ||
this._action = deps_1.default.ActionBase.getSpinner(); | ||
return this._action; | ||
fatal(input, options = {}) { this.error(input, Object.assign({}, options, { severity: 'fatal' })); } | ||
warn(input) { this.error(input, { severity: 'warn', exit: false }); } | ||
log(...input) { this.info(...input); } | ||
info(...input) { subject.next({ type: 'output', scope: this.scope, severity: 'info', input }); } | ||
debug(...input) { subject.next({ type: 'output', scope: this.scope, severity: 'debug', input }); } | ||
trace(...input) { subject.next({ type: 'output', scope: this.scope, severity: 'trace', input }); } | ||
exit(code = 1, error) { throw new exit_1.ExitError(code, error); } | ||
async done() { | ||
config_1.config.action.stop(); | ||
await new Promise((resolve, reject) => { | ||
children.subscribe({ error: reject, complete: resolve }); | ||
subject.next({ type: 'done' }); | ||
}); | ||
reset(); | ||
} | ||
styledObject(...args) { require('./styled/object').default(...args); } | ||
table(...args) { (require('./styled/table'))(...args); } | ||
prompt(name, options = {}) { | ||
return this.action.pauseAsync(() => { | ||
return this.Prompt.prompt(name, options); | ||
return deps_1.default.prompt.prompt(name, options); | ||
}, deps_1.default.chalk.cyan('?')); | ||
} | ||
confirm(message) { | ||
return this.action.pauseAsync(() => __awaiter(this, void 0, void 0, function* () { | ||
const confirm = () => __awaiter(this, void 0, void 0, function* () { | ||
let response = (yield this.Prompt.prompt(message)).toLowerCase(); | ||
return this.action.pauseAsync(async () => { | ||
const confirm = async () => { | ||
let response = (await deps_1.default.prompt.prompt(message)).toLowerCase(); | ||
if (['n', 'no'].includes(response)) | ||
@@ -47,99 +58,31 @@ return false; | ||
return confirm(); | ||
}); | ||
}; | ||
return confirm(); | ||
}), deps_1.default.chalk.cyan('?')); | ||
}, deps_1.default.chalk.cyan('?')); | ||
} | ||
log(data, ...args) { | ||
this.action.pause(() => { | ||
return this.stdout.log(data, ...args); | ||
}); | ||
} | ||
warn(err, options = {}) { | ||
this.emit('warn', typeof err === 'string' ? new Error(err) : err); | ||
this.action.pause(() => { | ||
return this.Errors.warn(err, options); | ||
}, deps_1.default.chalk.bold.yellow('!')); | ||
} | ||
error(err, options = {}) { | ||
this.emit('error', typeof err === 'string' ? new Error(err) : err); | ||
this.action.pause(() => { | ||
return this.Errors.error(err, options); | ||
}, deps_1.default.chalk.bold.red('!')); | ||
} | ||
exit(code = 1) { | ||
this.Errors.exit(code); | ||
} | ||
table(data, options) { | ||
let table = require('./table'); | ||
return table(this, data, options); | ||
} | ||
styledJSON(obj) { | ||
let json = JSON.stringify(obj, null, 2); | ||
if (deps_1.default.chalk.enabled) { | ||
let cardinal = require('cardinal'); | ||
let theme = require('cardinal/themes/jq'); | ||
this.log(cardinal.highlight(json, { json: true, theme: theme })); | ||
} | ||
else { | ||
this.log(json); | ||
} | ||
} | ||
styledHeader(header) { | ||
this.log(deps_1.default.chalk.dim('=== ') + deps_1.default.chalk.bold(header)); | ||
} | ||
styledObject(obj, keys) { | ||
const util = require('util'); | ||
let keyLengths = Object.keys(obj).map(key => key.toString().length); | ||
let maxKeyLength = Math.max.apply(Math, keyLengths) + 2; | ||
function pp(obj) { | ||
if (typeof obj === 'string' || typeof obj === 'number') { | ||
return obj; | ||
} | ||
else if (typeof obj === 'object') { | ||
return Object.keys(obj) | ||
.map(k => k + ': ' + util.inspect(obj[k])) | ||
.join(', '); | ||
} | ||
else { | ||
return util.inspect(obj); | ||
} | ||
} | ||
let logKeyValue = (key, value) => { | ||
this.log(`${deps_1.default.chalk.blue(key)}:` + ' '.repeat(maxKeyLength - key.length - 1) + pp(value)); | ||
}; | ||
for (var key of keys || Object.keys(obj).sort()) { | ||
let value = obj[key]; | ||
if (Array.isArray(value)) { | ||
if (value.length > 0) { | ||
logKeyValue(key, value[0]); | ||
for (var e of value.slice(1)) { | ||
this.log(' '.repeat(maxKeyLength) + pp(e)); | ||
} | ||
} | ||
} | ||
else if (value !== null && value !== undefined) { | ||
logKeyValue(key, value); | ||
} | ||
} | ||
} | ||
get color() { | ||
return deprecatedColor(); | ||
} | ||
/** | ||
* puts in a handler for process.on('uncaughtException') and process.on('unhandledRejection') | ||
*/ | ||
handleUnhandleds() { | ||
this.Errors.handleUnhandleds(); | ||
} | ||
/** | ||
* cleanup any outstanding output like actions that need to be stopped | ||
*/ | ||
done() { | ||
this.action.stop(); | ||
} | ||
} | ||
exports.CLI = CLI; | ||
function getExitCode(options) { | ||
let exit = options.exit === undefined ? options.exitCode : options.exit; | ||
if (exit === false) | ||
return false; | ||
if (exit === undefined) | ||
return 1; | ||
return exit; | ||
} | ||
function reset() { | ||
children = Rx.Observable.forkJoin(errors_1.default(subject), output_1.default(subject), logger_1.default(subject)).share(); | ||
children.subscribe(); | ||
} | ||
reset(); | ||
exports.cli = new CLI(); | ||
exports.default = exports.cli; | ||
// swallow error event so it does not cause a crash | ||
exports.cli.on('error', () => { }); | ||
process.once('exit', async () => { | ||
try { | ||
await exports.cli.done(); | ||
} | ||
catch (err) { | ||
console.error(err); | ||
process.exitCode = 1; | ||
} | ||
}); |
"use strict"; | ||
// tslint:disable | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const _ = require("lodash"); | ||
const deps_1 = require("./deps"); | ||
@@ -14,3 +16,2 @@ function linewrap(length, s) { | ||
} | ||
let { default: _ } = require('ts-lodash'); | ||
const maxLength = _.maxBy(items, '[0].length')[0].length; | ||
@@ -17,0 +18,0 @@ const lines = items.map(i => { |
@@ -1,2 +0,1 @@ | ||
import deps from './deps'; | ||
export interface IPromptOptions { | ||
@@ -6,5 +5,2 @@ prompt?: string; | ||
} | ||
export default class Prompt extends deps.Base { | ||
prompt(name: string, inputOptions?: Partial<IPromptOptions>): Promise<string>; | ||
private normal(options, retries?); | ||
} | ||
export declare function prompt(name: string, inputOptions?: Partial<IPromptOptions>): Promise<string>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const deps_1 = require("./deps"); | ||
class Prompt extends deps_1.default.Base { | ||
prompt(name, inputOptions = {}) { | ||
const options = Object.assign({ isTTY: !!(process.env.TERM !== 'dumb' && process.stdin.isTTY), name, prompt: name ? deps_1.default.chalk.dim(`${name}: `) : deps_1.default.chalk.dim('> '), type: 'normal' }, inputOptions); | ||
switch (options.type) { | ||
case 'normal': | ||
return this.normal(options); | ||
case 'mask': | ||
case 'hide': | ||
return deps_1.default.passwordPrompt(options.prompt, { method: options.type }); | ||
default: | ||
throw new Error(`unexpected type ${options.type}`); | ||
} | ||
function prompt(name, inputOptions = {}) { | ||
const options = Object.assign({ isTTY: !!(process.env.TERM !== 'dumb' && process.stdin.isTTY), name, prompt: name ? deps_1.default.chalk.dim(`${name}: `) : deps_1.default.chalk.dim('> '), type: 'normal' }, inputOptions); | ||
switch (options.type) { | ||
case 'normal': | ||
return normal(options); | ||
case 'mask': | ||
case 'hide': | ||
return deps_1.default.passwordPrompt(options.prompt, { method: options.type }); | ||
default: | ||
throw new Error(`unexpected type ${options.type}`); | ||
} | ||
normal(options, retries = 100) { | ||
if (retries < 0) | ||
throw new Error('no input'); | ||
return new Promise(resolve => { | ||
process.stdin.setEncoding('utf8'); | ||
this.stderr.write(options.prompt); | ||
process.stdin.resume(); | ||
process.stdin.once('data', data => { | ||
process.stdin.pause(); | ||
data = data.trim(); | ||
if (data === '') { | ||
resolve(this.normal(options, retries - 1)); | ||
} | ||
else { | ||
resolve(data); | ||
} | ||
}); | ||
} | ||
exports.prompt = prompt; | ||
function normal(options, retries = 100) { | ||
if (retries < 0) | ||
throw new Error('no input'); | ||
return new Promise(resolve => { | ||
process.stdin.setEncoding('utf8'); | ||
process.stderr.write(options.prompt); | ||
process.stdin.resume(); | ||
process.stdin.once('data', data => { | ||
process.stdin.pause(); | ||
data = data.trim(); | ||
if (data === '') { | ||
resolve(normal(options, retries - 1)); | ||
} | ||
else { | ||
resolve(data); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
exports.default = Prompt; |
{ | ||
"name": "cli-ux", | ||
"description": "set of CLI output utilities", | ||
"version": "3.0.0-alpha.1", | ||
"author": "Jeff Dickey", | ||
"bugs": "https://github.com/heroku/cli-ux/issues", | ||
"description": "cli IO utilities", | ||
"version": "3.0.0-alpha.2", | ||
"author": "Jeff Dickey @jdxcode", | ||
"bugs": "https://github.com/dxcli/cli-ux/issues", | ||
"dependencies": { | ||
"@cli-engine/screen": "^0.0.0", | ||
"@heroku-cli/color": "^1.0.4", | ||
"@dxcli/screen": "^0.0.0", | ||
"@heroku/linewrap": "^1.0.0", | ||
"ansi-escapes": "^3.0.0", | ||
"ansi-styles": "^3.2.0", | ||
"cardinal": "^1.0.0", | ||
"chalk": "^2.3.0", | ||
"fs-extra": "^5.0.0", | ||
"lodash": "^4.17.4", | ||
"moment": "^2.20.1", | ||
"password-prompt": "^1.0.3", | ||
"rxjs": "^5.5.6", | ||
"semver": "^5.4.1", | ||
"strip-ansi": "^4.0.0", | ||
"supports-color": "^5.1.0", | ||
"ts-lodash": "^4.0.8" | ||
"supports-color": "^5.1.0" | ||
}, | ||
"devDependencies": { | ||
"@types/ansi-styles": "^2.0.30", | ||
"@types/jest": "^22.0.1", | ||
"@types/lodash": "^4.14.91", | ||
"@types/node": "^8.5.2", | ||
"@types/strip-ansi": "^3.0.0", | ||
"@dxcli/dev": "^1.1.3", | ||
"@dxcli/dev-semantic-release": "^0.0.3", | ||
"@dxcli/dev-test": "^0.2.1", | ||
"@dxcli/dev-tslint": "^0.0.14", | ||
"@types/fs-extra": "^5.0.0", | ||
"@types/node": "^9.3.0", | ||
"@types/semver": "^5.4.0", | ||
"@types/supports-color": "^3.1.0", | ||
"babel-core": "^6.26.0", | ||
"del-cli": "^1.1.0", | ||
"eslint": "^4.15.0", | ||
"eslint-config-dxcli": "^1.1.4", | ||
"husky": "^0.14.3", | ||
"jest": "^22.0.4", | ||
"prettier": "^1.9.2", | ||
"std-mocks": "^1.0.1", | ||
"ts-jest": "^22.0.0", | ||
"mocha": "^4.1.0", | ||
"nyc": "^11.4.1", | ||
"ts-node": "^4.1.0", | ||
"typescript": "^2.6.2" | ||
}, | ||
"dxcli": { | ||
"workflows": { | ||
"test": [ | ||
"eslint .", | ||
"tsc -p test --noEmit", | ||
"tslint -p test", | ||
"commitlint --from origin/master", | ||
"mocha \"test/**/*.ts\"" | ||
], | ||
"lint": [ | ||
"eslint .", | ||
"tsc -p test --noEmit", | ||
"tslint -p test", | ||
"commitlint --from origin/master" | ||
] | ||
} | ||
}, | ||
"engines": { | ||
"node": ">=6.0.0" | ||
"node": ">=8.0.0" | ||
}, | ||
"files": [ | ||
"lib" | ||
"/lib" | ||
], | ||
"homepage": "https://github.com/heroku/cli-ux", | ||
"homepage": "https://github.com/dxcli/cli-ux", | ||
"keywords": [ | ||
"cli" | ||
"dxcli" | ||
], | ||
"license": "ISC", | ||
"main": "./lib/index.js", | ||
"repository": "heroku/cli-ux", | ||
"license": "MIT", | ||
"main": "lib/index.js", | ||
"repository": "dxcli/cli-ux", | ||
"scripts": { | ||
"prepare": "del lib && tsc", | ||
"pretest": "tsc", | ||
"test": "jest" | ||
"commitmsg": "dxcli-dev-commitmsg", | ||
"lint": "dxcli-dev lint", | ||
"precommit": "dxcli-dev lint", | ||
"prepare": "rm -rf lib && tsc", | ||
"test": "dxcli-dev test" | ||
}, | ||
"types": "./lib/index.d.ts" | ||
"types": "lib/index.d.ts" | ||
} |
cli-ux | ||
========== | ||
====== | ||
[![Greenkeeper badge](https://badges.greenkeeper.io/heroku/cli-ux.svg)](https://greenkeeper.io/) | ||
[![CircleCI](https://circleci.com/gh/heroku/cli-ux.svg?style=svg)](https://circleci.com/gh/heroku/cli-ux) | ||
cli IO utilities | ||
[![Version](https://img.shields.io/npm/v/cli-ux.svg)](https://npmjs.org/package/cli-ux) | ||
[![CircleCI](https://circleci.com/gh/dxcli/cli-ux/tree/master.svg?style=svg)](https://circleci.com/gh/dxcli/cli-ux/tree/master) | ||
[![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/dxcli/cli-ux?branch=master&svg=true)](https://ci.appveyor.com/project/heroku/cli-ux/branch/master) | ||
[![Codecov](https://codecov.io/gh/dxcli/cli-ux/branch/master/graph/badge.svg)](https://codecov.io/gh/dxcli/cli-ux) | ||
[![Greenkeeper](https://badges.greenkeeper.io/dxcli/cli-ux.svg)](https://greenkeeper.io/) | ||
[![Known Vulnerabilities](https://snyk.io/test/npm/cli-ux/badge.svg)](https://snyk.io/test/npm/cli-ux) | ||
[![Downloads/week](https://img.shields.io/npm/dw/cli-ux.svg)](https://npmjs.org/package/cli-ux) | ||
[![License](https://img.shields.io/npm/l/cli-ux.svg)](https://github.com/dxcli/cli-ux/blob/master/package.json) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
11
14
8
9
48989
1456
+ Added@dxcli/screen@^0.0.0
+ Addedfs-extra@^5.0.0
+ Addedrxjs@^5.5.6
+ Addedsemver@^5.4.1
+ Added@dxcli/screen@0.0.0(transitive)
+ Addedfs-extra@5.0.0(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedjsonfile@4.0.0(transitive)
+ Addedrxjs@5.5.12(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedsymbol-observable@1.0.1(transitive)
+ Addeduniversalify@0.1.2(transitive)
- Removed@cli-engine/screen@^0.0.0
- Removed@heroku-cli/color@^1.0.4
- Removedansi-escapes@^3.0.0
- Removedcardinal@^1.0.0
- Removedmoment@^2.20.1
- Removedts-lodash@^4.0.8
- Removed@cli-engine/screen@0.0.0(transitive)
- Removed@heroku-cli/color@1.1.16(transitive)
- Removedansi-escapes@3.2.0(transitive)
- Removedansi-regex@4.1.1(transitive)
- Removedansicolors@0.2.1(transitive)
- Removedcardinal@1.0.0(transitive)
- Removedesprima@3.0.0(transitive)
- Removedmoment@2.30.1(transitive)
- Removedredeyed@1.0.1(transitive)
- Removedstrip-ansi@5.2.0(transitive)
- Removedts-lodash@4.0.11(transitive)
- Removedtslib@1.14.1(transitive)