Skip to content

Commit

Permalink
fix: use a real type for template and transform scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Dec 30, 2018
1 parent cdbc6fc commit 520cda0
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 30 deletions.
23 changes: 18 additions & 5 deletions src/controller/BaseController.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isString } from 'lodash';
import { Inject } from 'noicejs';

import { BotService } from 'src/BotService';
Expand All @@ -9,6 +10,7 @@ import { ServiceModule } from 'src/module/ServiceModule';
import { ServiceDefinition } from 'src/Service';
import { Transform, TransformData } from 'src/transform/Transform';
import { TYPE_JSON, TYPE_TEXT } from 'src/utils/Mime';
import { TemplateScope } from 'src/utils/Template';

export type BaseControllerOptions<TData extends ControllerData> = ControllerOptions<TData>;

Expand All @@ -35,7 +37,7 @@ export abstract class BaseController<TData extends ControllerData> extends BotSe

const transforms: Array<ServiceDefinition<TransformData>> = this.data.transforms || [];
for (const def of transforms) {
const transform = await this.services.createService<Transform, any>(def);
const transform = await this.services.createService<Transform, TransformData>(def);
this.transforms.push(transform);
}
}
Expand All @@ -59,24 +61,35 @@ export abstract class BaseController<TData extends ControllerData> extends BotSe

public abstract handle(cmd: Command): Promise<void>;

protected async transform(cmd: Command, type: string, body: any): Promise<any> {
protected async transform(cmd: Command, type: string, body: TemplateScope): Promise<TemplateScope> {
if (this.transforms.length === 0) {
this.logger.debug('controller has no transforms, skipping');
return body;
}

let result = body;
for (const transform of this.transforms) {
const check = await transform.check(cmd);
if (check) {
this.logger.debug({ transform: transform.name }, 'executing transform');
result = await transform.transform(cmd, type, result);
} else {
this.logger.debug({ check, transform: transform.name }, 'skipping transform');
this.logger.debug({ transform: transform.name }, 'skipping transform');
}
}
return result;
}

protected async transformJSON(cmd: Command, data: any): Promise<void> {
protected async transformJSON(cmd: Command, data: TemplateScope): Promise<void> {
this.logger.debug({ data }, 'transforming json body');

const body = await this.transform(cmd, TYPE_JSON, data);
return this.reply(cmd.context, body);

if (isString(body)) {
return this.reply(cmd.context, body);
} else {
this.logger.error({ body }, 'final transform did not return a string');
}
}

protected async reply(ctx: Context, body: string): Promise<void> {
Expand Down
5 changes: 1 addition & 4 deletions src/controller/EchoController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { BaseController } from 'src/controller/BaseController';
import { Controller, ControllerData, ControllerOptions } from 'src/controller/Controller';
import { Command } from 'src/entity/Command';
import { Transform } from 'src/transform/Transform';
import { TYPE_TEXT } from 'src/utils/Mime';
import { TemplateCompiler } from 'src/utils/TemplateCompiler';

export const NOUN_ECHO = 'echo';
Expand All @@ -24,8 +23,6 @@ export class EchoController extends BaseController<EchoControllerData> implement

public async handle(cmd: Command): Promise<void> {
this.logger.debug({ cmd }, 'echoing command');

const result = await this.transform(cmd, TYPE_TEXT, {});
return this.reply(cmd.context, result);
return this.transformJSON(cmd, {});
}
}
3 changes: 2 additions & 1 deletion src/controller/MathController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { BaseController } from 'src/controller/BaseController';
import { Controller, ControllerData, ControllerOptions } from 'src/controller/Controller';
import { Command } from 'src/entity/Command';
import { formatResult, ResultFormatOptions } from 'src/utils/Math';
import { TemplateScope } from 'src/utils/Template';

export const NOUN_MATH = 'math';

Expand Down Expand Up @@ -43,7 +44,7 @@ export class MathController extends BaseController<MathControllerData> implement
return this.reply(cmd.context, body);
}

protected eval(expr: string, scope: any): string {
protected eval(expr: string, scope: TemplateScope): string {
try {
const body = this.math.eval(expr, scope);
this.logger.debug({ body, expr }, 'evaluated expression');
Expand Down
4 changes: 1 addition & 3 deletions src/controller/SearchController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Container, Inject } from 'noicejs';
import { BaseController } from 'src/controller/BaseController';
import { Controller, ControllerData, ControllerOptions } from 'src/controller/Controller';
import { Command } from 'src/entity/Command';
import { TYPE_JSON } from 'src/utils/Mime';
import { Template } from 'src/utils/Template';
import { TemplateCompiler } from 'src/utils/TemplateCompiler';

Expand Down Expand Up @@ -47,7 +46,6 @@ export class SearchController extends BaseController<SearchControllerData> imple
uri: requestUrl,
});

const body = await this.transform(cmd, TYPE_JSON, response);
return this.reply(cmd.context, body);
return this.transformJSON(cmd, response);
}
}
4 changes: 1 addition & 3 deletions src/controller/WeatherController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { CoreOptions, RequiredUriUrl } from 'request';
import { BaseController } from 'src/controller/BaseController';
import { Controller, ControllerData, ControllerOptions } from 'src/controller/Controller';
import { Command } from 'src/entity/Command';
import { TYPE_JSON } from 'src/utils/Mime';
import { TemplateCompiler } from 'src/utils/TemplateCompiler';

