npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

swiss-node

v3.6.2

Published

Swiss Army Knife for node

Downloads

293

Readme

swiss-node

Swiss Army Knife for node

A collection of helper functions and useful little things for node.js

Uses swiss-ak

ask

A collection of functions to ask the user for input.

text

ask.text(question: string | Breadcrumb, initial: string, validate: (value: string) => ask.ValidationResponse, lc: LineCounter): Promise<string>

Get a text input from the user.

const name = await ask.text('What is your name?'); // 'Jack'

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:--------------------------------------------|:--------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | initial | No | string | Initial value | | 2 | validate | No | (value: string) => ask.ValidationResponse | Validation function | | 3 | lc | No | LineCounter | Line counter |

| Return Type | | |-------------------|--------------------------------------------------| | Promise<string> | Promise that resolves with the user input string |

autotext

ask.autotext(question: string | Breadcrumb, choices: ask.PromptChoice<T>[], initial: T | string, validate: (item: T, index: number, typedValue: string) => ask.ValidationResponse, lc: LineCounter): Promise<T>

Get a text input from the user, with auto-completion.

const name = await ask.autotext('What is your name?', ['Jack', 'Jane', 'Joe']); // 'Jack'

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:-------------------------------------------------------------------------|:-----------------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | choices | Yes | ask.PromptChoice<T>[] | Choices to autocomplete from | | 2 | initial | No | T \| string | Initial value | | 3 | validate | No | (item: T, index: number, typedValue: string) => ask.ValidationResponse | Validation function | | 4 | lc | No | LineCounter | Line counter |

| Return Type | | |--------------|--------------------------------------------------| | Promise<T> | Promise that resolves with the user input string |

number

ask.number(question: string | Breadcrumb, initial: number, validate: (value: number) => ask.ValidationResponse, lc: LineCounter): Promise<number>

Get a number input from the user.

const age = await ask.number('How old are you?'); // 30

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:--------------------------------------------|:--------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | initial | No | number | Initial value | | 2 | validate | No | (value: number) => ask.ValidationResponse | Validation function | | 3 | lc | No | LineCounter | Line counter |

| Return Type | | |-------------------|--------------------------------------------------| | Promise<number> | Promise that resolves with the user input number |

boolean

ask.boolean(question: string | Breadcrumb, initial: boolean, validate: (value: boolean) => ask.ValidationResponse, lc: LineCounter): Promise<boolean>

Get a boolean input from the user (yes or no)

const isCool = await ask.boolean('Is this cool?'); // true

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:---------------------------------------------|:--------|:--------------------| | 0 | question | Yes | string \| Breadcrumb | | Question to ask | | 1 | initial | No | boolean | true | Initial value | | 2 | validate | No | (value: boolean) => ask.ValidationResponse | | Validation function | | 3 | lc | No | LineCounter | | Line counter |

| Return Type | | |--------------------|---------------------------------------------------| | Promise<boolean> | Promise that resolves with the user input boolean |

booleanYN

ask.booleanYN(question: string | Breadcrumb, validate: (value: boolean) => ask.ValidationResponse, lc: LineCounter): Promise<boolean>

Get a boolean input from the user (yes or no)

Alternative interface to ask.boolean

const isCool = await ask.booleanYN('Is this cool?'); // true

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:---------------------------------------------|:--------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | validate | No | (value: boolean) => ask.ValidationResponse | Validation function | | 2 | lc | No | LineCounter | Line counter |

| Return Type | | |--------------------|---------------------------------------------------| | Promise<boolean> | Promise that resolves with the user input boolean |

select

ask.select(question: string | Breadcrumb, choices: ask.PromptChoice<T>[], initial: ask.PromptChoice<T> | number, validate: (item: T, index: number) => ask.ValidationResponse, lc: LineCounter): Promise<T>

Get the user to select an option from a list.

const colour = await ask.select('Whats your favourite colour?', ['red', 'green', 'blue']); // 'red'

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:-----------------------------------------------------|:-----------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | choices | Yes | ask.PromptChoice<T>[] | Choices to select from | | 2 | initial | No | ask.PromptChoice<T> \| number | Initial value | | 3 | validate | No | (item: T, index: number) => ask.ValidationResponse | Validation function | | 4 | lc | No | LineCounter | Line counter |

| Return Type | | |--------------|--------------------------------------------------| | Promise<T> | Promise that resolves with the user input string |

multiselect

ask.multiselect(question: string | Breadcrumb, choices: ask.PromptChoice<T>[], initial: ask.PromptChoice<T> | ask.PromptChoice<T>[] | number | number[], validate: (items: T[], indexes: number[]) => ask.ValidationResponse, lc: LineCounter): Promise<T[]>

Get the user to select multiple opts from a list.

const colours = await ask.multiselect('Whats your favourite colours?', ['red', 'green', 'blue']); // ['red', 'green']

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:---------------------------------------------------------------------|:-----------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | choices | Yes | ask.PromptChoice<T>[] | Choices to select from | | 2 | initial | No | ask.PromptChoice<T> \| ask.PromptChoice<T>[] \| number \| number[] | Initial value | | 3 | validate | No | (items: T[], indexes: number[]) => ask.ValidationResponse | Validation function | | 4 | lc | No | LineCounter | Line counter |

| Return Type | | |----------------|-------------------------------------------------| | Promise<T[]> | Promise that resolves with the user input array |

date

ask.date(questionText: string | Breadcrumb, initial: Date, validate: (date: Date) => ask.ValidationResponse, lc: LineCounter): Promise<Date>

Get a date input from the user.

const date = await ask.date('Whats the date?');
// [Date: 2023-01-01T12:00:00.000Z] (user inputted date, always at 12 midday)

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:-----------------------------------------|:--------------------| | 0 | questionText | No | string \| Breadcrumb | Question to ask | | 1 | initial | No | Date | Initial date | | 2 | validate | No | (date: Date) => ask.ValidationResponse | Validation function | | 3 | lc | No | LineCounter | Line counter |

| Return Type | | |-----------------|------------------------------------------------| | Promise<Date> | Promise that resolves with the user input date |

time

ask.time(questionText: string | Breadcrumb, initial: Date, validate: (date: Date) => ask.ValidationResponse, lc: LineCounter): Promise<Date>

Get a time input from the user.

const time = await ask.time('Whats the time?');
// [Date: 2023-01-01T12:00:00.000Z] (user inputted time, with todays date)

const time2 = await ask.time('Whats the time?', new Date('1999-12-31'));
// [Date: 1999-12-31T12:00:00.000Z] (user inputted time, with same date as initial)

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:-----------------------------------------|:--------------------| | 0 | questionText | No | string \| Breadcrumb | Question to ask | | 1 | initial | No | Date | Initial date | | 2 | validate | No | (date: Date) => ask.ValidationResponse | Validation function | | 3 | lc | No | LineCounter | Line counter |

| Return Type | | |-----------------|------------------------------------------------| | Promise<Date> | Promise that resolves with the user input date |

datetime

ask.datetime(questionText: string | Breadcrumb, initial: Date, validate: (date: Date) => ask.ValidationResponse, lc: LineCounter): Promise<Date>

Get a date and time input from the user.

const when = await ask.datetime('Whats the date/time?');
// [Date: 2023-03-05T20:30:00.000Z] (user inputted time & date)

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:-----------------------------------------|:--------------------| | 0 | questionText | No | string \| Breadcrumb | Question to ask | | 1 | initial | No | Date | Initial date | | 2 | validate | No | (date: Date) => ask.ValidationResponse | Validation function | | 3 | lc | No | LineCounter | Line counter |

| Return Type | | |-----------------|------------------------------------------------| | Promise<Date> | Promise that resolves with the user input date |

dateRange

ask.dateRange(questionText: string | Breadcrumb, initialStart: Date, initialEnd: Date, validate: (dates: [Date, Date]) => ask.ValidationResponse, lc: LineCounter): Promise<[Date, Date]>

Get a date range input from the user.

const range = await ask.dateRange('When is the festival?');
// [
//   [Date: 2023-03-01T12:00:00.000Z],
//   [Date: 2023-03-31T12:00:00.000Z]
// ]

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:--------------------------------------------------|:--------------------| | 0 | questionText | No | string \| Breadcrumb | Question to ask | | 1 | initialStart | No | Date | Initial start date | | 2 | initialEnd | No | Date | Initial end date | | 3 | validate | No | (dates: [Date, Date]) => ask.ValidationResponse | Validation function | | 4 | lc | No | LineCounter | Line counter |

| Return Type | | |-------------------------|------------------------------------------------------| | Promise<[Date, Date]> | Promise that resolves with the user input date range |

fileExplorer

fileExplorer

ask.fileExplorer(questionText: string | Breadcrumb, selectType: 'd' | 'f', startPath: string, validate: (path: string) => ask.ValidationResponse, lc: LineCounter): Promise<string>

Get a file or folder path from the user.

Note: Handles symlinks and resolves macOS aliases to their actual location.

Note: Accepts both relative and absolute paths as startPath (relative will not allow navigating up from the CWD)

const file = await ask.fileExplorer('What file?', 'f');
// '/Users/user/Documents/some_file.txt'

const dir = await ask.fileExplorer('What file?', 'd', '/Users/jackcannon/Documents');
// '/Users/jackcannon/Documents/some_folder'

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-------------------------------------------|:----------------|:-------------------------------------------| | 0 | questionText | Yes | string \| Breadcrumb | | Question to ask | | 1 | selectType | No | 'd' \| 'f' | 'f' | Type of item to select (directory or file) | | 2 | startPath | No | string | process.cwd() | Starting path | | 3 | validate | No | (path: string) => ask.ValidationResponse | | Validation function | | 4 | lc | No | LineCounter | | Line counter |

| Return Type | | |-------------------|------------------------------------------------| | Promise<string> | Promise that resolves with the user input path |

multiFileExplorer

ask.multiFileExplorer(questionText: string | Breadcrumb, selectType: 'd' | 'f', startPath: string, validate: (paths: string[]) => ask.ValidationResponse, lc: LineCounter): Promise<string[]>

Get multiple file or folder paths from the user.

Note: Handles symlinks and resolves macOS aliases to their actual location.

Note: Accepts both relative and absolute paths as startPath (relative will not allow navigating up from the CWD)

const files = await ask.multiFileExplorer('What files?', 'f');
// [
//   '/Users/user/Documents/some_file_1.txt',
//   '/Users/user/Documents/some_file_2.txt',
//   '/Users/user/Documents/some_file_3.txt'
// ]

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:----------------------------------------------|:----------------|:-------------------------------------------| | 0 | questionText | Yes | string \| Breadcrumb | | Question to ask | | 1 | selectType | No | 'd' \| 'f' | 'f' | Type of item to select (directory or file) | | 2 | startPath | No | string | process.cwd() | Starting path | | 3 | validate | No | (paths: string[]) => ask.ValidationResponse | | Validation function | | 4 | lc | No | LineCounter | | Line counter |

| Return Type | | |---------------------|-------------------------------------------------| | Promise<string[]> | Promise that resolves with the user input paths |

saveFileExplorer

ask.saveFileExplorer(questionText: string | Breadcrumb, startPath: string, suggestedFileName: string, validate: (dir: string, filename?: string) => ask.ValidationResponse): Promise<string>

Get a file path from the user, with the intention of saving a file to that path.

Note: Handles symlinks and resolves macOS aliases to their actual location.

Note: Accepts both relative and absolute paths as startPath (relative will not allow navigating up from the CWD)

const HOME_DIR = '/Users/user/Documents';
const savePath = await ask.saveFileExplorer('Save file', HOME_DIR, 'data.json');
// '/Users/user/Documents/data.json'

| # | Parameter Name | Required | Type | Default | Description | |:---:|:--------------------|:---------|:-------------------------------------------------------------|:----------------|:--------------------| | 0 | questionText | Yes | string \| Breadcrumb | | Question to ask | | 1 | startPath | No | string | process.cwd() | Starting path | | 2 | suggestedFileName | No | string | '' | Suggested file name | | 3 | validate | No | (dir: string, filename?: string) => ask.ValidationResponse | | Validation function |

| Return Type | | |-------------------|------------------------------------------------| | Promise<string> | Promise that resolves with the user input path |

table

A collection of functions for asking questions with tables.

table.select

ask.table.select(question: string | Breadcrumb, items: T[], settings: AskTableDisplaySettings<T>, initial: T | number, validate: (item: T) => ask.ValidationResponse, lc: LineCounter): Promise<T>

Get a single selection from a table.

const items = [
  { name: 'John', age: 25 },
  { name: 'Jane', age: 26 },
  { name: 'Derek', age: 27 }
];

const answer = await ask.table.select('Who?', items, {
  rows: ({ name, age }) => [name, age],
  headers: [['Name', 'Age']]
});
// ┏━━━┳━━━━━━━┳━━━━━┓
// ┃   ┃ Name  ┃ Age ┃
// ┡━━━╇━━━━━━━╇━━━━━┩
// │   │ John  │ 25  │
// ├───┼───────┼─────┤
// │ ❯ │ Jane  │ 26  │
// ├───┼───────┼─────┤
// │   │ Derek │ 27  │
// └───┴───────┴─────┘
// Returns: { name: 'Jane', age: 26 }

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:--------------------------------------|:--------|:-----------------------| | 0 | question | Yes | string \| Breadcrumb | | Question to ask | | 1 | items | Yes | T[] | | Items to select from | | 2 | settings | No | AskTableDisplaySettings<T> | {} | Settings for the table | | 3 | initial | No | T \| number | | Initial item | | 4 | validate | No | (item: T) => ask.ValidationResponse | | Validation function | | 5 | lc | No | LineCounter | | Line counter |

| Return Type | | |--------------|---------------------------------------------------| | Promise<T> | Promise that resolves with the user selected item |

table.multiselect

ask.table.multiselect(question: string | Breadcrumb, items: T[], settings: AskTableDisplaySettings<T>, initial: T[] | number[], validate: (items: T[]) => ask.ValidationResponse, lc: LineCounter): Promise<T[]>

Get multiple selections from a table.

const items = [
  { name: 'John', age: 25 },
  { name: 'Jane', age: 26 },
  { name: 'Derek', age: 27 }
];

