diff --git a/types/console-ui/console-ui-tests.ts b/types/console-ui/console-ui-tests.ts index 0092ce60db..f9a77ba820 100644 --- a/types/console-ui/console-ui-tests.ts +++ b/types/console-ui/console-ui-tests.ts @@ -1,4 +1,4 @@ -import { Question } from 'inquirer'; +import { DistinctQuestion } from 'inquirer'; import UI = require('console-ui'); new UI({ @@ -50,7 +50,7 @@ ui.startProgress('hello'); ui.stopProgress(); ui.stopProgress('hello'); // $ExpectError -const question: Question<{ answer: boolean }> = { +const question: DistinctQuestion<{ answer: boolean }> = { message: 'Yes / No?', type: 'confirm' }; diff --git a/types/console-ui/index.d.ts b/types/console-ui/index.d.ts index 407bdc5a6d..0e65b6e50a 100644 --- a/types/console-ui/index.d.ts +++ b/types/console-ui/index.d.ts @@ -5,7 +5,7 @@ // TypeScript Version: 3.3 import { Readable, Writable } from 'stream'; -import { Questions } from 'inquirer'; +import { QuestionCollection } from 'inquirer'; type WriteLevel = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR'; @@ -89,5 +89,5 @@ declare class UI { * Launch the prompt interface (inquiry session) with (Array of Questions || Question) * See [Inquirer.js#question](https://github.com/SBoudrias/Inquirer.js#question) for Question properties */ - prompt(questions: Questions, callback?: (answers: T) => void): Promise; + prompt(questions: QuestionCollection, callback?: (answers: T) => void): Promise; } diff --git a/types/inquirer/index.d.ts b/types/inquirer/index.d.ts index 9b2a8a19c9..db3ff4b870 100644 --- a/types/inquirer/index.d.ts +++ b/types/inquirer/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Inquirer.js 6.x +// Type definitions for inquirer 6.5 // Project: https://github.com/SBoudrias/Inquirer.js // Definitions by: Qubo // Parvez @@ -10,430 +10,932 @@ // Keith Kelly // Richard Lea // Jed Mao +// Manuel Thalmann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 3.3 +import { Interface as ReadlineInterface } from "readline"; +import { Observable } from "rxjs"; +import { ThroughStream } from "through"; +import Choice = require("./lib/objects/choice"); +import Choices = require("./lib/objects/choices"); +import Separator = require("./lib/objects/separator"); +import Prompt = require("./lib/prompts/base"); +import "./lib/prompts/checkbox"; +import "./lib/prompts/confirm"; +import "./lib/prompts/editor"; +import "./lib/prompts/expand"; +import "./lib/prompts/input"; +import "./lib/prompts/list"; +import "./lib/prompts/number"; +import "./lib/prompts/password"; +import "./lib/prompts/rawlist"; +import BottomBar = require("./lib/ui/bottom-bar"); +import PromptUI = require("./lib/ui/prompt"); +import "./lib/utils/events"; +import Paginator = require("./lib/utils/paginator"); +import "./lib/utils/readline"; +import ScreenManager = require("./lib/utils/screen-manager"); +import "./lib/utils/utils"; -import { ThroughStream } from 'through'; -import { Observable } from 'rxjs'; -import { Interface as ReadlineInterface } from 'readline'; +/** + * Represents a union which preserves autocompletion. + * + * @template T + * The keys which are available for autocompletion. + * + * @template F + * The fallback-type. + */ +type LiteralUnion = T | (F & {}); +/** + * Provides prompts for answering questions. + */ +interface PromptModuleBase { + /** + * Registers a new prompt-type. + * + * @param name + * The name of the prompt. + * + * @param prompt + * The constructor of the prompt. + */ + registerPrompt(name: string, prompt: inquirer.prompts.PromptConstructor): void; + + /** + * Registers the default prompts. + */ + restoreDefaultPrompts(): void; +} + +/** + * Represents a list-based question. + * + * @template T + * The type of the answers. + * + * @template TChoiceMap + * The valid choices for the question. + */ +interface ListQuestionOptionsBase extends inquirer.Question { + /** + * The choices of the prompt. + */ + choices?: inquirer.AsyncDynamicQuestionProperty>, T>; + + /** + * The number of elements to show on each page. + */ + pageSize?: number; +} + +/** + * Provides components for the module. + */ declare namespace inquirer { - type Prompts = { [name: string]: prompts.Base }; - type ChoiceType = string | objects.ChoiceOption | objects.Separator; - type Questions = - | Question - | Question[] - | ReadonlyArray> - | Observable>; - type Answers = Record - type StreamOptions = { - input?: NodeJS.ReadStream, - output?: NodeJS.WriteStream, - }; + /** + * Represents either a key of `T` or a `string`. + * + * @template T + * The type of the keys to suggest. + */ + type KeyUnion = LiteralUnion>; - interface Inquirer { - restoreDefaultPrompts(): void; - /** - * Expose helper functions on the top level for easiest usage by common users - * @param name - * @param prompt - */ - registerPrompt(name: string, prompt: PromptModule): void; - /** - * Create a new self-contained prompt module. - * @param opt Object specifying input and output streams for the prompt - */ - createPromptModule(opt?: StreamOptions): PromptModule; - /** - * Public CLI helper interface - * @param questions Questions settings array - * @return - */ - prompt: PromptModule; - prompts: Prompts; - Separator: objects.SeparatorStatic; - ui: { - BottomBar: ui.BottomBar; - Prompt: ui.PromptUI; - }; - } + /** + * Converts the specified union-type `U` to an intersection-type. + * + * @template U + * The union to convert to an intersection. + */ + type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; - interface PromptModule { - (questions: Questions): Promise & { ui: ui.PromptUI }; + /** + * Provides an input and an output-stream. + */ + interface StreamOptions { /** - * Register a prompt type - * @param name Prompt type name - * @param prompt Prompt constructor + * A stream to read the input from. */ - registerPrompt(name: string, prompt: prompts.Base): PromptModule; - /** - * Register the defaults provider prompts - */ - restoreDefaultPrompts(): void; - } + input?: NodeJS.ReadStream; - interface QuestionCommon { /** - * The name to use when storing the answer in the answers hash. - * If the name contains periods, it will define a path in the answers hash. + * A stream to write the output to. */ - name?: string; - /** - * The question to print. If defined as a function, the first parameter will be - * the current inquirer session answers. - * Defaults to the value of `name` (followed by a colon). - */ - message?: string | ((answers: A) => string); - /** - * Default value(s) to use if nothing is entered, or a function that returns - * the default value(s). If defined as a function, the first parameter will be - * the current inquirer session answers. - */ - default?: string | number | boolean | any[] | ((answers: A) => any) | ((answers: A) => Promise); - /** - * Change the default _prefix_ message. - */ - prefix?: string; - /** - * Change the default _suffix_ message. - */ - suffix?: string; - /** - * Receive the current user answers hash and should return `true` or `false` depending - * on whether or not this question should be asked. The value can also be a simple boolean. - */ - when?: boolean | ((answers: A) => boolean | Promise); - } - - interface QuestionOptions { - /** - * Choices array or a function returning a choices array. If defined as a function, - * the first parameter will be the current inquirer session answers. Array values can - * be simple `numbers`, `strings`, or `objects` containing a `name` (to display in list), - * a `value` (to save in the answers hash) and a `short` (to display after selection) - * properties. The choices array can also contain - * [a Separator](https://github.com/SBoudrias/Inquirer.js#separator). - */ - choices?: - | ReadonlyArray> - | ((answers: A) => ReadonlyArray>) - | ((answers: A) => Promise>>); - /** - * Receive the user input and return the filtered value to be used inside the program. - * The value returned will be added to the _Answers_ hash. - */ - filter?(input: string): any; - /** - * Receive the user input, answers hash and option flags, and return a transformed value - * to display to the user. The transformation only impacts what is shown while editing. - * It does not modify the answers hash. - */ - transformer?(input: string, answers: A, flags: any): string; - /** - * Change the number of lines that will be rendered when using `list`, `rawList`, - * `expand` or `checkbox`. - */ - pageSize?: number; - } - - type Question = ( - ListQuestion | - RawListQuestion | - ExpandQuestion | - CheckboxQuestion | - ConfirmQuestion | - InputQuestion | - NumberQuestion | - PasswordQuestion | - EditorQuestion - ) - - interface ListQuestion extends QuestionCommon, - Pick, 'choices' | 'filter' | 'pageSize'> { - type: 'list' - } - - interface RawListQuestion extends QuestionCommon, - Pick, 'choices' | 'filter' | 'pageSize'> { - type: 'rawlist' - } - - interface ExpandQuestion extends QuestionCommon, - Pick, 'choices' | 'pageSize'> { - type: 'expand' - } - - interface CheckboxQuestion extends QuestionCommon, - Pick, 'choices' | 'filter' | 'pageSize'> { - type: 'checkbox' - /** - * Receive the user input and answers hash. Should return `true` if the value is valid, - * and an error message (`String`) otherwise. If `false` is returned, a default error - * message is provided. - */ - validate?(input: string, answers?: A): boolean | string | Promise; - } - - interface ConfirmQuestion extends QuestionCommon, QuestionOptions { - type: 'confirm' - } - - interface InputQuestion extends QuestionCommon, - Pick, 'filter' | 'transformer'> { - type?: 'input' - /** - * Receive the user input and answers hash. Should return `true` if the value is valid, - * and an error message (`String`) otherwise. If `false` is returned, a default error - * message is provided. - */ - validate?(input: string, answers?: A): boolean | string | Promise; - } - - interface NumberQuestion extends QuestionCommon, - Pick, 'filter' | 'transformer'> { - type: 'number' - /** - * Receive the user input and answers hash. Should return `true` if the value is valid, - * and an error message (`String`) otherwise. If `false` is returned, a default error - * message is provided. - */ - validate?(input: number, answers?: A): boolean | string | Promise; - } - - interface PasswordQuestion extends QuestionCommon, - Pick, 'filter' | 'transformer'> { - type: 'password' - /** - * Hides the user input. - */ - mask?: string; - /** - * Receive the user input and answers hash. Should return `true` if the value is valid, - * and an error message (`String`) otherwise. If `false` is returned, a default error - * message is provided. - */ - validate?(input: string, answers?: A): boolean | string | Promise; - } - - interface EditorQuestion extends QuestionCommon, - Pick, 'filter'> { - type: 'editor' - /** - * Receive the user input and answers hash. Should return `true` if the value is valid, - * and an error message (`String`) otherwise. If `false` is returned, a default error - * message is provided. - */ - validate?(input: string, answers?: A): boolean | string | Promise; + output?: NodeJS.WriteStream; } /** - * Corresponding to the answer object creation in: - * https://github.com/SBoudrias/Inquirer.js/blob/ff075f587ef78504f0eae4ee5ca0656432429026/packages/inquirer/lib/ui/prompt.js#L88 + * Provides the functionality to prompt questions to the user. */ - interface Answer { - name: string, - answer: any, + interface PromptModule extends PromptModuleBase { + /** + * The prompts of the prompt-module. + */ + prompts: prompts.PromptCollection; + + /** + * Prompts the questions to the user. + */ + (questions: QuestionCollection): Promise & { ui: PromptUI }; + + /** + * Registers a new prompt-type. + * + * @param name + * The name of the prompt. + * + * @param prompt + * The constructor of the prompt. + */ + registerPrompt(name: string, prompt: prompts.PromptConstructor): this; } + interface Inquirer extends PromptModuleBase { + /** + * Registers a new prompt-type. + * + * @param name + * The name of the prompt. + * + * @param prompt + * The constructor of the prompt. + */ + registerPrompt(name: string, prompt: prompts.PromptConstructor): void; + + /** + * Creates a prompt-module. + * + * @param opt + * The streams for the prompt-module. + * + * @returns + * The new prompt-module. + */ + createPromptModule(opt?: StreamOptions): PromptModule; + + /** + * The default prompt-module. + */ + prompt: PromptModule; + + /** + * The prompts of the default prompt-module. + * + * @deprecated + */ + prompts: {}; + + /** + * Represents a choice-item separator. + */ + Separator: typeof Separator; + + /** + * Provides ui-components. + */ + ui: { + /** + * Represents the bottom-bar UI. + */ + BottomBar: typeof BottomBar; + + /** + * Represents the prompt ui. + */ + Prompt: typeof PromptUI; + }; + } + + /** + * A set of answers. + */ + interface Answers extends Record { } + + /** + * Provides the functionality to validate answers. + * + * @template T + * The type of the answers. + */ + type Validator = Question["validate"]; + + /** + * Provides the functionality to transform an answer. + * + * @template T + * The type of the answers. + */ + type Transformer = InputQuestionOptions["transformer"]; + + /** + * Represents a dynamic property for a question. + */ + type DynamicQuestionProperty = T | ((answers: TAnswers) => T); + + /** + * Represents a dynamic property for a question which can be fetched asynchronously. + */ + type AsyncDynamicQuestionProperty = DynamicQuestionProperty, TAnswers>; + + /** + * Provides options for a question. + * + * @template T + * The type of the answers. + */ + interface Question { + /** + * The type of the question. + */ + type?: string; + + /** + * The key to save the answer to the answers-hash. + */ + name?: KeyUnion; + + /** + * The message to show to the user. + */ + message?: AsyncDynamicQuestionProperty; + + /** + * The default value of the question. + */ + default?: AsyncDynamicQuestionProperty; + + /** + * The prefix of the `message`. + */ + prefix?: string; + + /** + * The suffix of the `message`. + */ + suffix?: string; + + /** + * Post-processes the answer. + * + * @param input + * The answer provided by the user. + */ + filter?(input: any): any; + + /** + * A value indicating whether the question should be prompted. + */ + when?: AsyncDynamicQuestionProperty; + + /** + * Validates the integrity of the answer. + * + * @param input + * The answer provided by the user. + * + * @param answers + * The answers provided by the user. + * + * @returns + * Either a value indicating whether the answer is valid or a `string` which describes the error. + */ + validate?(input: any, answers?: T): boolean | string | Promise; + } + + /** + * Represents a choice-item. + */ + interface ChoiceBase { + /** + * The type of the choice. + */ + type?: string; + } + + /** + * Provides options for a choice. + * + * @template T + * The type of the answers. + */ + interface ChoiceOptions extends ChoiceBase { + /** + * @inheritdoc + */ + type?: "choice"; + + /** + * The name of the choice to show to the user. + */ + name?: string; + + /** + * The value of the choice. + */ + value?: any; + + /** + * The short form of the name of the choice. + */ + short?: string; + + /** + * The extra properties of the choice. + */ + extra?: any; + } + + /** + * Provides options for a choice of the `ListPrompt`. + * + * @template T + * The type of the answers. + */ + interface ListChoiceOptions extends ChoiceOptions { + /** + * A value indicating whether the choice is disabled. + */ + disabled?: DynamicQuestionProperty; + } + + /** + * Provides options for a choice of the `CheckboxPrompt`. + * + * @template T + * The type of the answers. + */ + interface CheckboxChoiceOptions extends ListChoiceOptions { + /** + * A value indicating whether the choice should be initially checked. + */ + checked?: boolean; + } + + /** + * Provides options for a choice of the `ExpandPrompt`. + * + * @template T + * The type of the answers. + */ + interface ExpandChoiceOptions extends ChoiceOptions { + /** + * The key to press for selecting the choice. + */ + key?: string; + } + + /** + * Represents a separator. + */ + interface SeparatorOptions { + /** + * Gets the type of the choice. + */ + type: "separator"; + + /** + * Gets or sets the text of the separator. + */ + line?: string; + } + + /** + * Provides all valid choice-types for any kind of question. + * + * @template T + * The type of the answers. + */ + interface BaseChoiceMap { + Choice: Choice; + ChoiceOptions: ChoiceOptions; + SeparatorOptions: SeparatorOptions; + Separator: Separator; + } + + /** + * Provides all valid choice-types for the `ListQuestion`. + * + * @template T + * The type of the answers. + */ + interface ListChoiceMap extends BaseChoiceMap { + ListChoiceOptions: ListChoiceOptions; + } + + /** + * Provides all valid choice-types for the `CheckboxQuestion`. + * + * @template T + * The type of the answers. + */ + interface CheckboxChoiceMap extends BaseChoiceMap { + CheckboxChoiceOptions: CheckboxChoiceOptions; + } + + /** + * Provides all valid choice-types for the `ExpandQuestion`. + * + * @template T + * The type of the answers. + */ + interface ExpandChoiceMap extends BaseChoiceMap { + ExpandChoiceOptions: ExpandChoiceOptions; + } + + /** + * Provides all valid choice-types. + * + * @template T + * The type of the answers. + */ + interface AllChoiceMap { + BaseChoiceMap: BaseChoiceMap[keyof BaseChoiceMap]; + ListChoiceMap: ListChoiceMap[keyof ListChoiceMap]; + CheckboxChoiceMap: CheckboxChoiceMap[keyof CheckboxChoiceMap]; + ExpandChoiceMap: ExpandChoiceMap[keyof ExpandChoiceMap]; + } + + /** + * Provides valid choices for the question of the `TChoiceMap`. + * + * @template TChoiceMap + * The choice-types to provide. + */ + type DistinctChoice = + string | + TChoiceMap[keyof TChoiceMap]; + + /** + * Represents a set of choices. + */ + type ChoiceCollection = Array>; + + /** + * Provides options for a question for the `InputPrompt`. + * + * @template T + * The type of the answers. + */ + interface InputQuestionOptions extends Question { + /** + * Transforms the value to display to the user. + * + * @param input + * The input provided by the user. + * + * @param answers + * The answers provided by the users. + * + * @param flags + * Additional information about the value. + * + * @returns + * The value to display to the user. + */ + transformer?(input: any, answers: T, flags: { isFinal?: boolean }): string | Promise; + } + + /** + * Provides options for a question for the `InputPrompt`. + * + * @template T + * The type of the answers. + */ + interface InputQuestion extends InputQuestionOptions { + /** + * @inheritdoc + */ + type?: "input"; + } + + /** + * Provides options for a question for the `NumberPrompt`. + * + * @template T + * The type of the answers. + */ + interface NumberQuestionOptions extends InputQuestionOptions { } + + /** + * Provides options for a question for the `NumberPrompt`. + * + * @template T + * The type of the answers. + */ + interface NumberQuestion extends NumberQuestionOptions { + /** + * @inheritdoc + */ + type: "number"; + } + + /** + * Provides options for a question for the `PasswordPrompt`. + * + * @template T + * The type of the answers. + */ + interface PasswordQuestionOptions extends InputQuestionOptions { + /** + * The character to replace the user-input. + */ + mask?: string; + } + + /** + * Provides options for a question for the `PasswordPrompt`. + * + * @template T + * The type of the answers. + */ + interface PasswordQuestion extends PasswordQuestionOptions { + /** + * @inheritdoc + */ + type: "password"; + } + + /** + * Provides options for a question for the `ListPrompt`. + * + * @template T + * The type of the answers. + */ + interface ListQuestionOptions extends ListQuestionOptionsBase> { } + + /** + * Provides options for a question for the `ListPrompt`. + * + * @template T + * The type of the answers. + */ + interface ListQuestion extends ListQuestionOptions { + /** + * @inheritdoc + */ + type: "list"; + } + + /** + * Provides options for a question for the `RawListPrompt`. + * + * @template T + * The type of the answers. + */ + interface RawListQuestionOptions extends ListQuestionOptions { } + + /** + * Provides options for a question for the `RawListPrompt`. + * + * @template T + * The type of the answers. + */ + interface RawListQuestion extends ListQuestionOptionsBase> { + /** + * @inheritdoc + */ + type: "rawlist"; + } + + /** + * Provides options for a question for the `ExpandPrompt`. + * + * @template T + * The type of the answers. + */ + interface ExpandQuestionOptions extends ListQuestionOptionsBase> { } + + /** + * Provides options for a question for the `ExpandPrompt`. + * + * @template T + * The type of the answers. + */ + interface ExpandQuestion extends ExpandQuestionOptions { + /** + * @inheritdoc + */ + type: "expand"; + } + + /** + * Provides options for a question for the `CheckboxPrompt`. + * + * @template T + * The type of the answers. + */ + interface CheckboxQuestionOptions extends ListQuestionOptionsBase> { } + + /** + * Provides options for a question for the `CheckboxPrompt`. + * + * @template T + * The type of the answers. + */ + interface CheckboxQuestion extends CheckboxQuestionOptions { + /** + * @inheritdoc + */ + type: "checkbox"; + } + + /** + * Provides options for a question for the `ConfirmPrompt`. + * + * @template T + * The type of the answers. + */ + interface ConfirmQuestionOptions extends Question { } + + /** + * Provides options for a question for the `ConfirmPrompt`. + * + * @template T + * The type of the answers. + */ + interface ConfirmQuestion extends ConfirmQuestionOptions { + /** + * @inheritdoc + */ + type: "confirm"; + } + + /** + * Provides options for a question for the `EditorPrompt`. + * + * @template T + * The type of the answers. + */ + interface EditorQuestionOptions extends Question { } + + /** + * Provides options for a question for the `EditorPrompt`. + * + * @template T + * The type of the answers. + */ + interface EditorQuestion extends EditorQuestionOptions { + /** + * @inheritdoc + */ + type: "editor"; + } + + /** + * Provides the available question-types. + * + * @template T + * The type of the answers. + */ + interface QuestionMap { + /** + * The `InputQuestion` type. + */ + input: InputQuestion; + + /** + * The `NumberQuestion` type. + */ + number: NumberQuestion; + + /** + * The `PasswordQuestion` type. + */ + password: PasswordQuestion; + + /** + * The `ListQuestion` type. + */ + list: ListQuestion; + + /** + * The `RawListQuestion` type. + */ + rawList: RawListQuestion; + + /** + * The `ExpandQuestion` type. + */ + expand: ExpandQuestion; + + /** + * The `CheckboxQuestion` type. + */ + checkbox: CheckboxQuestion; + + /** + * The `ConfirmQuestion` type. + */ + confirm: ConfirmQuestion; + + /** + * The `EditorQuestion` type. + */ + editor: EditorQuestion; + } + + /** + * Represents one of the available questions. + * + * @template T + * The type of the answers. + */ + type DistinctQuestion = QuestionMap[keyof QuestionMap]; + + /** + * Represents a collection of questions. + * + * @template T + * The type of the answers. + */ + type QuestionCollection = + | DistinctQuestion + | ReadonlyArray> + | Observable>; + + /** + * Provides components for the prompts. + */ namespace prompts { /** - * Base prompt implementation - * Should be extended by prompt types. + * Provides a base for and prompt-options. * - * @interface Base + * @template T + * The type of the answers. */ - interface Base { - new (question: Question, rl: ReadlineInterface, answers: A): Base; + type PromptOptions = T & { /** - * Start the Inquiry session and manage output value filtering + * The choices of the prompt. + */ + choices: Choices; + }; + + /** + * Represents the state of a prompt. + */ + type PromptState = LiteralUnion<"pending" | "idle" | "loading" | "answered" | "done">; + + /** + * Represents a prompt. + */ + interface PromptBase { + /** + * Gets or sets a string which represents the state of the prompt. + */ + status: PromptState; + + /** + * Runs the prompt. * - * @returns {Promise} - * @memberof Base + * @returns + * The result of the prompt. */ run(): Promise; + } + + /** + * Provides the functionality to initialize new prompts. + */ + interface PromptConstructor { /** - * Called when the UI closes. Override to do any specific cleanup necessary + * Initializes a new instance of a prompt. + * + * @param question + * The question to prompt. + * + * @param readLine + * An object for reading from the command-line. + * + * @param answers + * The answers provided by the user. */ - close(): void; + new(question: any, readLine: ReadlineInterface, answers: Answers): PromptBase; + } + + /** + * Provides a set of prompt-constructors. + */ + type PromptCollection = Record; + + /** + * Provides data about the state of a prompt. + */ + interface PromptStateData { /** - * Generate the prompt question string + * Either a string which describes the error of the prompt or a boolean indicating whether the prompt-value is valid. */ - getQuestion(): string; + isValid: string | boolean; + } + + /** + * Provides data about the successful state of a prompt. + * + * @param T + * The type of the answer. + */ + interface SuccessfulPromptStateData extends PromptStateData { + /** + * @inheritdoc + */ + isValid: true; + + /** + * The value of the prompt. + */ + value: T; + } + + /** + * Provides data about the failed state of a prompt. + */ + interface FailedPromptStateData extends PromptStateData { + /** + * @inheritdoc + */ + isValid: false | string; + } + + /** + * Provides pipes for handling events of a prompt. + * + * @param T + * The type of the answer. + */ + interface PromptEventPipes { + /** + * A pypeline for succesful inputs. + */ + success: Observable>; + + /** + * An object representing an error. + */ + error: Observable; } } + /** + * Provides components for the ui. + */ namespace ui { - /** - * Base interface class other can inherits from + * Provides options for the bottom-bar UI. */ - interface BaseUI { - rl: ReadlineInterface; - new(opt: StreamOptions): BaseUI; + interface BottomBarOptions extends StreamOptions { /** - * Handle the ^C exit - * @return {null} + * The initial text to display. */ - onForceClose(): void; - /** - * Close the interface and cleanup listeners - */ - close(): void; - } - /** - * Base interface class other can inherits from - */ - interface PromptUI extends BaseUI { - process: Observable; - new(prompts: Prompts, opt: StreamOptions): PromptUI; - run(questions: Questions): Promise; - /** - * Once all prompt are over - */ - onCompletion(): void; - processQuestion(question: Question): Observable>; - fetchAnswer(question: Question): Observable>; - setDefaultType(question: Question): Observable>; - filterIfRunnable(question: Question): Observable>; + bottomBar?: string; } /** - * Sticky bottom bar user interface + * Represents a fetched answer. + * + * @template T + * The type of the answers. */ - interface BottomBar extends BaseUI { - new(opt?: StreamOptions & { bottomBar?: string }): BottomBar; + type FetchedQuestion = DistinctQuestion & { /** - * Render the prompt to screen - * @return self + * The type of the question. */ - render(): BottomBar; - clean(): BottomBar; - /** - * Update the bottom bar content and rerender - * @param bottomBar Bottom bar content - * @return self - */ - updateBottomBar(bottomBar: string): BottomBar; - /** - * Write out log data - * @param {String} data - The log data to be output - * @return self - */ - writeLog(data: string): BottomBar; - /** - * Make sure line end on a line feed - * @param str Input string - * @return The input string with a final line feed - */ - enforceLF(str: string): string; - /** - * Helper for writing message in Prompt - * @param message The message to be output - */ - write(message: string): void; - log: ThroughStream; - } - - } - - namespace objects { - /** - * Choice object - * Normalize input as choice object - * @constructor - * @param {String|Object} val Choice value. If an object is passed, it should contains - * at least one of `value` or `name` property - */ - interface Choice { - new (str: string): Choice; - new (separator: Separator): Choice; - new (option: ChoiceOption): Choice; - } - - interface ChoiceOption { - name?: string; - value?: any; - type?: string; - short?: string; - extra?: any; - key?: string; - checked?: boolean; - disabled?: string | ((answers: A) => any); - } - - /** - * Choices collection - * Collection of multiple `choice` object - * @constructor - * @param choices All `choice` to keep in the collection - */ - interface Choices { - new ( - choices: ReadonlyArray>, - answers?: A - ): Choices; - choices: ReadonlyArray>; - realChoices: ReadonlyArray>; - length: number; - realLength: number; - /** - * Get a valid choice from the collection - * @param selector The selected choice index - * @return Return the matched choice or undefined - */ - getChoice(selector: number): Choice; - /** - * Get a raw element from the collection - * @param selector The selected index value - * @return Return the matched choice or undefined - */ - get(selector: number): Choice; - /** - * Match the valid choices against a where clause - * @param whereClause Lodash `where` clause - * @return Matching choices or empty array - */ - where(whereClause: U): Choice[]; - /** - * Pluck a particular key from the choices - * @param propertyName Property name to select - * @return Selected properties - */ - pluck(propertyName: string): any[]; - forEach(application: (choice: Choice) => T): T[]; - } - - interface SeparatorStatic { - /** - * @param line Separation line content (facultative) - */ - new (line?: string): Separator; - /** - * Helper function returning false if object is a separator - * @param obj object to test against - * @return `false` if object is a separator - */ - exclude(obj: any): boolean; - } - - /** - * Separator object - * Used to space/separate choices group - * @constructor - * @param {String} line Separation line content (facultative) - */ - interface Separator { type: string; - line: string; + /** - * Stringify separator - * @return {String} the separator display string + * The message to show to the user. */ - toString(): string; + message: string; + + /** + * The default value of the question. + */ + default: any; + + /** + * The choices of the question. + */ + choices: ChoiceCollection; + }; + + /** + * Represents a fetched answer. + */ + interface FetchedAnswer { + /** + * The name of the answer. + */ + name: string; + + /** + * The value of the answer. + */ + answer: any; } } } +/** + * Provides the functionality to prompt questions. + */ declare var inquirer: inquirer.Inquirer; - export = inquirer; diff --git a/types/inquirer/inquirer-tests.ts b/types/inquirer/inquirer-tests.ts index 4c13cbdba2..b7ac309273 100644 --- a/types/inquirer/inquirer-tests.ts +++ b/types/inquirer/inquirer-tests.ts @@ -1,765 +1,49 @@ -import chalkPipe = require("chalk-pipe"); -import * as inquirer from "inquirer"; -import { from as rxjsFrom, Observable, Observer } from "rxjs"; - -/** - * Bottom Bar example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/bottom-bar.js - */ +import inquirer = require("inquirer"); +import InputPrompt = require("inquirer/lib/prompts/input"); { - var cmdify = require("cmdify"); - - var loader = [ - "/ Installing", - "| Installing", - "\\ Installing", - "- Installing" - ]; - var i = 4; - var ui = new inquirer.ui.BottomBar({ bottomBar: loader[i % 4] }); - - setInterval(() => { - ui.updateBottomBar(loader[i++ % 4]); - }, 300); - - var spawn = require("child_process").spawn; - - var cmd = spawn(cmdify("npm"), ["-g", "install", "inquirer"], { - stdio: "pipe" - }); - cmd.stdout.pipe(ui.log); - cmd.on("close", () => { - ui.updateBottomBar("Installation done!\n"); - process.exit(); - }); + new inquirer.Separator(""); + const promptModule = inquirer.createPromptModule(); + promptModule.prompts[""]; // $ExpectType PromptConstructor + promptModule.registerPrompt("", InputPrompt); // $ExpectType PromptModule + promptModule.restoreDefaultPrompts(); } - -/** - * Checkbox example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/checkbox.js - */ { - inquirer - .prompt([ + inquirer.prompt( + [ { - type: "checkbox", - message: "Select toppings", - name: "toppings", - choices: [ - new inquirer.Separator(" = The Meats = "), - { - name: "Pepperoni" - }, - { - name: "Ham" - }, - { - name: "Ground Meat" - }, - { - name: "Bacon" - }, - new inquirer.Separator(" = The Cheeses = "), - { - name: "Mozzarella", - checked: true - }, - { - name: "Cheddar" - }, - { - name: "Parmesan" - }, - new inquirer.Separator(" = The usual ="), - { - name: "Mushroom" - }, - { - name: "Tomato" - }, - new inquirer.Separator(" = The extras = "), - { - name: "Pineapple" - }, - { - name: "Olives", - disabled: "out of stock" - }, - { - name: "Extra cheese" - } - ], - validate: function(answer) { - if (answer.length < 1) { - return "You must choose at least one topping."; - } - - return true; - } + message: "", + default: "" } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); + ]); } - -/** - * Editor - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/editor.js - */ { - inquirer - .prompt([ - { - type: "editor", - name: "bio", - message: "Please write a short bio of at least 3 lines.", - validate: function(text) { - if (text.split("\n").length < 3) { - return "Must be at least 3 lines."; - } - - return true; - } - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); + new inquirer.ui.BottomBar(); + new inquirer.ui.Prompt(inquirer.prompt.prompts); } -/** - * Expand - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/expand.js - */ -{ - inquirer - .prompt([ - { - type: "expand", - message: "Conflict on `file.js`: ", - name: "overwrite", - choices: [ - { - key: "y", - name: "Overwrite", - value: "overwrite" - }, - { - key: "a", - name: "Overwrite this one and all next", - value: "overwrite_all" - }, - { - key: "d", - name: "Show diff", - value: "diff" - }, - new inquirer.Separator(), - { - key: "x", - name: "Abort", - value: "abort" - } - ] - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); +interface ChalkQuestionOptions extends inquirer.InputQuestionOptions { + previewColors: boolean; } -/** - * Hierarchical conversation example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/hierarchical.js - */ -var directionsPrompt: inquirer.Question<{ - direction: string; -}> = { - type: "list", - name: "direction", - message: "Which direction would you like to go?", - choices: ["Forward", "Right", "Left", "Back"] -}; - -function main() { - console.log( - "You find youself in a small room, there is a door in front of you." - ); - exitHouse(); +interface ChalkQuestion extends ChalkQuestionOptions { + type: "chalk"; } -function exitHouse() { - inquirer.prompt(directionsPrompt).then(answers => { - if (answers.direction === "Forward") { - console.log("You find yourself in a forest"); - console.log( - "There is a wolf in front of you; a friendly looking dwarf to the right and an impasse to the left." - ); - encounter1(); - } else { - console.log("You cannot go that way. Try again"); - exitHouse(); - } - }); +class ChalkPrompt extends InputPrompt { + /* stuff */ } -function encounter1() { - inquirer.prompt(directionsPrompt).then(answers => { - var direction = answers.direction; - if (direction === "Forward") { - console.log("You attempt to fight the wolf"); - console.log( - "Theres a stick and some stones lying around you could use as a weapon" - ); - encounter2b(); - } else if (direction === "Right") { - console.log("You befriend the dwarf"); - console.log("He helps you kill the wolf. You can now move forward"); - encounter2a(); - } else { - console.log("You cannot go that way"); - encounter1(); - } - }); -} +inquirer.registerPrompt("chalk", ChalkPrompt); -function encounter2a() { - inquirer.prompt(directionsPrompt).then(answers => { - var direction = answers.direction; - if (direction === "Forward") { - var output = "You find a painted wooden sign that says:"; - output += " \n"; - output += " ____ _____ ____ _____ \n"; - output += "(_ _)( _ )( _ \\( _ ) \n"; - output += " )( )(_)( )(_) ))(_)( \n"; - output += " (__) (_____)(____/(_____) \n"; - console.log(output); - } else { - console.log("You cannot go that way"); - encounter2a(); - } - }); -} - -function encounter2b() { - inquirer - .prompt({ - type: "list", - name: "weapon", - message: "Pick one", - choices: [ - "Use the stick", - "Grab a large rock", - "Try and make a run for it", - "Attack the wolf unarmed" - ] - }) - .then(() => { - console.log("The wolf mauls you. You die. The end."); - }); -} - -main(); - -/** - * Input prompt example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/input.js - */ -{ - inquirer - .prompt([ - { - type: "input", - name: "first_name", - message: "What's your first name" - }, - { - type: "input", - name: "last_name", - message: "What's your last name", - default: function() { - return "Doe"; - } - }, - { - type: "input", - name: "fav_color", - message: "What's your favorite color", - transformer: function(color, _answers, flags) { - const text = chalkPipe(color)(color); - if (flags.isFinal) { - return text + "!"; - } - - return text; - } - }, - { - type: "input", - name: "phone", - message: "What's your phone number", - validate: function(value) { - var pass = value.match( - /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i - ); - if (pass) { - return true; - } - - return "Please enter a valid phone number"; - } - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); -} - -/** - * List prompt example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/list.js - */ -{ - inquirer - .prompt([ - { - type: "list", - name: "theme", - message: "What do you want to do?", - choices: [ - "Order a pizza", - "Make a reservation", - new inquirer.Separator(), - "Ask for opening hours", - { - name: "Contact support", - disabled: "Unavailable at this time" - }, - "Talk to the receptionist" - ] - }, - { - type: "list", - name: "size", - message: "What size do you need?", - choices: [ - "Jumbo", - "Large", - "Standard", - "Medium", - "Small", - "Micro" - ], - filter: function(val) { - return val.toLowerCase(); - } - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); -} - -/** - * Paginated list - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/long-list.js - */ -{ - var choices = Array.apply(0, new Array(26)).map((_x: number, y: number) => - String.fromCharCode(y + 65) - ); - choices.push("Multiline option \n super cool feature"); - choices.push({ - name: - "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium.", - value: "foo", - short: "The long option" - }); - - inquirer - .prompt([ - { - type: "list", - name: "letter", - message: "What's your favorite letter?", - choices - }, - { - type: "checkbox", - name: "name", - message: "Select the letter contained in your name:", - choices - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); -} - -/** - * Nested Inquirer call - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/nested-call.js - */ -{ - inquirer - .prompt({ - type: "list", - name: "chocolate", - message: "What's your favorite chocolate?", - choices: ["Mars", "Oh Henry", "Hershey"] - }) - .then(() => { - inquirer.prompt({ - type: "list", - name: "beverage", - message: "And your favorite beverage?", - choices: ["Pepsi", "Coke", "7up", "Mountain Dew", "Red Bull"] - }); - }); -} - -/** - * Password prompt example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/password.js - */ -{ - const requireLetterAndNumber = (value: string) => { - if (/\w/.test(value) && /\d/.test(value)) { - return true; - } - - return "Password need to have at least a letter and a number"; - }; - - inquirer - .prompt([ - { - type: "password", - message: "Enter a password", - name: "password1", - validate: requireLetterAndNumber - }, - { - type: "password", - message: "Enter a masked password", - name: "password2", - mask: "*", - validate: requireLetterAndNumber - } - ]) - .then(answers => console.log(JSON.stringify(answers, null, " "))); -} - -/** - * Pizza delivery prompt example - * run example by writing `node pizza.js` in your console - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/pizza.js - */ -{ - console.log("Hi, welcome to Node Pizza"); - - inquirer - .prompt<{ - comments: string; - }>([ - { - type: "confirm", - name: "toBeDelivered", - message: "Is this for delivery?", - default: false - }, - { - type: "input", - name: "phone", - message: "What's your phone number?", - validate: function(value) { - var pass = value.match( - /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i - ); - if (pass) { - return true; - } - - return "Please enter a valid phone number"; - } - }, - { - type: "list", - name: "size", - message: "What size do you need?", - choices: ["Large", "Medium", "Small"], - filter: function(val) { - return val.toLowerCase(); - } - }, - { - type: "input", - name: "quantity", - message: "How many do you need?", - validate: function(value) { - var valid = !isNaN(parseFloat(value)); - return valid || "Please enter a number"; - }, - filter: Number - }, - { - type: "expand", - name: "toppings", - message: "What about the toppings?", - choices: [ - { - key: "p", - name: "Pepperoni and cheese", - value: "PepperoniCheese" - }, - { - key: "a", - name: "All dressed", - value: "alldressed" - }, - { - key: "w", - name: "Hawaiian", - value: "hawaiian" - } - ] - }, - { - type: "rawlist", - name: "beverage", - message: "You also get a free 2L beverage", - choices: ["Pepsi", "7up", "Coke"] - }, - { - type: "input", - name: "comments", - message: "Any comments on your purchase experience?", - default: "Nope, all good!" - }, - { - type: "list", - name: "prize", - message: "For leaving a comment, you get a freebie", - choices: ["cake", "fries"], - when: answers => answers.comments !== "Nope, all good!" - } - ]) - .then(answers => { - console.log("\nOrder receipt:"); - console.log(JSON.stringify(answers, null, " ")); - }); -} - -/** - * Raw List prompt example - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/rawlist.js - */ -{ - inquirer - .prompt([ - { - type: "rawlist", - name: "theme", - message: "What do you want to do?", - choices: [ - "Order a pizza", - "Make a reservation", - new inquirer.Separator(), - "Ask opening hours", - "Talk to the receptionist" - ] - }, - { - type: "rawlist", - name: "size", - message: "What size do you need", - choices: [ - "Jumbo", - "Large", - "Standard", - "Medium", - "Small", - "Micro" - ], - filter: function(val) { - return val.toLowerCase(); - } - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); -} - -/** - * Recursive prompt example - * Allows user to choose when to exit prompt - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/recursive.js - */ -{ - var output: string[] = []; - inquirer - .prompt<{ - tvShow: string; - askAgain: boolean; - }>([ - { - type: "input", - name: "tvShow", - message: "What's your favorite TV show?" - }, - { - type: "confirm", - name: "askAgain", - message: - "Want to enter another TV show favorite (just hit enter for YES)?", - default: true - } - ]) - .then(answers => { - output.push(answers.tvShow); - }); -} - -/** - * Rx Observable Array - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/rx-observable-array.js - */ -{ - var observable = rxjsFrom([ - { - type: "input", - name: "first_name", - message: "What's your first name" - }, - { - type: "input", - name: "last_name", - message: "What's your last name", - default: function() { - return "Doe"; - } - }, - { - type: "input", - name: "phone", - message: "What's your phone number", - validate: function(value) { - var pass = value.match( - /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i - ); - if (pass) { - return true; - } - - return "Please enter a valid phone number"; - } - } as inquirer.Question - ]); - - inquirer.prompt(observable as any).ui.process.subscribe( - function(ans) { - console.log("Answer is: ", ans); - }, - function(err) { - console.log("Error: ", err); - }, - function() { - console.log("Completed"); - } - ); -} - -/** - * Rx Observable create - * https://github.com/SBoudrias/Inquirer.js/blob/master/packages/inquirer/examples/rx-observable-create.js - */ -{ - var observe = Observable.create(function( - obs: Observer> - ) { - obs.next({ - type: "input", - name: "first_name", - message: "What's your first name" - }); - - obs.next({ - type: "input", - name: "last_name", - message: "What's your last name", - default: function() { - return "Doe"; - } - }); - - obs.next({ - type: "input", - name: "phone", - message: "What's your phone number", - validate: function(value) { - var pass = value.match( - /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i - ); - if (pass) { - return true; - } - - return "Please enter a valid phone number"; - } - }); - obs.complete(); - }); - - inquirer.prompt(observe).then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); -} - -/** - * When example - */ -{ - interface Answers { - bacon: boolean; - pizza: boolean; +declare module "inquirer" { + interface QuestionMap { + chalk: ChalkQuestion; } - - const likesFood = (aFood: keyof Answers) => (answers: Answers) => - answers[aFood]; - - inquirer - .prompt([ - { - type: "confirm", - name: "bacon", - message: "Do you like bacon?" - }, - { - type: "input", - name: "favorite", - message: "Bacon lover, what is your favorite type of bacon?", - when: function(answers) { - return answers.bacon; - } - }, - { - type: "confirm", - name: "pizza", - message: "Ok... Do you like pizza?", - when: function(answers) { - return !likesFood("bacon")(answers); - } - }, - { - type: "input", - name: "favorite", - message: "Whew! What is your favorite type of pizza?", - when: likesFood("pizza") - } - ]) - .then(answers => { - console.log(JSON.stringify(answers, null, " ")); - }); } + +inquirer.prompt([ + { + type: "chalk", + previewColors: true + } +]); diff --git a/types/inquirer/lib/objects/choice.d.ts b/types/inquirer/lib/objects/choice.d.ts new file mode 100644 index 0000000000..ac9fa0744d --- /dev/null +++ b/types/inquirer/lib/objects/choice.d.ts @@ -0,0 +1,67 @@ +import inquirer = require('../..'); + +/** + * Represents a choice for several question-types. + * + * @template T + * The type of the answers. + */ +declare class Choice implements + inquirer.ListChoiceOptions, + inquirer.CheckboxChoiceOptions, + inquirer.ExpandChoiceOptions { + /** + * @inheritdoc + */ + type?: "choice"; + + /** + * @inheritdoc + */ + name: string; + + /** + * @inheritdoc + */ + short: string; + + /** + * @inheritdoc + */ + value: any; + + /** + * @inheritdoc + */ + checked?: boolean; + + /** + * @inheritdoc + */ + disabled: boolean; + + /** + * The key to press for selecting the choice. + * + * @inheritdoc + */ + key?: string; + + /** + * @inheritdoc + */ + extra?: any; + + /** + * Initializes a new instance of the `Choice` class. + * + * @param value + * The value of the choice. + * + * @param answers + * An object which contains the answers to the questions. + */ + constructor(value: any, answers: T); +} + +export = Choice; diff --git a/types/inquirer/lib/objects/choices.d.ts b/types/inquirer/lib/objects/choices.d.ts new file mode 100644 index 0000000000..e535f2f905 --- /dev/null +++ b/types/inquirer/lib/objects/choices.d.ts @@ -0,0 +1,191 @@ +import inquirer = require("../.."); +import Choice = require("./choice"); +import Separator = require("./separator"); + +/** + * Represents a valid choice for the `Choices` class. + * + * @template T + * The type of the answers. + */ +type DistinctChoice = inquirer.AllChoiceMap[keyof inquirer.AllChoiceMap]; + +/** + * Represents a valid real choice for the `Choices` class. + * + * @template T + * The type of the answers. + */ +type RealChoice = Exclude, { type: Separator["type"] }>; + +/** + * Represents a property-name of any choice-type. + * + * @template T + * The type of the answers. + */ +type ChoiceProperty = inquirer.KeyUnion>>; + +/** + * A collection of multiple `Choice`-objects. + * + * @template T + * The type of the answers. + */ +declare class Choices { + /** + * The number of selectable choices. + */ + realLength: number; + + /** + * The number of choices. + */ + length: number; + + /** + * The unfiltered choices. + */ + choices: Array>; + + /** + * The selectable choices. + */ + realChoices: Array>; + + /** + * Initializes a new instance of the `Choices` class. + * + * @param choices + * The choices to add to the collection. + * + * @param answers + * The `answers`-object. + */ + constructor(choices: Array>, answers: T); + + /** + * Gets the choice at the specified index. + * + * @param index + * The index of the choice to get. + * + * @returns + * The choice at the specified index. + */ + getChoice(index: number): RealChoice; + + /** + * Gets the item at the specified index. + * + * @param index + * The index of the item to get. + * + * @returns + * The item at the specified index. + */ + get(index: number): DistinctChoice; + + /** + * Gets all choices which apply to the where-clause. + * + * @param whereClause + * The where-clause to apply. + * + * @returns + * The choices which apply to the where-clause. + */ + where(whereClause: object): Array>; + + /** + * Retrieves the specified `property` from all choices. + * + * @template TProperty + * The name of the property to get. + * + * @param property + * The property to query. + * + * @returns + * The value of the property of each choice. + */ + pluck>(property: TProperty | ChoiceProperty): Array<(RealChoice & { [key: string]: undefined })[TProperty]>; + + /** + * Returns the index of the first occurrence of a value in an array. + * + * @param searchElement + * The value to locate in the array. + * + * @param fromIndex + * The array index at which to begin the search. + * + * If fromIndex is omitted, the search starts at index 0. + * + * @returns + * The index of the specified `searchElement`. + */ + indexOf(searchElement: Choice | Separator, fromIndex?: number): number; + + /** + * Performs the specified action for each element in an array. + * + * @param callbackfn + * A function that accepts up to three arguments. + * + * `forEach` calls the callbackfn function one time for each element in the array. + * + * @param thisArg + * An object to which the this keyword can refer in the callbackfn function. + * + * If `thisArg` is omitted, undefined is used as the this value. + */ + forEach(callbackfn: (value: Choice | Separator, index: number, array: Array | Separator>) => void, thisArg?: any): void; + + /** + * Returns the elements of an array that meet the condition specified in a callback function. + * + * @param callbackfn + * A function that accepts up to three arguments. + * + * The filter method calls the `callbackfn` function one time for each element in the array. + * + * @param thisArg + * An object to which the `this` keyword can refer in the callbackfn function. + * + * If `thisArg` is omitted, undefined is used as the this value. + * + * @returns + * The elements in the collection which meet the conditions. + */ + filter | Separator>(callbackfn: (value: Choice | Separator, index: number, array: Array | Separator>) => value is TElement, thisArg?: any): TElement[]; + + /** + * Returns the value of the first element in the array where predicate is true, and `undefined` otherwise. + * + * @param predicate + * `find` calls `predicate` once for each element of the array, in ascending order, until it finds one where predicate returns `true`. + * + * If such an element is found, `find` immediately returns that element value. + * Otherwise, find returns undefined. + * + * @param thisArg + * If provided, it will be used as the `this` value for each invocation of `predicate`. + * + * If it is not provided, undefined is used instead. + */ + find(predicate: (value: Choice | Separator, index: number, obj: Array | Separator>) => boolean, thisArg?: any): Choice | Separator; + + /** + * Appends new elements to an array, and returns the new length of the array. + * + * @param items + * The elements to add to the array. + * + * @returns + * The new length of the array. + */ + push(...items: Array | Separator>): number; +} + +export = Choices; diff --git a/types/inquirer/lib/objects/separator.d.ts b/types/inquirer/lib/objects/separator.d.ts new file mode 100644 index 0000000000..6219abf7a8 --- /dev/null +++ b/types/inquirer/lib/objects/separator.d.ts @@ -0,0 +1,37 @@ +import inquirer = require("../.."); + +/** + * Represents a choice-item separator. + */ +declare class Separator implements inquirer.ChoiceBase, inquirer.SeparatorOptions { + /** + * @inheritdoc + */ + readonly type: "separator"; + + /** + * @inheritdoc + */ + line: string; + + /** + * Initializes a new instance of the `Separator` class. + * + * @param line + * The text of the separator. + */ + constructor(line?: string); + + /** + * Checks whether the specified `item` is not a separator. + * + * @param item + * The item to check. + * + * @returns + * A value indicating whether the item is not a separator. + */ + static exclude(item: any): boolean; +} + +export = Separator; diff --git a/types/inquirer/lib/prompts/base.d.ts b/types/inquirer/lib/prompts/base.d.ts new file mode 100644 index 0000000000..baa6d04f1b --- /dev/null +++ b/types/inquirer/lib/prompts/base.d.ts @@ -0,0 +1,100 @@ +import { Interface as ReadLineInterface } from "readline"; +import { Observable } from "rxjs"; +import inquirer = require("../.."); +import ScreenManager = require("../utils/screen-manager"); + +/** + * The question-options for the `Prompt`. + */ +type Question = inquirer.Question; + +/** + * Represents a prompt. + * + * @template TQuestion + * The options for the question. + */ +declare class Prompt implements inquirer.prompts.PromptBase { + /** + * @inheritdoc + */ + status: inquirer.prompts.PromptState; + + /** + * Gets or sets an object which contains the answers. + */ + protected answers: inquirer.Answers; + + /** + * Gets or sets the options of the prompt. + */ + protected opt: inquirer.prompts.PromptOptions; + + /** + * Gets or sets an object for performing read from and write to the console. + */ + protected rl: ReadLineInterface; + + /** + * Gets or sets an object for managing the console-screen. + */ + protected screen: ScreenManager; + + /** + * Initializes a new instance of the `Prompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadLineInterface, answers: inquirer.Answers); + + /** + * @inheritdoc + */ + run(): Promise; + + /** + * Runs the prompt. + * + * @param callback + * The callback for resolving the result. + */ + protected _run(callback: (callback: any) => void): void; + + /** + * Throws an error for a missing param. + * + * @param name + * The name of the missing param. + */ + protected throwParamError(name: string): void; + + /** + * Releases all unmanaged resources. + */ + protected close(): void; + + /** + * Handles the submit-event. + * + * @param observable + * The observable submit-event flow. + */ + protected handleSubmitEvents(observable: Observable): inquirer.prompts.PromptEventPipes; + + /** + * Generates the question-string. + * + * @returns + * The question-string. + */ + protected getQuestion(): string; +} + +export = Prompt; diff --git a/types/inquirer/lib/prompts/checkbox.d.ts b/types/inquirer/lib/prompts/checkbox.d.ts new file mode 100644 index 0000000000..223b502420 --- /dev/null +++ b/types/inquirer/lib/prompts/checkbox.d.ts @@ -0,0 +1,116 @@ +import inquirer = require("../.."); +import Prompt = require("./base"); +import { Interface as ReadLineInterface } from "readline"; +import Paginator = require("../utils/paginator"); + +/** + * The question-options for the `ChoicePrompt`. + */ +type Question = inquirer.CheckboxQuestionOptions; + +/** + * Represents a prompt which provides a set of choices to check. + * + * @template TQuestion + * The options for the question. + */ +declare class CheckboxPrompt extends Prompt { + /** + * Gets or sets the index of the currently focused choice. + */ + protected pointer: number; + + /** + * Gets or sets an object for paginating the content. + */ + protected paginator: Paginator; + + /** + * Initializes a new instance of the `CheckboxPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadLineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt. + * + * @param error + * An error message to render. + */ + protected render(error?: string): void; + + /** + * Handles the `success`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onEnd(eventArgs: inquirer.prompts.SuccessfulPromptStateData): void; + + /** + * Handles the `error`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onError(eventArgs: inquirer.prompts.FailedPromptStateData): void; + + /** + * Gets the current value of the prompt. + * + * @returns + * The current value of the prompt. + */ + protected getCurrentValue(): any; + + /** + * Handles the `UpdKey`-event of the prompt. + */ + protected onUpKey(): void; + + /** + * Handles the `DownKey`-event of the prompt. + */ + protected onDownKey(): void; + + /** + * Handles the `NumberKey`-event of the prompt. + * + * @param input + * The number which has been pressed. + */ + protected onNumberKey(input: number): void; + + /** + * Handles the `SpaceKey`-event of the prompt. + */ + protected onSpaceKey(): void; + + /** + * Handles the `AllKey`-event of the prompt. + */ + protected onAllKey(): void; + + /** + * Handles the `InverseKey`-event of the prompt. + */ + protected onInverseKey(): void; + + /** + * Toggles the state of a choice. + * + * @param index + * The index of the choice to toggle. + */ + protected toggleChoice(index: number): void; +} + +export = CheckboxPrompt; diff --git a/types/inquirer/lib/prompts/confirm.d.ts b/types/inquirer/lib/prompts/confirm.d.ts new file mode 100644 index 0000000000..27247afbaf --- /dev/null +++ b/types/inquirer/lib/prompts/confirm.d.ts @@ -0,0 +1,53 @@ +import Prompt = require("./base"); +import inquirer = require("../.."); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question-options for the `ConfirmPrompt`. + */ +type Question = inquirer.ConfirmQuestionOptions; + +/** + * Represents a prompt which provides a message to confirm. + * + * @template TQuestion + * The options for the question. + */ +declare class ConfirmPrompt extends Prompt { + /** + * Initializes a new instance of the `ConfirmPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(questions: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt. + * + * @param answer + * The answer provided by the user. + */ + protected render(answer?: boolean): this; + + /** + * Handles the `success`-event of the prompt. + * + * @param input + * The input provided by the user. + */ + protected onEnd(input: string): void; + + /** + * Handles the `Keypress`-event of the prompt. + */ + protected onKeypress(): void; +} + +export = ConfirmPrompt; diff --git a/types/inquirer/lib/prompts/editor.d.ts b/types/inquirer/lib/prompts/editor.d.ts new file mode 100644 index 0000000000..5c1efbcfa1 --- /dev/null +++ b/types/inquirer/lib/prompts/editor.d.ts @@ -0,0 +1,101 @@ +import Prompt = require("./base"); +import { Subject, Subscription } from "rxjs"; +import inquirer = require("../.."); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question-options for the `EditorPrompt`. + */ +type Question = inquirer.EditorQuestionOptions; + +/** + * Represents a prompt which provides a text-editor. + * + * @template TQuestion + * The options for the question. + */ +declare class EditorPrompt extends Prompt { + /** + * Resolves the value of the prompt. + */ + protected done: (value: any) => void; + + /** + * Gets or sets an object for subscribing to the editor-result. + */ + protected editorResult: Subject; + + /** + * Gets or sets a subscription to the `line`-event. + */ + protected lineSubscription: Subscription; + + /** + * Gets or sets the initial text. + */ + protected currentText: string; + + /** + * Initializes a new instance of the `EditorPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Runs the prompt. + * + * @param callback + * The callback for resolving the result. + */ + protected _run(callback: (value: any) => void): this; + + /** + * Renders the prompt. + * + * @param error + * The error to render. + */ + protected render(error?: string): void; + + /** + * Launches the default text-editor of the system. + */ + protected startExternalEditor(): void; + + /** + * Closes the external editor. + * + * @param error + * Either the error which occurred while executing the external editor or `null`. + * + * @param result + * The result of the editor. + */ + protected endExternalEditor(error: Error, result: string): void; + + /** + * Handles the `success`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onEnd(eventArgs: inquirer.prompts.SuccessfulPromptStateData): void; + + /** + * Handles the `error`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onError(eventArgs: inquirer.prompts.FailedPromptStateData): void; +} + +export = EditorPrompt; diff --git a/types/inquirer/lib/prompts/expand.d.ts b/types/inquirer/lib/prompts/expand.d.ts new file mode 100644 index 0000000000..46f9f3b521 --- /dev/null +++ b/types/inquirer/lib/prompts/expand.d.ts @@ -0,0 +1,149 @@ +import Paginator = require("../utils/paginator"); +import Prompt = require("./base"); +import inquirer = require("../.."); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question-options for the `ExpandPrompt`. + */ +type Question = inquirer.ExpandQuestionOptions; + +/** + * Represents a prompt which forces the user to make a choice by typing a specific key. + * + * @template TQuestion + * The options for the question. + */ +declare class ExpandPrompt extends Prompt { + /** + * Resolves the value of the prompt. + */ + protected done: (value: any) => void; + + /** + * Gets or sets the default key. + */ + protected rawDefault: string; + + /** + * Gets or sets an object for paginating the content. + */ + protected paginator: Paginator; + + /** + * Gets the promise of the keypress-eventhandler. + */ + protected keypressObs: Promise; + + /** + * Gets or sets the currently selected key. + */ + protected selectedKey: string; + + /** + * Gets or sets the answer of the prompt. + */ + protected answer: string; + + /** + * Initializes a new instance of the `ExpandPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt to the screen. + * + * @param error + * The error to render. + * + * @param hint + * The hint to render. + */ + protected render(error?: string, hint?: string): void; + + /** + * Determines the current value of the prompt. + * + * @param input + * The input provided by the user. + * + * @returns + * The current value of the prompt. + */ + protected getCurrentValue(input: string): any; + + /** + * Generates the string-representation of the choices. + * + * @deprecated + * + * @returns + * The string-representations of the choices. + */ + protected getChoices(): string; + + /** + * Handles the `success`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onSubmit(eventArgs: inquirer.prompts.SuccessfulPromptStateData): void; + + /** + * Handles the `error`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onError(eventArgs: inquirer.prompts.FailedPromptStateData): void; + + /** + * Handles the `keypress`-event of the prompt. + */ + protected onKeypress(): void; + + /** + * Validates the integrity of the choices. + * + * @param choices + * The choices to validate. + */ + protected validateChoices(choices: ExpandPrompt["opt"]["choices"]): void; + + /** + * Generates the string-representation of the choices. + * + * @param choices + * The choices to generate the string-representation for. + * + * @param defaultChoice + * The value of the default choice. + * + * @returns + * The string-representations of the choices. + */ + protected generateChoicesString(choices: ExpandPrompt["opt"]["choices"], defaultChoice: any): string; + + /** + * Renders the choices. + * + * @param choices + * The choices to render. + * + * @param pointer + * The value of the choice to select. + */ + protected renderChoices(choices: ExpandPrompt["opt"]["choices"], pointer: string): string; +} + +export = ExpandPrompt; diff --git a/types/inquirer/lib/prompts/input.d.ts b/types/inquirer/lib/prompts/input.d.ts new file mode 100644 index 0000000000..514664dfe8 --- /dev/null +++ b/types/inquirer/lib/prompts/input.d.ts @@ -0,0 +1,82 @@ +import Prompt = require("./base"); +import inquirer = require("../.."); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question-options for the `InputPrompt`. + */ +type Question = inquirer.InputQuestionOptions; + +/** + * Represents a prompt which allows the user to type an answer. + * + * @template TQuestion + * The options for the question. + */ +declare class InputPrompt extends Prompt { + /** + * Resolves the value of the prompt. + */ + protected done: (value: any) => void; + + /** + * The answer to this prompt. + */ + protected answer: any; + + /** + * Initializes a new instance of the `InputPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt. + * + * @param error + * The error to render. + */ + protected render(error?: string): void; + + /** + * Filters the specified `input`. + * + * @param input + * The input to filter. + * + * @returns + * The filtered input. + */ + protected filterInput(input: string): string; + + /** + * Handles the `success`-event of the prompt. + * + * @param eventArgs + * An object which contains eventr-data. + */ + protected onEnd(eventArgs: inquirer.prompts.SuccessfulPromptStateData): void; + + /** + * Handles the `error`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onError(eventArgs: inquirer.prompts.FailedPromptStateData): void; + + /** + * Handles the `keypress`-event of the prompt. + */ + protected onKeyPress(): void; +} + +export = InputPrompt; diff --git a/types/inquirer/lib/prompts/list.d.ts b/types/inquirer/lib/prompts/list.d.ts new file mode 100644 index 0000000000..ebb503dacb --- /dev/null +++ b/types/inquirer/lib/prompts/list.d.ts @@ -0,0 +1,89 @@ +import Prompt = require("./base"); +import inquirer = require("../.."); +import Paginator = require("../utils/paginator"); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question-options for the `ListPrompt`. + */ +type Question = inquirer.ListQuestionOptions; + +/** + * Represents a prompt which provides a list to choose an answer from. + * + * @template TQuestion + * The options for the question. + */ +declare class ListPrompt extends Prompt { + /** + * Resolves the value of the prompt. + */ + protected done: (value: any) => void; + + /** + * Gets or sets a value indicating whether the prompt has been rendered the first time. + */ + protected firstRender: boolean; + + /** + * The index of the selected choice. + */ + protected selected: number; + + /** + * Gets or sets an object for paginating the content. + */ + protected paginator: Paginator; + + /** + * Initializes a new instance of the `ListPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt. + */ + protected render(): void; + + /** + * Gets the current value of the prompt. + */ + protected getCurrentValue(): any; + + /** + * Handles the `upKey`-event. + */ + protected onUpKey(): void; + + /** + * Handles the `downKey`-event. + */ + protected onDownKey(): void; + + /** + * Handles the `numberKey`-event. + * + * @param input + * The number that has been pressed. + */ + protected onNumberKey(input: number): void; + + /** + * Handles the `success`-event of the prompt. + * + * @param value + * The value of the prompt. + */ + protected onSubmit(value: any): void; +} + +export = ListPrompt; diff --git a/types/inquirer/lib/prompts/number.d.ts b/types/inquirer/lib/prompts/number.d.ts new file mode 100644 index 0000000000..affde0b1db --- /dev/null +++ b/types/inquirer/lib/prompts/number.d.ts @@ -0,0 +1,32 @@ +import InputPrompt = require("./input"); +import inquirer = require("../.."); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question for the `NumberPrompt`. + */ +type Question = inquirer.NumberQuestionOptions; + +/** + * Provides a prompt which allows the user to type a number as answer. + * + * @template TQuestion + * The options for the question. + */ +declare class NumberPrompt extends InputPrompt { + /** + * Initializes a new instance of the `NumberPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); +} + +export = NumberPrompt; diff --git a/types/inquirer/lib/prompts/password.d.ts b/types/inquirer/lib/prompts/password.d.ts new file mode 100644 index 0000000000..3b3434efac --- /dev/null +++ b/types/inquirer/lib/prompts/password.d.ts @@ -0,0 +1,82 @@ +import Prompt = require("./base"); +import inquirer = require("../.."); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question for the `PasswordPrompt`. + */ +type Question = inquirer.PasswordQuestionOptions; + +/** + * Represents a prompt which allows the user to type a password. + * + * @template TQuestion + * The options for the question. + */ +declare class PasswordPrompt extends Prompt { + /** + * Resolves the value of the prompt. + */ + protected done: (value: any) => void; + + /** + * The answer to this prompt. + */ + protected answer: any; + + /** + * Initializes a new instance of the `PasswordPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt. + * + * @param error + * The error to render. + */ + protected render(error?: string): void; + + /** + * Filters the specified `input`. + * + * @param input + * The input to filter. + * + * @returns + * The filtered input. + */ + protected filterInput(input: string): string; + + /** + * Handles the `keypress`-event of the prompt. + */ + protected onKeyPress(): void; + + /** + * Handles the `success`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onEnd(eventArgs: inquirer.prompts.SuccessfulPromptStateData): void; + + /** + * Handles the `error`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onError(eventArgs: inquirer.prompts.FailedPromptStateData): void; +} + +export = PasswordPrompt; diff --git a/types/inquirer/lib/prompts/rawlist.d.ts b/types/inquirer/lib/prompts/rawlist.d.ts new file mode 100644 index 0000000000..c324ffa7fb --- /dev/null +++ b/types/inquirer/lib/prompts/rawlist.d.ts @@ -0,0 +1,111 @@ +import inquirer = require("../.."); +import Prompt = require("./base"); +import Paginator = require("../utils/paginator"); +import { Interface as ReadlineInterface } from "readline"; + +/** + * The question for the `RawListPrompt`. + */ +type Question = inquirer.RawListQuestionOptions; + +/** + * Represents a prompt which provides a list to choose an answer from. + * + * @template TQuestion + * The options for the question. + */ +declare class RawListPrompt extends Prompt { + /** + * Resolves the value of the prompt. + */ + protected done: (value: any) => void; + + /** + * The index of the selected choice. + */ + protected selected: number; + + /** + * Gets or sets the default index. + */ + protected rawDefault: number; + + /** + * Gets or sets an object for paginating the content. + */ + protected paginator: Paginator; + + /** + * Initializes a new instance of the `RawListPrompt` class. + * + * @param question + * The question to prompt the user to answer. + * + * @param readLine + * An object for performing read from and write to the console. + * + * @param answers + * The answer-object. + */ + constructor(question: TQuestion, readLine: ReadlineInterface, answers: inquirer.Answers); + + /** + * Renders the prompt. + * + * @param error + * The error to render. + */ + protected render(error?: string): void; + + /** + * Gets the value of the specified `index`. + * + * @param index + * The index to get the value for. + * + * @returns + * The value of the specified `index`. + */ + protected getCurrentValue(index: number): any; + + /** + * Handles the `Keypress`-event of the prompt. + */ + protected onKeypress(): void; + + /** + * Handles the `UpdKey`-event of the prompt. + */ + protected onUpKey(): void; + + /** + * Handles the `DownKey`-event of the prompt. + */ + protected onDownKey(): void; + + /** + * Handles the `ArrowKey`-event of the prompt. + * + * @param type + * A value indicating whether the up or the down-arrow is being pressed. + */ + protected onArrowKey(type: "up" | "down"): void; + + /** + * Handles the `success`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onEnd(eventArgs: inquirer.prompts.SuccessfulPromptStateData): void; + + /** + * Handles the `error`-event of the prompt. + * + * @param eventArgs + * An object which contains event-data. + */ + protected onError(): void; +} + +export = RawListPrompt; diff --git a/types/inquirer/lib/ui/baseUI.d.ts b/types/inquirer/lib/ui/baseUI.d.ts new file mode 100644 index 0000000000..e8651a6d4b --- /dev/null +++ b/types/inquirer/lib/ui/baseUI.d.ts @@ -0,0 +1,37 @@ +import { Interface as ReadlineInterface } from "readline"; +import inquirer = require("../.."); + +/** + * Represents a ui. + */ +declare class UI { + /** + * Gets or sets an object for performing read from and write to the console. + */ + protected rl: ReadlineInterface; + + /** + * Gets or sets the currently active prompt. + */ + protected activePrompt: inquirer.prompts.PromptBase; + + /** + * Initializes a new instance of the `UI` class. + * + * @param options + * The input- and output-stream of the ui. + */ + constructor(options?: inquirer.StreamOptions); + + /** + * Handles a forced exit of the application. + */ + protected onForceClose(): void; + + /** + * Releases all unmanaged resources. + */ + protected close(): void; +} + +export = UI; diff --git a/types/inquirer/lib/ui/bottom-bar.d.ts b/types/inquirer/lib/ui/bottom-bar.d.ts new file mode 100644 index 0000000000..6bcac76880 --- /dev/null +++ b/types/inquirer/lib/ui/bottom-bar.d.ts @@ -0,0 +1,65 @@ +import { ThroughStream } from "through"; +import inquirer = require("../.."); +import UI = require("./baseUI"); + +/** + * Represents the bottom-bar UI. + */ +declare class BottomBar extends UI { + /** + * Gets or sets a stream to write logs to. + */ + log: ThroughStream; + + /** + * Initializes a new instance of the `BottomBar` class. + * + * @param options + * Provides options for the bottom-bar ui. + */ + constructor(options?: inquirer.ui.BottomBarOptions); + + /** + * Renders the specified `text` to the bottom bar. + * + * @param text + * The text to print to the bottom bar. + */ + updateBottomBar(text: string): this; + + /** + * Renders the bottom bar. + */ + protected render(): this; + + /** + * Clean the bottom bar. + */ + protected clean(): this; + + /** + * Writes a message to the bottom bar. + * + * @param message + * The message to write. + */ + protected write(message: string): void; + + /** + * Writes the specified `data` to the log-zone. + * + * @param data + * The data to write to the log-zone. + */ + protected writeLog(data: any): this; + + /** + * Fixes the new-line characters of the specified `text`. + * + * @param text + * The text to process. + */ + protected enforceLF(text: string): string; +} + +export = BottomBar; diff --git a/types/inquirer/lib/ui/prompt.d.ts b/types/inquirer/lib/ui/prompt.d.ts new file mode 100644 index 0000000000..5e826eec42 --- /dev/null +++ b/types/inquirer/lib/ui/prompt.d.ts @@ -0,0 +1,96 @@ +import { defer, Observable } from "rxjs"; +import inquirer = require("../.."); +import UI = require("./baseUI"); + +/** + * Represents the prompt ui. + */ +declare class PromptUI extends UI { + /** + * Gets or sets the prompts of the ui. + */ + prompts: inquirer.prompts.PromptCollection; + + /** + * Gets or sets the answers provided by the user. + */ + answers: inquirer.Answers; + + /** + * Gets or sets the event-flow of the process. + */ + process: Observable; + + /** + * Initializes a new instance of the `PromptUI` class. + * + * @param prompts + * The prompts for the ui. + * + * @param options + * The input- and output-stream of the ui. + */ + constructor(prompts: inquirer.prompts.PromptCollection, options?: inquirer.StreamOptions); + + /** + * Runs the prompt-UI. + * + * @param questions + * The questions to prompt the user to answer. + * + * @returns + * The answers provided by the user. + */ + run(questions: Array>): Promise; + + /** + * Finishes the process. + */ + protected onCompletion(): inquirer.Answers; + + /** + * Processes a question. + * + * @param question + * The question to process. + * + * @returns + * The answer to the question. + */ + protected processQuestion(question: inquirer.DistinctQuestion): Observable; + + /** + * Fetches the answer to a question. + * + * @param question + * The question to fetch the answer for. + * + * @returns + * The answer to the question. + */ + protected fetchAnswer(question: inquirer.ui.FetchedQuestion): Observable; + + /** + * Sets the type of the question if no question-type is specified. + * + * @param question + * The question to set the default type for. + * + * @returns + * The processed question. + */ + protected setDefaultType(question: inquirer.DistinctQuestion): Observable>; + + /** + * Filters the question if it is runnable. + * + * @param question + * The question to filter. + * + * @returns + * Either the event-flow of the question if it is runnable or an empty event-flow. + */ + protected filterIfRunnable(question: inquirer.DistinctQuestion): Observable>; +} + +export = PromptUI; diff --git a/types/inquirer/lib/utils/events.d.ts b/types/inquirer/lib/utils/events.d.ts new file mode 100644 index 0000000000..882620e54c --- /dev/null +++ b/types/inquirer/lib/utils/events.d.ts @@ -0,0 +1,72 @@ +import { Interface as ReadlineInterface, Key } from "readline"; +import { Observable } from "rxjs"; + +/** + * Provides a description about a key. + */ +interface KeyDescriptor { + /** + * The value of the key. + */ + value: string; + + /** + * Thedescription of the key. + */ + key: Key; +} + +/** + * A set of events. + */ +interface Events { + /** + * The event-flow of the `line`-event of the readline-object. + */ + line: Observable; + + /** + * The event-flow of the `keypress`-event of the readline-object. + */ + keypress: Observable; + + /** + * The event-flow of the `normalizedUpKey`-event. + */ + normalizedUpKey: Observable; + + /** + * The event-flow of the `normalizedDownKey`-event. + */ + normalizedDownKey: Observable; + + /** + * The event-flow of the `numberKey`-event. + */ + numberKey: Observable; + + /** + * The event-flow of the `spaceKey`-event. + */ + spaceKey: Observable; + + /** + * The event-flow of the `aKey`-event. + */ + aKey: Observable; + + /** + * The event-flow of the `iKey`-event. + */ + iKey: Observable; +} + +/** + * Observes a readline-object. + * + * @param readline + * The readline-object to observe. + */ +declare function observe(readline: ReadlineInterface): Events; + +export = observe; diff --git a/types/inquirer/lib/utils/paginator.d.ts b/types/inquirer/lib/utils/paginator.d.ts new file mode 100644 index 0000000000..5588c30e0d --- /dev/null +++ b/types/inquirer/lib/utils/paginator.d.ts @@ -0,0 +1,45 @@ +import ScreenManager = require("./screen-manager"); + +/** + * Provides the functionality to draw paginated content using a `ScreenManager`. + */ +declare class Paginator { + /** + * Gets or sets the index of the currently focused line. + */ + protected pointer: number; + + /** + * Gets or sets the index of the last focused line. + */ + protected lastIndex: number; + + /** + * Gets or sets an object for drawing the paginated content. + */ + protected screen: ScreenManager; + + /** + * Initializes a new instance of the `Paginator` class. + * + * @param screenManager + * A screen-manager for drawing the paginated content. + */ + constructor(screenManager: ScreenManager); + + /** + * Paginates the specified `content`. + * + * @param content + * The content to paginate. + * + * @param selectedIndex + * The number of the selected line. + * + * @returns + * The paginated content. + */ + paginate(content: string, selectedIndex: number): string; +} + +export = Paginator; diff --git a/types/inquirer/lib/utils/readline.d.ts b/types/inquirer/lib/utils/readline.d.ts new file mode 100644 index 0000000000..be6c0f5a88 --- /dev/null +++ b/types/inquirer/lib/utils/readline.d.ts @@ -0,0 +1,56 @@ +import { Interface as ReadlineInterface } from "readline"; + +/** + * Moves the cursor to the left. + * + * @param readLine + * The readline-object. + * + * @param count + * The number of columns to move the cursor. + */ +export function left(readLine: ReadlineInterface, count: number): void; + +/** + * Moves the cursor to the right. + * + * @param readLine + * The readline-object. + * + * @param count + * The number of columns to move the cursor. + */ +export function right(readLine: ReadlineInterface, count: number): void; + +/** + * Moves the cursor upwards. + * + * @param readLine + * The readline-object. + * + * @param count + * The number of lines to move the cursor. + */ +export function up(readLine: ReadlineInterface, count: number): void; + +/** + * Moves the cursor downwards. + * + * @param readLine + * The readline-object. + * + * @param count + * The number of lines to move the cursor. + */ +export function down(readLine: ReadlineInterface, count: number): void; + +/** + * Clears one or more lines. + * + * @param readLine + * The readline-object. + * + * @param count + * The number of lines to clear. + */ +export function clearLine(readLine: ReadlineInterface, count: number): void; diff --git a/types/inquirer/lib/utils/screen-manager.d.ts b/types/inquirer/lib/utils/screen-manager.d.ts new file mode 100644 index 0000000000..0b9fdec862 --- /dev/null +++ b/types/inquirer/lib/utils/screen-manager.d.ts @@ -0,0 +1,90 @@ +import { Interface as ReadLineInterface } from "readline"; + +/** + * Provides the functionality to manage the content of a console-screen. + */ +declare class ScreenManager { + /** + * Gets or sets the height of the screen. + */ + height: number; + + /** + * Gets or sets the number of extra-lines below the prompt. + */ + extraLinesUnderPrompt: number; + + /** + * Gets or sets an object for performing read from and write to the console. + */ + rl: ReadLineInterface; + + /** + * Initializes a new instance of the `ScreenManager` class. + * + * @param readLine + * An object for performing read from and write to the console. + */ + constructor(readLine: ReadLineInterface); + + /** + * Renders content to the screen. + * + * @param content + * The content to render. + * + * @param bottomContent + * The content to render to the bottom of the screen. + */ + render(content: string, bottomContent: string): void; + + /** + * Cleans all lines expect the first `extraLines`. + * + * @param extraLines + * The number of lines at the begin to skip. + */ + clean(extraLines: number): void; + + /** + * Releases all unmanaged resources. + */ + done(): void; + + /** + * Releases the cursor. + */ + releaseCursor(): void; + + /** + * Identifies the width of the screen. + * + * @returns + * The width of the screen. + */ + protected normalizedCliWidth(): number; + + /** + * Splits the `text` into multiple lines with the specified max `width`. + * + * @param text + * The text to process. + * + * @param width + * The max width of each line. + */ + protected breakLines(text: string, width: number): string[]; + + /** + * Adds line-breaks to the specified `text` with the specified max `width`. + * + * @param text + * The text to process. + * + * @param width + * The max width of each line. + */ + protected forceLineReturn(text: string, width: number): string; +} + +export = ScreenManager; diff --git a/types/inquirer/lib/utils/utils.d.ts b/types/inquirer/lib/utils/utils.d.ts new file mode 100644 index 0000000000..070ba66b1a --- /dev/null +++ b/types/inquirer/lib/utils/utils.d.ts @@ -0,0 +1,34 @@ +import inquirer = require("../.."); +import { Observable } from "rxjs"; + +/** + * Represents a property-name of any question-type. + */ +type QuestionProperty = inquirer.KeyUnion>; + +/** + * Unpacks a question-property. + */ +type UnpackQuestionProperty = T extends inquirer.AsyncDynamicQuestionProperty ? (U extends Promise ? U2 : U) : T; + +/** + * Fetches a property of the specified `question`. + * + * @param question + * The question to fetch the property from. + * + * @param prop + * The name of the property to fetch. + * + * @param answers + * The answers provided by the user. + * + * @returns + * The processed question. + */ +export function fetchAsyncQuestionPropertyQuestionProperty( + question: inquirer.DistinctQuestion, + prop: QuestionProperty, + answers: inquirer.Answers): Observable; + +export { }; diff --git a/types/inquirer/test/bottom-bar.ts b/types/inquirer/test/bottom-bar.ts new file mode 100644 index 0000000000..724fdb7f56 --- /dev/null +++ b/types/inquirer/test/bottom-bar.ts @@ -0,0 +1,19 @@ +import { spawn } from "child_process"; +import BottomBar = require("inquirer/lib/ui/bottom-bar"); +// tslint:disable-next-line: no-var-requires +const cmdify = require("cmdify"); + +const loader = ['/ Installing', '| Installing', '\\ Installing', '- Installing']; +let i = 4; +const ui = new BottomBar({ bottomBar: loader[i % 4] }); + +setInterval(() => { + ui.updateBottomBar(loader[i++ % 4]); +}, 300); + +const cmd = spawn(cmdify('npm'), ['-g', 'install', 'inquirer'], { stdio: 'pipe' }); +cmd.stdout.pipe(ui.log); +cmd.on('close', () => { + ui.updateBottomBar('Installation done!\n'); + process.exit(); +}); diff --git a/types/inquirer/test/checkbox.ts b/types/inquirer/test/checkbox.ts new file mode 100644 index 0000000000..60b643501c --- /dev/null +++ b/types/inquirer/test/checkbox.ts @@ -0,0 +1,66 @@ +import inquirer = require("inquirer"); + +/** + * Checkbox list examples + */ +inquirer.prompt([ + { + type: 'checkbox', + message: 'Select toppings', + name: 'toppings', + choices: [ + new inquirer.Separator(' = The Meats = '), + { + name: 'Pepperoni' + }, + { + name: 'Ham' + }, + { + name: 'Ground Meat' + }, + { + name: 'Bacon' + }, + new inquirer.Separator(' = The Cheeses = '), + { + name: 'Mozzarella', + checked: true + }, + { + name: 'Cheddar' + }, + { + name: 'Parmesan' + }, + new inquirer.Separator(' = The usual ='), + { + name: 'Mushroom' + }, + { + name: 'Tomato' + }, + new inquirer.Separator(' = The extras = '), + { + name: 'Pineapple' + }, + { + name: 'Olives', + disabled: 'out of stock' + }, + { + name: 'Extra cheese' + } + ], + validate(answer) { + if (answer.length < 1) { + return 'You must choose at least one topping.'; + } + + return true; + } + } +]) + .then(answers => { + console.log(JSON.stringify(answers, null, ' ')); + }); diff --git a/types/inquirer/test/editor.ts b/types/inquirer/test/editor.ts new file mode 100644 index 0000000000..0f1466fdbc --- /dev/null +++ b/types/inquirer/test/editor.ts @@ -0,0 +1,22 @@ +import inquirer = require("inquirer"); + +/** + * Editor prompt example + */ +const questions: inquirer.QuestionCollection = [ + { + type: 'editor', + name: 'bio', + message: 'Please write a short bio of at least 3 lines.', + validate(text) { + if (text.split('\n').length < 3) { + return 'Must be at least 3 lines.'; + } + return true; + } + } +]; + +inquirer.prompt(questions).then(answers => { + console.log(JSON.stringify(answers, null, ' ')); +}); diff --git a/types/inquirer/test/expand.ts b/types/inquirer/test/expand.ts new file mode 100644 index 0000000000..3c3377c007 --- /dev/null +++ b/types/inquirer/test/expand.ts @@ -0,0 +1,38 @@ +import inquirer = require("inquirer"); + +/** + * Expand list examples + */ +inquirer.prompt([ + { + type: 'expand', + message: 'Conflict on `file.js`: ', + name: 'overwrite', + choices: [ + { + key: 'y', + name: 'Overwrite', + value: 'overwrite' + }, + { + key: 'a', + name: 'Overwrite this one and all next', + value: 'overwrite_all' + }, + { + key: 'd', + name: 'Show diff', + value: 'diff' + }, + new inquirer.Separator(), + { + key: 'x', + name: 'Abort', + value: 'abort' + } + ] + } +]) + .then(answers => { + console.log(JSON.stringify(answers, null, ' ')); + }); diff --git a/types/inquirer/test/hierarchical.ts b/types/inquirer/test/hierarchical.ts new file mode 100644 index 0000000000..de9ab354f3 --- /dev/null +++ b/types/inquirer/test/hierarchical.ts @@ -0,0 +1,104 @@ +import inquirer = require("inquirer"); + +/** + * Represents answers provided by the user. + */ +interface RPGAnswers { + /** + * The weapon chosen by the user. + */ + weapon: string; + + /** + * The direction chosen by the user. + */ + direction: "Forward" | "Right" | "Left" | "Back"; +} + +/** + * Heirarchical conversation example + */ +const directionsPrompt: inquirer.DistinctQuestion = { + type: 'list', + name: 'direction', + message: 'Which direction would you like to go?', + choices: ['Forward', 'Right', 'Left', 'Back'] +}; + +function main() { + console.log('You find youself in a small room, there is a door in front of you.'); + exitHouse(); +} + +function exitHouse() { + inquirer.prompt(directionsPrompt).then(answers => { + if (answers.direction === 'Forward') { + console.log('You find yourself in a forest'); + console.log( + 'There is a wolf in front of you; a friendly looking dwarf to the right and an impasse to the left.' + ); + encounter1(); + } else { + console.log('You cannot go that way. Try again'); + exitHouse(); + } + }); +} + +function encounter1() { + inquirer.prompt(directionsPrompt).then(answers => { + const direction = answers.direction; + if (direction === 'Forward') { + console.log('You attempt to fight the wolf'); + console.log( + 'Theres a stick and some stones lying around you could use as a weapon' + ); + encounter2b(); + } else if (direction === 'Right') { + console.log('You befriend the dwarf'); + console.log('He helps you kill the wolf. You can now move forward'); + encounter2a(); + } else { + console.log('You cannot go that way'); + encounter1(); + } + }); +} + +function encounter2a() { + inquirer.prompt(directionsPrompt).then(answers => { + const direction = answers.direction; + if (direction === 'Forward') { + let output = 'You find a painted wooden sign that says:'; + output += ' \n'; + output += ' ____ _____ ____ _____ \n'; + output += '(_ _)( _ )( _ \\( _ ) \n'; + output += ' )( )(_)( )(_) ))(_)( \n'; + output += ' (__) (_____)(____/(_____) \n'; + console.log(output); + } else { + console.log('You cannot go that way'); + encounter2a(); + } + }); +} + +function encounter2b() { + inquirer + .prompt({ + type: 'list', + name: 'weapon', + message: 'Pick one', + choices: [ + 'Use the stick', + 'Grab a large rock', + 'Try and make a run for it', + 'Attack the wolf unarmed' + ] + }) + .then(() => { + console.log('The wolf mauls you. You die. The end.'); + }); +} + +main(); diff --git a/types/inquirer/test/input.ts b/types/inquirer/test/input.ts new file mode 100644 index 0000000000..c034f558d8 --- /dev/null +++ b/types/inquirer/test/input.ts @@ -0,0 +1,53 @@ +import inquirer = require("inquirer"); +import chalkPipe = require("chalk-pipe"); + +/** + * Input prompt example + */ +const questions: inquirer.QuestionCollection = [ + { + type: 'input', + name: 'first_name', + message: "What's your first name" + }, + { + type: 'input', + name: 'last_name', + message: "What's your last name", + default() { + return 'Doe'; + } + }, + { + type: 'input', + name: 'fav_color', + message: "What's your favorite color", + transformer(color, answers, flags) { + const text = chalkPipe(color)(color); + if (flags.isFinal) { + return text + '!'; + } + + return text; + } + }, + { + type: 'input', + name: 'phone', + message: "What's your phone number", + validate(value) { + const pass = value.match( + /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i + ); + if (pass) { + return true; + } + + return 'Please enter a valid phone number'; + } + } +]; + +inquirer.prompt(questions).then(answers => { + console.log(JSON.stringify(answers, null, ' ')); +}); diff --git a/types/inquirer/test/list.ts b/types/inquirer/test/list.ts new file mode 100644 index 0000000000..d57fda37cc --- /dev/null +++ b/types/inquirer/test/list.ts @@ -0,0 +1,36 @@ +import inquirer = require("inquirer"); + +/** + * List prompt example + */ +inquirer + .prompt([ + { + type: 'list', + name: 'theme', + message: 'What do you want to do?', + choices: [ + 'Order a pizza', + 'Make a reservation', + new inquirer.Separator(), + 'Ask for opening hours', + { + name: 'Contact support', + disabled: 'Unavailable at this time' + }, + 'Talk to the receptionist' + ] + }, + { + type: 'list', + name: 'size', + message: 'What size do you need?', + choices: ['Jumbo', 'Large', 'Standard', 'Medium', 'Small', 'Micro'], + filter(val) { + return val.toLowerCase(); + } + } + ]) + .then(answers => { + console.log(JSON.stringify(answers, null, ' ')); + }); diff --git a/types/inquirer/test/long-list.ts b/types/inquirer/test/long-list.ts new file mode 100644 index 0000000000..ab1752a079 --- /dev/null +++ b/types/inquirer/test/long-list.ts @@ -0,0 +1,33 @@ +import inquirer = require("inquirer"); + +/** + * Paginated list + */ +const choices: inquirer.ChoiceCollection = new Array(26).fill(undefined).map((x, y) => String.fromCharCode(y + 65)); +choices.push('Multiline option \n super cool feature'); +choices.push({ + name: + // tslint:disable-next-line: max-line-length + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium.', + value: 'foo', + short: 'The long option' +}); + +inquirer + .prompt([ + { + type: 'list', + name: 'letter', + message: "What's your favorite letter?", + choices + }, + { + type: 'checkbox', + name: 'name', + message: 'Select the letter contained in your name:', + choices + } + ]) + .then(answers => { + console.log(JSON.stringify(answers, null, ' ')); + }); diff --git a/types/inquirer/test/nested-call.ts b/types/inquirer/test/nested-call.ts new file mode 100644 index 0000000000..4c24f76c1a --- /dev/null +++ b/types/inquirer/test/nested-call.ts @@ -0,0 +1,20 @@ +import inquirer = require("inquirer"); + +/** + * Nested Inquirer call + */ +inquirer + .prompt({ + type: 'list', + name: 'chocolate', + message: "What's your favorite chocolate?", + choices: ['Mars', 'Oh Henry', 'Hershey'] + }) + .then(() => { + inquirer.prompt({ + type: 'list', + name: 'beverage', + message: 'And your favorite beverage?', + choices: ['Pepsi', 'Coke', '7up', 'Mountain Dew', 'Red Bull'] + }); + }); diff --git a/types/inquirer/test/password.ts b/types/inquirer/test/password.ts new file mode 100644 index 0000000000..3f1880a51a --- /dev/null +++ b/types/inquirer/test/password.ts @@ -0,0 +1,30 @@ +import inquirer = require("inquirer"); + +/** + * Password prompt example + */ +const requireLetterAndNumber: inquirer.Validator = value => { + if (/\w/.test(value) && /\d/.test(value)) { + return true; + } + + return 'Password need to have at least a letter and a number'; +}; + +inquirer + .prompt([ + { + type: 'password', + message: 'Enter a password', + name: 'password1', + validate: requireLetterAndNumber + }, + { + type: 'password', + message: 'Enter a masked password', + name: 'password2', + mask: '*', + validate: requireLetterAndNumber + } + ]) + .then(answers => console.log(JSON.stringify(answers, null, ' '))); diff --git a/types/inquirer/test/pizza.ts b/types/inquirer/test/pizza.ts new file mode 100644 index 0000000000..73b4428d31 --- /dev/null +++ b/types/inquirer/test/pizza.ts @@ -0,0 +1,98 @@ +import inquirer = require("inquirer"); + +/** + * Pizza delivery prompt example + * run example by writing `node pizza.js` in your console + */ +console.log('Hi, welcome to Node Pizza'); + +const questions: inquirer.DistinctQuestion[] = [ + { + type: 'confirm', + name: 'toBeDelivered', + message: 'Is this for delivery?', + default: false + }, + { + type: 'input', + name: 'phone', + message: "What's your phone number?", + validate(value) { + const pass = value.match( + /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i + ); + if (pass) { + return true; + } + + return 'Please enter a valid phone number'; + } + }, + { + type: 'list', + name: 'size', + message: 'What size do you need?', + choices: ['Large', 'Medium', 'Small'], + filter(val) { + return val.toLowerCase(); + } + }, + { + type: 'input', + name: 'quantity', + message: 'How many do you need?', + validate(value) { + const valid = !isNaN(parseFloat(value)); + return valid || 'Please enter a number'; + }, + filter: Number + }, + { + type: 'expand', + name: 'toppings', + message: 'What about the toppings?', + choices: [ + { + key: 'p', + name: 'Pepperoni and cheese', + value: 'PepperoniCheese' + }, + { + key: 'a', + name: 'All dressed', + value: 'alldressed' + }, + { + key: 'w', + name: 'Hawaiian', + value: 'hawaiian' + } + ] + }, + { + type: 'rawlist', + name: 'beverage', + message: 'You also get a free 2L beverage', + choices: ['Pepsi', '7up', 'Coke'] + }, + { + type: 'input', + name: 'comments', + message: 'Any comments on your purchase experience?', + default: 'Nope, all good!' + }, + { + type: 'list', + name: 'prize', + message: 'For leaving a comment, you get a freebie', + choices: ['cake', 'fries'], + when(answers) { + return answers.comments !== 'Nope, all good!'; + } + } +]; + +inquirer.prompt(questions).then(answers => { + console.log('\nOrder receipt:'); + console.log(JSON.stringify(answers, null, ' ')); +}); diff --git a/types/inquirer/test/rawlist.ts b/types/inquirer/test/rawlist.ts new file mode 100644 index 0000000000..9d7bfb50a7 --- /dev/null +++ b/types/inquirer/test/rawlist.ts @@ -0,0 +1,32 @@ +import inquirer = require("inquirer"); + +/** + * Raw List prompt example + */ +inquirer + .prompt([ + { + type: 'rawlist', + name: 'theme', + message: 'What do you want to do?', + choices: [ + 'Order a pizza', + 'Make a reservation', + new inquirer.Separator(), + 'Ask opening hours', + 'Talk to the receptionist' + ] + }, + { + type: 'rawlist', + name: 'size', + message: 'What size do you need', + choices: ['Jumbo', 'Large', 'Standard', 'Medium', 'Small', 'Micro'], + filter(val) { + return val.toLowerCase(); + } + } + ]) + .then(answers => { + console.log(JSON.stringify(answers, null, ' ')); + }); diff --git a/types/inquirer/test/recursive.ts b/types/inquirer/test/recursive.ts new file mode 100644 index 0000000000..d3af6fa9d1 --- /dev/null +++ b/types/inquirer/test/recursive.ts @@ -0,0 +1,34 @@ +import inquirer = require("inquirer"); + +/** + * Recursive prompt example + * Allows user to choose when to exit prompt + */ +const output: any[] = []; + +const questions: inquirer.QuestionCollection = [ + { + type: 'input', + name: 'tvShow', + message: "What's your favorite TV show?" + }, + { + type: 'confirm', + name: 'askAgain', + message: 'Want to enter another TV show favorite (just hit enter for YES)?', + default: true + } +]; + +function ask() { + inquirer.prompt(questions).then(answers => { + output.push(answers.tvShow); + if (answers.askAgain) { + ask(); + } else { + console.log('Your favorite TV Shows:', output.join(', ')); + } + }); +} + +ask(); diff --git a/types/inquirer/test/rx-observable-array.ts b/types/inquirer/test/rx-observable-array.ts new file mode 100644 index 0000000000..57fbecc7e4 --- /dev/null +++ b/types/inquirer/test/rx-observable-array.ts @@ -0,0 +1,47 @@ +import inquirer = require("inquirer"); +import { from } from "rxjs"; + +const questions: inquirer.DistinctQuestion[] = [ + { + type: 'input', + name: 'first_name', + message: "What's your first name" + }, + { + type: 'input', + name: 'last_name', + message: "What's your last name", + default() { + return 'Doe'; + } + }, + { + type: 'input', + name: 'phone', + message: "What's your phone number", + validate(value) { + const pass = value.match( + /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i + ); + if (pass) { + return true; + } + + return 'Please enter a valid phone number'; + } + } +]; + +const observable = from(questions); + +inquirer.prompt(observable).ui.process.subscribe( + (ans) => { + console.log('Answer is: ', ans); + }, + (err) => { + console.log('Error: ', err); + }, + () => { + console.log('Completed'); + } +); diff --git a/types/inquirer/test/rx-observable-create.ts b/types/inquirer/test/rx-observable-create.ts new file mode 100644 index 0000000000..8b70bb9c96 --- /dev/null +++ b/types/inquirer/test/rx-observable-create.ts @@ -0,0 +1,40 @@ +import inquirer = require("inquirer"); +import { Observable, Observer } from "rxjs"; + +const observe = Observable.create((obs: Observer) => { + obs.next({ + type: 'input', + name: 'first_name', + message: "What's your first name" + }); + + obs.next({ + type: 'input', + name: 'last_name', + message: "What's your last name", + default() { + return 'Doe'; + } + }); + + obs.next({ + type: 'input', + name: 'phone', + message: "What's your phone number", + validate(value) { + const pass = value.match( + /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i + ); + if (pass) { + return true; + } + + return 'Please enter a valid phone number'; + } + }); + obs.complete(); +}); + +inquirer.prompt(observe).then(answers => { + console.log(JSON.stringify(answers, null, ' ')); +}); diff --git a/types/inquirer/test/spawn.ts b/types/inquirer/test/spawn.ts new file mode 100644 index 0000000000..75a5f5f5d2 --- /dev/null +++ b/types/inquirer/test/spawn.ts @@ -0,0 +1,6 @@ +import { spawn } from "child_process"; + +spawn('node', ['input.js'], { + cwd: __dirname, + stdio: 'inherit' +}); diff --git a/types/inquirer/test/when.ts b/types/inquirer/test/when.ts new file mode 100644 index 0000000000..fa8fa59613 --- /dev/null +++ b/types/inquirer/test/when.ts @@ -0,0 +1,44 @@ +import inquirer = require("inquirer"); + +/** + * When example + */ +const questions: inquirer.QuestionCollection = [ + { + type: 'confirm', + name: 'bacon', + message: 'Do you like bacon?' + }, + { + type: 'input', + name: 'favorite', + message: 'Bacon lover, what is your favorite type of bacon?', + when(answers) { + return answers.bacon; + } + }, + { + type: 'confirm', + name: 'pizza', + message: 'Ok... Do you like pizza?', + when(answers) { + return !likesFood('bacon')(answers); + } + }, + { + type: 'input', + name: 'favorite', + message: 'Whew! What is your favorite type of pizza?', + when: likesFood('pizza') + } +]; + +function likesFood(aFood: string) { + return (answers: inquirer.Answers) => { + return answers[aFood]; + }; +} + +inquirer.prompt(questions).then(answers => { + console.log(JSON.stringify(answers, null, ' ')); +}); diff --git a/types/inquirer/tsconfig.json b/types/inquirer/tsconfig.json index 893f8efd38..cd54ee649a 100644 --- a/types/inquirer/tsconfig.json +++ b/types/inquirer/tsconfig.json @@ -18,6 +18,23 @@ }, "files": [ "index.d.ts", - "inquirer-tests.ts" + "inquirer-tests.ts", + "test/bottom-bar.ts", + "test/checkbox.ts", + "test/editor.ts", + "test/expand.ts", + "test/hierarchical.ts", + "test/input.ts", + "test/list.ts", + "test/long-list.ts", + "test/nested-call.ts", + "test/password.ts", + "test/pizza.ts", + "test/rawlist.ts", + "test/recursive.ts", + "test/rx-observable-array.ts", + "test/rx-observable-create.ts", + "test/spawn.ts", + "test/when.ts" ] } diff --git a/types/inquirer/tslint.json b/types/inquirer/tslint.json index 3d59f55fda..3db14f85ea 100644 --- a/types/inquirer/tslint.json +++ b/types/inquirer/tslint.json @@ -1,80 +1 @@ -{ - "extends": "dtslint/dt.json", - "rules": { - "adjacent-overload-signatures": false, - "array-type": false, - "arrow-return-shorthand": false, - "ban-types": false, - "callable-types": false, - "comment-format": false, - "dt-header": false, - "npm-naming": false, - "eofline": false, - "export-just-namespace": false, - "import-spacing": false, - "interface-name": false, - "interface-over-type-literal": false, - "jsdoc-format": false, - "max-line-length": false, - "member-access": false, - "new-parens": false, - "no-any-union": false, - "no-boolean-literal-compare": false, - "no-conditional-assignment": false, - "no-consecutive-blank-lines": false, - "no-construct": false, - "no-declare-current-package": false, - "no-duplicate-imports": false, - "no-duplicate-variable": false, - "no-empty-interface": false, - "no-for-in-array": false, - "no-inferrable-types": false, - "no-internal-module": false, - "no-irregular-whitespace": false, - "no-mergeable-namespace": false, - "no-misused-new": false, - "no-namespace": false, - "no-object-literal-type-assertion": false, - "no-padding": false, - "no-redundant-jsdoc": false, - "no-redundant-jsdoc-2": false, - "no-redundant-undefined": false, - "no-reference-import": false, - "no-relative-import-in-test": false, - "no-self-import": false, - "no-single-declare-module": false, - "no-string-throw": false, - "no-unnecessary-callback-wrapper": false, - "no-unnecessary-class": false, - "no-unnecessary-generics": false, - "no-unnecessary-qualifier": false, - "no-unnecessary-type-assertion": false, - "no-useless-files": false, - "no-var-keyword": false, - "no-var-requires": false, - "no-void-expression": false, - "no-trailing-whitespace": false, - "object-literal-key-quotes": false, - "object-literal-shorthand": false, - "one-line": false, - "one-variable-per-declaration": false, - "only-arrow-functions": false, - "prefer-conditional-expression": false, - "prefer-const": false, - "prefer-declare-function": false, - "prefer-for-of": false, - "prefer-method-signature": false, - "prefer-template": false, - "radix": false, - "semicolon": false, - "space-before-function-paren": false, - "space-within-parens": false, - "strict-export-declare-modifiers": false, - "trim-file": false, - "triple-equals": false, - "typedef-whitespace": false, - "unified-signatures": false, - "void-return": false, - "whitespace": false - } -} +{ "extends": "dtslint/dt.json" } diff --git a/types/yeoman-environment/index.d.ts b/types/yeoman-environment/index.d.ts index b89596665e..06228c3c94 100644 --- a/types/yeoman-environment/index.d.ts +++ b/types/yeoman-environment/index.d.ts @@ -102,9 +102,9 @@ declare namespace Environment { } namespace Adapter { - type Question = inquirer.Question; + type Question = inquirer.DistinctQuestion; - type Questions = inquirer.Questions; + type Questions = inquirer.QuestionCollection; type Answers = inquirer.Answers; } diff --git a/types/yeoman-generator/index.d.ts b/types/yeoman-generator/index.d.ts index abe8bfa42c..4402e3aec5 100644 --- a/types/yeoman-generator/index.d.ts +++ b/types/yeoman-generator/index.d.ts @@ -17,7 +17,7 @@ import { Observable } from 'rxjs'; type Callback = (err: any) => void; declare namespace Generator { - type Question = inquirer.Question & { + type Question = inquirer.DistinctQuestion & { /** * whether to store the user's previous answer */