Система плагінів - Rete.js

Система плагінів

Вихідний код

Плагіни пропонують можливість додавати нові функції переважно через одну точку входу. Вони спілкуються один з одним за допомогою сигналів, які поширюються від батьківських плагінів до дочірніх. Оскільки плагіни можуть мати кілька дочірніх плагінів, ці сигнали передаються в тому порядку, в якому вони підключені (це може бути важливо під час включення плагінів, таких як rete-readonly-plugin)

Архітектура

Наступний приклад коду демонструє створення двох скоупів: батьківського та дочірнього. Обидва скоупи логують сигнали.

ts
import { Scope } from 'rete'; const parentScope = new Scope<number>('parent'); // number це продукуємий тип const childScope = new Scope<string, [number]>('child'); // [number] це очікуваний тип батьківського ланцюга parentScope.addPipe((context) => { // додати пайп до батьківської області console.log('parent', context); // number return context; }); childScope.addPipe((context) => { // додати пайп до дочірньої області console.log('child', context); // string | number return context; }); parentScope.use(childScope); // forward all signals to child scope const returnedNumber = await parentScope.emit(1); // can emit number const returnedString = await childScope.emit('a'); // can emit string

Майте на увазі, що порядок use і addPipe впливає на порядок виклику батьківського та дочірнього обробників.

Логи:

log
parent 1 child 1 child a

У деяких випадках сигнали можна змінювати або блокувати.

Блокувати або змінити
ts
parentScope.addPipe((context) => { return context * 2; }); childScope.addPipe((context) => { if (context === 'b') return // запобігання поширення 'b' return context; }); const doubledNumber = await parentScope.emit(1); // 2 const expectedString = await childScope.emit('a'); // 'a' const expectedUndefined = await childScope.emit('b'); // undefined

Статична типізація використовується для гарантії того, що очікувані сигнали використовуваних плагінів сумісні з сигналами, створеними батьківським плагіном.

ts
import { Scope } from 'rete'; const parentScope = new Scope<number>('parent'); const childScope = new Scope<string, [number | boolean]>('child'); parentScope.use(childScope); // Type 'boolean' is not assignable to type 'string | number'.ts(2345)

Дочірні плагіни можуть отримати доступ до екземпляра батьківського плагіна як для прямого доступу до його інтерфейсів, так і для продукування сигналів від імені батьківського плагіна

ts
import { Scope } from 'rete'; class Root extends Scope<number> { isRoot = true } class Root2 extends Scope<number> { isRoot2 = true } const parentScope = new Root('parent'); const childScope = new Scope<string, [number]>('child'); parentScope.use(childScope); const parent = childScope.parentScope(); // екземпляр Root, але Scope з точки зору TS const root = childScope.parentScope<Root>(Root); // екземпляр Root const wrongInstance = childScope.parentScope<Root2>(Root2); // викидає виняток