( // Module boilerplate to support node.js and AMD. (typeof module !== "undefined" && function (m) { module.exports = m(require('events')); }) || (typeof define === "function" && function (m) { define(["events"], m); }) )(function (events) { "use strict"; var EventEmitter = events.EventEmitter; var exports = {}; var DEBUG = typeof location != "undefined" && location.href.match(/debug=[123]/) ? true : false; // Only define Node-style usage using sync I/O if in node. if (typeof module === "object") (function () { var dirname = require('path').dirname; var Module = require("module"); exports.loadConfig = loadConfig; exports.resolveConfig = resolveConfig; // This is assumed to be used at startup and uses sync I/O as well as can // throw exceptions. It loads and parses a config file. function loadConfig(configPath, callback) { var config = require(configPath); var base = dirname(configPath); return resolveConfig(config, base, callback); } function resolveConfig(config, base, callback) { if (!callback) return resolveConfigSync(config, base); try { var result = resolveConfigSync(config, base); } catch (e) { var err = e; } process.nextTick(function() { callback(err, result); }); } function resolveConfigSync(config, base) { config.forEach(function (plugin, index) { // Shortcut where string is used for plugin without any options. if (typeof plugin === "string") { plugin = config[index] = { packagePath: plugin }; } // The plugin is a package on the disk. We need to load it. if (plugin.hasOwnProperty("packagePath") && !plugin.hasOwnProperty("setup")) { var defaults = resolveModuleSync(base, plugin.packagePath); Object.keys(defaults).forEach(function (key) { if (!plugin.hasOwnProperty(key)) { plugin[key] = defaults[key]; } }); plugin.packagePath = defaults.packagePath; plugin.setup = require(plugin.packagePath); } }); return config; } // Loads a module, getting metadata from either it's package.json or export // object. function resolveModuleSync(base, modulePath) { var packagePath; try { packagePath = resolvePackageSync(base, modulePath + "/package.json"); } catch (err) { if (err.code !== "ENOENT" && err.code !== 'MODULE_NOT_FOUND') throw err; } var metadata = packagePath && require(packagePath).plugin || {}; if (packagePath) { modulePath = dirname(packagePath); } else { modulePath = resolvePackageSync(base, modulePath); } var module = require(modulePath); metadata.provides = metadata.provides || module.provides || []; metadata.consumes = metadata.consumes || module.consumes || []; metadata.packagePath = modulePath; return metadata; } // Node style package resolving so that plugins' package.json can be found relative to the config file // It's not the full node require system algorithm, but it's the 99% case // This throws, make sure to wrap in try..catch function resolvePackageSync(base, packagePath) { return Module._resolveFilename(packagePath, { paths: Module._nodeModulePaths(base), filename: base + "/package.json", id: base + "/package.json", }); } }()); // Otherwise use amd to load modules. else (function () { exports.loadConfig = loadConfig; exports.resolveConfig = resolveConfig; function loadConfig(path, callback) { require([path], function (config) { resolveConfig(config, callback); }); } function resolveConfig(config, base, callback, errback) { if (typeof base == "function") return resolveConfig(config, "", arguments[1], arguments[2]); var paths = [], pluginIndexes = {}; config.forEach(function (plugin, index) { // Shortcut where string is used for plugin without any options. if (typeof plugin === "string") { plugin = config[index] = { packagePath: plugin }; } // The plugin is a package over the network. We need to load it. if (plugin.hasOwnProperty("packagePath") && !plugin.hasOwnProperty("setup")) { paths.push((base || "") + plugin.packagePath); pluginIndexes[plugin.packagePath] = index; } }); // Mass-Load path-based plugins using amd's require require(paths, function () { var args = arguments; paths.forEach(function (name, i) { var module = args[i]; var plugin = config[pluginIndexes[name]]; plugin.setup = module; plugin.provides = module.provides || []; plugin.consumes = module.consumes || []; }); callback(null, config); }, errback); } }()); exports.createApp = createApp; exports.Architect = Architect; // Check a plugin config list for bad dependencies and throw on error function checkConfig(config, lookup) { // Check for the required fields in each plugin. config.forEach(function (plugin) { if (plugin.checked) { return; } if (!plugin.hasOwnProperty("setup")) { throw new Error("Plugin is missing the setup function " + JSON.stringify(plugin)); } if (!plugin.hasOwnProperty("provides")) { throw new Error("Plugin is missing the provides array " + JSON.stringify(plugin)); } if (!plugin.hasOwnProperty("consumes")) { throw new Error("Plugin is missing the consumes array " + JSON.stringify(plugin)); } }); return checkCycles(config, lookup); } function checkCycles(config, lookup) { var plugins = []; config.forEach(function(pluginConfig, index) { plugins.push({ packagePath: pluginConfig.packagePath, provides: pluginConfig.provides.concat(), consumes: pluginConfig.consumes.concat(), i: index }); }); var resolved = { hub: true }; var changed = true; var sorted = []; while(plugins.length && changed) { changed = false; plugins.concat().forEach(function(plugin) { var consumes = plugin.consumes.concat(); var resolvedAll = true; for (var i=0; i