-
Notifications
You must be signed in to change notification settings - Fork 399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue 284 regex events #763
Conversation
1c9234c
to
b0378dd
Compare
Hi @pdontha 👋🏻 thanks for the pull request and welcome as a first-time contributor to Bolt JS! I've added a few reviewers to this pull request who can work with you to merge and release your work. In the meantime, can you please sign our CLA. You can do this by selecting the link in the CLAssistant message and signing the CLA with the same email address associated with your commits. I've also noticed that our CI is failing due to linting errors. Would you mind running Thanks again for the pull request! |
Codecov Report
@@ Coverage Diff @@
## main #763 +/- ##
==========================================
+ Coverage 65.24% 65.47% +0.22%
==========================================
Files 11 11
Lines 1082 1089 +7
Branches 320 323 +3
==========================================
+ Hits 706 713 +7
Misses 317 317
Partials 59 59
Continue to review full report at Codecov.
|
Thank you! I have signed the CLA with the correct email address. All fixed now. |
src/App.ts
Outdated
): void { | ||
this.listeners.push([onlyEvents, matchEventType(eventName), ...listeners] as Middleware<AnyMiddlewareArgs>[]); | ||
const eventMiddleware = patternsOrMiddleware.map((patternOrMiddleware) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there any limit to the number of event name or patterns that can precede the listener function? for example, should we allow the following?
app.event('app_home_opened', 'app_mentioned', async () => {
/* ... some listener code ... */
});
the way the PR is currently written, this call would be valid, but what does it mean? is it meant to allow the listener to be called when either an app_home_opened
event or an app_mentioned
event is triggered? let's take a look at what this set of arguments expands into for the line below, where the listeners are being stored.
this.listeners.push([
onlyEvents,
matchEventType('app_home_opened'),
matchEventType('app_mentioned'),
async () => { /* ... some listener code ... */ }
]);
now its a little easier to see how an incoming event is eventually makes its way to the listener. the event is processed through each middleware in the array, starting from the beginning. onlyEvents
will filter out any event that isn't from the Events API (makes sense, app.event()
is only for these kinds of events). matchEventType('app_home_opened')
will filter out any event that doesn't have a type
matching app_home_opened
. likewise matchEventType('app_mentioned')
will filter out any event that doesn't have a type
matching app_mentioned
.
but wait this means in order for the listener to be called, the incoming event mush both match app_home_opened
and app_mentioned
. earlier, my guess was that it was either, however now we know that's not the case. in fact, can any event type
actually match several names? is that a useful thing to implement?
hint: regular expressions are great at expressing how patterns should compose to form a match. what do i mean by "how patterns should compose?". specifically, the idea of AND versus OR between patterns can be expressed through a regular expression. /app_home_opened|app_mentioned/
is a perfectly reasonable way to express that the type should match either those two types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the code review and comments! It was very helpful in understanding the issue. There should be only one event name or pattern preceding the listener function. I have fixed the issue and committed the changes.
src/App.ts
Outdated
): void { | ||
this.listeners.push([onlyEvents, matchEventType(eventName), ...listeners] as Middleware<AnyMiddlewareArgs>[]); | ||
const eventMiddleware = patternsOrMiddleware.map((patternOrMiddleware) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this code imply about the order of patterns versus the listener? specifically, should the following code be allowed?
app.event('app_home_opened', async () => { /* ... some listener code ... */}, 'foo_bar_baz')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the updated code changes, arguments should be passed in an order(event name pattern, listener).
src/middleware/builtin.spec.ts
Outdated
return { | ||
payload: appHomeOpenedEvent, | ||
event: appHomeOpenedEvent, | ||
message: null as never, // a bit hackey to sartisfy TS compiler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good job including a comment to justify the use of the type assertion! i wish i knew a little more about what the TS compiler's complaint would have been if you hadn't used the type assertion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the comments with the reason for using type assertion here.
@@ -609,6 +630,30 @@ describe('matchEventType', () => { | |||
assert.isTrue(fakeNext.called); | |||
}); | |||
|
|||
it('should detect valid RegExp requests with app_mention', async () => { | |||
const fakeNext = sinon.fake(); | |||
await matchEventType(/app_mention|app_home_opened/)({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perfect! this is the intended usage and i'm glad you specifically have a test that illustrates it.
|
||
it('should detect valid RegExp requests with app_home_opened', async () => { | ||
const fakeNext = sinon.fake(); | ||
await matchEventType(/app_mention|app_home_opened/)({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the difference between this test case and the one above it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no big difference, I just wanted to cover tests for the regex(/app_mention|app_home_opened/) specific to app_home_opened. We can remove this test case if it’s unnecessary to have redundant tests.
.
|
||
it('should skip other requests for RegExp', async () => { | ||
const fakeNext = sinon.fake(); | ||
await matchEventType(/foo/)({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good call to have a test case for both matching and not matching.
I just reran the GitHub Actions job. Now the all the checks pass. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Although I already gave an approval to this pull request, let me share a minor concern in regard to a future enhancement for TypeScript users. As of today, That being said, this addition should be greatly helpful in many situations. Therefore, I'm positive to have this. I just wanted to mention this limitation for future maintainers and/or contributors. |
Summary
Fixed #284: Added support to events to handle regex.
Requirements (place an
x
in each[ ]
)