export interface WeatherControllerData extends ControllerData {
Expand Down Expand Up @@ -40,8 +39,7 @@ export class WeatherController extends BaseController<WeatherControllerData> imp
const weather = await this.getWeather(location);

this.logger.debug({ weather }, 'transforming weather data');
const body = await this.transform(cmd, TYPE_JSON, weather);
return this.reply(cmd.context, body);
return this.transformJSON(cmd, weather);
} catch (err) {
this.logger.error(err, 'error getting weather');
}
Expand Down
2 changes: 1 addition & 1 deletion src/listener/ExpressListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export class ExpressListener extends SessionListener<ExpressListenerData> implem
issuer: this.data.token.issuer,
jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme(this.data.token.scheme),
secretOrKey: this.data.token.secret,
}, (payload: any, done: VerifiedCallback) => this.createTokenSession(payload, done)));
}, (payload: unknown, done: VerifiedCallback) => this.createTokenSession(payload, done)));

// sessions are saved when created and keyed by uid, so pass that
auth.serializeUser((user: Context, done) => {
Expand Down
38 changes: 31 additions & 7 deletions src/listener/SlackListener.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RTMClient, WebClient } from '@slack/client';
import { RTMClient, WebClient, WebAPICallResult } from '@slack/client';
import * as escape from 'escape-html';
import { isNil } from 'lodash';
import { BaseError, Inject, logWithLevel } from 'noicejs';
Expand All @@ -18,6 +18,30 @@ export interface SlackListenerData extends ListenerData {
};
}

export interface SlackReaction {
item: {
channel: string;
ts: string;
};
}

export interface SlackMessage {
channel: string;
reactions: Array<SlackMessageReaction>;
text: string;
ts: string;
type: string;
user: string;
}

export interface SlackMessageReaction {
name: string;
}

export interface SlackSearchResults extends WebAPICallResult {
messages: Array<SlackMessage>;
}

export type SlackListenerOptions = BotServiceOptions<SlackListenerData>;

@Inject('bot', 'clock')
Expand Down Expand Up @@ -69,28 +93,28 @@ export class SlackListener extends SessionListener<SlackListenerData> implements
await this.client.disconnect();
}

protected async convertReaction(reaction: any): Promise<Message> {
protected async convertReaction(reaction: SlackReaction): Promise<Message> {
this.logger.debug({ reaction }, 'converting slack reaction');
const search = await this.webClient.channels.history({
channel: reaction.item.channel,
inclusive: true,
latest: reaction.item.ts,
oldest: reaction.item.ts,
});
}) as SlackSearchResults;

if (!search.ok) {
throw new NotFoundError('message not found for reaction');
}

const [head] = (search as any).messages;
const [head] = search.messages;
return this.convertMessage({
...head,
channel: reaction.item.channel,
});
}

protected async convertMessage(msg: any): Promise<Message> {
const {type, channel, user: uid, text, ts} = msg;
protected async convertMessage(msg: SlackMessage): Promise<Message> {
const { type, channel, user: uid, text, ts } = msg;
this.logger.debug({ channel, text, ts, type, uid }, 'converting slack message');

const context = await this.createContext({
Expand All @@ -113,7 +137,7 @@ export class SlackListener extends SessionListener<SlackListenerData> implements
});
}

protected reactionNames(reactions: Array<any> | undefined): Array<string> {
protected reactionNames(reactions: Array<SlackMessageReaction> | undefined): Array<string> {
if (isNil(reactions)) {
return [];
}
Expand Down
5 changes: 3 additions & 2 deletions src/transform/BaseTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Inject } from 'noicejs';
import { BotService } from 'src/BotService';
import { Command } from 'src/entity/Command';
import { Transform, TransformData, TransformOptions } from 'src/transform/Transform';
import { TemplateScope } from 'src/utils/Template';

@Inject()
export abstract class BaseTransform<TData extends TransformData> extends BotService<TData> implements Transform {
Expand All @@ -15,9 +16,9 @@ export abstract class BaseTransform<TData extends TransformData> extends BotServ
return this.checkFilters(cmd, this.filters);
}

public abstract transform(cmd: Command, type: string, body: any): Promise<any>;
public abstract transform(cmd: Command, type: string, body: TemplateScope): Promise<TemplateScope>;

protected mergeScope(cmd: Command, data: any): any {
protected mergeScope(cmd: Command, data: TemplateScope): TemplateScope {
return { cmd, data };
}
}
4 changes: 2 additions & 2 deletions src/transform/TemplateTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Command } from 'src/entity/Command';
import { BaseTransform } from 'src/transform/BaseTransform';
import { Transform, TransformData, TransformOptions } from 'src/transform/Transform';
import { mapToDict } from 'src/utils/Map';
import { Template } from 'src/utils/Template';
import { Template, TemplateScope } from 'src/utils/Template';
import { TemplateCompiler } from 'src/utils/TemplateCompiler';

/**
Expand Down Expand Up @@ -35,7 +35,7 @@ export class TemplateTransform extends BaseTransform<TemplateTransformData> impl
}
}

public async transform(cmd: Command, type: string, body: any): Promise<any> {
public async transform(cmd: Command, type: string, body: TemplateScope): Promise<TemplateScope> {
const scope = this.mergeScope(cmd, body);
const out = new Map();
for (const [key, template] of this.templates) {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/Template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export interface TemplateOptions {
template: HandlebarsTemplateDelegate;
}

export type TemplateScope = unknown;
export type TemplateScope = object;

export class Template {
protected template: HandlebarsTemplateDelegate;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/TemplateCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class TemplateCompiler {
return `@${context.name}`;
}

public formatEntries(map: Map<string, string>, block: any): string {
public formatEntries(map: Map<string, string>, block: Handlebars.HelperOptions): string {
this.logger.debug({ block, map, type: typeof map }, 'formatting map entries');

const parts = [];
Expand Down

0 comments on commit 520cda0

Please sign in to comment.