type2docfx
Version:
A tool to convert json format output from TypeDoc to universal reference model for DocFx to consume.
123 lines (114 loc) • 5 kB
text/typescript
/**
* @module botbuilder-dialogs
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Promiseable, BotService } from 'botbuilder';
import { Dialog, DialogInstance } from './dialog';
import { DialogSet } from './dialogSet';
import { Context } from 'vm';
/**
* Function signature of a waterfall step.
*
* **Example usage:**
*
* ```JavaScript
* dialogs.add('addAlarm', [
* function (context, alarm, next) {
* dialogs.getInstance(context).state = Object.assign({}, alarm);
* if (!alarm.title) {
* return dialogs.prompt(context, 'titlePrompt', `What would you like to call your alarm?`);
* } else {
* return next(alarm.title);
* }
* },
* function (context, title, next) {
* const alarm = dialogs.getInstance(context).state;
* alarm.title = title;
* if (!alarm.time) {
* return dialogs.prompt(context, 'timePrompt', `What time would you like to set it for?`);
* } else {
* return next(alarm.time);
* }
* },
* function (context, time) {
* const alarm = dialogs.getInstance(context).state;
* alarm.time = time;
*
* // ... set alarm ...
*
* context.reply(`Alarm set.`);
* return dialogs.end(context);
* }
* ]);
* ```
* @param WaterfallStep.context The dialog context for the current turn of conversation.
* @param WaterfallStep.args Argument(s) passed into the dialog for the first step and then the results from calling a prompt or other dialog for subsequent steps.
* @param WaterfallStep.next Function passed into the step to let you manually skip to the next step in the waterfall.
*/
export type WaterfallStep = (context: BotContext, args?: any, next?: SkipStepFunction) => Promiseable<void>;
/**
* When called, control will skip to the next waterfall step.
* @param SkipStepFunction.args (Optional) additional argument(s) to pass into the next step.
*/
export type SkipStepFunction = (args?: any) => Promise<void>;
/**
* Dialog optimized for prompting a user with a series of questions. Waterfalls accept a stack of
* functions which will be executed in sequence. Each waterfall step can ask a question of the user
* by calling either a prompt or another dialog. When the called dialog completes control will be
* returned to the next step of the waterfall and any input collected by the prompt or other dialog
* will be passed to the step as an argument.
*
* When a step is executed it should call either `context.begin()`, `context.end()`,
* `context.replace()`, `context.cancelDialog()`, or a prompt. Failing to do so will result
* in the dialog automatically ending the next time the user replies.
*
* Similarly, calling a dialog/prompt from within the last step of the waterfall will result in
* the waterfall automatically ending once the dialog/prompt completes. This is often desired
* though as the result from tha called dialog/prompt will be passed to the waterfalls parent
* dialog.
*/
export class Waterfall implements Dialog {
private readonly steps: WaterfallStep[];
/**
* Creates a new waterfall dialog containing the given array of steps.
* @param steps Array of waterfall steps.
*/
constructor(steps: WaterfallStep[]) {
this.steps = (steps || []).slice(0);
}
public begin(context: BotContext, dialogs: DialogSet, args?: any): Promiseable<void> {
const instance = dialogs.getInstance(context) as WaterfallInstance<any>;
instance.step = 0;
return this.runStep(context, dialogs, args);
}
public resume(context: BotContext, dialogs: DialogSet, result?: any): Promiseable<void> {
const instance = dialogs.getInstance(context) as WaterfallInstance<any>;
instance.step += 1
return this.runStep(context, dialogs, result);
}
private runStep(context: BotContext, dialogs: DialogSet, result?: any): Promise<void> {
try {
const instance = dialogs.getInstance(context) as WaterfallInstance<any>;
const step = instance.step;
if (step >= 0 && step < this.steps.length) {
// Execute step
return Promise.resolve(this.steps[step](context, result, (r?: any) => {
// Skip to next step
instance.step += 1;
return this.runStep(context, r);
}));
} else {
// End of waterfall so just return to parent
return dialogs.end(context);
}
} catch (err) {
return Promise.reject(err);
}
}
}
interface WaterfallInstance<T extends Object> extends DialogInstance<T> {
step: number;
}