• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rokucommunity / roku-debug / 26120672946

19 May 2026 07:37PM UTC coverage: 70.727% (+0.7%) from 70.049%
26120672946

Pull #351

github

web-flow
Merge eb0b2e542 into 5bbd82240
Pull Request #351: 0.23.8

3328 of 5046 branches covered (65.95%)

Branch coverage included in aggregate %.

5834 of 7908 relevant lines covered (73.77%)

35.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.5
/src/debugProtocol/PluginInterface.ts
1
// inspiration: https://github.com/andywer/typed-emitter/blob/master/index.d.ts
2
export type Arguments<T> = [T] extends [(...args: infer U) => any]
2✔
3
    ? U
4
    : [T] extends [void] ? [] : [T];
139✔
5

139✔
6
export default class PluginInterface<TPlugin> {
139!
7
    constructor(
×
8
        plugins = [] as TPlugin[]
9
    ) {
10
        for (const plugin of plugins ?? []) {
11
            this.add(plugin);
12
        }
13
    }
14

1,663✔
15
    private plugins: Array<PluginContainer<TPlugin>> = [];
1,676✔
16

489✔
17
    /**
18
     * Call `event` on plugins
19
     */
1,663✔
20
    public async emit<K extends keyof TPlugin & string>(eventName: K, event: Arguments<TPlugin[K]>[0]) {
21
        for (let { plugin } of this.plugins) {
22
            if ((plugin as any)[eventName]) {
23
                await Promise.resolve((plugin as any)[eventName](event));
24
            }
25
        }
26
        return event;
72✔
27
    }
140✔
28

29
    /**
30
     * Add a plugin to the end of the list of plugins
31
     * @param plugin the plugin
140✔
32
     * @param priority the priority for the plugin. Lower number means higher priority. (ex: 1 executes before 5)
33
     */
140✔
34
    public add<T extends TPlugin = TPlugin>(plugin: T, priority = 1) {
2✔
35
        const container = {
36
            plugin: plugin,
140✔
37
            priority: priority
38
        };
39
        this.plugins.push(container);
40

41
        //sort the plugins by priority
42
        this.plugins.sort((a, b) => {
43
            return a.priority - b.priority;
44
        });
×
45

×
46
        return plugin;
47
    }
48

49
    /**
50
     * Adds a temporary plugin with a single event hook, and resolve a promise with the event from the next occurance of that event.
51
     * Once the event fires for the first time, the plugin is unregistered.
52
     * @param eventName the name of the event to subscribe to
53
     * @param priority the priority for this event. Lower number means higher priority. (ex: 1 executes before 5)
54
     */
×
55
    public once<TEventType>(eventName: keyof TPlugin, priority = 1): Promise<TEventType> {
1✔
56
        return this.onceIf(eventName, () => true, priority);
1✔
57
    }
1✔
58

1!
59
    /**
60
     * Adds a temporary plugin with a single event hook, and resolve a promise with the event from the next occurance of that event.
1✔
61
     * Once the event fires for the first time and the matcher evaluates to true, the plugin is unregistered.
62
     * @param eventName the name of the event to subscribe to
1✔
63
     * @param matcher a function to call that, when true, will deregister this hander and return the event
64
     * @param priority the priority for this event. Lower number means higher priority. (ex: 1 executes before 5)
65
     */
1✔
66
    public onceIf<TEventType>(eventName: keyof TPlugin, matcher: (TEventType) => boolean, priority = 1): Promise<TEventType> {
67
        return new Promise((resolve) => {
68
            const tempPlugin = {} as any;
69
            tempPlugin[eventName] = (event) => {
70
                if (matcher(event)) {
71
                    //remove the temp plugin
72
                    this.remove(tempPlugin);
1✔
73
                    //resolve the promise with this event
2✔
74
                    resolve(event);
1✔
75
                }
76
            };
77
            this.add(tempPlugin, priority);
78
        }) as any;
79
    }
80

81
    /**
82
     * Remove the specified plugin
×
83
     */
84
    public remove<T extends TPlugin = TPlugin>(plugin: T) {
85
        for (let i = this.plugins.length - 1; i >= 0; i--) {
2✔
86
            if (this.plugins[i].plugin === plugin) {
87
                this.plugins.splice(i, 1);
88
            }
89
        }
90
    }
91

92
    /**
93
     * Remove all plugins
94
     */
95
    public clear() {
96
        this.plugins = [];
97
    }
98
}
99

100
interface PluginContainer<TPlugin> {
101
    plugin: TPlugin;
102
    priority: number;
103
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc