Comparing version 5.1.0-beta.2 to 6.0.0-beta.1
import Enquirer from 'enquirer'; | ||
import { Observable } from 'rxjs'; | ||
import { Readable, Writable } from 'stream'; | ||
import { Writable, Readable } from 'stream'; | ||
import { WriteStream } from 'fs'; | ||
@@ -17,3 +17,3 @@ import * as _colorette from 'colorette'; | ||
SUBTASK = "SUBTASK", | ||
DATA = "DATA", | ||
OUTPUT = "OUTPUT", | ||
MESSAGE = "MESSAGE" | ||
@@ -41,3 +41,3 @@ } | ||
UNINITIALIZED = "UNINITIALIZED", | ||
PENDING = "PENDING", | ||
STARTED = "STARTED", | ||
COMPLETED = "COMPLETED", | ||
@@ -58,2 +58,294 @@ FAILED = "FAILED", | ||
/** Default loglevels for the logger */ | ||
declare enum LogLevels { | ||
STARTED = "STARTED", | ||
COMPLETED = "COMPLETED", | ||
FAILED = "FAILED", | ||
SKIPPED = "SKIPPED", | ||
OUTPUT = "OUTPUT", | ||
TITLE = "TITLE", | ||
ROLLBACK = "ROLLBACK", | ||
RETRY = "RETRY", | ||
SUBTASK = "SUBTASK" | ||
} | ||
/** | ||
* Tests to see if the object is an RxJS {@link Observable} | ||
* @param obj the object to test | ||
*/ | ||
declare function isObservable<T>(obj: any): obj is { | ||
subscribe: T; | ||
next: any; | ||
error: any; | ||
complete: any; | ||
}; | ||
declare function isUnicodeSupported(): boolean; | ||
declare const colorette: _colorette.Colorette; | ||
declare function indentString(string: string, count: number): string; | ||
declare const FIGURES_MAIN: { | ||
warning: string; | ||
cross: string; | ||
arrowDown: string; | ||
tick: string; | ||
arrowRight: string; | ||
pointer: string; | ||
checkboxOn: string; | ||
arrowLeft: string; | ||
squareSmallFilled: string; | ||
pointerSmall: string; | ||
}; | ||
type Figures = typeof FIGURES_MAIN; | ||
declare const figures: Figures; | ||
/** | ||
* A basic function to parse minutes and tasks passed given a duration. | ||
* Useful for renderers to show the task time. | ||
* | ||
* @param {number} duration | ||
* @returns {string} | ||
*/ | ||
declare function parseTaskTime(duration: number): string; | ||
declare function timestamp(): string; | ||
declare class ProcessOutput { | ||
stdout(buffer: string): boolean; | ||
stderr(buffer: string): boolean; | ||
} | ||
interface ProcessOutputRendererOptions { | ||
/** | ||
* Pass your implementation of process output class to write to stdout and stderr. | ||
* | ||
* @default 'ProcessOutput' | ||
* @global global option that can not be temperated with subtasks | ||
*/ | ||
processOutput?: ProcessOutput; | ||
} | ||
/** | ||
* This function asserts the given value as a function or itself. | ||
* If the value itself is a function it will evaluate it with the passed in arguments, | ||
* elsewise it will directly return itself. | ||
*/ | ||
declare function assertFunctionOrSelf<T>(functionOrSelf: T, ...args: T extends (...args: any[]) => any ? Parameters<T> : never): T extends (...args: any[]) => any ? ReturnType<T> : T; | ||
/** | ||
* Deep clones a object in the most easiest manner. | ||
*/ | ||
declare function cloneObject<T extends Record<PropertyKey, any>>(obj: T): T; | ||
interface BasePromptOptions { | ||
message: string | (() => string) | (() => Promise<string>); | ||
initial?: boolean | number | number[] | string | (() => string) | (() => Promise<string>); | ||
required?: boolean; | ||
stdin?: NodeJS.ReadStream; | ||
stdout?: NodeJS.WriteStream; | ||
header?: string; | ||
footer?: string; | ||
skip?: (value: any) => boolean | Promise<boolean>; | ||
format?: (value: any) => any | Promise<any>; | ||
result?: (value: any) => any | Promise<any>; | ||
validate?: (value: any, state: any) => boolean | Promise<boolean> | string | Promise<string> | Promise<string | boolean>; | ||
onSubmit?: (name: any, value: any, prompt: Enquirer.Prompt) => boolean | Promise<boolean>; | ||
onCancel?: (name: any, value: any, prompt: Enquirer.Prompt) => boolean | Promise<boolean>; | ||
} | ||
interface BasePromptOptionsWithName extends BasePromptOptions { | ||
name: string | (() => string); | ||
} | ||
interface ArrayPromptOptions extends BasePromptOptions { | ||
choices: string[] | BasePromptOptionsWithName[]; | ||
maxChoices?: number; | ||
multiple?: boolean; | ||
initial?: number | number[]; | ||
delay?: number; | ||
separator?: boolean; | ||
sort?: boolean; | ||
linebreak?: boolean; | ||
edgeLength?: number; | ||
align?: 'left' | 'right'; | ||
scroll?: boolean; | ||
hint?: string; | ||
} | ||
interface BooleanPromptOptions extends BasePromptOptions { | ||
initial?: boolean | (() => string) | (() => Promise<string>); | ||
} | ||
interface StringPromptOptions extends BasePromptOptions { | ||
initial?: string; | ||
multiline?: boolean; | ||
} | ||
interface ScalePromptOptions extends ArrayPromptOptions { | ||
scale: StringPromptOptions[]; | ||
margin?: [number, number, number, number]; | ||
} | ||
interface NumberPromptOptions extends BasePromptOptions { | ||
min?: number; | ||
max?: number; | ||
delay?: number; | ||
float?: boolean; | ||
round?: boolean; | ||
major?: number; | ||
minor?: number; | ||
initial?: number; | ||
} | ||
interface SnippetPromptOptions extends BasePromptOptions { | ||
newline?: string; | ||
fields: Partial<BasePromptOptionsWithName>[]; | ||
template: string; | ||
} | ||
interface SortPromptOptions extends BasePromptOptions { | ||
hint?: string; | ||
drag?: boolean; | ||
numbered?: boolean; | ||
} | ||
interface SurveyPromptOptions extends ArrayPromptOptions { | ||
scale: BasePromptOptionsWithName[]; | ||
margin: [number, number, number, number]; | ||
} | ||
interface QuizPromptOptions extends ArrayPromptOptions { | ||
correctChoice: number; | ||
} | ||
interface TogglePromptOptions extends BasePromptOptions { | ||
enabled?: string; | ||
disabled?: string; | ||
} | ||
/** Returns all the prompt options depending on the type selected. */ | ||
type PromptOptions<T extends boolean = false> = Unionize<{ | ||
[K in PromptTypes]-?: T extends true ? { | ||
type: K; | ||
} & PromptOptionsType<K> & { | ||
name: string | (() => string); | ||
} : { | ||
type: K; | ||
} & PromptOptionsType<K>; | ||
}> | ({ | ||
type: string; | ||
} & T extends true ? PromptOptionsType<string> & { | ||
name: string | (() => string); | ||
} : PromptOptionsType<string>); | ||
type Unionize<T extends Record<PropertyKey, unknown>> = { | ||
[P in keyof T]: T[P]; | ||
}[keyof T]; | ||
type PromptTypes = 'AutoComplete' | 'BasicAuth' | 'Confirm' | 'Editable' | 'Form' | 'Input' | 'Invisible' | 'List' | 'MultiSelect' | 'Numeral' | 'Password' | 'Quiz' | 'Scale' | 'Select' | 'Snippet' | 'Sort' | 'Survey' | 'Text' | 'Toggle'; | ||
type PromptOptionsType<T> = T extends keyof PromptOptionsMap ? PromptOptionsMap[T] : T extends string ? BasePromptOptions & Record<PropertyKey, unknown> : any; | ||
declare class PromptOptionsMap implements Record<PromptTypes, Record<PropertyKey, any>> { | ||
AutoComplete: ArrayPromptOptions; | ||
BasicAuth: StringPromptOptions; | ||
Confirm: BooleanPromptOptions; | ||
Editable: ArrayPromptOptions; | ||
Form: ArrayPromptOptions; | ||
Input: StringPromptOptions; | ||
Invisible: StringPromptOptions; | ||
List: ArrayPromptOptions; | ||
MultiSelect: ArrayPromptOptions; | ||
Numeral: NumberPromptOptions; | ||
Password: StringPromptOptions; | ||
Quiz: QuizPromptOptions; | ||
Scale: ScalePromptOptions; | ||
Select: ArrayPromptOptions; | ||
Snippet: SnippetPromptOptions; | ||
Sort: SortPromptOptions; | ||
Survey: SurveyPromptOptions; | ||
Text: StringPromptOptions; | ||
Toggle: TogglePromptOptions; | ||
} | ||
interface PromptSettings { | ||
error?: boolean; | ||
cancelCallback?: (settings?: PromptSettings) => string | Error | PromptError | void; | ||
stdout?: WriteStream | Writable; | ||
enquirer?: Enquirer; | ||
} | ||
interface PromptInstance extends Omit<BasePromptOptions, 'onCancel' | 'onSubmit'> { | ||
submit: () => void; | ||
cancel: (err?: string) => void; | ||
} | ||
/** | ||
* Create a new prompt with Enquirer externally. | ||
* This extends enquirer so you dont have to give a name to single prompts and such so it is also | ||
* useful to use externally. | ||
* @param this | ||
* @param options | ||
* @param settings | ||
*/ | ||
declare function createPrompt(this: any, options: PromptOptions | PromptOptions<true>[], settings?: PromptSettings): Promise<any>; | ||
declare function destroyPrompt(this: TaskWrapper<any, any>, throwError?: boolean): void; | ||
declare function getRendererClass(renderer: ListrRendererValue): ListrRendererFactory; | ||
declare function getRenderer(renderer: ListrRendererValue, fallbackRenderer?: ListrRendererValue, fallbackCondition?: ListrOptions['rendererFallback'], silentCondition?: ListrOptions['rendererSilent']): SupportedRenderer; | ||
/** Generate a basic uuid with no requirement of being unbelievable unique. */ | ||
declare function generateUUID(): string; | ||
/** | ||
* A internal logger for using in the verbose renderer mostly. | ||
*/ | ||
declare class ListrLogger { | ||
private options?; | ||
readonly process: ProcessOutput; | ||
constructor(options?: ListrLoggerOptions); | ||
started(message: string, options?: LogEntityOptions): void; | ||
failed(message: string, options?: LogEntityOptions): void; | ||
skipped(message: string, options?: LogEntityOptions): void; | ||
completed(message: string, options?: LogEntityOptions): void; | ||
output(message: string, options?: LogEntityOptions): void; | ||
title(message: string, options?: LogEntityOptions): void; | ||
subtask(message: string, options?: LogEntityOptions): void; | ||
retry(message: string, options?: LogEntityOptions): void; | ||
rollback(message: string, options?: LogEntityOptions): void; | ||
wrap(message: string, options?: { | ||
format?: LoggerFormat; | ||
}): string; | ||
suffix(message: string, ...suffixes: LoggerPrefixOrSuffix[]): string; | ||
prefix(message: string, ...prefixes: LoggerPrefixOrSuffix[]): string; | ||
applyToEntity(message: string, options?: LogEntityOptions<true>): string; | ||
protected format(level: LogLevels, message: string, options?: LogEntityOptions): string; | ||
protected style(level: LogLevels, message: string): string; | ||
} | ||
/** | ||
* Options for the logger | ||
*/ | ||
interface ListrLoggerOptions extends ProcessOutputRendererOptions { | ||
/** | ||
* useIcons instead of text for log level | ||
* @default false | ||
*/ | ||
useIcons?: boolean; | ||
entityOptions?: LogEntityOptions<true>; | ||
} | ||
interface LogEntityOptions<MultipleOnly extends boolean = false> { | ||
prefix?: MultipleOnly extends false ? LoggerPrefixOrSuffix | LoggerPrefixOrSuffix[] : LoggerPrefixOrSuffix[]; | ||
suffix?: MultipleOnly extends false ? LoggerPrefixOrSuffix | LoggerPrefixOrSuffix[] : LoggerPrefixOrSuffix[]; | ||
} | ||
type LoggerFormat = (message?: string) => string; | ||
interface LoggerPrefixOrSuffixFn<Args extends any[] = any[]> { | ||
condition?: ((...args: Args) => boolean) | boolean; | ||
data: ((...args: Args) => string) | string; | ||
args?: Args; | ||
format?: LoggerFormat; | ||
conditionalFormat?: (...args: Args) => LoggerFormat; | ||
} | ||
type LoggerPrefixOrSuffix<Args extends any[] = any[]> = LoggerPrefixOrSuffixFn<Args> | string; | ||
interface LoggerRendererOptions { | ||
logger?: ListrLogger; | ||
} | ||
interface RendererPresetTimer { | ||
/** | ||
* show duration for all tasks | ||
* | ||
* @default false | ||
* @global global option that can not be temperated with subtasks | ||
*/ | ||
timer?: LoggerPrefixOrSuffixFn<[number]>; | ||
} | ||
interface RendererPresetTimestamp { | ||
timestamp?: LoggerPrefixOrSuffixFn; | ||
} | ||
/** Default updating renderer for Listr2 */ | ||
@@ -145,9 +437,2 @@ declare class DefaultRenderer implements ListrRenderer { | ||
/** | ||
* show duration for all tasks | ||
* | ||
* @default false | ||
* @global global option that can not be temperated with subtasks | ||
*/ | ||
showTimer?: boolean; | ||
/** | ||
* removes empty lines from the data output | ||
@@ -165,3 +450,3 @@ * | ||
formatOutput?: 'truncate' | 'wrap'; | ||
}; | ||
} & RendererPresetTimer & LoggerRendererOptions; | ||
/** per task options for the default renderer */ | ||
@@ -186,7 +471,3 @@ static rendererTaskOptions: { | ||
persistentOutput?: boolean; | ||
/** | ||
* show the task time if it was successful | ||
*/ | ||
showTimer?: boolean; | ||
}; | ||
} & RendererPresetTimer; | ||
private id?; | ||
@@ -197,2 +478,3 @@ private bottomBar; | ||
private spinnerPosition; | ||
private readonly logger; | ||
constructor(tasks: Task<any, typeof DefaultRenderer>[], options: (typeof DefaultRenderer)['rendererOptions'], events: EventManager<ListrEventType, ListrEventMap>); | ||
@@ -202,5 +484,3 @@ getTaskOptions(task: Task<any, typeof DefaultRenderer>): (typeof DefaultRenderer)['rendererTaskOptions']; | ||
hasPersistentOutput(task: Task<any, typeof DefaultRenderer>): boolean; | ||
hasTimer(task: Task<any, typeof DefaultRenderer>): boolean; | ||
getSelfOrParentOption<T extends keyof (typeof DefaultRenderer)['rendererOptions']>(task: Task<any, typeof DefaultRenderer>, key: T): (typeof DefaultRenderer)['rendererOptions'][T]; | ||
getTaskTime(task: Task<any, typeof DefaultRenderer>): string; | ||
getSelfOrParentOption<K extends keyof (typeof DefaultRenderer)['rendererOptions']>(task: Task<any, typeof DefaultRenderer>, key: K): (typeof DefaultRenderer)['rendererOptions'][K]; | ||
createRender(options?: { | ||
@@ -213,10 +493,9 @@ tasks?: boolean; | ||
end(): void; | ||
private multiLineRenderer; | ||
protected getSymbol(task: Task<ListrContext, typeof DefaultRenderer>, data?: boolean): string; | ||
private renderer; | ||
private renderBottomBar; | ||
private renderPrompt; | ||
private dumpData; | ||
private formatString; | ||
private indentMultilineOutput; | ||
private getSymbol; | ||
private addSuffixToMessage; | ||
private dump; | ||
private format; | ||
private indent; | ||
} | ||
@@ -247,119 +526,143 @@ | ||
static nonTTY: boolean; | ||
static rendererOptions: { | ||
/** | ||
* if true this will add | ||
* timestamp at the begin of the rendered line | ||
* | ||
* @example | ||
* | ||
* ```bash | ||
* [12:33:44] ✔ Do something important | ||
* ``` | ||
* | ||
* @default false | ||
*/ | ||
prefixWithTimestamp?: boolean; | ||
/** | ||
* choose between process.stdout and process.stderr | ||
* | ||
* @default stdout | ||
*/ | ||
output?: 'stdout' | 'stderr'; | ||
}; | ||
static rendererTaskOptions: never; | ||
static rendererOptions: RendererPresetTimer & RendererPresetTimestamp & LoggerRendererOptions; | ||
static rendererTaskOptions: RendererPresetTimer; | ||
private readonly logger; | ||
constructor(tasks: Task<any, typeof SimpleRenderer>[], options: (typeof SimpleRenderer)['rendererOptions']); | ||
static now(): Date; | ||
static formatTitle(task?: Task<any, typeof SimpleRenderer>): string; | ||
log(output?: string): void; | ||
end(): void; | ||
render(): void; | ||
private simpleRenderer; | ||
getSelfOrParentOption<K extends keyof (typeof SimpleRenderer)['rendererOptions']>(task: Task<any, typeof SimpleRenderer>, key: K): (typeof SimpleRenderer)['rendererOptions'][K]; | ||
private renderer; | ||
} | ||
/** Default loglevels for the logger */ | ||
declare enum LogLevels { | ||
SILENT = "SILENT", | ||
FAILED = "FAILED", | ||
SKIPPED = "SKIPPED", | ||
SUCCESS = "SUCCESS", | ||
DATA = "DATA", | ||
STARTED = "STARTED", | ||
TITLE = "TITLE", | ||
RETRY = "RETRY", | ||
ROLLBACK = "ROLLBACK" | ||
} | ||
/** | ||
* Options for the logger | ||
* ListrTask. | ||
* | ||
* Defines the task, conditions and options to run a specific task in the listr. | ||
*/ | ||
interface LoggerOptions { | ||
useIcons: boolean; | ||
interface ListrTask<Ctx = ListrContext, Renderer extends ListrRendererFactory = any> { | ||
/** | ||
* Title of the task. | ||
* | ||
* Give this task a title if you want to track it by name in the current renderer. | ||
* | ||
* Tasks without a title will hide in the default renderer and are useful for running a background instance. | ||
* On verbose renderer, state changes from these tasks will log as 'Task without a title.' | ||
*/ | ||
title?: string; | ||
/** | ||
* The task itself. | ||
* | ||
* Task can be a sync or async function, an Observable, or a Stream. | ||
* Task will be executed, if the certain criteria of the state are met and whenever the time for that specific task has come. | ||
*/ | ||
task: ListrTaskFn<Ctx, Renderer>; | ||
/** | ||
* Skip this task depending on the context. | ||
* | ||
* The function that has been passed in will be evaluated at the runtime when the task tries to initially run. | ||
*/ | ||
skip?: boolean | string | ((ctx: Ctx) => boolean | string | Promise<boolean | string>); | ||
/** | ||
* Enable a task depending on the context. | ||
* | ||
* The function that has been passed in will be evaluated at the initial creation of the Listr class for rendering purposes, | ||
* as well as re-evaluated when the time for that specific task has come. | ||
*/ | ||
enabled?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>); | ||
/** | ||
* Adds the given number of retry attempts to the task if the task fails. | ||
*/ | ||
retry?: number; | ||
/** | ||
* Runs a specific event if the current task or any of the subtasks has failed. | ||
* | ||
* Mostly useful for rollback purposes for subtasks. | ||
* But can also be useful whenever a task is failed and some measures have to be taken to ensure the state is not changed. | ||
*/ | ||
rollback?: ListrTaskFn<Ctx, Renderer>; | ||
/** | ||
* Set exit on the error option from task-level instead of setting it for all the subtasks. | ||
*/ | ||
exitOnError?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>); | ||
/** | ||
* Per task options, that depends on the selected renderer. | ||
* | ||
* These options depend on the implementation of the selected renderer. If the selected renderer has no options it will | ||
* be displayed as never. | ||
*/ | ||
options?: ListrGetRendererTaskOptions<Renderer>; | ||
} | ||
/** | ||
* A internal logger for using in the verbose renderer mostly. | ||
* Task can be set of sync or async function, an Observable or a stream. | ||
*/ | ||
declare class Logger { | ||
private options?; | ||
constructor(options?: LoggerOptions); | ||
fail(message: string): void; | ||
skip(message: string): void; | ||
success(message: string): void; | ||
data(message: string): void; | ||
start(message: string): void; | ||
title(message: string): void; | ||
retry(message: string): void; | ||
rollback(message: string): void; | ||
protected parseMessage(level: LogLevels, message: string): string; | ||
protected logColoring({ level, message }: { | ||
level: LogLevels; | ||
message: string; | ||
}): string; | ||
private wrapInBrackets; | ||
type ListrTaskResult<Ctx> = string | Promise<any> | Listr<Ctx, ListrRendererValue, any> | Readable | NodeJS.ReadableStream | Observable<any>; | ||
type ListrTaskFn<Ctx, Renderer extends ListrRendererFactory> = (ctx: Ctx, task: TaskWrapper<Ctx, Renderer>) => void | ListrTaskResult<Ctx>; | ||
type ListrTaskPrompt = undefined | PromptInstance | PromptError; | ||
interface ListrTaskRetry { | ||
count: number; | ||
withError?: Error; | ||
} | ||
interface ListrTaskMessage { | ||
/** Run time of the task, if it has been successfully resolved. */ | ||
duration?: number; | ||
/** Error message of the task, if it has been failed. */ | ||
error?: string; | ||
/** Skip message of the task, if it has been skipped. */ | ||
skip?: string; | ||
/** Rollback message of the task, if the rollback finishes */ | ||
rollback?: string; | ||
/** Retry messages */ | ||
retry?: ListrTaskRetry; | ||
} | ||
declare class TestRenderer implements ListrRenderer { | ||
tasks: Task<any, typeof TestRenderer>[]; | ||
options: (typeof TestRenderer)['rendererOptions']; | ||
/** designates whether this renderer can output to a non-tty console */ | ||
static nonTTY: boolean; | ||
/** renderer options for the verbose renderer */ | ||
static rendererOptions: { | ||
subtasks?: boolean; | ||
state?: ListrTaskState[]; | ||
output?: boolean; | ||
title?: boolean; | ||
messages?: (keyof ListrTaskMessage)[]; | ||
} & LoggerRendererOptions; | ||
/** per task options for the verbose renderer */ | ||
static rendererTaskOptions: never; | ||
private readonly logger; | ||
constructor(tasks: Task<any, typeof TestRenderer>[], options: (typeof TestRenderer)['rendererOptions']); | ||
render(): void; | ||
end(): void; | ||
private renderer; | ||
} | ||
declare class TestRendererEvent<T extends ListrTaskEventType> { | ||
event: T; | ||
data: ListrTaskEventMap[T]; | ||
task?: Task<any, typeof TestRenderer>; | ||
constructor(event: T, data: ListrTaskEventMap[T], task?: Task<any, typeof TestRenderer>); | ||
toJson(): string; | ||
} | ||
declare class VerboseRenderer implements ListrRenderer { | ||
tasks: Task<any, typeof VerboseRenderer>[]; | ||
options: (typeof VerboseRenderer)['rendererOptions']; | ||
events?: EventManager<ListrEventType, ListrEventMap>; | ||
/** designates whether this renderer can output to a non-tty console */ | ||
static nonTTY: boolean; | ||
/** renderer options for the verbose renderer */ | ||
static rendererOptions: ({ | ||
static rendererOptions: { | ||
/** | ||
* useIcons instead of text for log level | ||
* @default false | ||
*/ | ||
useIcons?: boolean; | ||
/** | ||
* log tasks with empty titles | ||
* @default true | ||
*/ | ||
logEmptyTitle?: boolean; | ||
/** | ||
* log title changes | ||
* @default true | ||
*/ | ||
* log title changes | ||
* @default true | ||
*/ | ||
logTitleChange?: boolean; | ||
/** | ||
* show duration for all tasks | ||
*/ | ||
showTimer?: boolean; | ||
} & { | ||
/** | ||
* inject a custom logger | ||
*/ | ||
logger?: new (...args: any) => Logger; | ||
/** | ||
* inject options to custom logger | ||
*/ | ||
options?: any; | ||
}); | ||
} & RendererPresetTimer & RendererPresetTimestamp & LoggerRendererOptions; | ||
/** per task options for the verbose renderer */ | ||
static rendererTaskOptions: never; | ||
static rendererTaskOptions: RendererPresetTimer; | ||
private logger; | ||
constructor(tasks: Task<any, typeof VerboseRenderer>[], options: (typeof VerboseRenderer)['rendererOptions'], events?: EventManager<ListrEventType, ListrEventMap>); | ||
constructor(tasks: Task<any, typeof VerboseRenderer>[], options: (typeof VerboseRenderer)['rendererOptions']); | ||
render(): void; | ||
end(): void; | ||
private verboseRenderer; | ||
getSelfOrParentOption<K extends keyof (typeof VerboseRenderer)['rendererOptions']>(task: Task<any, typeof VerboseRenderer>, key: K): (typeof VerboseRenderer)['rendererOptions'][K]; | ||
private renderer; | ||
} | ||
@@ -375,2 +678,6 @@ | ||
type ListrFallbackRenderer = typeof VerboseRenderer; | ||
/** Name of testing renderer */ | ||
type ListrTestRendererValue = 'test'; | ||
/** Type of testing renderer */ | ||
type ListrTestRenderer = typeof TestRenderer; | ||
/** Silent rendere for internal usage */ | ||
@@ -388,19 +695,19 @@ type ListrSilentRendererValue = 'silent'; | ||
*/ | ||
type ListrRendererValue = ListrSilentRendererValue | ListrDefaultRendererValue | ListrSimpleRendererValue | ListrFallbackRendererValue | ListrRendererFactory; | ||
type ListrRendererValue = ListrSilentRendererValue | ListrDefaultRendererValue | ListrSimpleRendererValue | ListrFallbackRendererValue | ListrTestRendererValue | ListrRendererFactory; | ||
/** | ||
* Returns the class type from friendly names of the renderers. | ||
*/ | ||
type ListrGetRendererClassFromValue<T extends ListrRendererValue> = T extends ListrDefaultRendererValue ? ListrDefaultRenderer : T extends ListrSimpleRendererValue ? ListrSimpleRenderer : T extends ListrFallbackRendererValue ? ListrFallbackRenderer : T extends ListrSilentRenderer ? ListrSilentRenderer : T extends ListrRendererFactory ? T : never; | ||
type ListrGetRendererClassFromValue<T extends ListrRendererValue> = T extends ListrDefaultRendererValue ? ListrDefaultRenderer : T extends ListrSimpleRendererValue ? ListrSimpleRenderer : T extends ListrFallbackRendererValue ? ListrFallbackRenderer : T extends ListrTestRendererValue ? ListrTestRenderer : T extends ListrSilentRenderer ? ListrSilentRenderer : T extends ListrRendererFactory ? T : never; | ||
/** | ||
* Returns the friendly names from the type of renderer classes. | ||
*/ | ||
type ListrGetRendererValueFromClass<T extends ListrRendererFactory> = T extends DefaultRenderer ? ListrDefaultRendererValue : T extends SimpleRenderer ? ListrSimpleRendererValue : T extends VerboseRenderer ? ListrFallbackRendererValue : T extends SilentRenderer ? ListrSilentRenderer : T extends ListrRendererFactory ? T : never; | ||
type ListrGetRendererValueFromClass<T extends ListrRendererFactory> = T extends DefaultRenderer ? ListrDefaultRendererValue : T extends SimpleRenderer ? ListrSimpleRendererValue : T extends VerboseRenderer ? ListrFallbackRendererValue : T extends TestRenderer ? ListrTestRendererValue : T extends SilentRenderer ? ListrSilentRenderer : T extends ListrRendererFactory ? T : never; | ||
/** | ||
* Returns renderer global options depending on the renderer type. | ||
*/ | ||
type ListrGetRendererOptions<T extends ListrRendererValue> = T extends ListrDefaultRendererValue ? ListrDefaultRenderer['rendererOptions'] : T extends ListrSimpleRendererValue ? ListrSimpleRenderer['rendererOptions'] : T extends ListrFallbackRendererValue ? ListrFallbackRenderer['rendererOptions'] : T extends ListrSilentRenderer ? ListrSilentRenderer['rendererOptions'] : T extends ListrRendererFactory ? T['rendererOptions'] : never; | ||
type ListrGetRendererOptions<T extends ListrRendererValue> = T extends ListrDefaultRendererValue ? ListrDefaultRenderer['rendererOptions'] : T extends ListrSimpleRendererValue ? ListrSimpleRenderer['rendererOptions'] : T extends ListrFallbackRendererValue ? ListrFallbackRenderer['rendererOptions'] : T extends ListrTestRendererValue ? ListrTestRenderer['rendererOptions'] : T extends ListrSilentRenderer ? ListrSilentRenderer['rendererOptions'] : T extends ListrRendererFactory ? T['rendererOptions'] : never; | ||
/** | ||
* Returns renderer per task options depending on the renderer type. | ||
*/ | ||
type ListrGetRendererTaskOptions<T extends ListrRendererValue> = T extends ListrDefaultRendererValue ? ListrDefaultRenderer['rendererTaskOptions'] : T extends ListrSimpleRendererValue ? ListrSimpleRenderer : T extends ListrFallbackRendererValue ? ListrFallbackRenderer['rendererTaskOptions'] : T extends ListrSilentRenderer ? ListrSilentRenderer['rendererTaskOptions'] : T extends ListrRendererFactory ? T['rendererTaskOptions'] : never; | ||
type ListrGetRendererTaskOptions<T extends ListrRendererValue> = T extends ListrDefaultRendererValue ? ListrDefaultRenderer['rendererTaskOptions'] : T extends ListrSimpleRendererValue ? ListrSimpleRenderer : T extends ListrFallbackRendererValue ? ListrFallbackRenderer['rendererTaskOptions'] : T extends ListrTestRendererValue ? ListrTestRenderer['rendererTaskOptions'] : T extends ListrSilentRenderer ? ListrSilentRenderer['rendererTaskOptions'] : T extends ListrRendererFactory ? T['rendererTaskOptions'] : never; | ||
/** Select renderer as default renderer */ | ||
@@ -431,3 +738,3 @@ interface ListrDefaultRendererOptions<T extends ListrRendererValue> { | ||
/** A function to what to do on render */ | ||
render: () => void; | ||
render: () => void | Promise<void>; | ||
/** A function to what to do on end of the render */ | ||
@@ -449,3 +756,3 @@ end: (err?: Error) => void; | ||
/** A function to what to do on render */ | ||
render: () => void; | ||
render: () => void | Promise<void>; | ||
/** A function to what to do on end of the render */ | ||
@@ -467,60 +774,2 @@ end: (err?: Error) => void; | ||
/** | ||
* ListrTask. | ||
* | ||
* Defines the task, conditions and options to run a specific task in the listr. | ||
*/ | ||
interface ListrTask<Ctx = ListrContext, Renderer extends ListrRendererFactory = any> { | ||
/** | ||
* Title of the task. | ||
* | ||
* Give this task a title if you want to track it by name in the current renderer. | ||
* | ||
* Tasks without a title will hide in the default renderer and are useful for running a background instance. | ||
* On verbose renderer, state changes from these tasks will log as 'Task without a title.' | ||
*/ | ||
title?: string; | ||
/** | ||
* The task itself. | ||
* | ||
* Task can be a sync or async function, an Observable, or a Stream. | ||
* Task will be executed, if the certain criteria of the state are met and whenever the time for that specific task has come. | ||
*/ | ||
task: (ctx: Ctx, task: TaskWrapper<Ctx, Renderer>) => void | ListrTaskResult<Ctx>; | ||
/** | ||
* Skip this task depending on the context. | ||
* | ||
* The function that has been passed in will be evaluated at the runtime when the task tries to initially run. | ||
*/ | ||
skip?: boolean | string | ((ctx: Ctx) => boolean | string | Promise<boolean | string>); | ||
/** | ||
* Enable a task depending on the context. | ||
* | ||
* The function that has been passed in will be evaluated at the initial creation of the Listr class for rendering purposes, | ||
* as well as re-evaluated when the time for that specific task has come. | ||
*/ | ||
enabled?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>); | ||
/** | ||
* Adds the given number of retry attempts to the task if the task fails. | ||
*/ | ||
retry?: number; | ||
/** | ||
* Runs a specific event if the current task or any of the subtasks has failed. | ||
* | ||
* Mostly useful for rollback purposes for subtasks. | ||
* But can also be useful whenever a task is failed and some measures have to be taken to ensure the state is not changed. | ||
*/ | ||
rollback?: (ctx: Ctx, task: TaskWrapper<Ctx, Renderer>) => void | ListrTaskResult<Ctx>; | ||
/** | ||
* Set exit on the error option from task-level instead of setting it for all the subtasks. | ||
*/ | ||
exitOnError?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>); | ||
/** | ||
* Per task options, that depends on the selected renderer. | ||
* | ||
* These options depend on the implementation of the selected renderer. If the selected renderer has no options it will | ||
* be displayed as never. | ||
*/ | ||
options?: ListrGetRendererTaskOptions<Renderer>; | ||
} | ||
/** | ||
* Options to set the behavior of this base task. | ||
@@ -604,6 +853,2 @@ */ | ||
/** | ||
* Task can be set of sync or async function, an Observable or a stream. | ||
*/ | ||
type ListrTaskResult<Ctx> = string | Promise<any> | Listr<Ctx, ListrRendererValue, any> | Readable | NodeJS.ReadableStream | Observable<any>; | ||
/** | ||
* Parent class options. | ||
@@ -622,13 +867,2 @@ * | ||
type ListrSubClassOptions<Ctx = ListrContext, Renderer extends ListrRendererValue = ListrDefaultRendererValue> = ListrOptions<Ctx> & Omit<ListrDefaultRendererOptions<Renderer>, 'renderer'>; | ||
/** The internal communication event. */ | ||
type ListrEvent = { | ||
type: Exclude<ListrTaskEventType, 'MESSAGE' | 'DATA'>; | ||
data?: string | boolean; | ||
} | { | ||
type: ListrTaskEventType.DATA; | ||
data: string; | ||
} | { | ||
type: ListrTaskEventType.MESSAGE; | ||
data: Task<any, any>['message']; | ||
}; | ||
@@ -664,127 +898,2 @@ /** The internal error handling mechanism.. */ | ||
interface BasePromptOptions { | ||
message: string | (() => string) | (() => Promise<string>); | ||
initial?: boolean | number | number[] | string | (() => string) | (() => Promise<string>); | ||
required?: boolean; | ||
stdin?: NodeJS.ReadStream; | ||
stdout?: NodeJS.WriteStream; | ||
header?: string; | ||
footer?: string; | ||
skip?: (value: any) => boolean | Promise<boolean>; | ||
format?: (value: any) => any | Promise<any>; | ||
result?: (value: any) => any | Promise<any>; | ||
validate?: (value: any, state: any) => boolean | Promise<boolean> | string | Promise<string> | Promise<string | boolean>; | ||
onSubmit?: (name: any, value: any, prompt: Enquirer.Prompt) => boolean | Promise<boolean>; | ||
onCancel?: (name: any, value: any, prompt: Enquirer.Prompt) => boolean | Promise<boolean>; | ||
} | ||
interface BasePromptOptionsWithName extends BasePromptOptions { | ||
name: string | (() => string); | ||
} | ||
interface ArrayPromptOptions extends BasePromptOptions { | ||
choices: string[] | BasePromptOptionsWithName[]; | ||
maxChoices?: number; | ||
multiple?: boolean; | ||
initial?: number | number[]; | ||
delay?: number; | ||
separator?: boolean; | ||
sort?: boolean; | ||
linebreak?: boolean; | ||
edgeLength?: number; | ||
align?: 'left' | 'right'; | ||
scroll?: boolean; | ||
hint?: string; | ||
} | ||
interface BooleanPromptOptions extends BasePromptOptions { | ||
initial?: boolean | (() => string) | (() => Promise<string>); | ||
} | ||
interface StringPromptOptions extends BasePromptOptions { | ||
initial?: string; | ||
multiline?: boolean; | ||
} | ||
interface ScalePromptOptions extends ArrayPromptOptions { | ||
scale: StringPromptOptions[]; | ||
margin?: [number, number, number, number]; | ||
} | ||
interface NumberPromptOptions extends BasePromptOptions { | ||
min?: number; | ||
max?: number; | ||
delay?: number; | ||
float?: boolean; | ||
round?: boolean; | ||
major?: number; | ||
minor?: number; | ||
initial?: number; | ||
} | ||
interface SnippetPromptOptions extends BasePromptOptions { | ||
newline?: string; | ||
fields: Partial<BasePromptOptionsWithName>[]; | ||
template: string; | ||
} | ||
interface SortPromptOptions extends BasePromptOptions { | ||
hint?: string; | ||
drag?: boolean; | ||
numbered?: boolean; | ||
} | ||
interface SurveyPromptOptions extends ArrayPromptOptions { | ||
scale: BasePromptOptionsWithName[]; | ||
margin: [number, number, number, number]; | ||
} | ||
interface QuizPromptOptions extends ArrayPromptOptions { | ||
correctChoice: number; | ||
} | ||
interface TogglePromptOptions extends BasePromptOptions { | ||
enabled?: string; | ||
disabled?: string; | ||
} | ||
/** Returns all the prompt options depending on the type selected. */ | ||
type PromptOptions<T extends boolean = false> = Unionize<{ | ||
[K in PromptTypes]-?: T extends true ? { | ||
type: K; | ||
} & PromptOptionsType<K> & { | ||
name: string | (() => string); | ||
} : { | ||
type: K; | ||
} & PromptOptionsType<K>; | ||
}> | ({ | ||
type: string; | ||
} & T extends true ? PromptOptionsType<string> & { | ||
name: string | (() => string); | ||
} : PromptOptionsType<string>); | ||
type Unionize<T extends Record<PropertyKey, unknown>> = { | ||
[P in keyof T]: T[P]; | ||
}[keyof T]; | ||
type PromptTypes = 'AutoComplete' | 'BasicAuth' | 'Confirm' | 'Editable' | 'Form' | 'Input' | 'Invisible' | 'List' | 'MultiSelect' | 'Numeral' | 'Password' | 'Quiz' | 'Scale' | 'Select' | 'Snippet' | 'Sort' | 'Survey' | 'Text' | 'Toggle'; | ||
type PromptOptionsType<T> = T extends keyof PromptOptionsMap ? PromptOptionsMap[T] : T extends string ? BasePromptOptions & Record<PropertyKey, unknown> : any; | ||
declare class PromptOptionsMap implements Record<PromptTypes, Record<PropertyKey, any>> { | ||
AutoComplete: ArrayPromptOptions; | ||
BasicAuth: StringPromptOptions; | ||
Confirm: BooleanPromptOptions; | ||
Editable: ArrayPromptOptions; | ||
Form: ArrayPromptOptions; | ||
Input: StringPromptOptions; | ||
Invisible: StringPromptOptions; | ||
List: ArrayPromptOptions; | ||
MultiSelect: ArrayPromptOptions; | ||
Numeral: NumberPromptOptions; | ||
Password: StringPromptOptions; | ||
Quiz: QuizPromptOptions; | ||
Scale: ScalePromptOptions; | ||
Select: ArrayPromptOptions; | ||
Snippet: SnippetPromptOptions; | ||
Sort: SortPromptOptions; | ||
Survey: SurveyPromptOptions; | ||
Text: StringPromptOptions; | ||
Toggle: TogglePromptOptions; | ||
} | ||
interface PromptSettings { | ||
error?: boolean; | ||
cancelCallback?: (settings?: PromptSettings) => string | Error | PromptError | void; | ||
stdout?: WriteStream | Writable; | ||
enquirer?: Enquirer; | ||
} | ||
interface PromptInstance extends Omit<BasePromptOptions, 'onCancel' | 'onSubmit'> { | ||
submit: () => void; | ||
cancel: (err?: string) => void; | ||
} | ||
/** | ||
@@ -835,21 +944,2 @@ * Extend the task to have more functionality while accessing from the outside. | ||
type TaskPrompt = undefined | PromptInstance | PromptError; | ||
interface TaskRetry { | ||
count: number; | ||
withError?: Error; | ||
} | ||
interface TaskMessage { | ||
/** Run time of the task, if it has been successfully resolved. */ | ||
duration?: number; | ||
/** Error message of the task, if it has been failed. */ | ||
error?: string; | ||
/** Skip message of the task, if it has been skipped. */ | ||
skip?: string; | ||
/** Rollback message of the task, if the rollback finishes */ | ||
rollback?: string; | ||
/** Retry messages */ | ||
retry?: TaskRetry; | ||
} | ||
type TaskFn<Ctx, Renderer extends ListrRendererFactory> = (ctx: Ctx, task: TaskWrapper<Ctx, Renderer>) => void | ListrTaskResult<Ctx>; | ||
/** | ||
@@ -868,3 +958,3 @@ * Create a task from the given set of variables and make it runnable. | ||
/** The task object itself, to further utilize it. */ | ||
task: TaskFn<Ctx, Renderer>; | ||
task: ListrTaskFn<Ctx, Renderer>; | ||
/** Extend current task with multiple subtasks. */ | ||
@@ -879,3 +969,3 @@ subtasks: Task<Ctx, Renderer>[]; | ||
/** Current retry number of the task if retrying */ | ||
retry?: TaskRetry; | ||
retry?: ListrTaskRetry; | ||
/** | ||
@@ -886,7 +976,7 @@ * A channel for messages. | ||
*/ | ||
message: TaskMessage; | ||
message: ListrTaskMessage; | ||
/** Per task options for the current renderer of the task. */ | ||
rendererTaskOptions: ListrGetRendererTaskOptions<Renderer>; | ||
/** This will be triggered each time a new render should happen. */ | ||
prompt: TaskPrompt; | ||
prompt: ListrTaskPrompt; | ||
private enabled; | ||
@@ -907,3 +997,3 @@ constructor(listr: Listr<Ctx, any, any>, tasks: ListrTask<Ctx, any>, options: ListrOptions, rendererOptions: ListrGetRendererOptions<Renderer>); | ||
/** Returns whether this task is in progress. */ | ||
isPending(): boolean; | ||
isStarted(): boolean; | ||
/** Returns whether this task is skipped. */ | ||
@@ -942,3 +1032,3 @@ isSkipped(): boolean; | ||
[ListrTaskEventType.TITLE]: string; | ||
[ListrTaskEventType.DATA]: string; | ||
[ListrTaskEventType.OUTPUT]: string; | ||
[ListrTaskEventType.MESSAGE]: Task<any, any>['message']; | ||
@@ -987,30 +1077,5 @@ } | ||
declare const colorette: _colorette.Colorette; | ||
declare const RENDERER_TIMESTAMP: LoggerPrefixOrSuffixFn; | ||
declare const RENDERER_TIMER: LoggerPrefixOrSuffixFn<[number]>; | ||
/** | ||
* Create a new prompt with Enquirer externally. | ||
* This extends enquirer so you dont have to give a name to single prompts and such so it is also | ||
* useful to use externally. | ||
* @param this | ||
* @param options | ||
* @param settings | ||
*/ | ||
declare function createPrompt(this: any, options: PromptOptions | PromptOptions<true>[], settings?: PromptSettings): Promise<any>; | ||
declare function destroyPrompt(this: TaskWrapper<any, any>, throwError?: boolean): void; | ||
declare const figures: { | ||
warning: string; | ||
cross: string; | ||
arrowDown: string; | ||
tick: string; | ||
arrowRight: string; | ||
pointer: string; | ||
checkboxOn: string; | ||
arrowLeft: string; | ||
squareSmallFilled: string; | ||
pointerSmall: string; | ||
}; | ||
declare function isUnicodeSupported(): boolean; | ||
export { Listr, ListrBaseClassOptions, ListrBaseRenderer, ListrContext, ListrDefaultNonTTYRendererOptions, ListrDefaultRenderer, ListrDefaultRendererOptions, ListrDefaultRendererValue, ListrError, ListrErrorTypes, ListrEvent, ListrEventType, ListrFallbackRenderer, ListrFallbackRendererValue, ListrGetRendererClassFromValue, ListrGetRendererOptions, ListrGetRendererTaskOptions, ListrGetRendererValueFromClass, ListrOptions, ListrRenderer, ListrRendererFactory, ListrRendererOptions, ListrRendererValue, ListrSilentRenderer, ListrSilentRendererValue, ListrSimpleRenderer, ListrSimpleRendererValue, ListrSubClassOptions, ListrTask, ListrTaskEventType, Task as ListrTaskObject, ListrTaskResult, ListrTaskState, TaskWrapper as ListrTaskWrapper, LogLevels, Logger, Manager, PromptError, PromptInstance, PromptOptions, PromptOptionsMap, PromptOptionsType, PromptSettings, PromptTypes, SupportedRenderer, Unionize, colorette, createPrompt, destroyPrompt, figures, isUnicodeSupported }; | ||
export { DefaultRenderer, Figures, Listr, ListrBaseClassOptions, ListrBaseRenderer, ListrContext, ListrDefaultNonTTYRendererOptions, ListrDefaultRenderer, ListrDefaultRendererOptions, ListrDefaultRendererValue, ListrError, ListrErrorTypes, ListrEventType, ListrFallbackRenderer, ListrFallbackRendererValue, ListrGetRendererClassFromValue, ListrGetRendererOptions, ListrGetRendererTaskOptions, ListrGetRendererValueFromClass, ListrLogger, ListrLoggerOptions, ListrOptions, ListrRenderer, ListrRendererFactory, ListrRendererOptions, ListrRendererValue, ListrSilentRenderer, ListrSilentRendererValue, ListrSimpleRenderer, ListrSimpleRendererValue, ListrSubClassOptions, ListrTask, ListrTaskEventType, ListrTaskFn, ListrTaskMessage, Task as ListrTaskObject, ListrTaskPrompt, ListrTaskResult, ListrTaskRetry, ListrTaskState, TaskWrapper as ListrTaskWrapper, ListrTestRenderer, ListrTestRendererValue, LogEntityOptions, LogLevels, LoggerFormat, LoggerPrefixOrSuffix, LoggerPrefixOrSuffixFn, LoggerRendererOptions, Manager, ProcessOutput, ProcessOutputRendererOptions, PromptError, PromptInstance, PromptOptions, PromptOptionsMap, PromptOptionsType, PromptSettings, PromptTypes, RENDERER_TIMER, RENDERER_TIMESTAMP, RendererPresetTimer, RendererPresetTimestamp, SilentRenderer, SimpleRenderer, SupportedRenderer, TestRenderer, TestRendererEvent, Unionize, VerboseRenderer, assertFunctionOrSelf, cloneObject, colorette, createPrompt, destroyPrompt, figures, generateUUID, getRenderer, getRendererClass, indentString, isObservable, isUnicodeSupported, parseTaskTime, timestamp }; |
1380
dist/index.js
@@ -34,2 +34,3 @@ "use strict"; | ||
__export(src_exports, { | ||
DefaultRenderer: () => DefaultRenderer, | ||
Listr: () => Listr, | ||
@@ -39,8 +40,18 @@ ListrError: () => ListrError, | ||
ListrEventType: () => ListrEventType, | ||
ListrLogger: () => ListrLogger, | ||
ListrTaskEventType: () => ListrTaskEventType, | ||
ListrTaskState: () => ListrTaskState, | ||
LogLevels: () => LogLevels, | ||
Logger: () => Logger, | ||
Manager: () => Manager, | ||
ProcessOutput: () => ProcessOutput, | ||
PromptError: () => PromptError, | ||
RENDERER_TIMER: () => RENDERER_TIMER, | ||
RENDERER_TIMESTAMP: () => RENDERER_TIMESTAMP, | ||
SilentRenderer: () => SilentRenderer, | ||
SimpleRenderer: () => SimpleRenderer, | ||
TestRenderer: () => TestRenderer, | ||
TestRendererEvent: () => TestRendererEvent, | ||
VerboseRenderer: () => VerboseRenderer, | ||
assertFunctionOrSelf: () => assertFunctionOrSelf, | ||
cloneObject: () => cloneObject, | ||
colorette: () => colorette, | ||
@@ -50,3 +61,10 @@ createPrompt: () => createPrompt, | ||
figures: () => figures, | ||
isUnicodeSupported: () => isUnicodeSupported | ||
generateUUID: () => generateUUID, | ||
getRenderer: () => getRenderer, | ||
getRendererClass: () => getRendererClass, | ||
indentString: () => indentString, | ||
isObservable: () => isObservable, | ||
isUnicodeSupported: () => isUnicodeSupported, | ||
parseTaskTime: () => parseTaskTime, | ||
timestamp: () => timestamp | ||
}); | ||
@@ -61,3 +79,3 @@ module.exports = __toCommonJS(src_exports); | ||
ListrTaskState2["UNINITIALIZED"] = "UNINITIALIZED"; | ||
ListrTaskState2["PENDING"] = "PENDING"; | ||
ListrTaskState2["STARTED"] = "STARTED"; | ||
ListrTaskState2["COMPLETED"] = "COMPLETED"; | ||
@@ -103,3 +121,3 @@ ListrTaskState2["FAILED"] = "FAILED"; | ||
ListrTaskEventType2["SUBTASK"] = "SUBTASK"; | ||
ListrTaskEventType2["DATA"] = "DATA"; | ||
ListrTaskEventType2["OUTPUT"] = "OUTPUT"; | ||
ListrTaskEventType2["MESSAGE"] = "MESSAGE"; | ||
@@ -109,54 +127,3 @@ return ListrTaskEventType2; | ||
// src/utils/general.ts | ||
var import_rfdc = __toESM(require("rfdc")); | ||
var clone = (0, import_rfdc.default)({ circles: true }); | ||
function cloneObject(obj) { | ||
return clone(obj); | ||
} | ||
__name(cloneObject, "cloneObject"); | ||
// src/interfaces/listr-error.interface.ts | ||
var ListrError = class extends Error { | ||
constructor(error, type, task) { | ||
super(error.message); | ||
this.error = error; | ||
this.type = type; | ||
this.task = task; | ||
this.name = "ListrError"; | ||
this.path = [...task.listr.path ?? [], task.title].join(" > "); | ||
if ((task == null ? void 0 : task.options.collectErrors) === "full") { | ||
this.task = cloneObject(task); | ||
this.ctx = cloneObject(task.listr.ctx); | ||
} | ||
this.stack = error == null ? void 0 : error.stack; | ||
} | ||
}; | ||
__name(ListrError, "ListrError"); | ||
var ListrErrorTypes = /* @__PURE__ */ ((ListrErrorTypes2) => { | ||
ListrErrorTypes2["WILL_RETRY"] = "WILL_RETRY"; | ||
ListrErrorTypes2["WILL_ROLLBACK"] = "WILL_ROLLBACK"; | ||
ListrErrorTypes2["HAS_FAILED_TO_ROLLBACK"] = "HAS_FAILED_TO_ROLLBACK"; | ||
ListrErrorTypes2["HAS_FAILED"] = "HAS_FAILED"; | ||
ListrErrorTypes2["HAS_FAILED_WITHOUT_ERROR"] = "HAS_FAILED_WITHOUT_ERROR"; | ||
return ListrErrorTypes2; | ||
})(ListrErrorTypes || {}); | ||
var PromptError = class extends Error { | ||
constructor(message) { | ||
super(message); | ||
this.name = "PromptError"; | ||
} | ||
}; | ||
__name(PromptError, "PromptError"); | ||
// src/utils/assert.ts | ||
function assertFunctionOrSelf(functionOrSelf, ...args) { | ||
if (typeof functionOrSelf === "function") { | ||
return functionOrSelf(...args); | ||
} else { | ||
return functionOrSelf; | ||
} | ||
} | ||
__name(assertFunctionOrSelf, "assertFunctionOrSelf"); | ||
// src/utils/is-observable.ts | ||
// src/utils/environment/is-observable.ts | ||
function isObservable(obj) { | ||
@@ -167,14 +134,3 @@ return !!obj && typeof obj.lift === "function" && typeof obj.subscribe === "function"; | ||
// src/renderer/default.renderer.ts | ||
var import_cli_truncate = __toESM(require("cli-truncate")); | ||
var import_log_update = __toESM(require("log-update")); | ||
var import_os = require("os"); | ||
var import_wrap_ansi = __toESM(require("wrap-ansi")); | ||
// src/utils/colorette.ts | ||
var import_colorette = require("colorette"); | ||
var _a; | ||
var colorette = (0, import_colorette.createColors)({ useColor: ((_a = process.env) == null ? void 0 : _a.LISTR_DISABLE_COLOR) !== "1" }); | ||
// src/utils/is-unicode-supported.ts | ||
// src/utils/environment/is-unicode-supported.ts | ||
function isUnicodeSupported() { | ||
@@ -188,3 +144,14 @@ if (process.platform !== "win32") { | ||
// src/utils/figures.ts | ||
// src/utils/format/colorette.ts | ||
var import_colorette = require("colorette"); | ||
var _a; | ||
var colorette = (0, import_colorette.createColors)({ useColor: ((_a = process.env) == null ? void 0 : _a.LISTR_DISABLE_COLOR) !== "1" }); | ||
// src/utils/format/indent-string.ts | ||
function indentString(string, count) { | ||
return string.replace(/^(?!\s*$)/gm, " ".repeat(count)); | ||
} | ||
__name(indentString, "indentString"); | ||
// src/utils/format/figures.ts | ||
var FIGURES_MAIN = { | ||
@@ -213,9 +180,3 @@ warning: "\u26A0", | ||
// src/utils/indent-string.ts | ||
function indentString(string, count) { | ||
return string.replace(/^(?!\s*$)/gm, " ".repeat(count)); | ||
} | ||
__name(indentString, "indentString"); | ||
// src/utils/parse-time.ts | ||
// src/utils/format/parse-time.ts | ||
function parseTaskTime(duration) { | ||
@@ -238,3 +199,421 @@ const seconds = Math.floor(duration / 1e3); | ||
// src/utils/format/timestamp.ts | ||
function timestamp() { | ||
const now = /* @__PURE__ */ new Date(); | ||
return String(now.getHours()).padStart(2, "0") + ":" + String(now.getMinutes()).padStart(2, "0") + ":" + String(now.getSeconds()).padStart(2, "0"); | ||
} | ||
__name(timestamp, "timestamp"); | ||
// src/utils/logger/logger.constants.ts | ||
var LogLevels = /* @__PURE__ */ ((LogLevels2) => { | ||
LogLevels2["STARTED"] = "STARTED"; | ||
LogLevels2["COMPLETED"] = "COMPLETED"; | ||
LogLevels2["FAILED"] = "FAILED"; | ||
LogLevels2["SKIPPED"] = "SKIPPED"; | ||
LogLevels2["OUTPUT"] = "OUTPUT"; | ||
LogLevels2["TITLE"] = "TITLE"; | ||
LogLevels2["ROLLBACK"] = "ROLLBACK"; | ||
LogLevels2["RETRY"] = "RETRY"; | ||
LogLevels2["SUBTASK"] = "SUBTASK"; | ||
return LogLevels2; | ||
})(LogLevels || {}); | ||
// src/utils/logger/logger.ts | ||
var import_os = require("os"); | ||
var ListrLogger = class { | ||
constructor(options) { | ||
this.options = options; | ||
this.options = { | ||
useIcons: true, | ||
...options | ||
}; | ||
this.process = this.options.processOutput ?? new ProcessOutput(); | ||
} | ||
started(message, options) { | ||
this.process.stdout(this.format("STARTED" /* STARTED */, message, options)); | ||
} | ||
failed(message, options) { | ||
this.process.stderr(this.format("FAILED" /* FAILED */, message, options)); | ||
} | ||
skipped(message, options) { | ||
this.process.stdout(this.format("SKIPPED" /* SKIPPED */, message, options)); | ||
} | ||
completed(message, options) { | ||
this.process.stdout(this.format("COMPLETED" /* COMPLETED */, message, options)); | ||
} | ||
output(message, options) { | ||
this.process.stdout(this.format("OUTPUT" /* OUTPUT */, message, options)); | ||
} | ||
title(message, options) { | ||
this.process.stdout(this.format("TITLE" /* TITLE */, message, options)); | ||
} | ||
subtask(message, options) { | ||
this.process.stdout(this.format("SUBTASK" /* SUBTASK */, message, options)); | ||
} | ||
retry(message, options) { | ||
this.process.stderr(this.format("RETRY" /* RETRY */, message, options)); | ||
} | ||
rollback(message, options) { | ||
this.process.stderr(this.format("ROLLBACK" /* ROLLBACK */, message, options)); | ||
} | ||
wrap(message, options) { | ||
message = `[${message}]`; | ||
if (options == null ? void 0 : options.format) { | ||
return options.format(message); | ||
} | ||
return message; | ||
} | ||
suffix(message, ...suffixes) { | ||
suffixes.filter(Boolean).forEach((suffix) => { | ||
if (typeof suffix === "string") { | ||
message = message + ` ${this.wrap(suffix)}`; | ||
} else if (typeof suffix === "object") { | ||
const args = suffix.args ?? []; | ||
if (typeof suffix.condition === "function" ? !suffix.condition(...args) : !(suffix.condition ?? true)) { | ||
return message; | ||
} | ||
message = message + ` ${this.wrap(typeof suffix.data === "string" ? suffix.data : suffix.data(...args), { | ||
format: suffix.conditionalFormat ? suffix.conditionalFormat(...args) : suffix.format | ||
})}`; | ||
} | ||
}); | ||
return message; | ||
} | ||
prefix(message, ...prefixes) { | ||
prefixes.filter(Boolean).forEach((prefix) => { | ||
if (typeof prefix === "string") { | ||
message = `${this.wrap(prefix)} ` + message; | ||
} else if (typeof prefix === "object") { | ||
const args = prefix.args ?? []; | ||
if (typeof prefix.condition === "function" ? !prefix.condition(...args) : !(prefix.condition ?? true)) { | ||
return message; | ||
} | ||
message = `${this.wrap(typeof prefix.data === "string" ? prefix.data : prefix.data(...args), { | ||
format: prefix.conditionalFormat ? prefix.conditionalFormat(...args) : prefix.format | ||
})} ` + message; | ||
} | ||
}); | ||
return message; | ||
} | ||
applyToEntity(message, options) { | ||
if (options == null ? void 0 : options.prefix) { | ||
message = this.prefix(message, ...options.prefix); | ||
} | ||
if (options == null ? void 0 : options.suffix) { | ||
message = this.suffix(message, ...options.suffix); | ||
} | ||
return message; | ||
} | ||
format(level, message, options) { | ||
let multiLineMessage; | ||
try { | ||
multiLineMessage = message.split(import_os.EOL); | ||
} catch { | ||
multiLineMessage = [message]; | ||
} | ||
multiLineMessage = multiLineMessage.filter((msg) => msg && msg.trim() !== "").map((msg) => { | ||
var _a2, _b, _c, _d; | ||
return this.applyToEntity(this.style(level, msg), { | ||
prefix: [...((_b = (_a2 = this.options) == null ? void 0 : _a2.entityOptions) == null ? void 0 : _b.prefix) ?? [], ...Array.isArray(options == null ? void 0 : options.prefix) ? options.prefix : [options == null ? void 0 : options.prefix]], | ||
suffix: [...((_d = (_c = this.options) == null ? void 0 : _c.entityOptions) == null ? void 0 : _d.suffix) ?? [], ...Array.isArray(options == null ? void 0 : options.suffix) ? options.suffix : [options == null ? void 0 : options.suffix]] | ||
}); | ||
}); | ||
message = multiLineMessage.join(import_os.EOL); | ||
return message; | ||
} | ||
style(level, message) { | ||
var _a2, _b, _c, _d, _e, _f, _g, _h, _i; | ||
let icon; | ||
let coloring = /* @__PURE__ */ __name((input) => { | ||
return input; | ||
}, "coloring"); | ||
switch (level) { | ||
case "FAILED" /* FAILED */: | ||
if ((_a2 = this.options) == null ? void 0 : _a2.useIcons) { | ||
coloring = colorette.red; | ||
icon = figures.cross; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "SKIPPED" /* SKIPPED */: | ||
if ((_b = this.options) == null ? void 0 : _b.useIcons) { | ||
coloring = colorette.yellow; | ||
icon = figures.arrowDown; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "COMPLETED" /* COMPLETED */: | ||
if ((_c = this.options) == null ? void 0 : _c.useIcons) { | ||
coloring = colorette.green; | ||
icon = figures.tick; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "OUTPUT" /* OUTPUT */: | ||
if ((_d = this.options) == null ? void 0 : _d.useIcons) { | ||
icon = figures.arrowRight; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "STARTED" /* STARTED */: | ||
if ((_e = this.options) == null ? void 0 : _e.useIcons) { | ||
icon = figures.pointer; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "TITLE" /* TITLE */: | ||
if ((_f = this.options) == null ? void 0 : _f.useIcons) { | ||
icon = figures.checkboxOn; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "RETRY" /* RETRY */: | ||
if ((_g = this.options) == null ? void 0 : _g.useIcons) { | ||
coloring = colorette.yellow; | ||
icon = figures.pointer; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "ROLLBACK" /* ROLLBACK */: | ||
if ((_h = this.options) == null ? void 0 : _h.useIcons) { | ||
coloring = colorette.red; | ||
icon = figures.arrowLeft; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
case "SUBTASK" /* SUBTASK */: | ||
if ((_i = this.options) == null ? void 0 : _i.useIcons) { | ||
coloring = colorette.yellowBright; | ||
icon = figures.pointer; | ||
} else { | ||
icon = this.wrap(level); | ||
} | ||
break; | ||
} | ||
message = coloring(icon) + " " + message; | ||
return message; | ||
} | ||
}; | ||
__name(ListrLogger, "ListrLogger"); | ||
// src/utils/logger/process-output.ts | ||
var import_os2 = require("os"); | ||
var ProcessOutput = class { | ||
stdout(buffer) { | ||
return process.stdout.write(buffer + import_os2.EOL); | ||
} | ||
stderr(buffer) { | ||
return process.stderr.write(buffer + import_os2.EOL); | ||
} | ||
}; | ||
__name(ProcessOutput, "ProcessOutput"); | ||
// src/utils/assert.ts | ||
function assertFunctionOrSelf(functionOrSelf, ...args) { | ||
if (typeof functionOrSelf === "function") { | ||
return functionOrSelf(...args); | ||
} else { | ||
return functionOrSelf; | ||
} | ||
} | ||
__name(assertFunctionOrSelf, "assertFunctionOrSelf"); | ||
// src/utils/clone.ts | ||
var import_rfdc = __toESM(require("rfdc")); | ||
var clone = (0, import_rfdc.default)({ circles: true }); | ||
function cloneObject(obj) { | ||
return clone(obj); | ||
} | ||
__name(cloneObject, "cloneObject"); | ||
// src/lib/task-wrapper.ts | ||
var import_through = __toESM(require("through")); | ||
// src/constants/clearline-regex.constants.ts | ||
var CLEAR_LINE_REGEX = "(?:\\u001b|\\u009b)\\[[\\=><~/#&.:=?%@~_-]*[0-9]*[\\a-ln-tqyz=><~/#&.:=?%@~_-]+"; | ||
var BELL_REGEX = /\u0007/; | ||
// src/lib/task-wrapper.ts | ||
var TaskWrapper = class { | ||
constructor(task, errors, options) { | ||
this.task = task; | ||
this.errors = errors; | ||
this.options = options; | ||
} | ||
/** Get the title of the current task. */ | ||
get title() { | ||
return this.task.title; | ||
} | ||
/** Change the title of the current task. */ | ||
set title(data) { | ||
this.task.title$ = data; | ||
} | ||
/** Get the output from the output channel. */ | ||
get output() { | ||
return this.task.output; | ||
} | ||
/** Send a output to the output channel. */ | ||
set output(data) { | ||
this.task.output$ = data; | ||
} | ||
/** Create a new subtask with given renderer selection from the parent task. */ | ||
newListr(task, options) { | ||
let tasks; | ||
if (typeof task === "function") { | ||
tasks = task(this); | ||
} else { | ||
tasks = task; | ||
} | ||
return new Listr(tasks, options, this.task); | ||
} | ||
/** Report a error in process for error collection. */ | ||
report(error, type) { | ||
var _a2; | ||
if (this.task.options.collectErrors !== false) { | ||
this.errors.push(new ListrError(error, type, this.task)); | ||
} | ||
this.task.message$ = { error: error.message ?? ((_a2 = this.task) == null ? void 0 : _a2.title) ?? "Task with no title." }; | ||
} | ||
/** Skip current task. */ | ||
skip(message) { | ||
var _a2; | ||
this.task.state$ = "SKIPPED" /* SKIPPED */; | ||
if (message) { | ||
this.task.message$ = { skip: message ?? ((_a2 = this.task) == null ? void 0 : _a2.title) ?? "Task with no title." }; | ||
} | ||
} | ||
/** Get the number of retrying, else returns false */ | ||
isRetrying() { | ||
return this.task.isRetrying() ? this.task.retry : { count: 0 }; | ||
} | ||
/** | ||
* Create a new Enquirer prompt using prompt options. | ||
* | ||
* Since process.stdout is controlled by Listr, this will passthrough all Enquirer data through internal stdout. | ||
*/ | ||
async prompt(options) { | ||
var _a2; | ||
return createPrompt.bind(this)(options, { ...(_a2 = this.options) == null ? void 0 : _a2.injectWrapper }); | ||
} | ||
/** Cancels the current prompt attach to this task. */ | ||
cancelPrompt(throwError = false) { | ||
return destroyPrompt.bind(this)(throwError); | ||
} | ||
/** | ||
* Pass stream of data to internal stdout. | ||
* | ||
* Since Listr2 takes control of process.stdout utilizing the default renderer, any data outputted to process.stdout | ||
* will corrupt its looks. | ||
* | ||
* This returns a fake stream to pass any stream inside Listr as task data. | ||
*/ | ||
stdout() { | ||
return (0, import_through.default)((chunk) => { | ||
chunk = chunk.toString(); | ||
chunk = chunk.replace(new RegExp(CLEAR_LINE_REGEX, "gmi"), ""); | ||
chunk = chunk.replace(new RegExp(BELL_REGEX, "gmi"), ""); | ||
if (chunk !== "") { | ||
this.output = chunk; | ||
} | ||
}); | ||
} | ||
/** Run this task. */ | ||
run(ctx) { | ||
return this.task.run(ctx, this); | ||
} | ||
}; | ||
__name(TaskWrapper, "TaskWrapper"); | ||
// src/utils/prompt.ts | ||
function defaultCancelCallback(settings) { | ||
const errorMsg = "Cancelled prompt."; | ||
if (this instanceof TaskWrapper) { | ||
this.task.prompt = new PromptError(errorMsg); | ||
} else if ((settings == null ? void 0 : settings.error) !== false) { | ||
throw new Error(errorMsg); | ||
} else { | ||
return errorMsg; | ||
} | ||
} | ||
__name(defaultCancelCallback, "defaultCancelCallback"); | ||
async function createPrompt(options, settings) { | ||
let cancelCallback; | ||
if (settings == null ? void 0 : settings.cancelCallback) { | ||
cancelCallback = settings.cancelCallback; | ||
} else { | ||
cancelCallback = defaultCancelCallback; | ||
} | ||
if (!Array.isArray(options)) { | ||
options = [{ ...options, name: "default" }]; | ||
} else if (options.length === 1) { | ||
options = options.reduce((o, option) => { | ||
return [...o, Object.assign(option, { name: "default" })]; | ||
}, []); | ||
} | ||
options = options.reduce((o, option) => { | ||
return [ | ||
...o, | ||
Object.assign(option, { | ||
// this is for outside calls, if it is not called from taskwrapper with bind | ||
stdout: this instanceof TaskWrapper ? (settings == null ? void 0 : settings.stdout) ?? this.stdout() : process.stdout, | ||
onCancel: cancelCallback.bind(this, settings) | ||
}) | ||
]; | ||
}, []); | ||
let enquirer; | ||
if (settings == null ? void 0 : settings.enquirer) { | ||
enquirer = settings.enquirer; | ||
} else { | ||
try { | ||
const imported = await import("enquirer"); | ||
enquirer = imported.default ? new imported.default() : new imported(); | ||
} catch (e) { | ||
this.task.prompt = new PromptError("Enquirer is a peer dependency that must be installed separately."); | ||
throw new Error(e); | ||
} | ||
} | ||
if (this instanceof TaskWrapper) { | ||
enquirer.on("prompt", (prompt) => this.task.prompt = prompt); | ||
enquirer.on("submit", () => this.task.prompt = void 0); | ||
this.task.on("STATE" /* STATE */, (event) => { | ||
if (event === "SKIPPED" /* SKIPPED */) { | ||
if (this.task.prompt && !(this.task.prompt instanceof PromptError)) { | ||
this.task.prompt.submit(); | ||
} | ||
} | ||
}); | ||
} | ||
const response = await enquirer.prompt(options); | ||
if (options.length === 1) { | ||
return response.default; | ||
} else { | ||
return response; | ||
} | ||
} | ||
__name(createPrompt, "createPrompt"); | ||
function destroyPrompt(throwError = false) { | ||
if (!this.task.prompt || this.task.prompt instanceof PromptError) { | ||
return; | ||
} | ||
if (throwError) { | ||
this.task.prompt.cancel(); | ||
} else { | ||
this.task.prompt.submit(); | ||
} | ||
} | ||
__name(destroyPrompt, "destroyPrompt"); | ||
// src/renderer/default.renderer.ts | ||
var import_cli_truncate = __toESM(require("cli-truncate")); | ||
var import_log_update = __toESM(require("log-update")); | ||
var import_os3 = require("os"); | ||
var import_wrap_ansi = __toESM(require("wrap-ansi")); | ||
var _DefaultRenderer = class { | ||
@@ -248,3 +627,5 @@ constructor(tasks, options, events) { | ||
this.spinnerPosition = 0; | ||
this.logger = new ListrLogger(); | ||
this.options = { ..._DefaultRenderer.rendererOptions, ...this.options }; | ||
this.logger = this.options.logger ?? new ListrLogger(); | ||
} | ||
@@ -261,5 +642,2 @@ getTaskOptions(task) { | ||
} | ||
hasTimer(task) { | ||
return this.getTaskOptions(task).showTimer === true; | ||
} | ||
getSelfOrParentOption(task, key) { | ||
@@ -269,17 +647,11 @@ var _a2, _b; | ||
} | ||
/* istanbul ignore next */ | ||
getTaskTime(task) { | ||
return colorette.dim(`[${parseTaskTime(task.message.duration)}]`); | ||
} | ||
createRender(options) { | ||
options = { | ||
...{ | ||
tasks: true, | ||
bottomBar: true, | ||
prompt: true | ||
}, | ||
tasks: true, | ||
bottomBar: true, | ||
prompt: true, | ||
...options | ||
}; | ||
const render = []; | ||
const renderTasks = this.multiLineRenderer(this.tasks); | ||
const renderTasks = this.renderer(this.tasks); | ||
const renderBottomBar = this.renderBottomBar(); | ||
@@ -291,8 +663,8 @@ const renderPrompt = this.renderPrompt(); | ||
if (options.bottomBar && (renderBottomBar == null ? void 0 : renderBottomBar.trim().length) > 0) { | ||
render.push((render.length > 0 ? import_os.EOL : "") + renderBottomBar); | ||
render.push((render.length > 0 ? import_os3.EOL : "") + renderBottomBar); | ||
} | ||
if (options.prompt && (renderPrompt == null ? void 0 : renderPrompt.trim().length) > 0) { | ||
render.push((render.length > 0 ? import_os.EOL : "") + renderPrompt); | ||
render.push((render.length > 0 ? import_os3.EOL : "") + renderPrompt); | ||
} | ||
return render.length > 0 ? render.join(import_os.EOL) : ""; | ||
return render.length > 0 ? render.join(import_os3.EOL) : ""; | ||
} | ||
@@ -323,8 +695,34 @@ render() { | ||
if (!this.options.clearOutput) { | ||
process.stdout.write(this.createRender({ prompt: false }) + import_os.EOL); | ||
this.logger.process.stdout(this.createRender({ prompt: false })); | ||
} | ||
} | ||
// eslint-disable-next-line complexity | ||
multiLineRenderer(tasks, level = 0) { | ||
var _a2, _b; | ||
getSymbol(task, data = false) { | ||
var _a2, _b, _c; | ||
if (task.isSkipped() && (data || this.getSelfOrParentOption(task, "collapseSkips"))) { | ||
return colorette.yellow(figures.arrowDown); | ||
} | ||
if (data) { | ||
return figures.pointerSmall; | ||
} | ||
if (task.isStarted()) { | ||
return ((_a2 = this.options) == null ? void 0 : _a2.lazy) || this.getSelfOrParentOption(task, "showSubtasks") !== false && task.hasSubtasks() && !task.subtasks.every((subtask) => !subtask.hasTitle()) ? colorette.yellow(figures.pointer) : colorette.yellowBright(this.spinner[this.spinnerPosition]); | ||
} else if (task.isCompleted()) { | ||
return task.hasSubtasks() && task.subtasks.some((subtask) => subtask.hasFailed()) ? colorette.yellow(figures.warning) : colorette.green(figures.tick); | ||
} else if (task.isRetrying()) { | ||
return ((_b = this.options) == null ? void 0 : _b.lazy) ? colorette.yellow(figures.warning) : colorette.yellow(this.spinner[this.spinnerPosition]); | ||
} else if (task.isRollingBack()) { | ||
return ((_c = this.options) == null ? void 0 : _c.lazy) ? colorette.red(figures.warning) : colorette.red(this.spinner[this.spinnerPosition]); | ||
} else if (task.hasRolledBack()) { | ||
return colorette.red(figures.arrowLeft); | ||
} else if (task.hasFailed()) { | ||
return task.hasSubtasks() ? colorette.red(figures.pointer) : colorette.red(figures.cross); | ||
} else if (task.isSkipped() && this.getSelfOrParentOption(task, "collapseSkips") === false) { | ||
return colorette.yellow(figures.warning); | ||
} | ||
return colorette.dim(figures.squareSmallFilled); | ||
} | ||
// eslint-disable-next-line complexity | ||
renderer(tasks, level = 0) { | ||
var _a2, _b, _c; | ||
let output = []; | ||
@@ -338,3 +736,3 @@ for (const task of tasks) { | ||
...output, | ||
this.formatString( | ||
this.format( | ||
!task.hasSubtasks() && task.message.error && this.getSelfOrParentOption(task, "showErrorMessage") ? task.message.error : task.title, | ||
@@ -348,8 +746,8 @@ this.getSymbol(task), | ||
...output, | ||
this.formatString( | ||
this.addSuffixToMessage( | ||
task.message.skip && this.getSelfOrParentOption(task, "showSkipMessage") ? task.message.skip : task.title, | ||
"SKIPPED", | ||
this.getSelfOrParentOption(task, "suffixSkips") | ||
), | ||
this.format( | ||
this.logger.suffix(task.message.skip && this.getSelfOrParentOption(task, "showSkipMessage") ? task.message.skip : task.title, { | ||
data: "SKIPPED" /* SKIPPED */, | ||
condition: this.getSelfOrParentOption(task, "suffixSkips"), | ||
format: colorette.dim | ||
}), | ||
this.getSymbol(task), | ||
@@ -360,10 +758,30 @@ level | ||
} else if (task.isRetrying() && this.getSelfOrParentOption(task, "suffixRetries")) { | ||
output = [...output, this.formatString(this.addSuffixToMessage(task.title, `RETRYING-${task.message.retry.count}`), this.getSymbol(task), level)]; | ||
} else if (task.isCompleted() && task.hasTitle() && (this.getSelfOrParentOption(task, "showTimer") || this.hasTimer(task))) { | ||
output = [...output, this.formatString(`${task == null ? void 0 : task.title} ${this.getTaskTime(task)}`, this.getSymbol(task), level)]; | ||
output = [ | ||
...output, | ||
this.format( | ||
this.logger.suffix(task.title, { | ||
data: `${"RETRY" /* RETRY */}:${task.message.retry.count}`, | ||
format: colorette.yellow | ||
}), | ||
this.getSymbol(task), | ||
level | ||
) | ||
]; | ||
} else if (task.isCompleted() && task.hasTitle() && assertFunctionOrSelf((_a2 = this.getSelfOrParentOption(task, "timer")) == null ? void 0 : _a2.condition, task.message.duration)) { | ||
output = [ | ||
...output, | ||
this.format( | ||
this.logger.suffix(task == null ? void 0 : task.title, { | ||
...this.getSelfOrParentOption(task, "timer"), | ||
args: [task.message.duration] | ||
}), | ||
this.getSymbol(task), | ||
level | ||
) | ||
]; | ||
} else { | ||
output = [...output, this.formatString(task.title, this.getSymbol(task), level)]; | ||
output = [...output, this.format(task.title, this.getSymbol(task), level)]; | ||
} | ||
} else { | ||
output = [...output, this.formatString(task.title, colorette.red(figures.squareSmallFilled), level)]; | ||
output = [...output, this.format(task.title, colorette.red(figures.squareSmallFilled), level)]; | ||
} | ||
@@ -373,12 +791,12 @@ } | ||
if (task.hasFailed() && this.getSelfOrParentOption(task, "collapseErrors") === false && (this.getSelfOrParentOption(task, "showErrorMessage") || !this.getSelfOrParentOption(task, "showSubtasks"))) { | ||
output = [...output, this.dumpData(task, level, "error")]; | ||
output = [...output, this.dump(task, level, "FAILED" /* FAILED */)]; | ||
} else if (task.isSkipped() && this.getSelfOrParentOption(task, "collapseSkips") === false && (this.getSelfOrParentOption(task, "showSkipMessage") || !this.getSelfOrParentOption(task, "showSubtasks"))) { | ||
output = [...output, this.dumpData(task, level, "skip")]; | ||
output = [...output, this.dump(task, level, "SKIPPED" /* SKIPPED */)]; | ||
} | ||
} | ||
if (task == null ? void 0 : task.output) { | ||
if ((task.isPending() || task.isRetrying() || task.isRollingBack()) && task.isPrompt()) { | ||
if ((task.isStarted() || task.isRetrying() || task.isRollingBack()) && task.isPrompt()) { | ||
this.promptBar = task.output; | ||
} else if (this.isBottomBar(task) || !task.hasTitle()) { | ||
const data = [this.dumpData(task, -1)]; | ||
const data = [this.dump(task, -1)]; | ||
if (!this.bottomBar[task.id]) { | ||
@@ -394,7 +812,7 @@ this.bottomBar[task.id] = {}; | ||
} | ||
if (!((_b = (_a2 = this.bottomBar[task.id]) == null ? void 0 : _a2.data) == null ? void 0 : _b.some((element) => data.includes(element))) && !task.isSkipped()) { | ||
if (!((_c = (_b = this.bottomBar[task.id]) == null ? void 0 : _b.data) == null ? void 0 : _c.some((element) => data.includes(element))) && !task.isSkipped()) { | ||
this.bottomBar[task.id].data = [...this.bottomBar[task.id].data, ...data]; | ||
} | ||
} else if (task.isPending() || task.isRetrying() || task.isRollingBack() || this.hasPersistentOutput(task)) { | ||
output = [...output, this.dumpData(task, level)]; | ||
} else if (task.isStarted() || task.isRetrying() || task.isRollingBack() || this.hasPersistentOutput(task)) { | ||
output = [...output, this.dump(task, level)]; | ||
} | ||
@@ -405,3 +823,3 @@ } | ||
this.getSelfOrParentOption(task, "showSubtasks") !== false && // if it doesnt have subtasks no need to check | ||
task.hasSubtasks() && (task.isPending() || task.hasFailed() || task.isCompleted() && !task.hasTitle() || // have to be completed and have subtasks | ||
task.hasSubtasks() && (task.isStarted() || task.hasFailed() || task.isCompleted() && !task.hasTitle() || // have to be completed and have subtasks | ||
task.isCompleted() && this.getSelfOrParentOption(task, "collapse") === false && !task.subtasks.some((subtask) => subtask.rendererOptions.collapse === true) || // if any of the subtasks have the collapse option of | ||
@@ -413,3 +831,3 @@ task.subtasks.some((subtask) => subtask.rendererOptions.collapse === false) || // if any of the subtasks has failed | ||
const subtaskLevel = !task.hasTitle() ? level : level + 1; | ||
const subtaskRender = this.multiLineRenderer(task.subtasks, subtaskLevel); | ||
const subtaskRender = this.renderer(task.subtasks, subtaskLevel); | ||
if ((subtaskRender == null ? void 0 : subtaskRender.trim()) !== "") { | ||
@@ -429,3 +847,3 @@ output = [...output, subtaskRender]; | ||
if (output.length > 0) { | ||
return output.join(import_os.EOL); | ||
return output.join(import_os3.EOL); | ||
} else { | ||
@@ -446,3 +864,3 @@ return; | ||
}, {}); | ||
return Object.values(this.bottomBar).reduce((o, value) => o = [...o, ...value.data], []).filter(Boolean).join(import_os.EOL); | ||
return Object.values(this.bottomBar).reduce((o, value) => o = [...o, ...value.data], []).filter(Boolean).join(import_os3.EOL); | ||
} | ||
@@ -455,23 +873,23 @@ } | ||
} | ||
dumpData(task, level, source = "output") { | ||
dump(task, level, source = "OUTPUT" /* OUTPUT */) { | ||
let data; | ||
switch (source) { | ||
case "output": | ||
case "OUTPUT" /* OUTPUT */: | ||
data = task.output; | ||
break; | ||
case "skip": | ||
case "SKIPPED" /* SKIPPED */: | ||
data = task.message.skip; | ||
break; | ||
case "error": | ||
case "FAILED" /* FAILED */: | ||
data = task.message.error; | ||
break; | ||
} | ||
if (task.hasTitle() && source === "error" && data === task.title) { | ||
if (task.hasTitle() && source === "FAILED" /* FAILED */ && data === task.title) { | ||
return; | ||
} | ||
if (typeof data === "string") { | ||
return this.formatString(data, this.getSymbol(task, true), level + 1); | ||
return this.format(data, this.getSymbol(task, true), level + 1); | ||
} | ||
} | ||
formatString(str, icon, level) { | ||
format(str, icon, level) { | ||
if (str.trim() === "") { | ||
@@ -486,8 +904,8 @@ return; | ||
case "truncate": | ||
parsedStr = str.split(import_os.EOL).map((s, i) => { | ||
return (0, import_cli_truncate.default)(this.indentMultilineOutput(s, i), columns); | ||
parsedStr = str.split(import_os3.EOL).map((s, i) => { | ||
return (0, import_cli_truncate.default)(this.indent(s, i), columns); | ||
}); | ||
break; | ||
case "wrap": | ||
parsedStr = (0, import_wrap_ansi.default)(str, columns, { hard: true }).split(import_os.EOL).map((s, i) => this.indentMultilineOutput(s, i)); | ||
parsedStr = (0, import_wrap_ansi.default)(str, columns, { hard: true }).split(import_os3.EOL).map((s, i) => this.indent(s, i)); | ||
break; | ||
@@ -500,32 +918,7 @@ default: | ||
} | ||
return indentString(parsedStr.join(import_os.EOL), level * this.options.indentation); | ||
return indentString(parsedStr.join(import_os3.EOL), level * this.options.indentation); | ||
} | ||
indentMultilineOutput(str, i) { | ||
indent(str, i) { | ||
return i > 0 ? indentString(str.trim(), 2) : str.trim(); | ||
} | ||
// eslint-disable-next-line complexity | ||
getSymbol(task, data = false) { | ||
var _a2, _b, _c; | ||
if (task.isPending() && !data) { | ||
return ((_a2 = this.options) == null ? void 0 : _a2.lazy) || this.getSelfOrParentOption(task, "showSubtasks") !== false && task.hasSubtasks() && !task.subtasks.every((subtask) => !subtask.hasTitle()) ? colorette.yellow(figures.pointer) : colorette.yellowBright(this.spinner[this.spinnerPosition]); | ||
} else if (task.isCompleted() && !data) { | ||
return task.hasSubtasks() && task.subtasks.some((subtask) => subtask.hasFailed()) ? colorette.yellow(figures.warning) : colorette.green(figures.tick); | ||
} else if (task.isRetrying() && !data) { | ||
return ((_b = this.options) == null ? void 0 : _b.lazy) ? colorette.yellow(figures.warning) : colorette.yellow(this.spinner[this.spinnerPosition]); | ||
} else if (task.isRollingBack() && !data) { | ||
return ((_c = this.options) == null ? void 0 : _c.lazy) ? colorette.red(figures.warning) : colorette.red(this.spinner[this.spinnerPosition]); | ||
} else if (task.hasRolledBack() && !data) { | ||
return colorette.red(figures.arrowLeft); | ||
} else if (task.hasFailed() && !data) { | ||
return task.hasSubtasks() ? colorette.red(figures.pointer) : colorette.red(figures.cross); | ||
} else if (task.isSkipped() && !data && this.getSelfOrParentOption(task, "collapseSkips") === false) { | ||
return colorette.yellow(figures.warning); | ||
} else if (task.isSkipped() && (data || this.getSelfOrParentOption(task, "collapseSkips"))) { | ||
return colorette.yellow(figures.arrowDown); | ||
} | ||
return !data ? colorette.dim(figures.squareSmallFilled) : figures.pointerSmall; | ||
} | ||
addSuffixToMessage(message, suffix, condition) { | ||
return condition ?? true ? message + colorette.dim(` [${suffix}]`) : message; | ||
} | ||
}; | ||
@@ -549,3 +942,2 @@ var DefaultRenderer = _DefaultRenderer; | ||
lazy: false, | ||
showTimer: false, | ||
removeEmptyLines: true, | ||
@@ -572,3 +964,2 @@ formatOutput: "truncate" | ||
var import_log_update2 = require("log-update"); | ||
var import_os2 = require("os"); | ||
var _SimpleRenderer = class { | ||
@@ -579,24 +970,9 @@ constructor(tasks, options) { | ||
this.options = { ..._SimpleRenderer.rendererOptions, ...options }; | ||
this.logger = this.options.logger ?? new ListrLogger({ | ||
useIcons: true, | ||
entityOptions: { | ||
prefix: [this.options.timestamp] | ||
} | ||
}); | ||
} | ||
// This is used for mocks, since mocking Date is cumbesome | ||
static now() { | ||
return /* @__PURE__ */ new Date(); | ||
} | ||
// Used to sanitize title output | ||
static formatTitle(task) { | ||
return (task == null ? void 0 : task.title) ? ` ${task.title}` : ""; | ||
} | ||
// Writes sanitized output | ||
log(output) { | ||
const logOut = /* @__PURE__ */ __name((msg) => { | ||
process[this.options.output].write(msg.endsWith(import_os2.EOL) ? msg : `${msg}${import_os2.EOL}`); | ||
}, "logOut"); | ||
if (!this.options.prefixWithTimestamp) { | ||
logOut(`${output}`); | ||
return; | ||
} | ||
const now = _SimpleRenderer.now(); | ||
const timestamp = String(now.getHours()).padStart(2, "0") + ":" + String(now.getMinutes()).padStart(2, "0") + ":" + String(now.getSeconds()).padStart(2, "0"); | ||
logOut(`${colorette.dim(`[${timestamp}]`)} ${output}`); | ||
} | ||
// eslint-disable-next-line | ||
@@ -606,22 +982,42 @@ end() { | ||
render() { | ||
this.simpleRenderer(this.tasks); | ||
this.renderer(this.tasks); | ||
} | ||
simpleRenderer(tasks) { | ||
getSelfOrParentOption(task, key) { | ||
var _a2, _b; | ||
return ((_a2 = task == null ? void 0 : task.rendererOptions) == null ? void 0 : _a2[key]) ?? ((_b = this.options) == null ? void 0 : _b[key]); | ||
} | ||
renderer(tasks) { | ||
tasks.forEach((task) => { | ||
task.on("SUBTASK" /* SUBTASK */, (subtasks) => { | ||
if (task.hasTitle()) { | ||
this.log(`${colorette.blue(figures.pointer)} ${task.title}`); | ||
this.logger.subtask(task.title); | ||
} | ||
this.simpleRenderer(subtasks); | ||
this.renderer(subtasks); | ||
}); | ||
task.on("STATE" /* STATE */, (state) => { | ||
if (state === "COMPLETED" /* COMPLETED */ && task.hasTitle()) { | ||
this.log(`${colorette.green(figures.tick)} ${task.title}`); | ||
var _a2; | ||
if (!task.hasTitle()) { | ||
return; | ||
} | ||
if (state === "STARTED" /* STARTED */) { | ||
this.logger.started(task.title); | ||
} else if (state === "COMPLETED" /* COMPLETED */) { | ||
const timer = this.getSelfOrParentOption(task, "timer"); | ||
this.logger.completed( | ||
task.title, | ||
timer && { | ||
suffix: { | ||
...timer, | ||
condition: !!((_a2 = task.message) == null ? void 0 : _a2.duration) && timer.condition, | ||
args: [task.message.duration] | ||
} | ||
} | ||
); | ||
} | ||
}); | ||
task.on("DATA" /* DATA */, (data) => { | ||
if (task.isPrompt() && !String(data).match(/^\n$/)) { | ||
(0, import_log_update2.stderr)(data); | ||
task.on("OUTPUT" /* OUTPUT */, (output) => { | ||
if (task.isPrompt() && !String(output).match(/^\n$/)) { | ||
(0, import_log_update2.stderr)(output); | ||
} else { | ||
this.log(`${figures.pointerSmall} ${data}`); | ||
this.logger.output(output); | ||
} | ||
@@ -631,14 +1027,29 @@ }); | ||
if (message.error) { | ||
const title = _SimpleRenderer.formatTitle(task); | ||
this.log(`${colorette.red(figures.cross)}${title}: ${message.error}`); | ||
this.logger.failed(task.title, { | ||
suffix: { | ||
data: `${"FAILED" /* FAILED */}: ${message.error}`, | ||
format: colorette.red | ||
} | ||
}); | ||
} else if (message.skip) { | ||
const title = _SimpleRenderer.formatTitle(task); | ||
const skip = task.title !== message.skip ? `: ${message.skip}` : ""; | ||
this.log(`${colorette.yellow(figures.arrowDown)}${title} [${colorette.yellow(`skipped${skip}`)}]`); | ||
this.logger.skipped(task.title, { | ||
suffix: { | ||
data: `${"SKIPPED" /* SKIPPED */}: ${message.skip}`, | ||
format: colorette.yellow | ||
} | ||
}); | ||
} else if (message.rollback) { | ||
const title = _SimpleRenderer.formatTitle(task); | ||
this.log(`${colorette.red(figures.arrowLeft)}${title}: ${message.rollback}`); | ||
this.logger.rollback(task.title, { | ||
suffix: { | ||
data: `${"ROLLBACK" /* ROLLBACK */}: ${message.rollback}`, | ||
format: colorette.red | ||
} | ||
}); | ||
} else if (message.retry) { | ||
const title = _SimpleRenderer.formatTitle(task); | ||
this.log(`[${colorette.yellow(`${message.retry.count}`)}]${title}`); | ||
this.logger.retry(task.title, { | ||
suffix: { | ||
data: `${"RETRY" /* RETRY */}:${message.retry.count}`, | ||
format: colorette.red | ||
} | ||
}); | ||
} | ||
@@ -654,167 +1065,110 @@ }); | ||
// designate your renderer options that will be showed inside the `ListrOptions` as rendererOptions | ||
SimpleRenderer.rendererOptions = { prefixWithTimestamp: false, output: "stdout" }; | ||
SimpleRenderer.rendererOptions = {}; | ||
// designate your custom internal task-based options that will show as `options` in the task itself | ||
SimpleRenderer.rendererTaskOptions = {}; | ||
// src/constants/listr.constants.ts | ||
var TASK_WITHOUT_TITLE = "Task without title."; | ||
// src/utils/logger.constants.ts | ||
var LogLevels = /* @__PURE__ */ ((LogLevels2) => { | ||
LogLevels2["SILENT"] = "SILENT"; | ||
LogLevels2["FAILED"] = "FAILED"; | ||
LogLevels2["SKIPPED"] = "SKIPPED"; | ||
LogLevels2["SUCCESS"] = "SUCCESS"; | ||
LogLevels2["DATA"] = "DATA"; | ||
LogLevels2["STARTED"] = "STARTED"; | ||
LogLevels2["TITLE"] = "TITLE"; | ||
LogLevels2["RETRY"] = "RETRY"; | ||
LogLevels2["ROLLBACK"] = "ROLLBACK"; | ||
return LogLevels2; | ||
})(LogLevels || {}); | ||
// src/utils/logger.ts | ||
var Logger = class { | ||
constructor(options) { | ||
// src/renderer/test.renderer.ts | ||
var _TestRenderer = class { | ||
constructor(tasks, options) { | ||
this.tasks = tasks; | ||
this.options = options; | ||
this.options = { ..._TestRenderer.rendererOptions, ...this.options }; | ||
this.logger = this.options.logger ?? new ListrLogger(); | ||
} | ||
fail(message) { | ||
message = this.parseMessage("FAILED" /* FAILED */, message); | ||
console.error(message); | ||
render() { | ||
this.renderer(this.tasks); | ||
} | ||
skip(message) { | ||
message = this.parseMessage("SKIPPED" /* SKIPPED */, message); | ||
console.info(message); | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
end() { | ||
} | ||
success(message) { | ||
message = this.parseMessage("SUCCESS" /* SUCCESS */, message); | ||
console.log(message); | ||
} | ||
data(message) { | ||
message = this.parseMessage("DATA" /* DATA */, message); | ||
console.info(message); | ||
} | ||
start(message) { | ||
message = this.parseMessage("STARTED" /* STARTED */, message); | ||
console.log(message); | ||
} | ||
title(message) { | ||
message = this.parseMessage("TITLE" /* TITLE */, message); | ||
console.info(message); | ||
} | ||
retry(message) { | ||
message = this.parseMessage("RETRY" /* RETRY */, message); | ||
console.warn(message); | ||
} | ||
rollback(message) { | ||
message = this.parseMessage("ROLLBACK" /* ROLLBACK */, message); | ||
console.warn(message); | ||
} | ||
parseMessage(level, message) { | ||
let multiLineMessage; | ||
try { | ||
multiLineMessage = message.split("\n"); | ||
} catch { | ||
multiLineMessage = [message]; | ||
} | ||
multiLineMessage = multiLineMessage.map((msg) => { | ||
return this.logColoring({ | ||
level, | ||
message: msg | ||
// verbose renderer multi-level | ||
renderer(tasks) { | ||
return tasks == null ? void 0 : tasks.forEach((task) => { | ||
if (this.options.subtasks) { | ||
task.on("SUBTASK" /* SUBTASK */, (subtasks) => { | ||
this.renderer(subtasks); | ||
}); | ||
} | ||
if (this.options.state) { | ||
task.on("STATE" /* STATE */, (state) => { | ||
this.logger.process.stdout(new TestRendererEvent("STATE" /* STATE */, state, task).toJson()); | ||
}); | ||
} | ||
if (this.options.output) { | ||
task.on("OUTPUT" /* OUTPUT */, (data) => { | ||
this.logger.process.stdout(new TestRendererEvent("OUTPUT" /* OUTPUT */, data, task).toJson()); | ||
}); | ||
} | ||
if (this.options.title) { | ||
task.on("TITLE" /* TITLE */, (title) => { | ||
this.logger.process.stdout(new TestRendererEvent("TITLE" /* TITLE */, title, task).toJson()); | ||
}); | ||
} | ||
task.on("MESSAGE" /* MESSAGE */, (message) => { | ||
const parsed = Object.fromEntries( | ||
Object.entries(message).map(([key, value]) => { | ||
if (this.options.messages.includes(key)) { | ||
return [key, value]; | ||
} | ||
}).filter(Boolean) | ||
); | ||
if (Object.keys(parsed).length > 0) { | ||
const output = new TestRendererEvent("MESSAGE" /* MESSAGE */, parsed, task).toJson(); | ||
if (["error", "rollback", "retry"].some((state) => Object.keys(parsed).includes(state))) { | ||
this.logger.process.stderr(output); | ||
} else { | ||
this.logger.process.stdout(output); | ||
} | ||
} | ||
}); | ||
}); | ||
message = multiLineMessage.join("\n"); | ||
return message; | ||
} | ||
logColoring({ level, message }) { | ||
var _a2, _b, _c, _d, _e, _f, _g, _h; | ||
let icon; | ||
let coloring = /* @__PURE__ */ __name((input) => { | ||
return input; | ||
}, "coloring"); | ||
switch (level) { | ||
case "FAILED" /* FAILED */: | ||
if ((_a2 = this.options) == null ? void 0 : _a2.useIcons) { | ||
coloring = colorette.red; | ||
icon = figures.cross; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "SKIPPED" /* SKIPPED */: | ||
if ((_b = this.options) == null ? void 0 : _b.useIcons) { | ||
coloring = colorette.yellow; | ||
icon = figures.arrowDown; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "SUCCESS" /* SUCCESS */: | ||
if ((_c = this.options) == null ? void 0 : _c.useIcons) { | ||
coloring = colorette.green; | ||
icon = figures.tick; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "DATA" /* DATA */: | ||
if ((_d = this.options) == null ? void 0 : _d.useIcons) { | ||
icon = figures.arrowRight; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "STARTED" /* STARTED */: | ||
if ((_e = this.options) == null ? void 0 : _e.useIcons) { | ||
icon = figures.pointer; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "TITLE" /* TITLE */: | ||
if ((_f = this.options) == null ? void 0 : _f.useIcons) { | ||
icon = figures.checkboxOn; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "RETRY" /* RETRY */: | ||
if ((_g = this.options) == null ? void 0 : _g.useIcons) { | ||
coloring = colorette.yellow; | ||
icon = figures.pointer; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
case "ROLLBACK" /* ROLLBACK */: | ||
if ((_h = this.options) == null ? void 0 : _h.useIcons) { | ||
coloring = colorette.red; | ||
icon = figures.arrowLeft; | ||
} else { | ||
icon = this.wrapInBrackets(level); | ||
} | ||
break; | ||
} | ||
return coloring(`${icon} ${message}`); | ||
}; | ||
var TestRenderer = _TestRenderer; | ||
__name(TestRenderer, "TestRenderer"); | ||
/** designates whether this renderer can output to a non-tty console */ | ||
TestRenderer.nonTTY = true; | ||
/** renderer options for the verbose renderer */ | ||
TestRenderer.rendererOptions = { | ||
subtasks: true, | ||
state: Object.values(ListrTaskState), | ||
output: true, | ||
title: true, | ||
messages: ["skip", "error", "retry", "rollback"] | ||
}; | ||
var TestRendererEvent = class { | ||
constructor(event, data, task) { | ||
this.event = event; | ||
this.data = data; | ||
this.task = task; | ||
} | ||
wrapInBrackets(level) { | ||
return `[${level}]`; | ||
toJson() { | ||
var _a2, _b; | ||
return JSON.stringify({ | ||
event: this.event, | ||
data: this.data, | ||
task: { | ||
title: (_a2 = this.task) == null ? void 0 : _a2.title, | ||
hasFinalized: (_b = this.task) == null ? void 0 : _b.hasFinalized() | ||
} | ||
}); | ||
} | ||
}; | ||
__name(Logger, "Logger"); | ||
__name(TestRendererEvent, "TestRendererEvent"); | ||
// src/renderer/verbose.renderer.ts | ||
var _VerboseRenderer = class { | ||
constructor(tasks, options, events) { | ||
constructor(tasks, options) { | ||
this.tasks = tasks; | ||
this.options = options; | ||
this.events = events; | ||
var _a2, _b; | ||
if ((_a2 = this.options) == null ? void 0 : _a2.logger) { | ||
this.logger = new this.options.logger(options == null ? void 0 : options.options); | ||
} else { | ||
this.logger = new Logger({ useIcons: (_b = this.options) == null ? void 0 : _b.useIcons }); | ||
} | ||
this.options = { ..._VerboseRenderer.rendererOptions, ...this.options }; | ||
this.logger = this.options.logger ?? new ListrLogger({ | ||
useIcons: false, | ||
entityOptions: { | ||
prefix: [this.options.timestamp] | ||
} | ||
}); | ||
} | ||
render() { | ||
this.verboseRenderer(this.tasks); | ||
this.renderer(this.tasks); | ||
} | ||
@@ -824,25 +1178,36 @@ // eslint-disable-next-line @typescript-eslint/no-empty-function | ||
} | ||
getSelfOrParentOption(task, key) { | ||
var _a2, _b; | ||
return ((_a2 = task == null ? void 0 : task.rendererOptions) == null ? void 0 : _a2[key]) ?? ((_b = this.options) == null ? void 0 : _b[key]); | ||
} | ||
// verbose renderer multi-level | ||
verboseRenderer(tasks) { | ||
renderer(tasks) { | ||
return tasks == null ? void 0 : tasks.forEach((task) => { | ||
var _a2; | ||
task.on("SUBTASK" /* SUBTASK */, (subtasks) => { | ||
this.verboseRenderer(subtasks); | ||
this.renderer(subtasks); | ||
}); | ||
task.on("STATE" /* STATE */, (state) => { | ||
var _a3, _b, _c; | ||
if (task.hasTitle() || ((_a3 = this.options) == null ? void 0 : _a3.logEmptyTitle) !== false) { | ||
const title = task.hasTitle() ? task.title : TASK_WITHOUT_TITLE; | ||
switch (state) { | ||
case "PENDING" /* PENDING */: | ||
this.logger.start(title); | ||
break; | ||
case "COMPLETED" /* COMPLETED */: | ||
this.logger.success(title + (((_b = this.options) == null ? void 0 : _b.showTimer) && ((_c = task.message) == null ? void 0 : _c.duration) ? ` [${parseTaskTime(task.message.duration)}]` : "")); | ||
break; | ||
} | ||
var _a3; | ||
if (!task.hasTitle()) { | ||
return; | ||
} | ||
if (state === "STARTED" /* STARTED */) { | ||
this.logger.started(task.title); | ||
} else if (state === "COMPLETED" /* COMPLETED */) { | ||
const timer = this.getSelfOrParentOption(task, "timer"); | ||
this.logger.completed( | ||
task.title, | ||
timer && { | ||
suffix: { | ||
...timer, | ||
condition: !!((_a3 = task.message) == null ? void 0 : _a3.duration) && timer.condition, | ||
args: [task.message.duration] | ||
} | ||
} | ||
); | ||
} | ||
}); | ||
task.on("DATA" /* DATA */, (data) => { | ||
this.logger.data(data); | ||
task.on("OUTPUT" /* OUTPUT */, (data) => { | ||
this.logger.output(data); | ||
}); | ||
@@ -856,10 +1221,9 @@ if (((_a2 = this.options) == null ? void 0 : _a2.logTitleChange) !== false) { | ||
if (message == null ? void 0 : message.error) { | ||
this.logger.fail(message.error); | ||
this.logger.failed(message.error); | ||
} else if (message == null ? void 0 : message.skip) { | ||
this.logger.skip(message.skip); | ||
this.logger.skipped(message.skip); | ||
} else if (message == null ? void 0 : message.rollback) { | ||
this.logger.rollback(message.rollback); | ||
} else if (message == null ? void 0 : message.retry) { | ||
const title = task.hasTitle() ? task.title : TASK_WITHOUT_TITLE; | ||
this.logger.retry(`[${message.retry.count}] ` + title); | ||
this.logger.retry(task.title, { suffix: message.retry.count.toString() }); | ||
} | ||
@@ -876,12 +1240,11 @@ }); | ||
VerboseRenderer.rendererOptions = { | ||
useIcons: false, | ||
logEmptyTitle: true, | ||
logTitleChange: true | ||
logTitleChange: false | ||
}; | ||
// src/utils/renderer.ts | ||
var renderers = { | ||
var RENDERERS = { | ||
default: DefaultRenderer, | ||
simple: SimpleRenderer, | ||
verbose: VerboseRenderer, | ||
test: TestRenderer, | ||
silent: SilentRenderer | ||
@@ -895,21 +1258,16 @@ }; | ||
if (typeof renderer === "string") { | ||
return renderers[renderer] || renderers.default; | ||
return RENDERERS[renderer] ?? RENDERERS.default; | ||
} | ||
return typeof renderer === "function" ? renderer : renderers.default; | ||
return typeof renderer === "function" ? renderer : RENDERERS.default; | ||
} | ||
__name(getRendererClass, "getRendererClass"); | ||
function getRenderer(renderer, fallbackRenderer, fallbackCondition, silentCondition) { | ||
let returnValue; | ||
let ret = getRendererClass(renderer); | ||
returnValue = { renderer: ret, nonTTY: false }; | ||
const evaluateSilent = assertFunctionOrSelf(silentCondition); | ||
const evaluateFallback = assertFunctionOrSelf(fallbackCondition); | ||
if (evaluateSilent) { | ||
ret = getRendererClass("silent"); | ||
returnValue = { renderer: ret, nonTTY: true }; | ||
} else if (!isRendererSupported(ret) || evaluateFallback) { | ||
ret = getRendererClass(fallbackRenderer); | ||
returnValue = { renderer: ret, nonTTY: true }; | ||
if (assertFunctionOrSelf(silentCondition)) { | ||
return { renderer: getRendererClass("silent"), nonTTY: true }; | ||
} | ||
return returnValue; | ||
const r = { renderer: getRendererClass(renderer), nonTTY: false }; | ||
if (!isRendererSupported(r.renderer) || assertFunctionOrSelf(fallbackCondition)) { | ||
return { renderer: getRendererClass(fallbackRenderer), nonTTY: true }; | ||
} | ||
return r; | ||
} | ||
@@ -928,2 +1286,35 @@ __name(getRenderer, "getRenderer"); | ||
// src/interfaces/listr-error.interface.ts | ||
var ListrError = class extends Error { | ||
constructor(error, type, task) { | ||
super(error.message); | ||
this.error = error; | ||
this.type = type; | ||
this.task = task; | ||
this.name = "ListrError"; | ||
this.path = [...task.listr.path ?? [], task.title].join(" > "); | ||
if ((task == null ? void 0 : task.options.collectErrors) === "full") { | ||
this.task = cloneObject(task); | ||
this.ctx = cloneObject(task.listr.ctx); | ||
} | ||
this.stack = error == null ? void 0 : error.stack; | ||
} | ||
}; | ||
__name(ListrError, "ListrError"); | ||
var ListrErrorTypes = /* @__PURE__ */ ((ListrErrorTypes2) => { | ||
ListrErrorTypes2["WILL_RETRY"] = "WILL_RETRY"; | ||
ListrErrorTypes2["WILL_ROLLBACK"] = "WILL_ROLLBACK"; | ||
ListrErrorTypes2["HAS_FAILED_TO_ROLLBACK"] = "HAS_FAILED_TO_ROLLBACK"; | ||
ListrErrorTypes2["HAS_FAILED"] = "HAS_FAILED"; | ||
ListrErrorTypes2["HAS_FAILED_WITHOUT_ERROR"] = "HAS_FAILED_WITHOUT_ERROR"; | ||
return ListrErrorTypes2; | ||
})(ListrErrorTypes || {}); | ||
var PromptError = class extends Error { | ||
constructor(message) { | ||
super(message); | ||
this.name = "PromptError"; | ||
} | ||
}; | ||
__name(PromptError, "PromptError"); | ||
// src/lib/task.ts | ||
@@ -958,3 +1349,3 @@ var Task = class extends EventManager { | ||
for (const subtask of this.subtasks) { | ||
if (subtask.state === "PENDING" /* PENDING */) { | ||
if (subtask.state === "STARTED" /* STARTED */) { | ||
subtask.state$ = "FAILED" /* FAILED */; | ||
@@ -968,3 +1359,3 @@ } | ||
this.output = data; | ||
this.emit("DATA" /* DATA */, data); | ||
this.emit("OUTPUT" /* OUTPUT */, data); | ||
this.emitShouldRefreshRender(); | ||
@@ -1003,4 +1394,4 @@ } | ||
/** Returns whether this task is in progress. */ | ||
isPending() { | ||
return this.state === "PENDING" /* PENDING */; | ||
isStarted() { | ||
return this.state === "STARTED" /* STARTED */; | ||
} | ||
@@ -1079,3 +1470,3 @@ /** Returns whether this task is skipped. */ | ||
const startTime = Date.now(); | ||
this.state$ = "PENDING" /* PENDING */; | ||
this.state$ = "STARTED" /* STARTED */; | ||
const skipped = await assertFunctionOrSelf(((_a2 = this.tasks) == null ? void 0 : _a2.skip) ?? false, context); | ||
@@ -1112,3 +1503,3 @@ if (skipped) { | ||
} | ||
if (this.isPending() || this.isRetrying()) { | ||
if (this.isStarted() || this.isRetrying()) { | ||
this.message$ = { duration: Date.now() - startTime }; | ||
@@ -1126,4 +1517,4 @@ this.state$ = "COMPLETED" /* COMPLETED */; | ||
await this.tasks.rollback(context, wrapper); | ||
this.message$ = { rollback: this.title }; | ||
this.state$ = "ROLLED_BACK" /* ROLLED_BACK */; | ||
this.message$ = { rollback: this.title }; | ||
} catch (err) { | ||
@@ -1156,179 +1547,2 @@ this.state$ = "FAILED" /* FAILED */; | ||
// src/lib/task-wrapper.ts | ||
var import_through = __toESM(require("through")); | ||
// src/constants/clearline-regex.constants.ts | ||
var CLEAR_LINE_REGEX = "(?:\\u001b|\\u009b)\\[[\\=><~/#&.:=?%@~_-]*[0-9]*[\\a-ln-tqyz=><~/#&.:=?%@~_-]+"; | ||
var BELL_REGEX = /\u0007/; | ||
// src/utils/prompt.ts | ||
function defaultCancelCallback(settings) { | ||
const errorMsg = "Cancelled prompt."; | ||
if (this instanceof TaskWrapper) { | ||
this.task.prompt = new PromptError(errorMsg); | ||
} else if ((settings == null ? void 0 : settings.error) !== false) { | ||
throw new Error(errorMsg); | ||
} else { | ||
return errorMsg; | ||
} | ||
} | ||
__name(defaultCancelCallback, "defaultCancelCallback"); | ||
async function createPrompt(options, settings) { | ||
let cancelCallback; | ||
if (settings == null ? void 0 : settings.cancelCallback) { | ||
cancelCallback = settings.cancelCallback; | ||
} else { | ||
cancelCallback = defaultCancelCallback; | ||
} | ||
if (!Array.isArray(options)) { | ||
options = [{ ...options, name: "default" }]; | ||
} else if (options.length === 1) { | ||
options = options.reduce((o, option) => { | ||
return [...o, Object.assign(option, { name: "default" })]; | ||
}, []); | ||
} | ||
options = options.reduce((o, option) => { | ||
return [ | ||
...o, | ||
Object.assign(option, { | ||
// this is for outside calls, if it is not called from taskwrapper with bind | ||
stdout: this instanceof TaskWrapper ? (settings == null ? void 0 : settings.stdout) ?? this.stdout() : process.stdout, | ||
onCancel: cancelCallback.bind(this, settings) | ||
}) | ||
]; | ||
}, []); | ||
let enquirer; | ||
if (settings == null ? void 0 : settings.enquirer) { | ||
enquirer = settings.enquirer; | ||
} else { | ||
try { | ||
const imported = await import("enquirer"); | ||
enquirer = imported.default ? new imported.default() : new imported(); | ||
} catch (e) { | ||
this.task.prompt = new PromptError("Enquirer is a peer dependency that must be installed separately."); | ||
throw new Error(e); | ||
} | ||
} | ||
if (this instanceof TaskWrapper) { | ||
enquirer.on("prompt", (prompt) => this.task.prompt = prompt); | ||
enquirer.on("submit", () => this.task.prompt = void 0); | ||
this.task.on("STATE" /* STATE */, (event) => { | ||
if (event === "SKIPPED" /* SKIPPED */) { | ||
if (this.task.prompt && !(this.task.prompt instanceof PromptError)) { | ||
this.task.prompt.submit(); | ||
} | ||
} | ||
}); | ||
} | ||
const response = await enquirer.prompt(options); | ||
if (options.length === 1) { | ||
return response.default; | ||
} else { | ||
return response; | ||
} | ||
} | ||
__name(createPrompt, "createPrompt"); | ||
function destroyPrompt(throwError = false) { | ||
if (!this.task.prompt || this.task.prompt instanceof PromptError) { | ||
return; | ||
} | ||
if (throwError) { | ||
this.task.prompt.cancel(); | ||
} else { | ||
this.task.prompt.submit(); | ||
} | ||
} | ||
__name(destroyPrompt, "destroyPrompt"); | ||
// src/lib/task-wrapper.ts | ||
var TaskWrapper = class { | ||
constructor(task, errors, options) { | ||
this.task = task; | ||
this.errors = errors; | ||
this.options = options; | ||
} | ||
/** Get the title of the current task. */ | ||
get title() { | ||
return this.task.title; | ||
} | ||
/** Change the title of the current task. */ | ||
set title(data) { | ||
this.task.title$ = data; | ||
} | ||
/** Get the output from the output channel. */ | ||
get output() { | ||
return this.task.output; | ||
} | ||
/** Send a output to the output channel. */ | ||
set output(data) { | ||
this.task.output$ = data; | ||
} | ||
/** Create a new subtask with given renderer selection from the parent task. */ | ||
newListr(task, options) { | ||
let tasks; | ||
if (typeof task === "function") { | ||
tasks = task(this); | ||
} else { | ||
tasks = task; | ||
} | ||
return new Listr(tasks, options, this.task); | ||
} | ||
/** Report a error in process for error collection. */ | ||
report(error, type) { | ||
var _a2; | ||
if (this.task.options.collectErrors !== false) { | ||
this.errors.push(new ListrError(error, type, this.task)); | ||
} | ||
this.task.message$ = { error: error.message ?? ((_a2 = this.task) == null ? void 0 : _a2.title) ?? "Task with no title." }; | ||
} | ||
/** Skip current task. */ | ||
skip(message) { | ||
var _a2; | ||
this.task.state$ = "SKIPPED" /* SKIPPED */; | ||
if (message) { | ||
this.task.message$ = { skip: message ?? ((_a2 = this.task) == null ? void 0 : _a2.title) ?? "Task with no title." }; | ||
} | ||
} | ||
/** Get the number of retrying, else returns false */ | ||
isRetrying() { | ||
return this.task.isRetrying() ? this.task.retry : { count: 0 }; | ||
} | ||
/** | ||
* Create a new Enquirer prompt using prompt options. | ||
* | ||
* Since process.stdout is controlled by Listr, this will passthrough all Enquirer data through internal stdout. | ||
*/ | ||
async prompt(options) { | ||
var _a2; | ||
return createPrompt.bind(this)(options, { ...(_a2 = this.options) == null ? void 0 : _a2.injectWrapper }); | ||
} | ||
/** Cancels the current prompt attach to this task. */ | ||
cancelPrompt(throwError = false) { | ||
return destroyPrompt.bind(this)(throwError); | ||
} | ||
/** | ||
* Pass stream of data to internal stdout. | ||
* | ||
* Since Listr2 takes control of process.stdout utilizing the default renderer, any data outputted to process.stdout | ||
* will corrupt its looks. | ||
* | ||
* This returns a fake stream to pass any stream inside Listr as task data. | ||
*/ | ||
stdout() { | ||
return (0, import_through.default)((chunk) => { | ||
chunk = chunk.toString(); | ||
chunk = chunk.replace(new RegExp(CLEAR_LINE_REGEX, "gmi"), ""); | ||
chunk = chunk.replace(new RegExp(BELL_REGEX, "gmi"), ""); | ||
if (chunk !== "") { | ||
this.output = chunk; | ||
} | ||
}); | ||
} | ||
/** Run this task. */ | ||
run(ctx) { | ||
return this.task.run(ctx, this); | ||
} | ||
}; | ||
__name(TaskWrapper, "TaskWrapper"); | ||
// src/listr.ts | ||
@@ -1380,3 +1594,3 @@ var Listr = class { | ||
this.tasks.forEach(async (task2) => { | ||
if (task2.isPending()) { | ||
if (task2.isStarted()) { | ||
task2.state$ = "FAILED" /* FAILED */; | ||
@@ -1404,3 +1618,3 @@ } | ||
} | ||
this.renderer.render(); | ||
await this.renderer.render(); | ||
this.ctx = ((_a2 = this.options) == null ? void 0 : _a2.ctx) ?? context ?? {}; | ||
@@ -1483,4 +1697,17 @@ await Promise.all(this.tasks.map((task) => task.check(this.ctx))); | ||
__name(Manager, "Manager"); | ||
// src/renderer/renderer-presets.constants.ts | ||
var RENDERER_TIMESTAMP = { | ||
condition: true, | ||
data: timestamp, | ||
format: colorette.dim | ||
}; | ||
var RENDERER_TIMER = { | ||
condition: true, | ||
data: parseTaskTime, | ||
format: colorette.dim | ||
}; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
DefaultRenderer, | ||
Listr, | ||
@@ -1490,8 +1717,18 @@ ListrError, | ||
ListrEventType, | ||
ListrLogger, | ||
ListrTaskEventType, | ||
ListrTaskState, | ||
LogLevels, | ||
Logger, | ||
Manager, | ||
ProcessOutput, | ||
PromptError, | ||
RENDERER_TIMER, | ||
RENDERER_TIMESTAMP, | ||
SilentRenderer, | ||
SimpleRenderer, | ||
TestRenderer, | ||
TestRendererEvent, | ||
VerboseRenderer, | ||
assertFunctionOrSelf, | ||
cloneObject, | ||
colorette, | ||
@@ -1501,3 +1738,10 @@ createPrompt, | ||
figures, | ||
isUnicodeSupported | ||
generateUUID, | ||
getRenderer, | ||
getRendererClass, | ||
indentString, | ||
isObservable, | ||
isUnicodeSupported, | ||
parseTaskTime, | ||
timestamp | ||
}); |
{ | ||
"name": "listr2", | ||
"version": "5.1.0-beta.2", | ||
"version": "6.0.0-beta.1", | ||
"description": "Terminal task list reborn! Create beautiful CLI interfaces via easy and logical to implement task lists that feel alive and interactive.", | ||
@@ -82,3 +82,3 @@ "license": "MIT", | ||
"@cenk1cenk2/cz-cc": "^1.5.9", | ||
"@cenk1cenk2/eslint-config": "2.5.52", | ||
"@cenk1cenk2/eslint-config": "2.6.0", | ||
"@types/clone": "^2.1.1", | ||
@@ -89,3 +89,2 @@ "@types/jest": "^29.0.0", | ||
"@types/wrap-ansi": "^3.0.0", | ||
"delay": "^5.0.0", | ||
"enquirer": "^2.3.6", | ||
@@ -92,0 +91,0 @@ "eslint": "^8.23.0", |
Sorry, the diff of this file is not supported yet
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
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
165947
23
4291