Skip to content

Commit 64b24f5

Browse files
authored
Merge pull request #35 from fletcherist/feature/matchers
Feature/matchers
2 parents 8cac580 + 9b1cbf5 commit 64b24f5

File tree

10 files changed

+141
-101
lines changed

10 files changed

+141
-101
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
<a name="1.3.3"></a>
2+
## [1.3.3](https://github.com/fletcherist/yandex-dialogs-sdk/compare/v1.3.2...v1.3.3) (2018-07-08)
3+
4+
5+
### Bug Fixes
6+
7+
* bug with commands (array) ([8cac580](https://github.com/fletcherist/yandex-dialogs-sdk/commit/8cac580))
8+
* package.json ([169a818](https://github.com/fletcherist/yandex-dialogs-sdk/commit/169a818))
9+
10+
11+
### Features
12+
13+
* add guess number game to examples ([3d34c26](https://github.com/fletcherist/yandex-dialogs-sdk/commit/3d34c26))
14+
* add youtube link to readme ([31c8328](https://github.com/fletcherist/yandex-dialogs-sdk/commit/31c8328))
15+
16+
17+
118
<a name="1.3.2"></a>
219
## [1.3.2](https://github.com/fletcherist/yandex-dialogs-sdk/compare/v1.2.1...v1.3.2) (2018-07-08)
320

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
{
22
"name": "yandex-dialogs-sdk",
3-
"version": "1.3.2",
3+
"version": "1.3.3",
44
"description": "Build your skill for Alice with ease.",
55
"main": "dist/index.js",
66
"scripts": {
77
"lint": "eslint src",
88
"test": "jest",
99
"dev": "tsc -w",
1010
"build": "tsc",
11-
"version": "npm run changelog && git add CHANGELOG.md && conventional-github-releaser -p angular",
11+
"version": "npm run changelog && git add CHANGELOG.md",
1212
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
13+
"release": "conventional-github-releaser -p angular",
1314
"deploy": "tsc && git push --follow-tags origin master && npm publish"
1415
},
1516
"repository": {

src/alice.ts

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ export default class Alice {
112112
const sessionId = selectSessionId(req)
113113
const session = this.sessions.findOrCreate(sessionId)
114114

115+
/*
116+
* Initializing context of the request
117+
*/
118+
const ctxDefaultParams = {
119+
req,
120+
session,
121+
sendResponse: sendResponse || null,
122+
/*
123+
* if Alice is listening on express.js port, add this server instance
124+
* to the context
125+
*/
126+
server: this.server || null,
127+
middlewares: this.middlewares,
128+
}
129+
const ctxInstance = new Ctx(ctxDefaultParams)
130+
const ctxWithMiddlewares = await applyMiddlewares(this.middlewares, ctxInstance)
131+
115132
/* check whether current scene is not defined */
116133
if (!session.getData('currentScene')) {
117134
session.setData('currentScene', null)
@@ -129,12 +146,12 @@ export default class Alice {
129146
*/
130147
if (matchedScene) {
131148
if (matchedScene.isLeaveCommand(requestedCommandName)) {
132-
matchedScene.handleRequest(req, sendResponse, session)
149+
await matchedScene.handleRequest(req, sendResponse, ctxWithMiddlewares)
133150
session.setData('currentScene', null)
134151
return true
135152
} else {
136153
const sceneResponse = await matchedScene.handleRequest(
137-
req, sendResponse, session,
154+
req, sendResponse, ctxWithMiddlewares,
138155
)
139156
if (sceneResponse) {
140157
return true
@@ -150,31 +167,15 @@ export default class Alice {
150167
if (matchedScene) {
151168
session.setData('currentScene', matchedScene.name)
152169
const sceneResponse = await matchedScene.handleRequest(
153-
req, sendResponse, session,
170+
req, sendResponse, ctxWithMiddlewares,
154171
)
155172
if (sceneResponse) {
156173
return true
157174
}
158175
}
159176
}
160177

161-
const requestedCommands = this.commands.search(requestedCommandName)
162-
163-
/*
164-
* Initializing context of the request
165-
*/
166-
const ctxDefaultParams = {
167-
req,
168-
session,
169-
sendResponse: sendResponse || null,
170-
/*
171-
* if Alice is listening on express.js port, add this server instance
172-
* to the context
173-
*/
174-
server: this.server || null,
175-
middlewares: this.middlewares,
176-
}
177-
178+
const requestedCommands = await this.commands.search(ctxWithMiddlewares)
178179
/*
179180
* Если новая сессия, то запускаем стартовую команду
180181
*/
@@ -183,10 +184,6 @@ export default class Alice {
183184
* Patch context with middlewares
184185
*/
185186
if (this.welcomeCallback) {
186-
// tslint:disable:no-shadowed-variable
187-
const ctxInstance = new Ctx(ctxDefaultParams)
188-
const ctxWithMiddlewares = await applyMiddlewares(this.middlewares, ctxInstance)
189-
// tslint:enable:no-shadowed-variable
190187
return await this.welcomeCallback(ctxWithMiddlewares)
191188
}
192189
}
@@ -196,22 +193,14 @@ export default class Alice {
196193
*/
197194
if (requestedCommands.length !== 0) {
198195
const requestedCommand: CommandInterface = requestedCommands[0]
199-
// tslint:disable:no-shadowed-variable
200-
const ctxInstance = new Ctx(merge(ctxDefaultParams, {
201-
command: requestedCommand,
202-
}))
203-
const ctxWithMiddlewares = await applyMiddlewares(this.middlewares, ctxInstance)
204-
// tslint:enable:no-shadowed-variable
196+
ctxWithMiddlewares.command = requestedCommand
205197
return await requestedCommand.callback(ctxWithMiddlewares)
206198
}
207199

208200
/*
209201
* Такой команды не было зарегестрировано.
210202
* Переходим в обработчик исключений
211203
*/
212-
const ctxInstance = new Ctx(ctxDefaultParams)
213-
const ctxWithMiddlewares = await applyMiddlewares(this.middlewares, ctxInstance)
214-
215204
if (!this.anyCallback) {
216205
throw new Error([
217206
`alice.any(ctx => ctx.reply('404')) Method must be defined`,
@@ -227,7 +216,7 @@ export default class Alice {
227216
public async handleRequest(
228217
req: WebhookRequest,
229218
sendResponse?: (res: WebhookResponse) => void,
230-
) {
219+
): Promise<any> {
231220
return await this.handleRequestBody(req, sendResponse)
232221
}
233222

src/command.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,24 @@ import {
33
TYPE_FIGURE,
44
TYPE_REGEXP,
55
TYPE_ARRAY,
6+
TYPE_MATCHER,
67
} from './constants'
78
import Ctx from './ctx'
8-
import { CommandInterface, CallbackType, CommandType } from './types/command'
9+
import {
10+
CommandInterface,
11+
CallbackType,
12+
CommandType,
13+
CommandNameType,
14+
} from './types/command'
915
import { CtxInterface } from './types/ctx'
16+
import { isFunction } from './utils'
1017

1118
export default class Command implements CommandInterface {
12-
public name: any[] | string | RegExp
13-
public type: | CommandType
19+
public name: CommandNameType
20+
public type: CommandType
1421
public callback: CallbackType
1522

16-
constructor(name: string, callback: CallbackType) {
23+
constructor(name: CommandNameType, callback: CallbackType) {
1724
if (name === undefined) { throw new Error('Command name is not specified') }
1825
this.name = name
1926
this.callback = callback
@@ -25,18 +32,20 @@ export default class Command implements CommandInterface {
2532
public _defineCommandType(name) {
2633
let type
2734

28-
if (typeof name === 'string') {
29-
type = TYPE_STRING
30-
if (name.includes('${')) {
31-
type = TYPE_FIGURE
32-
}
35+
if (isFunction(name)) {
36+
type = TYPE_MATCHER
37+
} else if (typeof name === 'string') {
38+
type = TYPE_STRING
39+
if (name.includes('${')) {
40+
type = TYPE_FIGURE
41+
}
3342
} else if (name instanceof RegExp) {
34-
type = TYPE_REGEXP
43+
type = TYPE_REGEXP
3544
} else if (Array.isArray(name)) {
36-
type = TYPE_ARRAY
45+
type = TYPE_ARRAY
3746
} else {
38-
throw new Error(`Command name is not of proper type.
39-
Could be only string, array of strings or regular expression`)
47+
throw new Error(`Command name is not of proper type.
48+
Could be only string, array of strings, regular expression or function`)
4049
}
4150
return type
4251
}

src/commands.ts

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import {
77
TYPE_ARRAY,
88
TYPE_REGEXP,
99
TYPE_FIGURE,
10+
TYPE_MATCHER,
1011
} from './constants'
1112
import { CommandsInterface } from './types/commands'
1213
import { CommandInterface } from './types/command'
14+
import { CtxInterface } from 'ctx'
1315

1416
export default class Commands implements CommandsInterface {
1517
public commands: CommandInterface[]
@@ -28,6 +30,9 @@ export default class Commands implements CommandsInterface {
2830
return this.commands
2931
}
3032

33+
get _matchers() {
34+
return this.commands.filter((command) => command.type === TYPE_MATCHER)
35+
}
3136
get _strings() {
3237
return this.commands.filter((command) =>
3338
[TYPE_FIGURE, TYPE_STRING, TYPE_ARRAY].includes(command.type),
@@ -40,31 +45,14 @@ export default class Commands implements CommandsInterface {
4045
return this.commands.filter((command) => command.type === TYPE_REGEXP)
4146
}
4247

43-
public _searchStrings(requestedCommandName) {
44-
const stringCommands = this._strings
45-
const fuse = new Fuse(stringCommands, this.fuseOptions)
46-
return fuse.search(requestedCommandName)
47-
}
48-
49-
public _searchFigures(requestedCommandName) {
50-
const figuresCommands = this._figures
51-
return figuresCommands.filter((figure) => {
52-
const reg = utils.getFiguresRegexp(figure.name)
53-
return requestedCommandName.match(reg)
54-
})
55-
}
56-
57-
public _searchRegexps(requestedCommandName) {
58-
const regexpCommands = this._regexps
59-
// @TODO: include matches and captured groups
60-
return regexpCommands.filter((reg) => requestedCommandName.match(reg.name))
61-
}
62-
63-
public search(requestedCommandName) {
64-
const matchedStrings = this._searchStrings(requestedCommandName)
65-
const matchedRegexps = this._searchRegexps(requestedCommandName)
66-
const matchedFigures = this._searchFigures(requestedCommandName)
67-
if (matchedStrings.length > 0) {
48+
public async search(ctx: CtxInterface) {
49+
const matchedStrings = this._searchStrings(ctx.message)
50+
const matchedRegexps = this._searchRegexps(ctx.message)
51+
const matchedFigures = this._searchFigures(ctx.message)
52+
const matchedMatchers = await this._searchMatchers(ctx)
53+
if (matchedMatchers.length > 0) {
54+
return matchedMatchers
55+
} else if (matchedStrings.length > 0) {
6856
return matchedStrings
6957
} else if (matchedRegexps.length > 0) {
7058
return matchedRegexps
@@ -93,6 +81,36 @@ export default class Commands implements CommandsInterface {
9381
public flush() {
9482
this.commands = []
9583
}
84+
85+
private async _searchMatchers(ctx: CtxInterface) {
86+
const matchers = this._matchers
87+
for (const matcher of matchers) {
88+
if (await matcher.name(ctx)) {
89+
return [matcher]
90+
}
91+
}
92+
return []
93+
}
94+
95+
private _searchStrings(requestedCommandName: string) {
96+
const stringCommands = this._strings
97+
const fuse = new Fuse(stringCommands, this.fuseOptions)
98+
return fuse.search(requestedCommandName)
99+
}
100+
101+
private _searchFigures(requestedCommandName: string) {
102+
const figuresCommands = this._figures
103+
return figuresCommands.filter((figure) => {
104+
const reg = utils.getFiguresRegexp(figure.name)
105+
return requestedCommandName.match(reg)
106+
})
107+
}
108+
109+
private _searchRegexps(requestedCommandName) {
110+
const regexpCommands = this._regexps
111+
// @TODO: include matches and captured groups
112+
return regexpCommands.filter((reg) => requestedCommandName.match(reg.name))
113+
}
96114
}
97115

98116
module.exports = Commands

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const TYPE_STRING = 'string'
22
export const TYPE_FIGURE = 'figure'
33
export const TYPE_REGEXP = 'regexp'
44
export const TYPE_ARRAY = 'array'
5+
export const TYPE_MATCHER = 'matcher'
56

67
export const ALICE_PROTOCOL_VERSION = '1.0'
78
export const DEFAULT_END_SESSION = false

src/ctx.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export default class Ctx implements CtxInterface {
2222
public replyBuilder: ReplyBuilder
2323
public buttonBuilder: ButtonBuilder
2424

25-
public sendResponse: (response: string) => void
26-
public enterScene: () => void
25+
public sendResponse: (response: WebhookResponse) => void
26+
public enterScene: (sceneName: string) => void
2727
public leaveScene: () => void
2828
constructor(params) {
2929
const {

src/scene.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Command from './Command'
44
import Ctx from './ctx'
55

66
import { configInterface } from './types/alice'
7+
import { WebhookRequest, WebhookResponse } from './types/webhook'
8+
import { CtxInterface } from 'ctx'
79

810
const selectCommand = (req) => req.request.command
911

@@ -70,32 +72,32 @@ export default class Scene extends Alice {
7072
return this.leaveCommand.name.toLowerCase() === commandName.toLowerCase()
7173
}
7274

73-
public async handleRequest(req, sendResponse, session) {
74-
const requestedCommandName = selectCommand(req)
75-
const requestedCommands = this.commands.search(requestedCommandName)
75+
public async handleRequest(
76+
req: WebhookRequest,
77+
sendResponse: (res: WebhookResponse) => void,
78+
ctx: CtxInterface,
79+
): Promise<any> {
7680

77-
if (this.isLeaveCommand(requestedCommandName)) {
81+
ctx.sendResponse = sendResponse
82+
ctx.leaveScene = super._handleLeaveScene
83+
ctx.enterScene = super._handleEnterScene
84+
85+
const requestedCommands = await this.commands.search(ctx)
86+
87+
if (this.isLeaveCommand(ctx.message)) {
7888
this._handleLeaveScene()
7989
}
8090

81-
const ctx = new Ctx({
82-
req,
83-
sendResponse: sendResponse || null,
84-
leaveScene: super._handleLeaveScene,
85-
enterScene: super._handleEnterScene,
86-
session,
87-
})
88-
8991
if (requestedCommands.length !== 0) {
9092
const requestedCommand = requestedCommands[0]
91-
return await requestedCommand.callback.call(this, ctx)
93+
return await requestedCommand.callback(ctx)
9294
}
9395

9496
if (this.anyCallback) {
95-
return this.anyCallback(ctx)
97+
return await this.anyCallback(ctx)
9698
}
9799

98-
return null
100+
return Promise.resolve()
99101
}
100102
}
101103

0 commit comments

Comments
 (0)