Beau/src/plugins.js

122 lines
3.3 KiB
JavaScript

const vm = require('vm');
const requireg = require('requireg');
const deepmerge = require('deepmerge');
const { toKebabCase, dynamicValueRegex, replaceInObject } = require('./shared');
const isPlainObject = require('is-plain-object');
class Plugins {
constructor(plugins = [], autoload = ['std']) {
this.registry = {
preRequestModifiers: [],
postRequestModifiers: [],
dynamicValues: []
};
this.context = {};
this.autoload = autoload;
this.loadPlugins(plugins.concat(this.autoload));
}
normalizePlugins(plugins) {
let results = {};
plugins.forEach(plugin => {
let name = plugin;
let settings = undefined;
if (typeof plugin === 'object') {
let keys = Object.keys(plugin);
if (keys.length !== 1) {
throw new Error(
`Plugin items should contain only one key.`
);
}
name = keys[0];
settings = plugin[name];
}
results[name] = settings;
});
return results;
}
loadPlugins(plugins) {
plugins = this.normalizePlugins(plugins);
Object.keys(plugins).forEach(name => {
const module = `beau-${toKebabCase(name)}`;
if (typeof requireg.resolve(module) !== 'undefined') {
const plugin = requireg(module);
new plugin(this, plugins[name]);
} else {
if (this.autoload.includes(name)) return;
console.warn(
`Plugin ${name} couldn't be found. It is available globally?`
);
}
});
}
executeModifier(modifier, obj, orig) {
let result = deepmerge({}, obj, { isMergeableObject: isPlainObject });
this.registry[modifier].forEach(
modifier => (result = modifier(result, orig))
);
return result;
}
replaceDynamicValues(obj) {
vm.createContext(this.context);
return replaceInObject(obj, val => {
let valIsEmpty = val.trim().length === 0;
if (valIsEmpty) {
return val;
}
try {
let onlyHasDynamic =
val.replace(dynamicValueRegex, '').trim() === '';
if (onlyHasDynamic) {
let call;
val.replace(dynamicValueRegex, (match, c) => {
call = c;
});
return vm.runInContext(call, this.context);
}
return val.replace(dynamicValueRegex, (match, call) => {
return vm.runInContext(call, this.context);
});
} catch (e) {
throw new Error(`DynamicValue: ` + e);
}
});
}
addPreRequestModifier(modifier) {
this.registry.preRequestModifiers.push(modifier);
}
addPostRequestModifier(modifier) {
this.registry.postRequestModifiers.push(modifier);
}
defineDynamicValue(name, fn) {
this.registry.dynamicValues.push({ name, fn });
this.context[name] = fn;
}
}
module.exports = Plugins;