const answer = await ask.table.multiselect('Who?', items, {
  rows: ({ name, age }) => [name, age],
  headers: [['Name', 'Age']]
});
┏━━━┳━━━━━━━┳━━━━━┓
┃   ┃ Name  ┃ Age ┃
┡━━━╇━━━━━━━╇━━━━━┩
│ ◉ │ John  │ 25  │
├───┼───────┼─────┤
│ ◯ │ Jane  │ 26  │
├───┼───────┼─────┤
│ ◉ │ Derek │ 27  │
└───┴───────┴─────┘
// [
//   { name: 'John', age: 25 },
//   { name: 'Derek', age: 27 }
// ]

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-----------------------------------------|:--------|:-----------------------| | 0 | question | Yes | string \| Breadcrumb | | Question to ask | | 1 | items | Yes | T[] | | Items to select from | | 2 | settings | No | AskTableDisplaySettings<T> | {} | Settings for the table | | 3 | initial | No | T[] \| number[] | | Initial items | | 4 | validate | No | (items: T[]) => ask.ValidationResponse | | Validation function | | 5 | lc | No | LineCounter | | Line counter |

| Return Type | | |----------------|----------------------------------------------------| | Promise<T[]> | Promise that resolves with the user selected items |

AskTableDisplaySettings

AskTableDisplaySettings<T>;

Settings for how the table should display the items

All settings are optional.

| Name | Type | Description | | --------- | ------------------------------- | ---------------------------------------------------------------- | | rows | any[][] \| (item: T) => any[] | Rows to display or function that takes an item and returns a row | | headers | any[][] \| RemapOf<T, string> | Header to display, or object with title for each item property | | options | table.TableOptions | Options object for table (some options are overridden) |

trim

ask.trim(question: string | Breadcrumb, totalFrames: number, frameRate: number, initial: Partial<Handles<number>>, validate: (handles: Handles<number>) => ask.ValidationResponse, lc: LineCounter): Promise<Handles<number>>

Get a start and end frame from the user

const handles = await ask.trim('Select a start and end frame', 100); // { start: 0, end: 100 }

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-------------------------------------------------------|:--------|:-------------------------| | 0 | question | Yes | string \| Breadcrumb | | Question to ask | | 1 | totalFrames | Yes | number | | Total number of frames | | 2 | frameRate | No | number | 60 | Frame rate | | 3 | initial | No | Partial<Handles<number>> | | Initial handle positions | | 4 | validate | No | (handles: Handles<number>) => ask.ValidationResponse | | Validation function | | 5 | lc | No | LineCounter | | Line counter |

| Return Type | | |----------------------------|------------------------------------------------------| | Promise<Handles<number>> | Promise that resolves with the user selected handles |

Extra

These are ask functions that don't prompt the user, but can help manage or organise how you use prompts

customise

ask.customise(options: Partial<ask.AskOptions>): void

Customise the behaviour/appearance of the ask prompts.

See ask.AskOptions for the options available.

ask.customise({ general: { themeColour: 'magenta' } }); // change the theme colour to magenta
ask.customise({ general: { lc } }); // set a line counter for that all prompts will add to when complete
ask.customise({ formatters: { formatPrompt: 'fullBox' } }); // change the format of the prompt

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:--------------------------|:-------------------------------------------------------------------| | 0 | options | Yes | Partial<ask.AskOptions> | Options to customise the behaviour/appearance of the ask prompts |

| Return Type | |-------------| | void |

loading

ask.loading(question: string | Breadcrumb, isComplete: boolean, isError: boolean, lc: LineCounter): { stop: () => void; }

Display an animated loading indicator that imitates the display of a prompt

Intended to be indicate a question is coming, but something is loading first. For general 'loading' indicators, use out.loading.

const loader = ask.loading('What is your name?');
// ...
loader.stop();

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-----------------------|:--------|:-----------------------------------------| | 0 | question | Yes | string \| Breadcrumb | | The question to display | | 1 | isComplete | No | boolean | false | Whether the loading is complete | | 2 | isError | No | boolean | false | Whether the loading is in an error state | | 3 | lc | No | LineCounter | | Line counter |

| Return Type | | |-------------------------|------------------------------------| | { stop: () => void; } | Loader object with a stop method |

countdown

ask.countdown(totalSeconds: number, template: (s: second) => string, isComplete: boolean, isError: boolean): Promise<void>

Animated countdown for a given number of seconds

await ask.countdown(5);

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:------------------------|:-----------------------------------------------| | 0 | totalSeconds | Yes | number | Total number of seconds to countdown from | | 1 | template | No | (s: second) => string | Template function to format the countdown text | | 2 | isComplete | No | boolean | Whether the countdown is complete | | 3 | isError | No | boolean | Whether the countdown is in an error state |

| Return Type | | |-----------------|------------------------------------------------------| | Promise<void> | Promise that resolves when the countdown is complete |

pause

ask.pause(text: string | Breadcrumb): Promise<void>

