Skip to content

Commit

Permalink
feat: ActionsBuilder now supports context and return type
Browse files Browse the repository at this point in the history
  • Loading branch information
aholstenson committed Sep 29, 2019
1 parent eba7270 commit ad508a0
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 124 deletions.
36 changes: 18 additions & 18 deletions src/ActionsBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Matcher, EncounterOptions } from './graph/matching';
import { ResolvedIntent } from './resolver/ResolvedIntent';
import { ResolvedIntents } from './resolver/ResolvedIntents';

export type Action<Values extends object> = (item: ResolvedIntent<Values>) => void;
export type Action<Context, ReturnType, Values extends object> = (item: ResolvedIntent<Values>, context: Context) => Promise<ReturnType> | ReturnType;

export class ActionsBuilder {
export class ActionsBuilder<Context=void, ReturnType=void> {
private language: Language;
private builder: IntentsBuilder;
private handlers: Map<string, any>;
Expand All @@ -20,7 +20,7 @@ export class ActionsBuilder {
this.id = 0;
}

public action(id?: string): ActionBuilder<{}> {
public action(id?: string): ActionBuilder<Context, ReturnType, {}> {
// Auto assign an id
const actualId = id ? id : id = ('__auto__' + ++this.id);

Expand Down Expand Up @@ -51,21 +51,21 @@ export class ActionsBuilder {
}

public build() {
return new Actions(this.language, this.builder.build(), this.handlers);
return new Actions<Context, ReturnType>(this.language, this.builder.build(), this.handlers);
}
}

export interface ActionBuilder<Values extends object> {
value<I extends string, V>(id: I, type: Value<V>): ActionBuilder<Values & { [K in I]: V }>;
export interface ActionBuilder<Context, ReturnType, Values extends object> {
value<I extends string, V>(id: I, type: Value<V>): ActionBuilder<Context, ReturnType, Values & { [K in I]: V }>;

add(...args: string[]): this;

handler(func: Action<Values>): this;
handler(func: Action<Context, ReturnType, Values>): this;

done(): ActionsBuilder;
done(): ActionsBuilder<Context, ReturnType>;
}

export class Actions {
export class Actions<Context, ReturnType> {
public readonly language: Language;
private handlers: Map<string, any>;
private matcher: Matcher<ResolvedIntents<any>>;
Expand All @@ -80,12 +80,12 @@ export class Actions {
this.handlers = handlers;
}

public match(expression: string, options: EncounterOptions): Promise<ResolvedActions> {
const map = (item: ResolvedIntent<any>): ResolvedAction => {
public match(expression: string, options?: EncounterOptions): Promise<ResolvedActions<Context, ReturnType>> {
const map = (item: ResolvedIntent<any>): ResolvedAction<Context, ReturnType> => {
const result = item as any;
result.activate = (...args: any[]) => {
result.activate = (context: Context) => {
const handler = this.handlers.get(item.intent);
const r = handler(item, ...args);
const r = handler(item, context);
return Promise.resolve(r);
};

Expand All @@ -102,11 +102,11 @@ export class Actions {
}
}

export interface ResolvedAction extends ResolvedIntent<any> {
activate: () => void;
export interface ResolvedAction<Context, ReturnType> extends ResolvedIntent<any> {
activate: (context: Context) => Promise<ReturnType>;
}

export interface ResolvedActions {
best: ResolvedAction | null;
matches: ResolvedAction[];
export interface ResolvedActions<Context, ReturnType> {
best: ResolvedAction<Context, ReturnType> | null;
matches: ResolvedAction<Context, ReturnType>[];
}
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export function intentsBuilder(lang: Language) {
return new IntentsBuilder(lang);
}

export function actionsBuilder(lang: Language) {
return new ActionsBuilder(lang);
export function actionsBuilder<Context, ReturnType>(lang: Language) {
return new ActionsBuilder<Context, ReturnType>(lang);
}
104 changes: 0 additions & 104 deletions test/actions.test.js

This file was deleted.

80 changes: 80 additions & 0 deletions test/actions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { en } from '../src/language/en';
import { actionsBuilder } from '../src';

describe('Actions', function() {
describe('Orders', function() {
const actions = actionsBuilder<number, string>(en)
.action('orders')
.add('Orders')
.add('Show orders')
.handler(() => 'executed orders')
.done()
.action()
.add('Orders that are active')
.add('Show orders that are active')
.handler((match, ctx) => 'active ' + ctx)
.done()
.build();

it('Language available', () => {
expect(actions.language).toEqual(en);
});

it('Match: orders', function() {
return actions.match('orders')
.then(results => {
expect(results.matches.length).toEqual(1);
expect(results.best.intent).toEqual('orders');
});
});

it('No match: show', function() {
return actions.match('show')
.then(results => {
expect(results.matches.length).toEqual(0);
});
});

it('Partial: orders', function() {
return actions.match('orders', { partial: true })
.then(results => {
expect(results.matches.length).toEqual(2);
});
});

it('Partial: or', function() {
return actions.match('or', { partial: true })
.then(results => {
expect(results.matches.length).toEqual(2);
});
});

it('Matched items have an activate() function', () => {
return actions.match('orders')
.then(results => {
expect(typeof results.best.activate).toEqual('function')
expect(typeof results.matches[0].activate).toEqual('function');
});
});

it('activate() functions is callable', () => {
return actions.match('orders')
.then(results => {
const p = results.best.activate(1234);
expect(typeof p.then).toEqual('function');
return p;
})
.then(v => expect(v).toEqual('executed orders'));
});

it('activate() passes context to handler', () => {
return actions.match('orders that are active')
.then(results => {
const p = results.best.activate(1234);
expect(typeof p.then).toEqual('function');
return p;
})
.then(v => expect(v).toEqual('active 1234'));
});
});
});

0 comments on commit ad508a0

Please sign in to comment.