@fraqjs/fraq 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +29 -4
- package/dist/index.mjs +37 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5567,13 +5567,31 @@ type ServiceClass<T extends object = object> = abstract new (...args: any[]) =>
|
|
|
5567
5567
|
//#endregion
|
|
5568
5568
|
//#region src/core/plugin.d.ts
|
|
5569
5569
|
type ParameterList = Array<any>;
|
|
5570
|
-
|
|
5570
|
+
type Injection = Record<string, ServiceClass>;
|
|
5571
|
+
type InjectedServices<I extends Injection | undefined> = I extends Injection
|
|
5572
|
+
? { [K in keyof I]: InstanceType<I[K]> }
|
|
5573
|
+
: {};
|
|
5574
|
+
type OptionalInjectedServices<I extends Injection | undefined> = I extends Injection
|
|
5575
|
+
? { [K in keyof I]: InstanceType<I[K]> | undefined }
|
|
5576
|
+
: {};
|
|
5577
|
+
interface Plugin<
|
|
5578
|
+
T extends ParameterList,
|
|
5579
|
+
I extends Injection | undefined,
|
|
5580
|
+
OI extends Injection | undefined = undefined,
|
|
5581
|
+
> {
|
|
5571
5582
|
name: string;
|
|
5572
5583
|
requires?: readonly ServiceClass[];
|
|
5584
|
+
inject?: I;
|
|
5585
|
+
optionalRequires?: readonly ServiceClass[];
|
|
5586
|
+
optionalInject?: OI;
|
|
5573
5587
|
provides?: readonly ServiceClass[];
|
|
5574
|
-
apply(ctx: Context
|
|
5588
|
+
apply(ctx: Context & InjectedServices<I> & OptionalInjectedServices<OI>, ...args: T): void | Promise<void>;
|
|
5575
5589
|
}
|
|
5576
|
-
declare function definePlugin<
|
|
5590
|
+
declare function definePlugin<
|
|
5591
|
+
T extends ParameterList,
|
|
5592
|
+
I extends Injection | undefined,
|
|
5593
|
+
OI extends Injection | undefined,
|
|
5594
|
+
>(plugin: Plugin<T, I, OI>): Plugin<T, I, OI>;
|
|
5577
5595
|
//#endregion
|
|
5578
5596
|
//#region src/core/context.d.ts
|
|
5579
5597
|
interface ContextOptions {
|
|
@@ -5603,7 +5621,10 @@ declare class Context {
|
|
|
5603
5621
|
private isStarted;
|
|
5604
5622
|
private constructor();
|
|
5605
5623
|
on<K extends keyof EventMap>(type: K, handler: (event: EventMap[K]) => void | Promise<void>): void;
|
|
5606
|
-
install<T extends ParameterList
|
|
5624
|
+
install<T extends ParameterList, I extends Injection | undefined, OI extends Injection | undefined>(
|
|
5625
|
+
plugin: Plugin<T, I, OI>,
|
|
5626
|
+
...args: T
|
|
5627
|
+
): void;
|
|
5607
5628
|
provide<T extends object>(service: ServiceClass<T>, instance: T): void;
|
|
5608
5629
|
resolve<T extends object>(service: ServiceClass<T>): T;
|
|
5609
5630
|
tryResolve<T extends object>(service: ServiceClass<T>): T | undefined;
|
|
@@ -5613,6 +5634,9 @@ declare class Context {
|
|
|
5613
5634
|
private acceptsParentEvent;
|
|
5614
5635
|
private applyPlugins;
|
|
5615
5636
|
private sortPlugins;
|
|
5637
|
+
private collectPendingProvidedServices;
|
|
5638
|
+
private areRequiredServicesAvailable;
|
|
5639
|
+
private areOptionalServicesReady;
|
|
5616
5640
|
private collectAvailableServices;
|
|
5617
5641
|
private createUnresolvablePluginError;
|
|
5618
5642
|
private createProxyContextForPlugin;
|
|
@@ -5669,6 +5693,7 @@ export {
|
|
|
5669
5693
|
ContextUrlOptions,
|
|
5670
5694
|
EventMap,
|
|
5671
5695
|
Filter,
|
|
5696
|
+
Injection,
|
|
5672
5697
|
LogHandler,
|
|
5673
5698
|
LogLevel,
|
|
5674
5699
|
LogMessage,
|
package/dist/index.mjs
CHANGED
|
@@ -419,7 +419,10 @@ var Context = class Context {
|
|
|
419
419
|
const available = /* @__PURE__ */ new Set();
|
|
420
420
|
for (const service of this.collectAvailableServices()) available.add(service);
|
|
421
421
|
while (pending.length > 0) {
|
|
422
|
-
const
|
|
422
|
+
const availableByPendingPlugins = this.collectPendingProvidedServices(pending);
|
|
423
|
+
const requiredReadyIndex = pending.findIndex(({ plugin }) => this.areRequiredServicesAvailable(plugin, available));
|
|
424
|
+
const optionalReadyIndex = pending.findIndex(({ plugin }) => this.areRequiredServicesAvailable(plugin, available) && this.areOptionalServicesReady(plugin, available, availableByPendingPlugins));
|
|
425
|
+
const nextIndex = optionalReadyIndex === -1 ? requiredReadyIndex : optionalReadyIndex;
|
|
423
426
|
if (nextIndex === -1) throw this.createUnresolvablePluginError(pending, available);
|
|
424
427
|
const [next] = pending.splice(nextIndex, 1);
|
|
425
428
|
sorted.push(next);
|
|
@@ -427,6 +430,21 @@ var Context = class Context {
|
|
|
427
430
|
}
|
|
428
431
|
return sorted;
|
|
429
432
|
}
|
|
433
|
+
collectPendingProvidedServices(pending) {
|
|
434
|
+
const providedServices = /* @__PURE__ */ new Map();
|
|
435
|
+
for (const installedPlugin of pending) for (const service of installedPlugin.plugin.provides ?? []) providedServices.set(service, installedPlugin);
|
|
436
|
+
return providedServices;
|
|
437
|
+
}
|
|
438
|
+
areRequiredServicesAvailable(plugin, available) {
|
|
439
|
+
return (plugin.requires ?? []).every((service) => available.has(service));
|
|
440
|
+
}
|
|
441
|
+
areOptionalServicesReady(plugin, available, pendingProviders) {
|
|
442
|
+
return (plugin.optionalRequires ?? []).every((service) => {
|
|
443
|
+
if (available.has(service)) return true;
|
|
444
|
+
const pendingProvider = pendingProviders.get(service);
|
|
445
|
+
return pendingProvider === void 0 || pendingProvider.plugin === plugin;
|
|
446
|
+
});
|
|
447
|
+
}
|
|
430
448
|
collectAvailableServices() {
|
|
431
449
|
const services = [...this.services.keys()];
|
|
432
450
|
if (this.parent) services.push(...this.parent.collectAvailableServices());
|
|
@@ -450,8 +468,18 @@ var Context = class Context {
|
|
|
450
468
|
}
|
|
451
469
|
createProxyContextForPlugin(plugin) {
|
|
452
470
|
const proxyLogger = new Logger((message) => this.logHandler?.(message), plugin.name);
|
|
471
|
+
let proxyInjections;
|
|
472
|
+
if (plugin.inject) {
|
|
473
|
+
proxyInjections = {};
|
|
474
|
+
for (const [key, service] of Object.entries(plugin.inject)) proxyInjections[key] = this.resolve(service);
|
|
475
|
+
}
|
|
476
|
+
if (plugin.optionalInject) {
|
|
477
|
+
proxyInjections ??= {};
|
|
478
|
+
for (const [key, service] of Object.entries(plugin.optionalInject)) proxyInjections[key] = this.tryResolve(service);
|
|
479
|
+
}
|
|
453
480
|
return new Proxy(this, { get(target, prop) {
|
|
454
481
|
if (prop === "logger") return proxyLogger;
|
|
482
|
+
else if (proxyInjections && prop in proxyInjections) return proxyInjections[prop];
|
|
455
483
|
else return target[prop];
|
|
456
484
|
} });
|
|
457
485
|
}
|
|
@@ -615,6 +643,14 @@ let filter;
|
|
|
615
643
|
//#endregion
|
|
616
644
|
//#region src/core/plugin.ts
|
|
617
645
|
function definePlugin(plugin) {
|
|
646
|
+
if (plugin.inject) {
|
|
647
|
+
if (plugin.requires) throw new Error(`Plugin "${plugin.name}" cannot have both "requires" and "inject" properties.`);
|
|
648
|
+
plugin.requires = Object.values(plugin.inject);
|
|
649
|
+
}
|
|
650
|
+
if (plugin.optionalInject) {
|
|
651
|
+
if (plugin.optionalRequires) throw new Error(`Plugin "${plugin.name}" cannot have both "optionalRequires" and "optionalInject" properties.`);
|
|
652
|
+
plugin.optionalRequires = Object.values(plugin.optionalInject);
|
|
653
|
+
}
|
|
618
654
|
return plugin;
|
|
619
655
|
}
|
|
620
656
|
//#endregion
|