mirror of
https://github.com/WeBankFinTech/fes.js.git
synced 2025-08-29 05:25:00 +08:00
151 lines
4.8 KiB
JavaScript
151 lines
4.8 KiB
JavaScript
/**
|
||
* @copy 该文件代码大部分出自 umi,有需要请参考:
|
||
* https://github.com/umijs/umi/blob/master/packages/runtime/src/Plugin/Plugin.ts
|
||
*/
|
||
|
||
import { assert } from '../utils';
|
||
|
||
function _compose({ fns, args }) {
|
||
if (fns.length === 1) {
|
||
return fns[0];
|
||
}
|
||
const last = fns.pop();
|
||
return fns.reduce((a, b) => () => b(a, args), last);
|
||
}
|
||
|
||
function isPromiseLike(obj) {
|
||
return !!obj && typeof obj === 'object' && typeof obj.then === 'function';
|
||
}
|
||
|
||
export const ApplyPluginsType = {
|
||
compose: 'compose',
|
||
event: 'event',
|
||
modify: 'modify'
|
||
};
|
||
|
||
export default class Plugin {
|
||
constructor(opts) {
|
||
this.validKeys = opts?.validKeys || [];
|
||
this.hooks = {};
|
||
// 共享
|
||
this.shared = {};
|
||
}
|
||
|
||
share(key, obj) {
|
||
assert(!Object.keys(this.shared).includes(key), 'share failed, key repeat');
|
||
this.shared[key] = obj;
|
||
}
|
||
|
||
getShared(key) {
|
||
return this.shared[key];
|
||
}
|
||
|
||
register(plugin) {
|
||
assert(!!plugin.apply, 'register failed, plugin.apply must supplied');
|
||
assert(!!plugin.path, 'register failed, plugin.path must supplied');
|
||
Object.keys(plugin.apply).forEach((key) => {
|
||
assert(
|
||
this.validKeys.indexOf(key) > -1,
|
||
`register failed, invalid key ${key} from plugin ${plugin.path}.`
|
||
);
|
||
if (!this.hooks[key]) this.hooks[key] = [];
|
||
this.hooks[key] = this.hooks[key].concat(plugin.apply[key]);
|
||
});
|
||
}
|
||
|
||
getHooks(keyWithDot) {
|
||
const [key, ...memberKeys] = keyWithDot.split('.');
|
||
let hooks = this.hooks[key] || [];
|
||
if (memberKeys.length) {
|
||
hooks = hooks
|
||
.map((hook) => {
|
||
try {
|
||
let ret = hook;
|
||
for (const memberKey of memberKeys) {
|
||
ret = ret[memberKey];
|
||
}
|
||
return ret;
|
||
} catch (e) {
|
||
return null;
|
||
}
|
||
})
|
||
.filter(Boolean);
|
||
}
|
||
return hooks;
|
||
}
|
||
|
||
applyPlugins({
|
||
key,
|
||
type,
|
||
initialValue,
|
||
args,
|
||
async
|
||
}) {
|
||
const hooks = this.getHooks(key) || [];
|
||
|
||
if (args) {
|
||
assert(
|
||
typeof args === 'object',
|
||
'applyPlugins failed, args must be plain object.'
|
||
);
|
||
}
|
||
|
||
switch (type) {
|
||
case ApplyPluginsType.modify:
|
||
if (async) {
|
||
return hooks.reduce(
|
||
async (memo, hook) => {
|
||
assert(typeof hook === 'function' || typeof hook === 'object' || isPromiseLike(hook),
|
||
`applyPlugins failed, all hooks for key ${key} must be function, plain object or Promise.`);
|
||
if (isPromiseLike(memo)) {
|
||
memo = await memo;
|
||
}
|
||
if (typeof hook === 'function') {
|
||
const ret = hook(memo, args);
|
||
if (isPromiseLike(ret)) {
|
||
return ret;
|
||
}
|
||
return ret;
|
||
}
|
||
if (isPromiseLike(hook)) {
|
||
hook = await hook;
|
||
}
|
||
return { ...memo, ...hook };
|
||
},
|
||
isPromiseLike(initialValue)
|
||
? initialValue
|
||
: Promise.resolve(initialValue)
|
||
);
|
||
}
|
||
return hooks.reduce((memo, hook) => {
|
||
assert(
|
||
typeof hook === 'function' || typeof hook === 'object',
|
||
`applyPlugins failed, all hooks for key ${key} must be function or plain object.`
|
||
);
|
||
if (typeof hook === 'function') {
|
||
return hook(memo, args);
|
||
}
|
||
return { ...memo, ...hook };
|
||
}, initialValue);
|
||
|
||
|
||
case ApplyPluginsType.event:
|
||
return hooks.forEach((hook) => {
|
||
assert(
|
||
typeof hook === 'function',
|
||
`applyPlugins failed, all hooks for key ${key} must be function.`
|
||
);
|
||
hook(args);
|
||
});
|
||
|
||
case ApplyPluginsType.compose:
|
||
return () => _compose({
|
||
fns: hooks.concat(initialValue),
|
||
args
|
||
})();
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
}
|