Skip to content

Commit

Permalink
/2
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante committed Apr 1, 2024
1 parent a4ff552 commit e613863
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 12 deletions.
22 changes: 21 additions & 1 deletion source/one-event.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,31 @@ It also supports filtering:
import {oneEvent} from 'webext-events';

// Wait until the user opens a new tab, but it has it be HTTPS
await oneEvent(chrome.tabs.onCreated, (tab) => tab.pendingUrl?.startsWith('https'));
await oneEvent(chrome.tabs.onCreated, {
filter: (tab) => tab.pendingUrl?.startsWith('https'),
});

console.log('Hurray, a new HTTPS tab was created')
```
And abort signals:
```js
import {oneEvent} from 'webext-events';

// Wait until the user opens a new tab, but only for one second
const timeout = AbortSignal.timeout(1000);
await oneEvent(chrome.tabs.onCreated, {
signal: timeout,
});

if (timeout.aborted) {
console.log('No tab was created in time')
} else {
console.log('Hurray, a new tab was created')
}
```
## Compatibility
- Any browser
Expand Down
14 changes: 7 additions & 7 deletions source/one-event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('oneEvent', () => {
expect(chrome.runtime.onMessage.hasListeners()).toBe(false);
const eventPromise = oneEvent(
chrome.runtime.onMessage,
({greeting}) => greeting === 'sup',
{filter: ({greeting}) => greeting === 'sup'},
);
expect(chrome.runtime.onMessage.hasListeners()).toBe(true);

Expand All @@ -47,22 +47,22 @@ describe('oneEvent', () => {
});

it('it should resolve original event\'s parameters', () => {
void oneEvent(chrome.tabs.onMoved, (tabId, moveInfo) => {
void oneEvent(chrome.tabs.onMoved, {filter(tabId, moveInfo) {
expectTypeOf(tabId).toEqualTypeOf<number>();
expectTypeOf(moveInfo).toEqualTypeOf<chrome.tabs.TabMoveInfo>();
return true;
});
}});

void oneEvent(chrome.runtime.onMessage, (message, sender, sendResponse) => {
void oneEvent(chrome.runtime.onMessage, {filter(message, sender, sendResponse) {
expectTypeOf(message).toEqualTypeOf<any>();
expectTypeOf(sender).toEqualTypeOf<Runtime.MessageSender>();
expectTypeOf(sendResponse).toEqualTypeOf<(response?: any) => void>();
return true;
});
}});

void oneEvent(chrome.cookies.onChanged, changeInfo => {
void oneEvent(chrome.cookies.onChanged, {filter(changeInfo) {
expectTypeOf(changeInfo).toEqualTypeOf<Cookies.CookieChangeInfo>();
return true;
});
}});
});
});
22 changes: 18 additions & 4 deletions source/one-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ type EventParameters
<Event extends RemovableEvent<AnyFunction>> =
Parameters<Parameters<Event['addListener']>[0]>;

export async function oneEvent<
Event extends RemovableEvent<AnyFunction>,
>(
export async function oneEvent<Event extends RemovableEvent<AnyFunction>>(
event: Event,
filter?: (...parameters: EventParameters<Event>) => boolean,
{
filter,
signal,
}: {
filter?: (...parameters: EventParameters<Event>) => boolean;
signal?: AbortSignal;
} = {},
): Promise<void> {
if (signal?.aborted) {
return;
}

await new Promise<void>(resolve => {
// TODO: VoidFunction should not be necessary, it's equivalent to using "any"
const listener: VoidFunction = (...parameters: EventParameters<Event>) => {
Expand All @@ -25,5 +33,11 @@ export async function oneEvent<
};

event.addListener(listener);

// TODO: The abort listener is left behind if never aborted
signal?.addEventListener('abort', () => {
resolve();
event.removeListener(listener);
});
});
}

0 comments on commit e613863

Please sign in to comment.