Refractor plugins helper

This commit is contained in:
Chi Vinh Le
2017-04-01 00:48:59 +07:00
parent 56a1503e3a
commit 5a5f1bc508
5 changed files with 66 additions and 160 deletions
+2 -2
View File
@@ -6,7 +6,7 @@ import isEqual from 'lodash/isEqual';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations';
const lang = new I18n(translations);
import {graphImporter} from 'coral-framework/helpers/plugins';
import {queriesAndMutators as pluginQueriesAndMutators} from 'coral-framework/helpers/plugins';
import {TabBar, Tab, TabContent, Spinner} from 'coral-ui';
@@ -306,5 +306,5 @@ export default compose(
removeCommentTag,
deleteAction,
queryStream,
...graphImporter
...pluginQueriesAndMutators,
)(Embed);
+2 -2
View File
@@ -1,11 +1,11 @@
import * as authActions from './auth';
import * as assetActions from './asset';
import * as notificationActions from './notification';
import {actionsImporter} from '../helpers/plugins';
import {actions as pluginActions} from '../helpers/plugins';
export default {
authActions,
assetActions,
notificationActions,
pluginActions: actionsImporter
pluginActions,
};
+3 -2
View File
@@ -1,11 +1,12 @@
import React, {Component} from 'react';
import {injectPlugins} from 'coral-framework/helpers/plugins';
import {getSlotComponents} from 'coral-framework/helpers/plugins';
class Slot extends Component {
render() {
const {fill, ...rest} = this.props;
return (
<div>
{injectPlugins(this.props)}
{getSlotComponents(fill, rest)}
</div>
);
}
+57 -152
View File
@@ -1,157 +1,62 @@
import {client as clientPlugins} from 'pluginsConfig';
import React from 'react';
import mapValues from 'lodash/mapValues';
import values from 'lodash/values';
import flatten from 'lodash/flatten';
import merge from 'lodash/merge';
function injectPlugins ({fill, ...props}) {
let context,
importedFiles;
function buildContext() {
/**
* buildContext creates the context for the plugins
* require.context(<path>, true, <regexp>
* path: The path where the importer builds the context. 'plugins' is allowed as path because it's an alias
* regxp: A Regular Expression to match the files that the importer needs. i.e (index.js, config.json)
* data such as path and regexp cannot be passed as arguments or variables
*/
context = require.context('plugins', true, /\.\/(.*)\/client\/(index|config).(js|json)$/);
return importedFiles = context
.keys()
.map(key => shapeData(key));
}
function getConfig (name) {
/**
* getConfig finds a the config file for each plugin
* returns the config.json as an object to be passed as props to the plugin
*/
return importedFiles
.filter(key => key.format === 'json' && key.name === name)
.reduce((acc, plugin) => {
return context(plugin.key);
}, {});
}
function addProps (plugin) {
/**
* addProps add properties to the injected plugins
*/
plugin.props = {
...getConfig(plugin.name),
...props
};
return plugin;
}
function filterBySlot (plugin) {
/**
* filterBySlot
*/
return plugin.props.slot === fill;
}
function init() {
/**
* init will build the context and
* returns a map with each plugin and its instance
*/
buildContext();
return importedFiles
.filter(filterByUserConfig)
.filter(key => key.format === 'js')
.map(addProps)
.filter(filterBySlot)
.reduce((entry, plugin, i) => {
const component = context(plugin.key);
const element = React.createElement(component, {
key: i,
...plugin.props
}, null);
entry = [...entry, element];
return entry;
}, []);
}
return init();
}
function shapeData(test) {
/**
* shapeData shapes each item in the plugins array with useful data
* returns an Object with the name of the plugin, the format, and it's key(filename)
*/
const match = test.match(/\.\/(.*)\/client\/.*.(json|js)$/);
return {
name: match[1],
format: match[2],
key: match[0]
};
}
function filterByUserConfig (plugin) {
/**
* filterByUserConfig will filter the imported files and will only keep the allowed plugins
*/
return clientPlugins.indexOf(plugin.name) > -1;
}
function importAll(context) {
/**
* importAll builds the map to import
*/
return context
.keys()
.map(key => shapeData(key))
.filter(filterByUserConfig)
.reduce((entry, actionsPlugin) => {
const input = context(actionsPlugin.key);
return {...entry, ...input};
}, {});
}
function importAllAsArr(context) {
/**
* importAllAsArr builds the array to import
*/
return context
.keys()
.map(key => shapeData(key))
.filter(filterByUserConfig)
.reduce((entry, graphPlugin) => {
const input = context(graphPlugin.key);
const res = Object.keys(input)
.map(key => input[key]);
return [...entry, ...res];
}, []);
}
function actionsImporter () {
return importAll(require.context('plugins', true, /\.\/(.*)\/client\/actions.js$/));
}
function reducersImporter () {
return importAll(require.context('plugins', true, /\.\/(.*)\/client\/reducer.js$/));
}
function graphImporter () {
return importAllAsArr(require.context('plugins', true, /\.\/(.*)\/client\/(queries|mutations)\/index.js$/));
}
export default {
injectPlugins,
actionsImporter: actionsImporter(),
reducersImporter: reducersImporter(),
graphImporter: graphImporter()
// Gather require context information of different parts of the plugins.
const contextMap = {
actions: require.context('plugins', true, /\.\/(.*)\/client\/actions.js$/),
reducers: require.context('plugins', true, /\.\/(.*)\/client\/reducer.js$/),
graph: require.context('plugins', true, /\.\/(.*)\/client\/(mutations|queries)\/index.js$/),
configs: require.context('plugins', true, /\.\/(.*)\/client\/config.json$/),
components: require.context('plugins', true, /\.\/(.*)\/client\/index.js$/),
};
const getPluginName = (key) => key.match(/\.\/(.*)\/client\/.*$/)[1];
const isActivePlugin = (plugin) => clientPlugins.indexOf(plugin) > -1;
/**
* Loads all enabled modules of the context and returns an
* Array with {plugin, module} entries.
*/
function loadActiveModules(context) {
return context
.keys()
.map(key => ({key, plugin: getPluginName(key)}))
.filter(info => isActivePlugin(info.plugin))
.map(info => ({plugin: info.plugin, module: context(info.key)}));
}
const loaded = mapValues(contextMap, loadActiveModules);
/**
* getConfig returns the config object of given plugin.
*/
function getConfig(plugin) {
return loaded.configs.filter(o => o.plugin === plugin)[0].module;
}
/**
* getSlotComponents returns React Elements for given slot.
*/
export function getSlotComponents(slot, props = {}) {
return loaded.components
.map((o, i) => ({
component: o.module,
props: {...getConfig(o.plugin), ...props, key: i},
}))
.filter(o => o.props.slot === slot)
.map(o => React.createElement(o.component, o.props));
}
// actions is a map of redux actions .
export const actions = merge(...loaded.actions.map(o => ({...o.module})));
// reducers is a map of redux reducers.
export const reducers = merge(...loaded.reducers.map(o => ({...o.module})));
// queriesAndMutators is an array of graphQL queries and mutators.
export const queriesAndMutators = flatten(loaded.graph.map(o => values(o.module)));
+2 -2
View File
@@ -1,11 +1,11 @@
import auth from './auth';
import user from './user';
import asset from './asset';
import {reducersImporter} from '../helpers/plugins';
import {reducers as pluginReducers} from '../helpers/plugins';
export default {
auth,
user,
asset,
...reducersImporter
...pluginReducers
};