feat(lib/plugins): do API decorator filtering
This commit is contained in:
parent
72035286a9
commit
84bb9992f5
2 changed files with 75 additions and 25 deletions
|
|
@ -1,36 +1,77 @@
|
|||
import { getPluginDependencies, pMetadata } from '.'
|
||||
import type {
|
||||
InitPluginApi,
|
||||
Plugin,
|
||||
PluginApi,
|
||||
PreInitPluginApi,
|
||||
} from '../types'
|
||||
import type { InternalPluginMeta } from '.'
|
||||
import type { AnyPlugin, InternalPluginMeta } from '.'
|
||||
|
||||
export type PluginApiDecoratorStore<
|
||||
A extends PreInitPluginApi | InitPluginApi | PluginApi,
|
||||
> = [decorator: Parameters<A['decorate']>[0], handleError: (e: unknown) => void]
|
||||
> = WeakMap<AnyPlugin, Parameters<A['decorate']>[0][]>
|
||||
|
||||
export const pDecorators: {
|
||||
preInit: PluginApiDecoratorStore<PreInitPluginApi>[]
|
||||
init: PluginApiDecoratorStore<InitPluginApi>[]
|
||||
start: PluginApiDecoratorStore<PluginApi>[]
|
||||
} = {
|
||||
preInit: [],
|
||||
init: [],
|
||||
start: [],
|
||||
// Set of plugins that will always decorate the API of every other plugin.
|
||||
export const pImplicitDeps = new Set<AnyPlugin>()
|
||||
|
||||
export const pDecoratorsPreInit: PluginApiDecoratorStore<PreInitPluginApi> =
|
||||
new WeakMap()
|
||||
|
||||
export const pDecoratorsInit: PluginApiDecoratorStore<InitPluginApi> =
|
||||
new WeakMap()
|
||||
|
||||
export const pDecoratorsStart: PluginApiDecoratorStore<PluginApi> =
|
||||
new WeakMap()
|
||||
|
||||
export function addPluginApiDecorator(
|
||||
store: PluginApiDecoratorStore<any>,
|
||||
plugin: AnyPlugin,
|
||||
decorator: Parameters<NonNullable<AnyPlugin['api']>['decorate']>[0],
|
||||
) {
|
||||
let list = store.get(plugin)
|
||||
if (!list) {
|
||||
list = []
|
||||
store.set(plugin, list)
|
||||
}
|
||||
|
||||
list.push(decorator)
|
||||
}
|
||||
|
||||
export function decoratePluginApi(
|
||||
store: PluginApiDecoratorStore<
|
||||
PreInitPluginApi | InitPluginApi | PluginApi
|
||||
>[],
|
||||
plugin: Plugin,
|
||||
>,
|
||||
plugin: Plugin<any, any>,
|
||||
meta: InternalPluginMeta,
|
||||
) {
|
||||
for (const [decorator, handleError] of store)
|
||||
try {
|
||||
decorator(plugin as Plugin<any, any>, meta.options)
|
||||
} catch (e) {
|
||||
handleError(e)
|
||||
// Don't decorate implicit dependencies
|
||||
if (pImplicitDeps.has(plugin)) return
|
||||
|
||||
// Decorate the plugin API with implicit dependencies
|
||||
// Implicit dependencies are internal plugin APIs, so we can run this without try-catch
|
||||
// If anything fails, everything else would fail anyway
|
||||
for (const dep of pImplicitDeps) {
|
||||
const decorators = store.get(dep)
|
||||
if (decorators)
|
||||
for (const decorator of decorators) decorator(plugin, meta.options)
|
||||
}
|
||||
|
||||
const deps = getPluginDependencies(plugin)
|
||||
const { handleError: handleDependentError } = meta
|
||||
|
||||
for (const dep of deps) {
|
||||
const decorators = store.get(dep)
|
||||
|
||||
if (decorators) {
|
||||
const { handleError } = pMetadata.get(dep)!
|
||||
|
||||
try {
|
||||
for (const decorator of decorators)
|
||||
decorator(plugin, meta.options)
|
||||
} catch (e) {
|
||||
handleError(e)
|
||||
handleDependentError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,14 @@ import {
|
|||
PluginFlags,
|
||||
PluginStatus as Status,
|
||||
} from '../constants'
|
||||
import { decoratePluginApi, pDecorators } from './decorators'
|
||||
import {
|
||||
addPluginApiDecorator,
|
||||
decoratePluginApi,
|
||||
pDecoratorsInit,
|
||||
pDecoratorsPreInit,
|
||||
pDecoratorsStart,
|
||||
pImplicitDeps,
|
||||
} from './decorators'
|
||||
import { pLeafOrSingleNodes, pPending } from './dependency-graph'
|
||||
import type {
|
||||
InitPluginApi,
|
||||
|
|
@ -88,8 +95,10 @@ export function registerPlugin<O extends PluginApiExtensionsOptions>(
|
|||
pMetadata.set(plugin, meta)
|
||||
pList.set(manifest.id, plugin)
|
||||
|
||||
if (iflags & InternalPluginFlags.ImplicitDependency)
|
||||
if (iflags & InternalPluginFlags.ImplicitDependency) {
|
||||
pLeafOrSingleNodes.add(plugin)
|
||||
pImplicitDeps.add(plugin)
|
||||
}
|
||||
// Only add to pending if the plugin is enabled
|
||||
else if (flags & PluginFlags.Enabled) pPending.add(plugin)
|
||||
|
||||
|
|
@ -159,11 +168,11 @@ function preparePluginPreInit(plugin: AnyPlugin) {
|
|||
plugin,
|
||||
unscoped: pUnscopedApi,
|
||||
decorate: decorator => {
|
||||
pDecorators.preInit.push([decorator, meta.handleError])
|
||||
addPluginApiDecorator(pDecoratorsPreInit, plugin, decorator)
|
||||
},
|
||||
} satisfies PreInitPluginApi
|
||||
|
||||
decoratePluginApi(pDecorators.preInit, plugin, meta)
|
||||
decoratePluginApi(pDecoratorsPreInit, plugin, meta)
|
||||
|
||||
meta.apiLevel = PluginApiLevel.PreInit
|
||||
}
|
||||
|
|
@ -172,10 +181,10 @@ function preparePluginInit(plugin: AnyPlugin) {
|
|||
const meta = pMetadata.get(plugin)!
|
||||
const api = plugin.api as InitPluginApi
|
||||
api.decorate = decorator => {
|
||||
pDecorators.init.push([decorator, meta.handleError])
|
||||
addPluginApiDecorator(pDecoratorsInit, plugin, decorator)
|
||||
}
|
||||
|
||||
decoratePluginApi(pDecorators.init, plugin, meta)
|
||||
decoratePluginApi(pDecoratorsInit, plugin, meta)
|
||||
|
||||
meta.apiLevel = PluginApiLevel.Init
|
||||
}
|
||||
|
|
@ -184,10 +193,10 @@ function preparePluginStart(plugin: AnyPlugin) {
|
|||
const meta = pMetadata.get(plugin)!
|
||||
const api = plugin.api as PluginApi
|
||||
api.decorate = decorator => {
|
||||
pDecorators.start.push([decorator, meta.handleError])
|
||||
addPluginApiDecorator(pDecoratorsStart, plugin, decorator)
|
||||
}
|
||||
|
||||
decoratePluginApi(pDecorators.start, plugin, meta)
|
||||
decoratePluginApi(pDecoratorsStart, plugin, meta)
|
||||
|
||||
meta.apiLevel = PluginApiLevel.Start
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue