Skip to content

Commit c9e0bac

Browse files
joeyguerraJoey Guerra
andauthored
chore(docs): fix #1813 and other doc inconsistencies (#1821)
Co-authored-by: Joey Guerra <joey@joeyguerra.com>
1 parent 1057f5d commit c9e0bac

File tree

2 files changed

+57
-35
lines changed

2 files changed

+57
-35
lines changed

docs/patterns.md

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ Setting this up is very easy:
2929
// Commands:
3030
// None
3131

32-
module.exports = (robot) => {
33-
robot.hear(/^hubot:? (.+)/i, (res) => {
32+
export default async (robot) => {
33+
robot.hear(/^hubot:? (.+)/i, async (res) => {
3434
let response = `Sorry, I'm a diva and only respond to ${robot.name}`
3535
response += robot.alias ? ` or ${robot.alias}` : ''
36-
return res.reply(response)
36+
return await res.reply(response)
3737
})
3838
}
3939
```
@@ -63,9 +63,9 @@ Here is the setup:
6363
// Commands:
6464
// None
6565
//
66-
module.exports = (robot) => {
67-
robot.respond(/help\s*(.*)?$/i, (res) => {
68-
return res.reply('That means nothing to me anymore. Perhaps you meant "docs" instead?')
66+
export default async (robot) => {
67+
robot.respond(/help\s*(.*)?$/i, async (res) => {
68+
return await res.reply('That means nothing to me anymore. Perhaps you meant "docs" instead?')
6969
})
7070
}
7171

@@ -80,26 +80,30 @@ To do this, you can set up a lock in the Hubot [brain](scripting.html#persistenc
8080
Setting up the lock looks something like this:
8181

8282
```javascript
83-
module.exports = (robot) => {
84-
robot.brain.on('loaded', ()=>{
83+
export default async (robot) => {
84+
robot.brain.on('loaded', () => {
8585
// Clear the lock on startup in case Hubot has restarted and Hubot's brain has persistence (e.g. redis).
8686
// We don't want any orphaned locks preventing us from running commands.
8787
robot.brain.remove('yourLockName')
88-
}
88+
})
8989

90-
robot.respond(/longrunningthing/i, (msg) => {
90+
robot.respond(/longrunningthing/i, async (msg) => {
9191
const lock = robot.brain.get('yourLockName')
9292
if (lock) {
93-
return msg.send(`I'm sorry, ${msg.message.user.name}, I'm afraid I can't do that. I'm busy doing something for ${lock.user.name}.`)
93+
return await msg.send(`I'm sorry, ${msg.message.user.name}, I'm afraid I can't do that. I'm busy doing something for ${lock.user.name}.`)
9494
}
9595

9696
robot.brain.set('yourLockName', msg.message) // includes user, room, etc about who locked
9797

98-
yourLongClobberingAsyncThing(err, res).then(
98+
try {
99+
await yourLongClobberingAsyncThing()
99100
// Clear the lock
100101
robot.brain.remove('yourLockName')
101-
msg.reply('Finally Done')
102-
)).catch(e => console.error(e))
102+
await msg.reply('Finally Done')
103+
} catch (e) {
104+
console.error(e)
105+
}
106+
})
103107
}
104108
```
105109

@@ -114,8 +118,8 @@ Due to the way Node.js handles HTTP and HTTPS requests, you need to specify a di
114118
3. Add the following code, modified for your needs:
115119

116120
```javascript
117-
const proxy = require('proxy-agent')
118-
module.exports = (robot) => {
121+
import proxy from 'proxy-agent'
122+
export default async (robot) => {
119123
robot.globalHttpOptions.httpAgent = proxy('http://my-proxy-server.internal', false)
120124
robot.globalHttpOptions.httpsAgent = proxy('http://my-proxy-server.internal', true)
121125
}
@@ -133,8 +137,8 @@ For example, the [factoid lookup command](https://github.com/github/hubot-script
133137
// use case: Hubot>fact1
134138
// This listener doesn't require you to type the bot's name first
135139

136-
const {TextMessage} = require('../src/message')
137-
module.exports = (robot) => {
140+
import {TextMessage} from '../src/message.mjs'
141+
export default async (robot) => {
138142
// Dynamically populated list of factoids
139143
const facts = {
140144
fact1: 'stuff',
@@ -157,9 +161,9 @@ module.exports = (robot) => {
157161
}
158162
},
159163
// Callback
160-
(res) => {
164+
async (res) => {
161165
const fact = res.match
162-
res.reply(`${fact} is ${facts[fact]}`)
166+
await res.reply(`${fact} is ${facts[fact]}`)
163167
}
164168
)
165169
}
@@ -207,28 +211,28 @@ const POWER_USERS = [
207211
'Shell' // String that matches the user ID set by the adapter
208212
]
209213

210-
module.exports = (robot) => {
211-
robot.listenerMiddleware((context, next, done) => {
214+
export default async (robot) => {
215+
robot.listenerMiddleware(async (context) => {
212216
if (POWER_COMMANDS.indexOf(context.listener.options.id) > -1) {
213217
if (POWER_USERS.indexOf(context.response.message.user.name) > -1){
214218
// User is allowed access to this command
215-
next()
219+
return true
216220
} else {
217221
// Restricted command, but user isn't in whitelist
218-
context.response.reply(`I'm sorry, @${context.response.message.user.name}, but you don't have access to do that.`)
219-
done()
222+
await context.response.reply(`I'm sorry, @${context.response.message.user.name}, but you don't have access to do that.`)
223+
return false
220224
}
221225
} else {
222226
// This is not a restricted command; allow everyone
223-
next()
227+
return true
224228
}
225229
})
226230

227231
robot.listen(message => {
228232
return true
229233
}, {id: 'deploy.web'},
230-
res => {
231-
res.reply('Deploying web...')
234+
async res => {
235+
await res.reply('Deploying web...')
232236
})
233237
}
234238
```

docs/scripting.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ Every middleware receives the same API signature of `context`. Different kinds o
842842
843843
Asynchronous middleware should catch its own exceptions, emit an `error` event, and return `true` or `false`. Any uncaught exceptions will interrupt all execution of middleware.
844844
845-
# <a name="listener-middleware">Listener Middleware</a>
845+
## Listener Middleware
846846
847847
Listener middleware inserts logic between the listener matching a message and the listener executing. This allows you to create extensions that run for every matching script. Examples include centralized authorization policies, rate limiting, logging, and metrics. Middleware is implemented like other hubot scripts: instead of using the `hear` and `respond` methods, middleware is registered using `listenerMiddleware`.
848848
@@ -965,21 +965,39 @@ Response middleware runs against every message hubot sends to a chat room. It's
965965
966966
## Response Middleware Example
967967
968-
This simple example changes the format of links sent to a chat room from markdown links (like [example](https://example.com)) to the format supported by [Slack](https://slack.com), <https://example.com|example>.
968+
Response middleware allows you to intercept and modify outgoing messages before they're sent to the chat room. The `context.strings` array contains the actual message text that will be sent.
969+
970+
This example changes the format of links from markdown links (like [example](https://example.com)) to the format supported by [Slack](https://slack.com), <https://example.com|example>:
969971
970972
```javascript
971973
// .mjs
972-
export default async robot=> {
973-
robot.responseMiddleware(async context=> {
974-
if(!context.plaintext) return true
975-
context.strings.forEach(string => {
976-
string.replace(/\[([^\[\]]*?)\]\((https?:\/\/.*?)\)/, "<$2|$1>"
974+
export default async robot => {
975+
robot.responseMiddleware(async context => {
976+
// Only process plaintext messages (send, reply, etc.)
977+
if (!context.plaintext) return true
978+
979+
// Modify each string in the response
980+
context.strings = context.strings.map(string => {
981+
// Convert markdown links to Slack format
982+
return string.replace(/\[([^\[\]]*?)\]\((https?:\/\/.*?)\)/, "<$2|$1>")
977983
})
984+
978985
return true
979986
})
980987
}
981988
```
982989
990+
## How to Use Response Middleware
991+
992+
Response middleware is called every time a message is sent from a listener. Key points:
993+
994+
- Access the outgoing message strings via `context.strings` - this is an array of strings being sent
995+
- Modify the strings by reassigning `context.strings` or mapping over the array
996+
- The `context.method` tells you how the message was sent (`send`, `reply`, `emote`, etc.)
997+
- Return `true` to allow the message to continue to the adapter, or `false` to stop it
998+
- Be careful not to create infinite loops by sending new messages from middleware, as they will also trigger middleware
999+
- Use `context.plaintext` to distinguish between regular messages and other message types
1000+
9831001
## Response Middleware API
9841002
9851003
Response middleware callbacks receive 1 parameters, `context` and are Promises/async/await. Receive middleware context includes these fields:

0 commit comments

Comments
 (0)