Pause the program until the user presses enter

await ask.pause();

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-----------------------|:-------------------------------|:----------------| | 0 | text | No | string \| Breadcrumb | 'Press enter to continue...' | Text to display |

| Return Type | | |-----------------|---------------------------------------------------| | Promise<void> | Promise that resolves when the user presses enter |

imitate

ask.imitate(question: string | Breadcrumb, result: any, isComplete: boolean, isError: boolean, errorMessage: string, lc: LineCounter): void

Imitate the display of a prompt

imitate('What is your name?', 'Jack', true);

ask.imitate('What is your name?', 'Jack', true);

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-----------------------|:--------|:-------------------------------| | 0 | question | Yes | string \| Breadcrumb | | Question to ask | | 1 | result | No | any | | Result to display | | 2 | isComplete | No | boolean | true | Whether the result is complete | | 3 | isError | No | boolean | false | Whether the result is an error | | 4 | errorMessage | No | string | | Error message | | 5 | lc | No | LineCounter | | Line counter |

| Return Type | |-------------| | void |

prefill

ask.prefill(question: string | Breadcrumb, value: T | undefined, askFn: (question: string | Breadcrumb, lc: LineCounter) => Promise<T> | T, lc: LineCounter): Promise<T>

Auto-fills an ask prompt with the provided value, if defined.

Continues to display the 'prompt', but already 'submitted'

Good for keeping skipping parts of forms, but providing context and keeping display consistent

let data = {};
const name1 = ask.prefill('What is your name?', data.name,  ask.text); // User input

data = {name: 'Jack'}
const name2 = ask.prefill('What is your name?', data.name,  ask.text); // Jack

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:-----------------------------------------------------------------------|:--------------------------------| | 0 | question | Yes | string \| Breadcrumb | Question to display | | 1 | value | Yes | T \| undefined | Value to prefill | | 2 | askFn | Yes | (question: string \| Breadcrumb, lc: LineCounter) => Promise<T> \| T | Ask function to use if no value | | 3 | lc | No | LineCounter | Line counter |

| Return Type | | |--------------|---------------------------------------------------------| | Promise<T> | Promise that resolves with the prefilled or asked value |

wizard

ask.wizard(startObj: Partial<T>): ask.Wizard<T>

Create a wizard object that can be used to build up a complex object

interface Example {
  foo: string;
  bar: number;
  baz: string;
}

const base: Partial<Example> = {
  baz: 'baz'
};

const wiz = ask.wizard<Example>(base);

await wiz.add('foo', ask.text('What is foo?')); // User input: foo

await wiz.add('bar', ask.number('What is bar?')); // User input: 123

const result = wiz.get(); // { baz: 'baz', foo: 'foo', bar: 123 }

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-------------|:--------|:-----------------------------| | 0 | startObj | No | Partial<T> | {} | Initial object to start with |

| Return Type | | |-----------------|---------------| | ask.Wizard<T> | Wizard object |

menu

ask.menu(question: string | Breadcrumb, items: MenuItem<T>[], initial: MenuItem<T> | T | number, validate: (value: T, index: number) => ask.ValidationResponse, lc: LineCounter): Promise<T>

Wrapper for ask.select that styles the output as a menu, with icons and colours, and supports nested submenus

// Example 1
const menuItems: ask.MenuItem<string>[] = [
  { value: 'done', title: colr.dim(`[ Finished ]`), icon: '✔', colour: colr.dark.green.bold },
  { value: 'create', title: `${colr.bold('Create')} a new thing`, icon: '+', colour: colr.black.greenBg },
  { value: 'duplicate', title: `${colr.bold('Duplicate')} a thing`, icon: '⌥', colour: colr.black.cyanBg },
  { value: 'edit', title: `${colr.bold('Edit')} a thing`, icon: '↻', colour: colr.black.yellowBg },
  { value: 'delete', title: `${colr.bold('Remove')} thing(s)`, icon: '×', colour: colr.black.redBg },
  { value: 'delete-all', title: colr.bold(`Remove all`), icon: '✖', colour: colr.black.darkBg.redBg }
];
const result = await ask.menu('Pick a menu item', menuItems, 'edit'); // 'duplicate' (or other value)

// Example 2 - Submenus
const actions = (itemType: string) => ({
  items: [
    { title: 'Find', icon: '⌕', colour: colr.sets.blue, value: `find-${itemType}` },
    { title: 'Add', icon: '✚', colour: colr.sets.green, value: `add-${itemType}` },
    { title: 'Edit', icon: '✎', colour: colr.sets.yellow, value: `edit-${itemType}` },
    { title: 'Delete', icon: '⨯', colour: colr.sets.red, value: `delete-${itemType}` }
  ]
});
const menuItems: ask.MenuItem<string>[] = [
  { title: 'Task', icon: '⚑', colour: colr.darkBg.cyanBg, submenu: actions('task') },
  { title: 'Project', icon: '⎔', colour: colr.darkBg.magentaBg, submenu: actions('project') },
  { title: 'Milestone', icon: '◈', colour: colr.darkBg.yellowBg, submenu: actions('milestone') },
  { title: 'Permission', icon: '⚷', colour: colr.light.greyBg, submenu: actions('permission') }
];
const result = await ask.menu('What do you want to work with?', menuItems);

