hubot 8.0.3 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hubot",
3
- "version": "8.0.3",
3
+ "version": "8.1.0",
4
4
  "author": "hubot",
5
5
  "keywords": [
6
6
  "github",
@@ -15,28 +15,26 @@
15
15
  "url": "https://github.com/hubotio/hubot.git"
16
16
  },
17
17
  "dependencies": {
18
- "async": "^3.2.4",
19
18
  "cline": "^0.8.2",
20
19
  "coffeescript": "^2.7.0",
21
20
  "connect-multiparty": "^2.2.0",
22
21
  "express": "^4.18.2",
23
22
  "express-basic-auth": "^1.2.1",
24
23
  "optparse": "^1.0.5",
25
- "pino": "^8.11.0",
26
- "standard": "^17.1.0"
24
+ "pino": "^8.11.0"
27
25
  },
28
26
  "devDependencies": {
29
27
  "chai": "^4.3.7",
30
28
  "is-circular": "^1.0.2",
31
29
  "mocha": "^10.2.0",
32
- "mockery": "^2.1.0",
33
30
  "semantic-release": "^21.0.1",
34
31
  "sinon": "^15.0.4",
35
- "sinon-chai": "^3.7.0"
32
+ "sinon-chai": "^3.7.0",
33
+ "standard": "^17.1.0"
36
34
  },
37
35
  "engines": {
38
- "node": "> 4.0.0",
39
- "npm": "> 2.0.0"
36
+ "node": "> 16.20.2",
37
+ "npm": "> 8.19.4"
40
38
  },
41
39
  "main": "./index",
42
40
  "bin": {
package/src/adapter.js CHANGED
@@ -16,8 +16,8 @@ class Adapter extends EventEmitter {
16
16
  // envelope - A Object with message, room and user details.
17
17
  // strings - One or more Strings for each message to send.
18
18
  //
19
- // Returns nothing.
20
- send (envelope/* , ...strings */) {}
19
+ // Returns results from adapter.
20
+ async send (envelope, ...strings) {}
21
21
 
22
22
  // Public: Raw method for sending emote data back to the chat source.
23
23
  // Defaults as an alias for send
@@ -25,10 +25,9 @@ class Adapter extends EventEmitter {
25
25
  // envelope - A Object with message, room and user details.
26
26
  // strings - One or more Strings for each message to send.
27
27
  //
28
- // Returns nothing.
29
- emote (envelope/* , ...strings */) {
30
- const strings = [].slice.call(arguments, 1)
31
- return this.send.apply(this, [envelope].concat(strings))
28
+ // Returns results from adapter.
29
+ async emote (envelope, ...strings) {
30
+ return this.senda(envelope, ...strings)
32
31
  }
33
32
 
34
33
  // Public: Raw method for building a reply and sending it back to the chat
@@ -37,24 +36,24 @@ class Adapter extends EventEmitter {
37
36
  // envelope - A Object with message, room and user details.
38
37
  // strings - One or more Strings for each reply to send.
39
38
  //
40
- // Returns nothing.
41
- reply (envelope/* , ...strings */) {}
39
+ // Returns results from adapter.
40
+ async reply (envelope, ...strings) {}
42
41
 
43
42
  // Public: Raw method for setting a topic on the chat source. Extend this.
44
43
  //
45
44
  // envelope - A Object with message, room and user details.
46
45
  // strings - One more more Strings to set as the topic.
47
46
  //
48
- // Returns nothing.
49
- topic (envelope/* , ...strings */) {}
47
+ // Returns results from adapter.
48
+ async topic (envelope, ...strings) {}
50
49
 
51
50
  // Public: Raw method for playing a sound in the chat source. Extend this.
52
51
  //
53
52
  // envelope - A Object with message, room and user details.
54
53
  // strings - One or more strings for each play message to send.
55
54
  //
56
- // Returns nothing
57
- play (envelope/* , ...strings */) {}
55
+ // Returns results from adapter.
56
+ async play (envelope, ...strings) {}
58
57
 
59
58
  // Public: Raw method for invoking the bot to run. Extend this.
60
59
  //
@@ -69,8 +68,8 @@ class Adapter extends EventEmitter {
69
68
  // Public: Dispatch a received message to the robot.
70
69
  //
71
70
  // Returns nothing.
72
- receive (message) {
73
- this.robot.receive(message)
71
+ async receive (message) {
72
+ await this.robot.receive(message)
74
73
  }
75
74
 
76
75
  // Public: Get an Array of User objects stored in the brain.
@@ -22,21 +22,17 @@ class Shell extends Adapter {
22
22
  this.name = 'Shell'
23
23
  }
24
24
 
25
- send (envelope/* , ...strings */) {
26
- const strings = [].slice.call(arguments, 1)
27
-
25
+ async send (envelope, ...strings) {
28
26
  Array.from(strings).forEach(str => console.log(bold(str)))
29
27
  }
30
28
 
31
- emote (envelope/* , ...strings */) {
32
- const strings = [].slice.call(arguments, 1)
29
+ async emote (envelope, ...strings) {
33
30
  Array.from(strings).map(str => this.send(envelope, `* ${str}`))
34
31
  }
35
32
 
36
- reply (envelope/* , ...strings */) {
37
- const strings = [].slice.call(arguments, 1).map((s) => `${envelope.user.name}: ${s}`)
38
-
39
- this.send.apply(this, [envelope].concat(strings))
33
+ async reply (envelope, ...strings) {
34
+ strings = strings.map((s) => `${envelope.user.name}: ${s}`)
35
+ this.send(envelope, ...strings)
40
36
  }
41
37
 
42
38
  run () {
package/src/listener.js CHANGED
@@ -20,19 +20,19 @@ class Listener {
20
20
  constructor (robot, matcher, options, callback) {
21
21
  this.robot = robot
22
22
  this.matcher = matcher
23
- this.options = options
23
+ this.options = options ?? {}
24
24
  this.callback = callback
25
25
 
26
26
  if (this.matcher == null) {
27
27
  throw new Error('Missing a matcher for Listener')
28
28
  }
29
29
 
30
- if (this.callback == null) {
30
+ if (!this.callback) {
31
31
  this.callback = this.options
32
32
  this.options = {}
33
33
  }
34
34
 
35
- if (this.options.id == null) {
35
+ if (!this.options?.id) {
36
36
  this.options.id = null
37
37
  }
38
38
 
@@ -49,60 +49,40 @@ class Listener {
49
49
  //
50
50
  // message - A Message instance.
51
51
  // middleware - Optional Middleware object to execute before the Listener callback
52
- // callback - Optional Function called with a boolean of whether the matcher matched
53
52
  //
54
- // Returns a boolean of whether the matcher matched.
55
- // Returns before executing callback
56
- call (message, middleware, didMatchCallback) {
57
- // middleware argument is optional
58
- if (didMatchCallback == null && typeof middleware === 'function') {
59
- didMatchCallback = middleware
60
- middleware = undefined
53
+ // Returns the result of the callback.
54
+ async call (message, middleware) {
55
+ if (middleware && typeof middleware === 'function') {
56
+ const fn = middleware
57
+ middleware = new Middleware(this.robot)
58
+ middleware.register(fn)
61
59
  }
62
60
 
63
- // ensure we have a Middleware object
64
- if (middleware == null) {
61
+ if (!middleware) {
65
62
  middleware = new Middleware(this.robot)
66
63
  }
67
64
 
68
65
  const match = this.matcher(message)
69
- if (match) {
70
- if (this.regex) {
71
- this.robot.logger.debug(`Message '${message}' matched regex /${inspect(this.regex)}/; listener.options = ${inspect(this.options)}`)
72
- }
73
-
74
- // special middleware-like function that always executes the Listener's
75
- // callback and calls done (never calls 'next')
76
- const executeListener = (context, done) => {
77
- this.robot.logger.debug(`Executing listener callback for Message '${message}'`)
78
- try {
79
- this.callback(context.response)
80
- } catch (err) {
81
- this.robot.emit('error', err, context.response)
82
- }
83
- done()
84
- }
66
+ if (!match) return null
67
+ if (this.regex) {
68
+ this.robot.logger.debug(`Message '${message}' matched regex /${inspect(this.regex)}/; listener.options = ${inspect(this.options)}`)
69
+ }
85
70
 
86
- // When everything is finished (down the middleware stack and back up),
87
- // pass control back to the robot
88
- const allDone = function allDone () {
89
- // Yes, we tried to execute the listener callback (middleware may
90
- // have intercepted before actually executing though)
91
- if (didMatchCallback != null) {
92
- process.nextTick(() => didMatchCallback(true))
93
- }
94
- }
71
+ const response = new this.robot.Response(this.robot, message, match)
95
72
 
96
- const response = new this.robot.Response(this.robot, message, match)
97
- middleware.execute({ listener: this, response }, executeListener, allDone)
98
- return true
99
- } else {
100
- if (didMatchCallback != null) {
101
- // No, we didn't try to execute the listener callback
102
- process.nextTick(() => didMatchCallback(false))
103
- }
104
- return false
73
+ try {
74
+ const shouldContinue = await middleware.execute({ listener: this, response })
75
+ if (shouldContinue === false) return null
76
+ } catch (e) {
77
+ this.robot.logger.error(`Error executing middleware for listener: ${e.stack}`)
78
+ }
79
+ try {
80
+ return await this.callback(response)
81
+ } catch (e) {
82
+ this.robot.logger.error(`Error executing listener callback: ${e.stack}`)
83
+ this.robot.emit('error', e, response)
105
84
  }
85
+ return null
106
86
  }
107
87
  }
108
88
 
package/src/message.js CHANGED
@@ -7,7 +7,7 @@ class Message {
7
7
  constructor (user, done) {
8
8
  this.user = user
9
9
  this.done = done || false
10
- this.room = this.user.room
10
+ this.room = this.user?.room
11
11
  }
12
12
 
13
13
  // Indicates that no other Listener should be called on this object
package/src/middleware.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const async = require('async')
4
-
5
3
  class Middleware {
6
4
  constructor (robot) {
7
5
  this.robot = robot
@@ -16,68 +14,29 @@ class Middleware {
16
14
  // context - context object that is passed through the middleware stack.
17
15
  // When handling errors, this is assumed to have a `response` property.
18
16
  //
19
- // next(context, done) - Called when all middleware is complete (assuming
20
- // all continued by calling respective 'next' functions)
21
- //
22
- // done() - Initial (final) completion callback. May be wrapped by
23
- // executed middleware.
24
- //
25
- // Returns nothing
26
- // Returns before executing any middleware
27
- execute (context, next, done) {
28
- const self = this
29
-
30
- if (done == null) {
31
- done = function () {}
32
- }
33
-
34
- // Execute a single piece of middleware and update the completion callback
35
- // (each piece of middleware can wrap the 'done' callback with additional
36
- // logic).
37
- function executeSingleMiddleware (doneFunc, middlewareFunc, cb) {
38
- // Match the async.reduce interface
39
- function nextFunc (newDoneFunc) {
40
- cb(null, newDoneFunc || doneFunc)
41
- }
42
-
43
- // Catch errors in synchronous middleware
17
+ // Returns bool, true | false, whether or not to continue execution
18
+ async execute (context) {
19
+ let shouldContinue = true
20
+ for await (const middleware of this.stack) {
44
21
  try {
45
- middlewareFunc(context, nextFunc, doneFunc)
46
- } catch (err) {
47
- // Maintaining the existing error interface (Response object)
48
- self.robot.emit('error', err, context.response)
49
- // Forcibly fail the middleware and stop executing deeper
50
- doneFunc()
22
+ shouldContinue = await middleware(context)
23
+ if (shouldContinue === false) break
24
+ } catch (e) {
25
+ this.robot.emit('error', e, context.response)
26
+ break
51
27
  }
52
28
  }
53
-
54
- // Executed when the middleware stack is finished
55
- function allDone (_, finalDoneFunc) {
56
- next(context, finalDoneFunc)
57
- }
58
-
59
- // Execute each piece of middleware, collecting the latest 'done' callback
60
- // at each step.
61
- process.nextTick(async.reduce.bind(null, this.stack, done, executeSingleMiddleware, allDone))
29
+ return shouldContinue
62
30
  }
63
31
 
64
32
  // Public: Registers new middleware
65
33
  //
66
- // middleware - A generic pipeline component function that can either
67
- // continue the pipeline or interrupt it. The function is called
68
- // with (robot, context, next, done). If execution should
69
- // continue (next middleware, final callback), the middleware
70
- // should call the 'next' function with 'done' as an optional
71
- // argument.
72
- // If not, the middleware should call the 'done' function with
73
- // no arguments. Middleware may wrap the 'done' function in
74
- // order to execute logic after the final callback has been
75
- // executed.
34
+ // middleware - Middleware function to execute prior to the listener callback. Return false to prevent execution of the listener callback.
76
35
  //
77
36
  // Returns nothing.
78
37
  register (middleware) {
79
- if (middleware.length !== 3) {
80
- throw new Error(`Incorrect number of arguments for middleware callback (expected 3, got ${middleware.length})`)
38
+ if (middleware.length !== 1) {
39
+ throw new Error(`Incorrect number of arguments for middleware callback (expected 1, got ${middleware.length})`)
81
40
  }
82
41
  this.stack.push(middleware)
83
42
  }
package/src/response.js CHANGED
@@ -14,8 +14,7 @@ class Response {
14
14
  this.match = match
15
15
  this.envelope = {
16
16
  room: this.message.room,
17
- user: this.message.user,
18
- message: this.message
17
+ user: this.message.user
19
18
  }
20
19
  }
21
20
 
@@ -24,10 +23,9 @@ class Response {
24
23
  // strings - One or more strings to be posted. The order of these strings
25
24
  // should be kept intact.
26
25
  //
27
- // Returns nothing.
28
- send (/* ...strings */) {
29
- const strings = [].slice.call(arguments)
30
- this.runWithMiddleware.apply(this, ['send', { plaintext: true }].concat(strings))
26
+ // Returns result from middleware.
27
+ async send (...strings) {
28
+ return await this.#runWithMiddleware('send', { plaintext: true }, ...strings)
31
29
  }
32
30
 
33
31
  // Public: Posts an emote back to the chat source
@@ -35,10 +33,9 @@ class Response {
35
33
  // strings - One or more strings to be posted. The order of these strings
36
34
  // should be kept intact.
37
35
  //
38
- // Returns nothing.
39
- emote (/* ...strings */) {
40
- const strings = [].slice.call(arguments)
41
- this.runWithMiddleware.apply(this, ['emote', { plaintext: true }].concat(strings))
36
+ // Returns result from middleware.
37
+ async emote (...strings) {
38
+ return await this.#runWithMiddleware('emote', { plaintext: true }, ...strings)
42
39
  }
43
40
 
44
41
  // Public: Posts a message mentioning the current user.
@@ -46,10 +43,9 @@ class Response {
46
43
  // strings - One or more strings to be posted. The order of these strings
47
44
  // should be kept intact.
48
45
  //
49
- // Returns nothing.
50
- reply (/* ...strings */) {
51
- const strings = [].slice.call(arguments)
52
- this.runWithMiddleware.apply(this, ['reply', { plaintext: true }].concat(strings))
46
+ // Returns result from middleware.
47
+ async reply (...strings) {
48
+ return await this.#runWithMiddleware('reply', { plaintext: true }, ...strings)
53
49
  }
54
50
 
55
51
  // Public: Posts a topic changing message
@@ -57,10 +53,9 @@ class Response {
57
53
  // strings - One or more strings to set as the topic of the
58
54
  // room the bot is in.
59
55
  //
60
- // Returns nothing.
61
- topic (/* ...strings */) {
62
- const strings = [].slice.call(arguments)
63
- this.runWithMiddleware.apply(this, ['topic', { plaintext: true }].concat(strings))
56
+ // Returns result from middleware.
57
+ async topic (...strings) {
58
+ return await this.#runWithMiddleware('topic', { plaintext: true }, ...strings)
64
59
  }
65
60
 
66
61
  // Public: Play a sound in the chat source
@@ -68,10 +63,9 @@ class Response {
68
63
  // strings - One or more strings to be posted as sounds to play. The order of
69
64
  // these strings should be kept intact.
70
65
  //
71
- // Returns nothing
72
- play (/* ...strings */) {
73
- const strings = [].slice.call(arguments)
74
- this.runWithMiddleware.apply(this, ['play'].concat(strings))
66
+ // Returns result from middleware.
67
+ async play (...strings) {
68
+ return await this.#runWithMiddleware('play', ...strings)
75
69
  }
76
70
 
77
71
  // Public: Posts a message in an unlogged room
@@ -79,27 +73,17 @@ class Response {
79
73
  // strings - One or more strings to be posted. The order of these strings
80
74
  // should be kept intact.
81
75
  //
82
- // Returns nothing
83
- locked (/* ...strings */) {
84
- const strings = [].slice.call(arguments)
85
- this.runWithMiddleware.apply(this, ['locked', { plaintext: true }].concat(strings))
76
+ // Returns result from middleware.
77
+ async locked (...strings) {
78
+ await this.#runWithMiddleware('locked', { plaintext: true }, ...strings)
86
79
  }
87
80
 
88
- // Private: Call with a method for the given strings using response
81
+ // Call with a method for the given strings using response
89
82
  // middleware.
90
- runWithMiddleware (methodName, opts/* , ...strings */) {
91
- const self = this
92
- const strings = [].slice.call(arguments, 2)
93
- const copy = strings.slice(0)
94
- let callback
95
-
96
- if (typeof copy[copy.length - 1] === 'function') {
97
- callback = copy.pop()
98
- }
99
-
83
+ async #runWithMiddleware (methodName, opts, ...strings) {
100
84
  const context = {
101
85
  response: this,
102
- strings: copy,
86
+ strings,
103
87
  method: methodName
104
88
  }
105
89
 
@@ -107,17 +91,9 @@ class Response {
107
91
  context.plaintext = true
108
92
  }
109
93
 
110
- function responseMiddlewareDone () {}
111
- function runAdapterSend (_, done) {
112
- const result = context.strings
113
- if (callback != null) {
114
- result.push(callback)
115
- }
116
- self.robot.adapter[methodName].apply(self.robot.adapter, [self.envelope].concat(result))
117
- done()
118
- }
119
-
120
- return this.robot.middleware.response.execute(context, runAdapterSend, responseMiddlewareDone)
94
+ const shouldContinue = await this.robot.middleware.response.execute(context)
95
+ if (shouldContinue === false) return
96
+ return await this.robot.adapter[methodName](this.envelope, ...context.strings)
121
97
  }
122
98
 
123
99
  // Public: Picks a random item from the given items.
package/src/robot.js CHANGED
@@ -4,7 +4,6 @@ const fs = require('fs')
4
4
  const path = require('path')
5
5
  const pathToFileURL = require('url').pathToFileURL
6
6
 
7
- const async = require('async')
8
7
  const pino = require('pino')
9
8
  const HttpClient = require('./httpclient')
10
9
 
@@ -244,11 +243,8 @@ class Robot {
244
243
  //
245
244
  // middleware - A function that determines whether or not a given matching
246
245
  // Listener should be executed. The function is called with
247
- // (context, next, done). If execution should
248
- // continue (next middleware, Listener callback), the middleware
249
- // should call the 'next' function with 'done' as an argument.
250
- // If not, the middleware should call the 'done' function with
251
- // no arguments.
246
+ // (context). If execution should, the middleware should return
247
+ // true. If not, the middleware should return false.
252
248
  //
253
249
  // Returns nothing.
254
250
  listenerMiddleware (middleware) {
@@ -260,9 +256,8 @@ class Robot {
260
256
  //
261
257
  // middleware - A function that examines an outgoing message and can modify
262
258
  // it or prevent its sending. The function is called with
263
- // (context, next, done). If execution should continue,
264
- // the middleware should call next(done). If execution should
265
- // stop, the middleware should call done(). To modify the
259
+ // (context). If execution should continue, return true
260
+ // otherwise return false to stop. To modify the
266
261
  // outgoing message, set context.string to a new message.
267
262
  //
268
263
  // Returns nothing.
@@ -273,11 +268,10 @@ class Robot {
273
268
  // Public: Registers new middleware for execution before matching
274
269
  //
275
270
  // middleware - A function that determines whether or not listeners should be
276
- // checked. The function is called with (context, next, done). If
277
- // ext, next, done). If execution should continue to the next
278
- // middleware or matching phase, it should call the 'next'
279
- // function with 'done' as an argument. If not, the middleware
280
- // should call the 'done' function with no arguments.
271
+ // checked. The function is called with (context). If execution
272
+ // should continue to the next
273
+ // middleware or matching phase, it should return true or nothing
274
+ // otherwise return false to stop.
281
275
  //
282
276
  // Returns nothing.
283
277
  receiveMiddleware (middleware) {
@@ -290,14 +284,12 @@ class Robot {
290
284
  // message - A Message instance. Listeners can flag this message as 'done' to
291
285
  // prevent further execution.
292
286
  //
293
- // cb - Optional callback that is called when message processing is complete
294
- //
295
- // Returns nothing.
296
- // Returns before executing callback
297
- receive (message, cb) {
298
- // When everything is finished (down the middleware stack and back up),
299
- // pass control back to the robot
300
- this.middleware.receive.execute({ response: new Response(this, message) }, this.processListeners.bind(this), cb)
287
+ // Returns array of results from listeners.
288
+ async receive (message) {
289
+ const context = { response: new Response(this, message) }
290
+ const shouldContinue = await this.middleware.receive.execute(context)
291
+ if (shouldContinue === false) return null
292
+ return await this.processListeners(context)
301
293
  }
302
294
 
303
295
  // Private: Passes the given message to any interested Listeners.
@@ -305,45 +297,40 @@ class Robot {
305
297
  // message - A Message instance. Listeners can flag this message as 'done' to
306
298
  // prevent further execution.
307
299
  //
308
- // done - Optional callback that is called when message processing is complete
309
- //
310
- // Returns nothing.
311
- // Returns before executing callback
312
- processListeners (context, done) {
300
+ // Returns array of results from listeners.
301
+ async processListeners (context) {
313
302
  // Try executing all registered Listeners in order of registration
314
303
  // and return after message is done being processed
304
+ const results = []
315
305
  let anyListenersExecuted = false
316
-
317
- async.detectSeries(this.listeners, (listener, done) => {
306
+ for await (const listener of this.listeners) {
318
307
  try {
319
- listener.call(context.response.message, this.middleware.listener, function (listenerExecuted) {
320
- anyListenersExecuted = anyListenersExecuted || listenerExecuted
321
- // Defer to the event loop at least after every listener so the
322
- // stack doesn't get too big
323
- process.nextTick(() =>
324
- // Stop processing when message.done == true
325
- done(null, context.response.message.done)
326
- )
327
- })
308
+ const match = listener.matcher(context.response.message)
309
+ if (!match) {
310
+ continue
311
+ }
312
+ const result = await listener.call(context.response.message, this.middleware.listener)
313
+ results.push(result)
314
+ anyListenersExecuted = true
328
315
  } catch (err) {
329
- this.emit('error', err, new this.Response(this, context.response.message, []))
330
- // Continue to next listener when there is an error
331
- done(null, false)
316
+ this.emit('error', err, context)
332
317
  }
333
- },
334
- // Ignore the result ( == the listener that set message.done = true)
335
- _ => {
336
- // If no registered Listener matched the message
337
-
338
- if (!(context.response.message instanceof Message.CatchAllMessage) && !anyListenersExecuted) {
339
- this.logger.debug('No listeners executed; falling back to catch-all')
340
- this.receive(new Message.CatchAllMessage(context.response.message), done)
341
- } else {
342
- if (done != null) {
343
- process.nextTick(done)
344
- }
318
+ if (context.response.message.done) {
319
+ break
345
320
  }
346
- })
321
+ }
322
+
323
+ if (!isCatchAllMessage(context.response.message) && !anyListenersExecuted) {
324
+ this.logger.debug('No listeners executed; falling back to catch-all')
325
+ try {
326
+ const result = await this.receive(new Message.CatchAllMessage(context.response.message))
327
+ results.push(result)
328
+ } catch (err) {
329
+ this.emit('error', err, context)
330
+ }
331
+ }
332
+
333
+ return results
347
334
  }
348
335
 
349
336
  async loadmjs (filePath) {
@@ -616,10 +603,8 @@ class Robot {
616
603
  // strings - One or more Strings for each message to send.
617
604
  //
618
605
  // Returns whatever the extending adapter returns.
619
- send (envelope/* , ...strings */) {
620
- const strings = [].slice.call(arguments, 1)
621
-
622
- return this.adapter.send.apply(this.adapter, [envelope].concat(strings))
606
+ async send (envelope, ...strings) {
607
+ return await this.adapter.send(envelope, ...strings)
623
608
  }
624
609
 
625
610
  // Public: A helper reply function which delegates to the adapter's reply
@@ -629,10 +614,8 @@ class Robot {
629
614
  // strings - One or more Strings for each message to send.
630
615
  //
631
616
  // Returns whatever the extending adapter returns.
632
- reply (envelope/* , ...strings */) {
633
- const strings = [].slice.call(arguments, 1)
634
-
635
- return this.adapter.reply.apply(this.adapter, [envelope].concat(strings))
617
+ async reply (envelope, ...strings) {
618
+ return await this.adapter.reply(envelope, ...strings)
636
619
  }
637
620
 
638
621
  // Public: A helper send function to message a room that the robot is in.
@@ -641,11 +624,9 @@ class Robot {
641
624
  // strings - One or more Strings for each message to send.
642
625
  //
643
626
  // Returns whatever the extending adapter returns.
644
- messageRoom (room/* , ...strings */) {
645
- const strings = [].slice.call(arguments, 1)
627
+ async messageRoom (room, ...strings) {
646
628
  const envelope = { room }
647
-
648
- return this.adapter.send.apply(this.adapter, [envelope].concat(strings))
629
+ return await this.adapter.send(envelope, ...strings)
649
630
  }
650
631
 
651
632
  // Public: A wrapper around the EventEmitter API to make usage
@@ -656,10 +637,8 @@ class Robot {
656
637
  // when event happens.
657
638
  //
658
639
  // Returns nothing.
659
- on (event/* , ...args */) {
660
- const args = [].slice.call(arguments, 1)
661
-
662
- this.events.on.apply(this.events, [event].concat(args))
640
+ on (event, ...args) {
641
+ this.events.on(event, ...args)
663
642
  }
664
643
 
665
644
  // Public: A wrapper around the EventEmitter API to make usage
@@ -669,10 +648,8 @@ class Robot {
669
648
  // args... - Arguments emitted by the event
670
649
  //
671
650
  // Returns nothing.
672
- emit (event/* , ...args */) {
673
- const args = [].slice.call(arguments, 1)
674
-
675
- this.events.emit.apply(this.events, [event].concat(args))
651
+ emit (event, ...args) {
652
+ this.events.emit(event, ...args)
676
653
  }
677
654
 
678
655
  // Public: Kick off the event loop for the adapter