diff --git a/HELP.md b/HELP.md index aaae4055..1f38ad40 100644 --- a/HELP.md +++ b/HELP.md @@ -335,9 +335,14 @@ const config = { prefix /* base URL or function which returns base URL (optional) */ }; +const plugins = [ + __dirname + '/plugin.js' +]; + app.use(cloudcmd({ - socket, /* used by Config, Edit (optional) and Console (required) */ - config, /* config data (optional) */ + socket, /* used by Config, Edit (optional) and Console (required) */ + config, /* config data (optional) */ + plugins, /* optional */ })); server.listen(port); diff --git a/README.md b/README.md index 6197d9c2..6f4f425f 100644 --- a/README.md +++ b/README.md @@ -89,9 +89,14 @@ const config = { prefix /* base URL or function which returns base URL (optional) */ }; +const plugins= [ + __dirname + '/plugin.js' +]; + app.use(cloudcmd({ - socket, /* used by Config, Edit (optional) and Console (required) */ - config, /* config data (optional) */ + socket, /* used by Config, Edit (optional) and Console (required) */ + config, /* config data (optional) */ + plugins, /* optional */ })); server.listen(port); diff --git a/lib/client.js b/lib/client.js index 4526060e..fdbe78a0 100644 --- a/lib/client.js +++ b/lib/client.js @@ -157,6 +157,7 @@ var Util, DOM, CloudFunc, join; Util.exec.series([ initModules, baseInit, + loadPlugins, function() { CloudCmd.route(location.hash); } @@ -194,6 +195,13 @@ var Util, DOM, CloudFunc, join; Util.exec.if(document.body.scrollIntoViewIfNeeded, func, funcBefore); }; + function loadPlugins(callback) { + var prefix = CloudCmd.PREFIX; + var plugins = prefix + '/plugins.js'; + + DOM.load.js(plugins, callback); + } + this.join = function(urls) { var prefix = CloudCmd.PREFIX; diff --git a/lib/cloudcmd.js b/lib/cloudcmd.js index 349056bd..ae61a8f2 100644 --- a/lib/cloudcmd.js +++ b/lib/cloudcmd.js @@ -12,6 +12,7 @@ var rest = require(DIR_SERVER + 'rest'); var route = require(DIR_SERVER + 'route'); var validate = require(DIR_SERVER + 'validate'); var prefixer = require(DIR_SERVER + 'prefixer'); +var pluginer = require(DIR_SERVER + 'plugins'); var apart = require('apart'); var join = require('join-io'); @@ -50,9 +51,13 @@ function getPrefix(prefix) { module.exports = function(params) { var p = params || {}; var options = p.config || {}; + var plugins = p.plugins; + var keys = Object.keys(options); var prefix; + checkPlugins(plugins); + keys.forEach(function(name) { var value = options[name]; @@ -84,7 +89,7 @@ module.exports = function(params) { if (p.socket) listen(prefix, p.socket); - return cloudcmd(prefix); + return cloudcmd(prefix, plugins); }; function defaultTrue(value) { @@ -169,7 +174,7 @@ function listen(prefix, socket) { }); } -function cloudcmd(prefix) { +function cloudcmd(prefix, plugins) { var isOption = function(name) { return config(name); }; @@ -260,6 +265,7 @@ function cloudcmd(prefix) { is : isMinify }), + pluginer(plugins), ponseStatic ]; @@ -290,3 +296,10 @@ function setUrl(pref) { }; } +function checkPlugins(plugins) { + if (typeof plugins === 'undefined') + return; + + if (!Array.isArray(plugins)) + throw Error('plugins should be an array!'); +} diff --git a/lib/server/plugins.js b/lib/server/plugins.js new file mode 100644 index 00000000..8b8edbbd --- /dev/null +++ b/lib/server/plugins.js @@ -0,0 +1,20 @@ +'use strict'; + +var currify = require('currify/legacy'); +var files = require('files-io'); + +module.exports = currify(function(plugins, req, res, next) { + if (req.url !== '/plugins.js') + return next(); + + if (!plugins || !plugins.length) + return res.send(''); + + files.readPipe(plugins, res, (e) => { + if (!e) + return; + + res.end(e.message); + }); +}); + diff --git a/test/before.js b/test/before.js index 76939270..66f18cc3 100644 --- a/test/before.js +++ b/test/before.js @@ -14,7 +14,9 @@ const {assign} = Object; const pathConfig = os.homedir() + '/.cloudcmd.json'; const currentConfig = readjson.sync.try(pathConfig); -module.exports = (config, fn = config) => { +module.exports = (_config, _plugins, _fn) => { + const {config, plugins, fn} = parse(_config, _plugins, _fn); + const app = express(); const server = http.createServer(app); const after = () => { @@ -28,6 +30,7 @@ module.exports = (config, fn = config) => { app.use(cloudcmd({ socket, + plugins, config: assign(defaultConfig(), config) })); @@ -43,3 +46,25 @@ function defaultConfig() { }; } +function parse(config, plugins, fn) { + if (typeof plugins === 'undefined') + return { + fn: config, + config: undefined, + plugins: undefined + } + + if (typeof fn === 'undefined') + return { + config, + fn: plugins, + plugins: undefined + } + + return { + config, + plugins, + fn + }; +} + diff --git a/test/lib/cloudcmd.js b/test/lib/cloudcmd.js new file mode 100644 index 00000000..ca113b82 --- /dev/null +++ b/test/lib/cloudcmd.js @@ -0,0 +1,21 @@ +'use strict'; + +const test = require('tape'); +const cloudcmd = require('../..'); + +test('cloudcmd: args: no', (t) => { + const fn = () => cloudcmd(); + + t.doesNotThrow(fn, /plugins should be an array!/, 'should throw when plugins not an array'); + t.end(); +}); + +test('cloudcmd: args: plugins: error', (t) => { + const fn = () => cloudcmd({ + plugins: '' + }); + + t.throws(fn, /plugins should be an array!/, 'should throw when plugins not an array'); + t.end(); +}); + diff --git a/test/plugins.js b/test/plugins.js new file mode 100644 index 00000000..339c8cdf --- /dev/null +++ b/test/plugins.js @@ -0,0 +1,82 @@ +'use strict'; + +const fs = require('fs'); +const test = require('tape'); +const promisify = require('es6-promisify'); +const pullout = require('pullout'); +const request = require('request'); + +const before = require('./before'); + +const warp = (fn, ...a) => (...b) => fn(...b, ...a); + +const _pullout = promisify(pullout); + +const get = promisify((url, fn) => { + fn(null, request(url)); +}); + +test('cloudcmd: plugins', (t) => { + const config = {}; + const plugins = []; + + before(config, plugins, (port, after) => { + get(`http://localhost:${port}/plugins.js`) + .then(warp(_pullout, 'string')) + .then((content) => { + t.equal(content, '', 'should content be empty'); + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); + +test('cloudcmd: plugins', (t) => { + const config = {}; + const plugins = [ + __filename + ]; + + before(config, plugins, (port, after) => { + get(`http://localhost:${port}/plugins.js`) + .then(warp(_pullout, 'string')) + .then((content) => { + const file = fs.readFileSync(__filename, 'utf8'); + t.equal(content, file, 'should return file plugin content'); + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); + +test('cloudcmd: plugins: load error', (t) => { + const config = {}; + const noEntry = __filename + Math.random(); + const plugins = [ + __filename, + noEntry + ]; + + const msg = `ENOENT: no such file or directory, open '${noEntry}'`; + + before(config, plugins, (port, after) => { + get(`http://localhost:${port}/plugins.js`) + .then(warp(_pullout, 'string')) + .then((content) => { + const file = fs.readFileSync(__filename, 'utf8') + msg; + t.equal(content, file, 'should return file plugin content'); + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); +