| # | Parameter Name | Required | Type | Description | |:---:|:---------------|:---------|:------------------------------------------------------|:-----------------------| | 0 | question | Yes | string \| Breadcrumb | Question to display | | 1 | items | Yes | MenuItem<T>[] | Menu items | | 2 | initial | No | MenuItem<T> \| T \| number | Initial item to select | | 3 | validate | No | (value: T, index: number) => ask.ValidationResponse | Validation function | | 4 | lc | No | LineCounter | Line counter |

| Return Type | | |--------------|----------------------------------------------| | Promise<T> | Promise that resolves with the selected item |

section

ask.section(question: string | Breadcrumb, sectionHeader: (lc: LineCounter) => void | Promise<any>, ...questionFns: [...T][]): Promise<TupleFromQuestionFuncs<T>>

Allows information to be displayed before a question, and follow up questions to be asked, while only leaving the 'footprint' of a single question afterwards.

const ans1 = await ask.text('Question 1:');
const ans2 = await ask.section('Question 2:',
  (lc: LineCounter) => {
    lc.log('Some information');
  },
  (qst) => ask.text(qst),
  () => ask.text('Question 2b:')
);

During the section, it looks like this:

Question 1: answer1
┄┄┄┄┄◦┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄◦┄┄┄┄┄┄
Some information
┄┄┄┄┄◦┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄◦┄┄┄┄┄┄
Question 2: answer2
Question 2b: answer2b

After the last question in the section has been submitted, it looks like this:

Question 1: answer1
Question 2a: [ answer2, answer2b ]

| # | Parameter Name | Required | Type | Description | |:----:|:----------------|:---------|:--------------------------------------------|:------------------------| | 0 | question | Yes | string \| Breadcrumb | Question to ask | | 1 | sectionHeader | No | (lc: LineCounter) => void \| Promise<any> | Section header function | | 2… | questionFns | No | [...T][] | Question functions |

| Return Type | | |--------------------------------------|-------------------------------------------| | Promise<TupleFromQuestionFuncs<T>> | Promise that resolves with the user input |

separator

ask.separator(version: 'down' | 'none' | 'up', spacing: number, offset: number, width: number, lc: LineCounter): void

Prints a separator line to the console.

ask.separator('down');
// ┄┄┄┄┄▿┄┄┄┄┄┄┄▿┄┄┄┄┄┄┄▿┄┄┄┄┄┄┄▿┄┄┄┄┄┄┄▿┄┄┄┄┄┄┄▿┄┄┄┄┄┄

ask.separator('none', 15);
// ┄┄┄┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄┄┄┄┄┄┄┄◦┄┄┄┄┄┄┄┄┄┄┄

ask.separator('up', 5, 2);
// ┄┄┄┄┄┄┄┄▵┄┄┄┄▵┄┄┄┄▵┄┄┄┄▵┄┄┄┄▵┄┄┄┄▵┄┄┄┄▵┄┄┄┄▵┄┄┄┄┄┄┄┄

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:---------------------------|:-----------------------------------|:------------------------------------| | 0 | version | No | 'down' \| 'none' \| 'up' | 'down' | Type of separator | | 1 | spacing | No | number | 8 | Spacing between the separator nodes | | 2 | offset | No | number | 0 | Offset of the separator nodes | | 3 | width | No | number | out.utils.getTerminalWidth() - 2 | Width of the separator | | 4 | lc | No | LineCounter | | Line counter |

| Return Type | |-------------| | void |

utils

itemsToPromptObjects

ask.utils.itemsToPromptObjects(items: T[], titles: string[], titleFn: TitleFn<T>): { title: string; value: T; }[]

Take an array of items and convert them to an array of prompt objects

ask.utils.itemsToPromptObjects(['lorem', 'ipsum', 'dolor'])
// [
//   { title: 'lorem', value: 'lorem' },
//   { title: 'ipsum', value: 'ipsum' },
//   { title: 'dolor', value: 'dolor' }
// ]

ask.utils.itemsToPromptObjects(['lorem', 'ipsum', 'dolor'], ['Lorem', 'Ipsum', 'Dolor'])
// [
//   { title: 'Lorem', value: 'lorem' },
//   { title: 'Ipsum', value: 'ipsum' },
//   { title: 'Dolor', value: 'dolor' }
// ]

