prompt-anything
Advanced tools
Comparing version 1.1.0 to 1.1.1
import { VisualInterface } from "./Visual"; | ||
import { MessageInterface } from "./Message"; | ||
export interface ChannelInterface { | ||
send: (format: VisualInterface) => Promise<MessageInterface>; | ||
export interface ChannelInterface<MessageType extends MessageInterface> { | ||
send: (format: VisualInterface) => Promise<MessageType>; | ||
} |
@@ -8,4 +8,4 @@ /// <reference types="node" /> | ||
import { ChannelInterface } from './interfaces/Channel'; | ||
export declare type PromptFunction<DataType> = (this: Prompt<DataType>, m: MessageInterface, data: DataType) => Promise<DataType>; | ||
export interface PromptCollector<DataType> extends EventEmitter { | ||
export declare type PromptFunction<DataType, MessageType extends MessageInterface> = (m: MessageType, data: DataType) => Promise<DataType>; | ||
export interface PromptCollector<DataType, MessageType extends MessageInterface> extends EventEmitter { | ||
emit(event: 'reject', message: MessageInterface, error: Rejection): boolean; | ||
@@ -32,3 +32,3 @@ emit(event: 'accept', message: MessageInterface, data: DataType): boolean; | ||
}; | ||
export declare abstract class Prompt<DataType> { | ||
export declare abstract class Prompt<DataType, MessageType extends MessageInterface> { | ||
/** | ||
@@ -40,3 +40,3 @@ * Create a collector that is part of a prompt | ||
*/ | ||
abstract createCollector(channel: ChannelInterface, data: DataType): PromptCollector<DataType>; | ||
abstract createCollector(channel: ChannelInterface<MessageType>, data: DataType): PromptCollector<DataType, MessageType>; | ||
/** | ||
@@ -50,3 +50,3 @@ * When a message is rejected, this function is additionally called | ||
*/ | ||
abstract onReject(message: MessageInterface, error: Rejection, channel: ChannelInterface, data: DataType): Promise<void>; | ||
abstract onReject(message: MessageType, error: Rejection, channel: ChannelInterface<MessageType>, data: DataType): Promise<void>; | ||
/** | ||
@@ -57,3 +57,3 @@ * When the collector expires, call this function | ||
*/ | ||
abstract onInactivity(channel: ChannelInterface, data: DataType): Promise<void>; | ||
abstract onInactivity(channel: ChannelInterface<MessageType>, data: DataType): Promise<void>; | ||
/** | ||
@@ -67,10 +67,10 @@ * When a message specifies it wants to exit the prompt, | ||
*/ | ||
abstract onExit(message: MessageInterface, channel: ChannelInterface, data: DataType): Promise<void>; | ||
abstract onExit(message: MessageType, channel: ChannelInterface<MessageType>, data: DataType): Promise<void>; | ||
visualGenerator: VisualGenerator<DataType> | VisualInterface; | ||
collector?: PromptCollector<DataType>; | ||
collector?: PromptCollector<DataType, MessageType>; | ||
readonly duration: number; | ||
readonly messages: Array<StoredMessage>; | ||
readonly function?: PromptFunction<DataType>; | ||
readonly function?: PromptFunction<DataType, MessageType>; | ||
readonly condition?: PromptCondition<DataType>; | ||
constructor(visualGenerator: VisualGenerator<DataType> | VisualInterface, f?: PromptFunction<DataType>, condition?: PromptCondition<DataType>, duration?: number); | ||
constructor(visualGenerator: VisualGenerator<DataType> | VisualInterface, f?: PromptFunction<DataType, MessageType>, condition?: PromptCondition<DataType>, duration?: number); | ||
/** | ||
@@ -90,3 +90,3 @@ * Returns the visual given the data | ||
*/ | ||
static handleCollector<DataType>(emitter: PromptCollector<DataType>, func: PromptFunction<DataType>, data?: DataType, duration?: number): void; | ||
static handleCollector<DataType, MessageType extends MessageInterface>(emitter: PromptCollector<DataType, MessageType>, func: PromptFunction<DataType, MessageType>, data?: DataType, duration?: number): void; | ||
/** | ||
@@ -102,3 +102,3 @@ * Handle each individual message from a collector to determine | ||
*/ | ||
static handleMessage<DataType>(emitter: PromptCollector<DataType>, message: MessageInterface, func: PromptFunction<DataType>, data?: DataType): Promise<void>; | ||
static handleMessage<DataType, MessageType extends MessageInterface>(emitter: PromptCollector<DataType, MessageType>, message: MessageInterface, func: PromptFunction<DataType, MessageType>, data?: DataType): Promise<void>; | ||
/** | ||
@@ -110,3 +110,3 @@ * Send a visual | ||
*/ | ||
sendVisual(visual: VisualInterface, channel: ChannelInterface): Promise<MessageInterface>; | ||
sendVisual(visual: VisualInterface, channel: ChannelInterface<MessageType>): Promise<MessageType>; | ||
/** | ||
@@ -118,3 +118,3 @@ * Send the visual generated by the visual generator | ||
*/ | ||
sendUserVisual(channel: ChannelInterface, data: DataType): Promise<MessageInterface>; | ||
sendUserVisual(channel: ChannelInterface<MessageType>, data: DataType): Promise<MessageInterface>; | ||
/** | ||
@@ -139,3 +139,3 @@ * Store a message sent by the user into this prompt's store | ||
*/ | ||
collect(channel: ChannelInterface, data: DataType): Promise<PromptResult<DataType>>; | ||
collect(channel: ChannelInterface<MessageType>, data: DataType): Promise<PromptResult<DataType>>; | ||
} |
@@ -147,3 +147,3 @@ "use strict"; | ||
const collector = this.collector; | ||
Prompt.handleCollector(collector, this.function.bind(this), data, this.duration); | ||
Prompt.handleCollector(collector, this.function, data, this.duration); | ||
const handleInternalError = (error) => collector.emit('error', error); | ||
@@ -150,0 +150,0 @@ // Internally handled events |
import { Prompt } from "./Prompt"; | ||
import { TreeNode } from "./TreeNode"; | ||
export declare class PromptNode<DataType> extends TreeNode<PromptNode<DataType>> { | ||
prompt: Prompt<DataType>; | ||
constructor(prompt: Prompt<DataType>); | ||
import { MessageInterface } from "./interfaces/Message"; | ||
export declare class PromptNode<DataType, MessageType extends MessageInterface> extends TreeNode<PromptNode<DataType, MessageType>> { | ||
prompt: Prompt<DataType, MessageType>; | ||
constructor(prompt: Prompt<DataType, MessageType>); | ||
/** | ||
@@ -17,3 +18,3 @@ * Asserts that the children of this node are valid. | ||
*/ | ||
getNext(data: DataType): Promise<PromptNode<DataType> | null>; | ||
getNext(data: DataType): Promise<PromptNode<DataType, MessageType> | null>; | ||
/** | ||
@@ -24,3 +25,3 @@ * Sets the children of this node. | ||
*/ | ||
setChildren(nodes: Array<PromptNode<DataType>>): this; | ||
setChildren(nodes: Array<PromptNode<DataType, MessageType>>): this; | ||
/** | ||
@@ -31,3 +32,3 @@ * Push a new node to this node's children. | ||
*/ | ||
addChild(node: PromptNode<DataType>): this; | ||
addChild(node: PromptNode<DataType, MessageType>): this; | ||
} |
import { Prompt } from './Prompt'; | ||
import { PromptNode } from './PromptNode'; | ||
import { ChannelInterface } from './interfaces/Channel'; | ||
export declare class PromptRunner<DataType> { | ||
import { MessageInterface } from './interfaces/Message'; | ||
export declare class PromptRunner<DataType, MessageType extends MessageInterface> { | ||
initialData: DataType; | ||
readonly ran: Array<Prompt<DataType>>; | ||
readonly ran: Array<Prompt<DataType, MessageType>>; | ||
constructor(initialData: DataType); | ||
@@ -15,3 +16,3 @@ /** | ||
*/ | ||
static valid<DataType>(prompt: PromptNode<DataType>): boolean; | ||
static valid<DataType, MessageType extends MessageInterface>(prompt: PromptNode<DataType, MessageType>): boolean; | ||
/** | ||
@@ -23,3 +24,3 @@ * Returns the index of a prompt that have been executed | ||
*/ | ||
indexOf(prompt: Prompt<DataType>): number; | ||
indexOf(prompt: Prompt<DataType, MessageType>): number; | ||
/** | ||
@@ -32,3 +33,3 @@ * Returns the indexes of prompts that have been executed by | ||
*/ | ||
indexesOf(prompts: Array<Prompt<DataType>>): Array<number>; | ||
indexesOf(prompts: Array<Prompt<DataType, MessageType>>): Array<number>; | ||
/** | ||
@@ -40,3 +41,3 @@ * Get the first node whose condition passes, given this | ||
*/ | ||
getFirstNode(nodes: Array<PromptNode<DataType>>): Promise<PromptNode<DataType> | null>; | ||
getFirstNode(nodes: Array<PromptNode<DataType, MessageType>>): Promise<PromptNode<DataType, MessageType> | null>; | ||
/** | ||
@@ -49,3 +50,3 @@ * Validate the node prompt and all its children before | ||
*/ | ||
run(rootNode: PromptNode<DataType>, channel: ChannelInterface): Promise<DataType>; | ||
run(rootNode: PromptNode<DataType, MessageType>, channel: ChannelInterface<MessageType>): Promise<DataType>; | ||
/** | ||
@@ -58,3 +59,3 @@ * Get the first node whose condition passes, and run | ||
*/ | ||
runArray(rootNode: Array<PromptNode<DataType>>, channel: ChannelInterface): Promise<DataType>; | ||
runArray(rootNode: Array<PromptNode<DataType, MessageType>>, channel: ChannelInterface<MessageType>): Promise<DataType>; | ||
/** | ||
@@ -66,3 +67,3 @@ * Run the PromptNode without validating | ||
*/ | ||
execute(rootNode: PromptNode<DataType>, channel: ChannelInterface): Promise<DataType>; | ||
execute(rootNode: PromptNode<DataType, MessageType>, channel: ChannelInterface<MessageType>): Promise<DataType>; | ||
} |
{ | ||
"name": "prompt-anything", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Framework to build a a tree of modular and interactable prompts for anything", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
# Prompt Anything | ||
[](https://codeclimate.com/github/synzen/discord-menus/maintainability) | ||
<a href="https://codeclimate.com/github/synzen/discord-menus/test_coverage"><img src="https://api.codeclimate.com/v1/badges/4be50d131276538502d1/test_coverage" /></a> | ||
[](https://codeclimate.com/github/synzen/prompt-anything/maintainability) | ||
[](https://codeclimate.com/github/synzen/prompt-anything/test_coverage) | ||
 | ||
@@ -16,2 +17,3 @@ A modular and customizable framework to build prompts of any kind (such as ones within the console)! Originally inspired by the need to create console-like prompts in other applications such as chatting with bots. | ||
- [Skipping Message Collection](#skipping-message-collection) | ||
- [Time Limits](#time-limits) | ||
- [Connecting Prompts](#connecting-prompts) | ||
@@ -33,4 +35,4 @@ - [Running Prompts](#running-prompts) | ||
interface ChannelInterface { | ||
send: (visual: VisualInterface) => Promise<MessageInterface>; | ||
interface ChannelInterface<MessageType extends MessageInterface> { | ||
send: (visual: VisualInterface) => Promise<MessageType>; | ||
} | ||
@@ -40,7 +42,7 @@ ``` | ||
```ts | ||
class MyPrompt<DataType> extends Prompt<DataType> { | ||
createCollector(channel: ChannelInterface, data: DataType): PromptCollector<DataType> { | ||
const emitter = new EventEmitter() | ||
class MyPrompt<DataType, MessageType> extends Prompt<DataType, MessageType> { | ||
createCollector(channel: ChannelInterface<MessageType>, data: DataType): PromptCollector<DataType, MessageType> { | ||
const emitter: PromptCollector<DataType, MessageType> = new EventEmitter() | ||
// Collect your messages via your listeners, and return an emitter that follows these rules | ||
myCollector.on('myMessage', (message: MessageInterface) => { | ||
myCollector.on('myMessage', (message: MessageType) => { | ||
// Emit the messages from your collector here | ||
@@ -57,5 +59,5 @@ emitter.emit('message', message) | ||
// Implement abstract methods. These events are automatically called | ||
abstract async onReject(message: MessageInterface, error: Rejection, channel: ChannelInterface): Promise<void>; | ||
abstract async onInactivity(channel: ChannelInterface): Promise<void>; | ||
abstract async onExit(message: MessageInterface, channel: ChannelInterface): Promise<void>; | ||
abstract async onReject(message: MessageType, error: Rejection, channel: ChannelInterface<MessageType>): Promise<void>; | ||
abstract async onInactivity(channel: ChannelInterface<MessageType>): Promise<void>; | ||
abstract async onExit(message: MessageType, channel: ChannelInterface<MessageType>): Promise<void>; | ||
} | ||
@@ -88,3 +90,3 @@ ``` | ||
// askNameFn is run on every message collected during this prompt. This should be a pure function. (see below for details) | ||
const askNameFn: PromptFunction<MyData> = async (m: MessageInterface, data: MyData) => { | ||
const askNameFn: PromptFunction<MyData, MessageType> = async (m: MessageType, data: MyData) => { | ||
// This data is returned to the next prompt | ||
@@ -97,3 +99,3 @@ return { | ||
// Third argument is the optional PromptCondition | ||
const askNamePrompt = new MyPrompt<MyData>(askNameVisual, askNameFn) | ||
const askNamePrompt = new MyPrompt<MyData, MessageType>(askNameVisual, askNameFn) | ||
``` | ||
@@ -120,3 +122,3 @@ The `PromptFunction` should be [pure function](https://en.wikipedia.org/wiki/Pure_function) to | ||
} | ||
const askNamePrompt = new MyPrompt<MyData>({ | ||
const askNamePrompt = new MyPrompt<MyData, MessageType>({ | ||
text: 'What is your name?' | ||
@@ -131,3 +133,3 @@ }, askNameFn, askNameCondition) | ||
```ts | ||
const askNamePrompt = new MyPrompt<MyData>((data: MyData): VisualInterface => ({ | ||
const askNamePrompt = new MyPrompt<MyData, MessageType>((data: MyData): VisualInterface => ({ | ||
text: `Hello ${data.human ? 'non-human' : 'human'}! What is your name?` | ||
@@ -146,3 +148,3 @@ }), askNameFn) | ||
```ts | ||
const askAgeFn: PromptFunction<MyData> = async (m: MessageInterface, data: MyData) => { | ||
const askAgeFn: PromptFunction<MyData, MessageType> = async (m: MessageType, data: MyData) => { | ||
const age = Number(m.content) | ||
@@ -161,6 +163,6 @@ if (isNaN(age)) { | ||
To skip message collecting and only send a message (usually done at the end of prompts), simply leave the second argument of `Prompt` as `undefined`. | ||
To skip message collecting and only send a prompt's visual (usually done at the end of prompts), simply leave the second argument of `Prompt` as `undefined`. | ||
```ts | ||
const askNamePrompt = new MyPrompt<MyData>({ | ||
const askNamePrompt = new MyPrompt<MyData, MessageType>({ | ||
text: 'The end is nigh' | ||
@@ -170,2 +172,11 @@ }) | ||
#### Time Limits | ||
To automatically end message collection after a set duration, pass your duration in milliseconds as the 4th argument to `Prompt`. Your implemented `onInactivity` method will then be called. | ||
```ts | ||
const duration = 90000 | ||
const askNamePrompt = new MyPrompt<MyData, MessageType>(askNameVisual, askNameFn, askNameCondition, duration) | ||
``` | ||
### Connecting Prompts | ||
@@ -176,8 +187,8 @@ | ||
```ts | ||
const askNameNode = new PromptNode<MyData>(askNamePrompt) | ||
const askAgeNode = new PromptNode<MyData>(askAgePrompt) | ||
const askLocationNode = new PromptNode<MyData>(askLocationPrompt) | ||
const askNameNode = new PromptNode<MyData, MessageType>(askNamePrompt) | ||
const askAgeNode = new PromptNode<MyData, MessageType>(askAgePrompt) | ||
const askLocationNode = new PromptNode<MyData, MessageType>(askLocationPrompt) | ||
// After we ask for the location, we'd like to send a prompt in a different language based on their input | ||
const englishAskNode = new PromptNode<MyData>(englishAskPrompt) | ||
const spanishAskNode = new PromptNode<MyData>(spanishAskPrompt) | ||
const englishAskNode = new PromptNode<MyData, MessageType>(englishAskPrompt) | ||
const spanishAskNode = new PromptNode<MyData, MessageType>(spanishAskPrompt) | ||
@@ -198,6 +209,7 @@ askNameNode.addChild(askAgeNode) | ||
After your prompt nodes are created, pass the root node into a `PromptRunner`. | ||
After your prompt nodes are created, create a `PromptRunner` that is initialized with the data you'll be passing to the first prompt, then call its run method with the first prompt node. | ||
```ts | ||
const runner = new PromptRunner<MyData>({}) | ||
// The initial data that is given to the first prompt is passed to the PromptRunner's constructor | ||
const runner = new PromptRunner<MyData, MessageType>({}) | ||
@@ -217,3 +229,3 @@ // run resolves with the data returned from the last prompt | ||
// runArray resolves with the data returned from the last prompt | ||
const channel: ChannelInterface = myImplementedChannel() | ||
const channel: ChannelInterface<MessageType> = myImplementedChannel() | ||
const lastPromptData: MyData = await runner.runArray([ | ||
@@ -251,3 +263,3 @@ askSurnameNode, | ||
// Set up spies and the global emitter we'll use | ||
const emitter: PromptCollector<AgeData> = new EventEmitter() | ||
const emitter: PromptCollector<AgeData, MessageType> = new EventEmitter() | ||
const spy = jest.spyOn(MyPrompt.prototype, 'createCollector') | ||
@@ -257,3 +269,3 @@ .mockReturnValue(emitter) | ||
// Ask name Prompt that collects messages | ||
const askNameFn: PromptFunction<AgeData> = async function (m, data) { | ||
const askNameFn: PromptFunction<AgeData, MessageType> = async function (m, data) { | ||
return { | ||
@@ -264,3 +276,3 @@ ...data, | ||
} | ||
const askName = new ConsolePrompt(() => ({ | ||
const askName = new MyPrompt<AgeData>(() => ({ | ||
text: `What's your name?` | ||
@@ -270,3 +282,3 @@ }), askNameFn) | ||
// Ask age Prompt that collects messages | ||
const askAgeFn: PromptFunction<AgeData> = async function (m, data) { | ||
const askAgeFn: PromptFunction<AgeData, MessageType> = async function (m, data) { | ||
if (isNaN(Number(m.content))) { | ||
@@ -280,3 +292,3 @@ throw new Errors.Rejection() | ||
} | ||
const askAge = new MyPrompt((data) => ({ | ||
const askAge = new MyPrompt<AgeData>((data) => ({ | ||
text: `How old are you, ${data.name}?` | ||
@@ -283,0 +295,0 @@ }), askAgeFn) |
41782
723
322