ask.utils.itemsToPromptObjects(['lorem', 'ipsum', 'dolor'], undefined, (s) => s.toUpperCase())
// [
//   { title: 'LOREM', value: 'lorem' },
//   { title: 'IPSUM', value: 'ipsum' },
//   { title: 'DOLOR', value: 'dolor' }
// ]

| # | Parameter Name | Required | Type | Default | Description | |:---:|:---------------|:---------|:-------------|:--------|:----------------------------| | 0 | items | Yes | T[] | | Items to convert | | 1 | titles | No | string[] | [] | Titles to use | | 2 | titleFn | No | TitleFn<T> | | Function to generate titles |

| Return Type | | |----------------------------------|-------------------------| | { title: string; value: T; }[] | Array of prompt objects |

AskOptions

ask.AskOptions;

Options to customise the behaviour/appearance of the ask prompts.

Use with ask.customise to set these options.

general Options

ask.AskOptions.general;

General options for customising ask prompts

| Name | Type | Description | |--------------------------------|---------------------|--------------------------------------------------------------------| | themeColour | string (Colour) | Set the main theme colour | | lc | LineCounter | A line counter that all ask prompts will add to when complete | | boxType | 'thin' \| 'thick' | What type of box drawing lines to use | | beeps | boolean | Whether to make an audio beeps when appropriate | | maxItemsOnScreen | number | How many select/multiselect items to have on screen at most | | scrollMargin | number | How much space to leaving when 'scrolling' lists of items | | fileExplorerColumnWidth | number | How wide to make each panel of the fileExplorer interface | | fileExplorerMaxItems | number | How many items to show in each panel of the fileExplorer interface | | tableSelectMaxHeightPercentage | number | Percent of terminal height to use at max for table selects | | timelineSpeed | number | How many frames to move on a timeline at a time | | timelineFastSpeed | number | How many frames to move on a timeline at a time (fast mode) |

text Options

ask.AskOptions.text;

English natural-language elements that you may wish to localise

| Name | Type | Description | |------------------------------------|----------------------------|-------------------------------------------------------------| | boolTrueKeys | string | What buttons to use to indicate true for boolean prompts | | boolFalseKeys | string | What buttons to use to indicate false for boolean prompts | | boolYes | string | 'Yes' | | boolNo | string | 'No' | | boolYesNoSeparator | string | '/' | | boolYN | string | '(Y/n)' | | selectAll | string | '[Select All]' | | done | string | 'done' | | items | (num: number) => string | '[X items]' | | countdown | (secs: number) => string | 'Starting in Xs...' | | file | string | 'File' | | directory | string | 'Directory' | | loading | string | 'Loading...' | | selected | (num: number) => string | 'X selected' | | specialNewFolderEnterNothingCancel | string | 'Enter nothing to cancel' | | specialNewFolderAddingFolderTo | string | 'Adding folder to ' | | specialNewFolderQuestion | (hl: any) => string | 'What do you want to name the new folder?' | | specialSaveFileSavingFileTo | string | 'Saving file to ' | | specialSaveFileQuestion | (hl: any) => string | 'What do you want to name the file?' |

formatters Options

ask.AskOptions.formatters;

Functions for formatting how the prompts should display

formatPrompt
ask.AskOptions.formatters.formatPrompt;

How to format the prompts

Presets: oneLine, halfBox, halfBoxClosed, fullBox, fullBoxClosed

Type:

(
  question: string | Breadcrumb,
  value: string,
  items: string | undefined,
  errorMessage: string | undefined,
  theme: AskOptionsForState,
  isComplete: boolean,
  isExit: boolean
) => string;
formatItems
ask.AskOptions.formatters.formatItems;

How to format lists of items

Presets: block, blockAlt, simple, simpleAlt

Type:

<T extends unknown>(
  allItems: PromptChoiceFull<T>[],
  scrolledItems: ScrolledItems<PromptChoiceFull<T>>,
  selected: number[] | undefined,
  type: 'single' | 'multi',
  theme: AskOptionsForState,
  isExit: boolean
) => string;

colours Options

ask.AskOptions.colours;

Colours for all the different elements

All colours can be a single WrapFn value, or a set of WrapFn values, one for each state (normal, error, done) When single value, it is used for all states. When only a few states are set, the others will remain unchanged.

| Name | Description | |--------------------------|-------------------------------------------------------------------------------------------------| | decoration | General decoration and cosmetics | | questionText | The text of the question of the prompt | | specialIcon | Special icon for the 'state' | | openingIcon | The initial/opening icon | | promptIcon | The icon that indicates where you are typing | | result | General result | | resultText | String results | | resultNumber | Number results | | resultBoolean | Boolean results | | resultArray | Array results | | resultDate | Date results | | loadingIcon | Icon for ask.loading | | errorMsg | The error message (if there is one) | | item | A normal item in a list | | itemIcon | Icon for a normal item in a list | | itemHover | A hovered item in a list | | itemHoverIcon | Icon for a hovered item in a list | | itemBlockHover | A hovered item in a list (block mode) | | itemBlockHoverIcon | Icon for a hovered item in a list (block mode) | | itemSelected | A selected item in a list | | itemSelectedIcon | Icon for a selected item in a list | | itemUnselected | An unselected item in a list | | itemUnselectedIcon | Icon for an unselected item in a list | | scrollbarTrack | The track for the scrollbar | | scrollbarBar | The bar for the scrollbar | | selectAllText | 'Select All' item in a multi-select | | boolYNText | The '(Y/n)' bit for the booleanYN prompt | | countdown | ask.countdown | | pause | ask.pause | | specialHover | The focus of what the user is controlling (for dates, fileExplorer, etc) | | specialSelected | Something that has been selected (for dates, fileExplorer, etc) | | specialHighlight | More important that normal (e.g. date within a range) (for dates, fileExplorer, etc) | | specialNormal | Normal items (for dates, fileExplorer, etc) | | specialFaded | Not important (for dates, fileExplorer, etc) | | specialHint | Hints/tips/advice (for dates, fileExplorer, etc) | | specialInactiveHover | The focus of what the user is controlling (Inactive) (for dates, fileExplorer, etc) | | specialInactiveSelected | Something that has been selected (Inactive) (for dates, fileExplorer, etc) | | specialInactiveHighlight | More important that normal (e.g. date within a range) (Inactive) (for dates, fileExplorer, etc) | | specialInactiveNormal | Normal items (Inactive) (for dates, fileExplorer, etc) | | specialInactiveFaded | Not important (Inactive) (for dates, fileExplorer, etc) | | specialInactiveHint | Hints/tips/advice (Inactive) (for dates, fileExplorer, etc) | | specialInfo | Action bar at bottom (for dates, fileExplorer, etc) | | specialErrorMsg | Error messages (for dates, fileExplorer, etc) | | specialErrorIcon | Icon for errors (for dates, fileExplorer, etc) | | tableSelectHover | Hover for table selects only (shouldn't be 'block'/bg styles) | | timelineTrack | The (inactive) track of a timeline | | timelineTrackActive | The active track of a timeline | | timelineHandle | The (inactive) control handle on a timeline | | timelineHandleActive | The active control handle on a timeline |

symbols Options

ask.AskOptions.symbols;

Variety of symbols and 'icons' for different aspects of the display

All symbols can be a single string value, or a set of string values, one for each state (normal, error, done) When single value, it is used for all states. When only a few states are set, the others will remain unchanged.

| Name | Description | |--------------------------|---------------------------------------------------------------------------| | specialIcon | Special icon for the 'state' | | openingIcon | The initial/opening icon | | promptIcon | The icon that indicates where you are typing | | errorMsgPrefix | Icon shown before error messages | | itemIcon | Icon for a normal item in a list | | itemHoverIcon | Icon for a hovered item in a list | | itemSelectedIcon | Icon for a selected item in a list | | itemUnselectedIcon | Icon for an unselected item in a list | | scrollUpIcon | Used to indicate you can scroll up | | scrollDownIcon | Used to indicate you can scroll down | | scrollbarTrack | The track part of the scrollbar | | scrollbarTrackTrimTop | The trimmed top of the track (half height) | | scrollbarTrackTrimBottom | The trimmed bottom of the track (half height) | | scrollbarBar | The bar part of the scrollbar | | scrollbarBarTrimTop | The trimmed top of the bar (half height) | | scrollbarBarTrimBottom | The trimmed bottom of the bar (half height) | | separatorLine | Line added by ask.separator | | separatorNodeDown | Node is ask.separator line that indicates 'down' | | separatorNodeNone | Node is ask.separator line that breaks up the pattern | | separatorNodeUp | Node is ask.separator line that indicates 'up' | | specialErrorIcon | Icon for errors (for dates, fileExplorer, etc) | | folderOpenableIcon | Shown at end of line for folders to show they can be opened (right-wards) | | fileOpenableIcon | File version of folderOpenableIcon. Typically empty | | symlinkIcon | Shown at end of line for symlinks or aliases | | timelineTrack | The track of a timeline | | timelineHandle | The control handle on a timeline | | timelineBar | The 'bar' (active portion) of a timeline |

PromptChoice

ask.PromptChoice<T>;

A choice for a prompt

Equivalent to T | { title?: string; value?: T; selected?: boolean; }

ValidationResponse

ask.ValidationResponse;

Response type for ask validation functions.

| Response | Type | Result | Error Message | |----------------------|-----------|---------------|---------------| | new Error('error') | Error | ❌ - Rejected | 'error' | | 'error' | string | ❌ - Rejected | 'error' | | false | boolean | ❌ - Rejected | None | | true | boolean | ✅ - Accepted | N/A | | null | null | ✅ - Accepted | N/A | | undefined | undefined | ✅ - Accepted | N/A |

Equivalent to Error | string | boolean | void