subdivision
Advanced tools
Comparing version 0.3.4 to 0.4.0
@@ -36,2 +36,14 @@ (function (subdivision) { | ||
/** | ||
* Returns all the addins from the given path without any kind of filtering | ||
* @returns an array of addins | ||
*/ | ||
subdivision.getAllAddins = function (path, skipSort) { | ||
var node = subdivision.registry.$getNode(path, false); | ||
if (node === null) { | ||
return []; | ||
} | ||
return skipSort ? node.addins : subdivision.utils.topologicalSort(node.addins); | ||
}; | ||
/** | ||
* Returns an array of all the addins immediately under the given path using the search criteria | ||
@@ -43,7 +55,26 @@ * Search criteria goes as the parameter for lodash filter function, if undefined then all the addins are returned | ||
subdivision.getAddins = function (path, searchCriteria, skipSort) { | ||
var node = subdivision.registry.$getNode(path, false); | ||
if (node === null) { | ||
return []; | ||
} | ||
var result = skipSort ? node.addins : subdivision.utils.topologicalSort(node.addins); | ||
var condition; | ||
var result = subdivision.getAllAddins(path, skipSort); | ||
result = _.filter(result, function (addin) { | ||
if (!addin.hasOwnProperty('isEnabled')) { | ||
return true; | ||
} | ||
if (_.isBoolean(addin.isEnabled)) { | ||
return addin.isEnabled; | ||
} | ||
if (_.isFunction(addin.isEnabled)) { | ||
return addin.isEnabled(); | ||
} | ||
if (_.isString(addin.isEnabled) && subdivision.Condition) { | ||
condition = subdivision.getCondition(addin.isEnabled); | ||
if (condition === undefined) { //generate condition from isValid parser | ||
condition = new subdivision.Condition({ | ||
isValid: addin.isEnabled | ||
}); | ||
} | ||
return condition.isValid(addin); | ||
} | ||
return false; | ||
}); | ||
if (searchCriteria === undefined) { | ||
@@ -50,0 +81,0 @@ return _.clone(result); |
@@ -31,2 +31,3 @@ (function (subdivision) { | ||
subdivision.vent.trigger('before:start'); | ||
if (subdivision.defaultManifest) { | ||
@@ -43,4 +44,6 @@ subdivision.vent.trigger('before:readDefaultManifest'); | ||
buildCommandsInternal(); | ||
}).then(function () { | ||
subdivision.vent.trigger('after:start'); | ||
}); | ||
}; | ||
})(subdivision); |
@@ -70,5 +70,7 @@ (function (subdivision) { | ||
if (name === undefined || name === null) { | ||
throw new Error('name must not be undefined or null'); | ||
} | ||
//this cannot happen because the constructor generates a name | ||
// if (name === undefined || name === null) { | ||
// throw new Error('name must not be undefined or null'); | ||
// } | ||
if (conditions[name] && !force) { | ||
@@ -75,0 +77,0 @@ return false; |
@@ -6,2 +6,2 @@ // subdivision v0.3.4 | ||
!function(a,b){if("function"==typeof define&&define.amd)define(["lodash","exports"],function(c,d){a.subdivision=b(a,d,c)});else if("undefined"!=typeof exports){var c=require("lodash");b(a,exports,c)}else a.subdivision=b(a,{},a._)}(this,function(a,b,c){!function(a){"use strict";var b=[],d=b.slice,e={on:function(a,b,c){if(!g(this,"on",a,[b,c])||!b)return this;this._events=this._events?this._events:{};var d=this._events[a]||(this._events[a]=[]);return d.push({callback:b,context:c,ctx:c||this}),this},once:function(a,b,d){if(!g(this,"once",a,[b,d])||!b)return this;var e=this,f=c.once(function(){e.off(a,f),b.apply(this,arguments)});return f._callback=b,this.on(a,f,d)},off:function(a,b,d){var e,f,h,i,j,k,l,m;if(!this._events||!g(this,"off",a,[b,d]))return this;if(!a&&!b&&!d)return this._events=void 0,this;for(i=a?[a]:c.keys(this._events),j=0,k=i.length;k>j;j++)if(a=i[j],h=this._events[a]){if(this._events[a]=e=[],b||d)for(l=0,m=h.length;m>l;l++)f=h[l],(b&&b!==f.callback&&b!==f.callback._callback||d&&d!==f.context)&&e.push(f);e.length||delete this._events[a]}return this},offContext:function(a){this.off(null,null,a)},trigger:function(a){if(!this._events)return this;var b=d.call(arguments,1);if(!g(this,"trigger",a,b))return this;var c=this._events[a],e=this._events.all;return c&&h(c,b),e&&h(e,arguments),this},stopListening:function(a,b,d){var e=this._listeningTo;if(!e)return this;var f=!b&&!d;d||"object"!=typeof b||(d=this),a&&((e={})[a._listenId]=a);for(var g in e)a=e[g],a.off(b,d,this),(f||c.isEmpty(a._events))&&delete this._listeningTo[g];return this}},f=/\s+/,g=function(a,b,c,d){if(!c)return!0;if("object"==typeof c){for(var e in c)a[b].apply(a,[e,c[e]].concat(d));return!1}if(f.test(c)){for(var g=c.split(f),h=0,i=g.length;i>h;h++)a[b].apply(a,[g[h]].concat(d));return!1}return!0},h=function(a,b){var c,d=-1,e=a.length,f=b[0],g=b[1],h=b[2];switch(b.length){case 0:for(;++d<e;)(c=a[d]).callback.call(c.ctx);return;case 1:for(;++d<e;)(c=a[d]).callback.call(c.ctx,f);return;case 2:for(;++d<e;)(c=a[d]).callback.call(c.ctx,f,g);return;case 3:for(;++d<e;)(c=a[d]).callback.call(c.ctx,f,g,h);return;default:for(;++d<e;)(c=a[d]).callback.apply(c.ctx,b);return}},i={listenTo:"on",listenToOnce:"once"};c.each(i,function(a,b){e[b]=function(b,d,e){var f=this._listeningTo||(this._listeningTo={}),g=b._listenId||(b._listenId=c.uniqueId("l"));return f[g]=b,e||"object"!=typeof d||(e=this),b[a](d,e,this),this}}),a.Events=e,a.createEventBus=function(b){return b=b||{},c.assign(b,a.Events)}}(b),function(a){"use strict";function b(a){this.id=g++,this.mergedIds={},this.addins=[a],this.order=c.isNumber(a.order)?a.order:0,this.dependsOnClusters={},this.activeAddin=a}function d(a){var b,c,d;for(c=1;c<arguments.length;c++)for(d=arguments[c],b=0;b<d.length;b++)if(d[b].containsAddin(a))return d[b];return null}function e(a){var e,f,g,h,i,j=[],k=null,l=null;for(e=c.map(a,function(a){return new b(a)});e.length>0;)if(f=e.pop(),h=f.activeAddin,c.isString(h.order))for(i=h.order.split(","),g=0;g<i.length;g++)if(0===c.indexOf(i[g],">"))if(1===c.indexOf(i[g],">",1)){if(k=i[g].substring(2),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for >> dependency");if(l.id===f.id&&!l.verifyOrder(k,h.id))throw new Error("Could not find appropriate order for "+k+" and "+h.id);f.dependsOnClusters[l.id]=!0,c.includes(j,f)||j.push(f)}else{if(g!==i.length-1)throw new Error("> dependency must be last in "+h.order+" at "+h.id);if(k=i[g].substring(1),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for > dependency");if(l.id!==f.id){if(l.last().id===k){if(l.dependsOnClusters[f.id])throw new Error("Could not find appropriate order for "+k+" and "+h.id);l.mergeToEnd(f),c.remove(j,f);break}throw new Error("Could not fulfill > dependency for "+k+" because "+l.last().id+" already has the same dependency")}if(!l.verifyOrder(k,h.id,!0))throw new Error("Could not find appropriate order for "+k+" and "+h.id);c.includes(j,f)||j.push(f)}else{if(0!==c.indexOf(i[g],"<"))throw new Error("order must begin with <, <<, >, >> or be a number");if(1===c.indexOf(i[g],"<",1)){if(k=i[g].substring(2),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for << dependency");if(l.id===f.id&&!l.verifyOrder(h.id,k))throw new Error("Could not find appropriate order for "+k+" and "+h.id);l.dependsOnClusters[f.id]=!0,c.includes(j,f)||j.push(f)}else{if(g!==i.length-1)throw new Error("< dependency must be last in "+h.order+" at "+h.id);if(k=i[g].substring(1),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for < dependency");if(l.id!==f.id){if(l.first().id===k){if(f.dependsOnClusters[l.id])throw new Error("Could not find appropriate order for "+k+" and "+h.id);l.mergeToFront(f),c.remove(j,f);break}throw new Error("Could not fulfill < dependency for "+k+" because "+l.first().id+" already has the same dependency")}if(!l.verifyOrder(h.id,k,!0))throw new Error("Could not find appropriate order for "+k+" and "+h.id);c.includes(j,f)||j.push(f)}}else{if(!c.isNumber(h.order))throw new Error("order must begin with <, <<, >, >> or be a number");j.push(f)}return j}function f(a){for(var b,d,e,f,g,h=[],i=[],j=c.clone(a),k=[];j.length>0;){for(g=j.length,k=[],i=[],b=0;b<j.length;b++)0===c.keys(j[b].dependsOnClusters).length?k.push(j[b]):i.push(j[b]);for(b=0;b<k.length;b++)for(f=c.keys(k[b].mergedIds),f.push(String(k[b].id)),e=0;e<f.length;e++)for(d=0;d<i.length;d++)delete i[d].dependsOnClusters[f[e]];for(k=c.sortBy(k,"order"),b=0;b<k.length;b++)for(d=0;d<k[b].addins.length;d++)h.push(k[b].addins[d]);if(j=i,g===j.length)throw new Error("Circular dependency detected in topological sort")}return h}var g=0;b.prototype.containsAddin=function(a){return-1!==c.findIndex(this.addins,{id:a})},b.prototype.verifyOrder=function(a,b,d){if(a===b)return!1;var e=c.findIndex(this.addins,{id:a});if(-1===e)throw new Error("Could not find addin with id "+a+" in cluster "+this.id);var f=c.findIndex(this.addins,{id:b});if(-1===f)throw new Error("Could not find addin with id "+b+" in cluster "+this.id);var g=f-e;return d?1===g:g>0},b.prototype.first=function(){return this.addins[0]},b.prototype.last=function(){return this.addins[this.addins.length-1]},b.prototype.mergeToEnd=function(a){var b;for(b=0;b<a.addins.length;b++)this.addins.push(a.addins[b]);this.mergedIds[a.id]=!0,this.mergedIds=c.assign(this.mergedIds,a.mergedIds),this.dependsOnClusters=c.assign(this.dependsOnClusters,a.dependsOnClusters)},b.prototype.mergeToFront=function(a){var b;for(b=a.addins.length-1;b>=0;b--)this.addins.unshift(a.addins[b]);this.mergedIds[a.id]=!0,this.mergedIds=c.assign(this.mergedIds,a.mergedIds),this.dependsOnClusters=c.assign(this.dependsOnClusters,a.dependsOnClusters)},a.utils||(a.utils={}),a.utils.topologicalSort=function(b){var c=a.utils.topologicalSort._formSortClusters(b);return a.utils.topologicalSort._sortClusters(c)},a.utils.topologicalSort._formSortClusters=e,a.utils.topologicalSort._sortClusters=f}(b),function(a){"use strict";function b(a,d){if(this.data=null,this.depth=d,c.isEmpty(a))throw new Error("can not evaluate an empty expression");a=a.trim();for(var e,f=!1;!f;)e=this.analyzeExpression(a),e.parenthesesExpression?a=a.substring(1,a.length-1):f=!0;if(e.unaryOperator){var g=new b(e.expression,this.depth+1);this.data=this.createUnaryNotNodeData(g)}else if(e.literal)this.data=this.createLiteralNodeData(e.literal);else{if(!e.binaryOperator)throw new Error("could not analyze expression: "+a);this.data=this.createBinaryOperandNodeData(new b(e.leftOperand,this.depth+1),new b(e.rightOperand,this.depth+1),e.binaryOperator)}}function d(){this.expresionTreeRoot=null}var e="(",f=")",g="!",h="|",i="&";b.prototype.analyzeExpression=function(a){for(var b,c=0,d=0,j=null,k=0,l=0,m=a.length;m>l;l++)if(b=a[l],b===e?c++:b===f&&d++,!(this.isWhiteSpaceChar(b)||c>d))if(c===d&&this.isBinaryOperand(b))(!j||j&&j===i&&b===h)&&(j=b,k=l);else if(d>c)throw new Error("mismatch of parentheses");if(null!==j){var n=a.substring(0,k).trim(),o=a.substring(k+1,a.length+1).trim();if(!n||!o)throw new Error("one or more operands are missing in expression: "+a);return{leftOperand:n,binaryOperator:j,rightOperand:o}}if(a[0]===e){if(c===d){if(a[a.length-1]===f)return{parenthesesExpression:!0};throw new Error("operator is missing between two operands")}throw c>d?new Error("unclosed parentheses"):new Error("mismatch of parentheses")}if(a[0]===g)return{unaryOperator:g,expression:a.substring(1,a.length+1)};if(0===c)return{literal:a};throw new Error("should not have happened. expresion does not fall into any one of the patterns")},b.prototype.isBinaryOperand=function(a){return a===h||a===i},b.prototype.isWhiteSpaceChar=function(a){return a!==a.trim()},b.prototype.createUnaryNotNodeData=function(a){return{operator:g,child:a,evaluate:function(b){return b.not(a.evaluate(b))}}},b.prototype.createLiteralNodeData=function(a){return{literal:a,evaluate:function(b){var c=b.literal(a);if(null===c||void 0===c)throw new Error("could not resolve literal: "+a);return c}}},b.prototype.createBinaryOperandNodeData=function(a,b,c){return{operator:c,leftChildNode:a,rightChildNode:b,evaluate:function(c){return this.operator===h?c.or(a.evaluate(c),b.evaluate(c)):this.operator===i?c.and(a.evaluate(c),b.evaluate(c)):void 0}}},b.prototype.evaluate=function(a){return this.data.evaluate(a)},d.prototype.parse=function(a){this.expresionTreeRoot=new b(a,0);var c=this.expresionTreeRoot;return function(a){return c.evaluate(a)}},d.prototype.evaluate=function(a,b){if(!b)throw new Error("context was not supplied");return this.parse(a)(b)},a.utils||(a.utils={}),a.utils.BooleanPhraseParser=d}(b),function(a){"use strict";function b(){return c.isFunction(a.buildServices)?(a.vent.trigger("before:buildServices"),a.buildServices().then(function(){a.vent.trigger("after:buildServices")})):Promise.resolve()}function d(){var b=a.build(a.systemPaths.commands);c.forEach(b,function(b){a.addCommand(b,!0)})}a.systemPaths={prefix:"subdivision"},a.vent=a.createEventBus(),a.start=function(){return a.defaultManifest&&(a.vent.trigger("before:readDefaultManifest"),a.readManifest(a.defaultManifest),a.vent.trigger("after:readDefaultManifest")),a.$generateBuilders(),b().then(function(){d()})}}(b),function(a){"use strict";function b(a){this.name=a,this.nodes={},this.addins=[]}var d,e="/";b.prototype.addAddin=function(a){this.addins.push(a)},a.registry={$defaultOrder:100,$getNode:function(e,f){c.isString(e)&&(e=a.registry.breakPath(e));var g,h=d;for(g=0;g<e.length;g++){if(!h.nodes[e[g]]){if(!f)return null;h.nodes[e[g]]=new b(e[g])}h=h.nodes[e[g]]}return h},verifyAxis:function(a){return c.isString(a)?c.isEmpty(a)||c.indexOf(a,e)>=0?!1:!0:!1},joinPath:function(){if(0===arguments.length)return"";if(arguments[0]instanceof Array)return a.registry.joinPath.apply(this,c.flatten(arguments[0]));var b=Array.prototype.slice.call(arguments,0),d=[];return c.forEach(b,function(b){var c,e=a.registry.breakPath(b);for(c=0;c<e.length;c++)d.push(e[c])}),0===d.length?"":d.join(e)},breakPath:function(b){if(!c.isString(b))throw new Error("path must be a string "+JSON.stringify(b));if(""===b)return[];var d=b.split(e);return c.forEach(d,function(b){if(!a.registry.verifyAxis(b))throw new Error("Invalid axis "+b)}),d},pathExists:function(a){var b=this.$getNode(a,!1);return null!==b},getSubPaths:function(a){var b=this.$getNode(a,!1);return null!==b?c.keys(b.nodes):null},$clear:function(){d=new b("")}},a.registry.$clear()}(b),function(a){"use strict";a.defaultManifest={paths:[]}}(b),function(a){"use strict";var b=0;a.Addin=function(c){return a.Addin.$internalConstructor("addin",b++,c)},a.Addin.$internalConstructor=function(a,b,d){d=c.isFunction(d)?d():d||{};var e=c.assign({},d);return e.id=e.id?String(e.id):a+b,e.order=e.order||0,e},a.addAddin=function(b,c){if(void 0===b||null===b)throw new Error("path was not defined for addin "+JSON.stringify(c));var d=a.registry.$getNode(b,!0);c&&d.addAddin(c)},a.getAddins=function(b,d,e){var f=a.registry.$getNode(b,!1);if(null===f)return[];var g=e?f.addins:a.utils.topologicalSort(f.addins);return void 0===d?c.clone(g):c.filter(g,d)}}(b),function(a){"use strict";function b(c,d,e,f){var g=a.getBuilder(c);return g.preBuildTarget&&(d=b(g.preBuildTarget,d,e,f)),g.build(d,e,f)}function d(b,c,e,f){try{var g=a.getBuilder(b),h=Promise.resolve(c);return g.preBuildTarget&&(h=d(g.preBuildTarget,c,e,f)),h.then(function(a){return g.build(a,e,f)})}catch(i){return Promise.reject(i)}}var e,f,g=0;a.Builder=function(b){var d=a.Addin.$internalConstructor("builder",g++,b);if(!c.isFunction(d.build))throw new Error('Builder options must contain the "build" function '+JSON.stringify(b));return d.target=void 0===d.target?"":d.target,d},a.systemPaths.builders=a.registry.joinPath(a.systemPaths.prefix,"builders"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{id:"subdivision.defaultBuilder",type:"subdivision.builder",target:null,order:a.registry.$defaultOrder,build:function(a){return c.cloneDeep(a)}}]}),a.addBuilder=function(b,c){var d=new a.Builder(b);return null===d.target?!f||c?(f=d,!0):!1:!e.hasOwnProperty(d.target)||c?(e[d.target]=d,!0):!1},a.getBuilder=function(a){if(null===a&&f)return f;if(e.hasOwnProperty(a))return e[a];if(f)return f;throw new Error('No builder of type "'+a+'" was defined and no default builder was registered')},a.build=function(d,e,f,g){var h=a.getAddins(d,f,g);return 0===h.length?h:c.map(h,function(a){return b(a.type,a,e,{path:d})})},a.build.async=function(b,e,f,g){var h=a.getAddins(b,f,g);if(0===h.length)return Promise.resolve(h);var i=c.map(h,function(a){return d(a.type,a,e,{path:b})});return Promise.all(i)},a.buildAddin=function(a,c){return b(a.type,a,c,{path:null})},a.buildAddin.async=function(a,b){return d(a.type,a,b,{path:null})},a.buildTree=function(d,e){var f=a.getAddins(d);return 0===f.length?f:c.map(f,function(c){var f=b(c.type,c,e,{path:d}),g=c.itemsProperty||"$items";return f[g]=a.buildTree(a.registry.joinPath(d,c.id),e),f})},a.$generateBuilders=function(){a.$clearBuilders();var b=a.getAddins(a.systemPaths.builders,{target:null});b.length>0&&(f=new a.Builder(b[0])),b=a.getAddins(a.systemPaths.builders),c.forEach(b,function(b){a.addBuilder(b)})},a.$clearBuilders=function(){e={},f=null},a.$clearBuilders(),Object.defineProperty(a,"builders",{enumerable:!0,configurable:!1,get:function(){return c.clone(e)}})}(b),function(a){"use strict";function b(a){return a?b(a.$next).then(function(){var b;return a.hasOwnProperty("initialize")&&c.isFunction(a.initialize)&&(b=a.initialize()),Promise.resolve(b)}):Promise.resolve()}var d;a.Service=function(b,d){var e=Object.create(d||{});return c.isFunction(b)&&(b=b()),b=b||{},e=c.assign(e,{$vent:a.createEventBus(),$next:d?d:void 0},b)},a.systemPaths.services=a.registry.joinPath(a.systemPaths.prefix,"services"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.service",id:"subdivision.serviceBuilder",order:a.registry.$defaultOrder,build:function(b){if(c.isString(b.name)&&!c.isEmpty(b.name))return a.addService(b.name,b.content,b.override);throw new Error("Service name must be defined "+JSON.stringify(b))}}]}),a.getService=function(a){return d[a]},a.addService=function(b,c,e){b=String(b).trim();var f;e||(f=a.getService(b));var g=new a.Service(c,f);return d[b]=g,g.$name=b,g},a.$clearServices=function(){d={}},a.buildServices=function(){a.$clearServices();var d=a.build(a.systemPaths.services),e=new Set;return c.reduce(d,function(c,d){return e.has(d.$name)?c:(e.add(d.$name),a.vent.trigger("before:service:initialized",d.$name),c.then(function(){return b(a.getService(d.$name)).then(function(){a.vent.trigger("after:service:initialized",d.$name,a.getService(d.$name))})}))},Promise.resolve())},Object.defineProperty(a,"services",{enumerable:!0,configurable:!1,get:function(){return c.clone(d)}})}(b),function(a){"use strict";var b=0,d={};a.Command=function(d){d=d||{};var e=a.Addin.$internalConstructor("command",b++,d);if(e.name=d.name||e.id,!c.isFunction(e.execute))throw new Error('Command options must contain the "execute" function '+JSON.stringify(d));return e.hasOwnProperty("isValid")||(e.isValid=!0),e.hasOwnProperty("canExecute")||(e.canExecute=a.Command.$canExecute),e},a.Command.$canExecute=function(){var b,d=!0;this.hasOwnProperty("condition")&&(b=this.condition,c.isString(b)&&(b=a.getCondition(b),void 0===b&&(b=new a.Condition({isValid:this.condition}))),d=b.isValid(this));var e=!0;return this.hasOwnProperty("isValid")&&(e=c.isFunction(this.isValid)?this.isValid():Boolean(this.isValid)),d&&e},a.systemPaths.commands=a.registry.joinPath(a.systemPaths.prefix,"commands"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.command",id:"subdivision.commandBuilder",order:a.registry.$defaultOrder,build:function(b){return new a.Command(b)}}]}),a.getCommand=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");return d[a]},a.addCommand=function(b,e){var f=new a.Command(b),g=f.name;if(void 0===g||null===g)throw new Error("name must not be undefined or null");return d[g]&&!e?!1:(a.removeCommand(g),d[g]=f,c.isFunction(f.initialize)&&f.initialize(),!0)},a.removeCommand=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");d[a]&&c.isFunction(d[a].destroy)&&d[a].destroy(),d[a]=void 0},a.$clearCommands=function(){d={}},Object.defineProperty(a,"commands",{enumerable:!0,configurable:!1,get:function(){return c.clone(d)}})}(b),function(a){"use strict";var b=0,d={};a.Condition=function(d){d=d||{};var e=a.Addin.$internalConstructor("condition",b++,d);if(e.name=d.name||e.id,c.isString(e.isValid)){var f=e.isValid;e.isValid=function(){var b=new a.utils.BooleanPhraseParser,c=a.Condition.$buildContext(),d=b.evaluate(f,c);return d.isValid()}}if(!c.isFunction(e.isValid))throw new Error("A condition must have an isValid function "+e.id);return e},a.Condition.$buildContext=function(){var b=a.build(a.systemPaths.conditionOperations,null,{literal:"!"})[0],c=a.build(a.systemPaths.conditionOperations,null,{literal:"&"})[0],d=a.build(a.systemPaths.conditionOperations,null,{literal:"|"})[0];if(b&&c&&d)return{not:b.generator,and:c.generator,or:d.generator,literal:function(b){return a.getCondition(b)}};throw new Error('Condition operators for "not", "and", "or" must exist')},a.systemPaths.conditions=a.registry.joinPath(a.systemPaths.prefix,"conditions"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.condition",id:"subdivision.conditionBuilder",order:a.registry.$defaultOrder,build:function(b){var c=new a.Condition(b);return c}}]}),a.getCondition=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");return d[a]},a.addCondition=function(b,e){var f=new a.Condition(b),g=f.name;if(void 0===g||null===g)throw new Error("name must not be undefined or null");return d[g]&&!e?!1:(a.removeCondition(g),d[g]=f,c.isFunction(f.initialize)&&f.initialize(),!0)},a.removeCondition=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");d[a]&&c.isFunction(d[a].destroy)&&d[a].destroy(),d[a]=void 0},a.$clearConditions=function(){d={}},a.systemPaths.conditionOperations=a.registry.joinPath(a.systemPaths.prefix,"conditionOperations"),a.Condition.$conditionOperationBuilder={target:"subdivision.conditionOperation",id:"subdivision.conditionOperationBuilder",order:a.registry.$defaultOrder,build:function(a){return{literal:a.literal,generator:a.generator}}},a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[a.Condition.$conditionOperationBuilder]}),a.defaultManifest.paths.push({path:a.systemPaths.conditionOperations,addins:[{id:"NotConditionOperation",literal:"!",type:"subdivision.conditionOperation",generator:function(a){return{isValid:function(){if(c.isFunction(a.isValid))return!Boolean(a.isValid());throw new Error('Cannot evaluate "!" operation because the target has no isValid function '+JSON.stringify(a))}}}},{id:"OrConditionOperation",literal:"|",type:"subdivision.conditionOperation",generator:function(a,b){return{isValid:function(){if(!c.isFunction(a.isValid))throw new Error('Cannot evaluate "|" operation because the first target has no isValid function '+JSON.stringify(a));if(!c.isFunction(b.isValid))throw new Error('Cannot evaluate "|" operation because the second target has no isValid function '+JSON.stringify(b));return Boolean(a.isValid())||Boolean(b.isValid())}}}},{id:"AndConditionOperation",literal:"&",type:"subdivision.conditionOperation",generator:function(a,b){return{isValid:function(){if(!c.isFunction(a.isValid))throw new Error('Cannot evaluate "&" operation because the first target has no isValid function '+JSON.stringify(a));if(!c.isFunction(b.isValid))throw new Error('Cannot evaluate "&" operation because the second target has no isValid function '+JSON.stringify(b));return Boolean(a.isValid())&&Boolean(b.isValid())}}}}]}),Object.defineProperty(a,"conditions",{enumerable:!0,configurable:!1,get:function(){return c.clone(d)}})}(b),function(a){"use strict";var b;a.systemPaths.values=a.registry.joinPath(a.systemPaths.prefix,"values"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.value",id:"subdivision.valueBuilder",order:a.registry.$defaultOrder,build:function(b){if(c.isNil(b.name))throw new Error("Value name must be defined "+JSON.stringify(b));if(!b.hasOwnProperty("value"))throw new Error("Value must have a value property "+JSON.stringify(b));a.addValue(b.name,b.value,!0)}}]}),a.getValue=function(a){return b[a]},a.addValue=function(a,d,e){if(c.isNil(a))throw new Error("Value name must be defined");if(!e&&b.hasOwnProperty(a))throw new Error("A value with the name "+a+" already exists");b[a]=d},a.$clearValues=function(){b={}},a.buildValues=function(){a.vent.trigger("before:values:built"),a.$clearValues(),a.build(a.systemPaths.values),a.vent.trigger("after:values:built")},Object.defineProperty(a,"values",{enumerable:!0,configurable:!1,get:function(){return c.clone(b)}})}(b),function(a){"use strict";a.readManifest=function(b){c.forEach(b.paths,function(b){c.forEach(b.addins,function(c){a.addAddin(b.path,new a.Addin(c))})})}}(b)}); | ||
!function(a,b){if("function"==typeof define&&define.amd)define(["lodash","exports"],function(c,d){a.subdivision=b(a,d,c)});else if("undefined"!=typeof exports){var c=require("lodash");b(a,exports,c)}else a.subdivision=b(a,{},a._)}(this,function(a,b,c){!function(a){"use strict";var b=[],d=b.slice,e={on:function(a,b,c){if(!g(this,"on",a,[b,c])||!b)return this;this._events=this._events?this._events:{};var d=this._events[a]||(this._events[a]=[]);return d.push({callback:b,context:c,ctx:c||this}),this},once:function(a,b,d){if(!g(this,"once",a,[b,d])||!b)return this;var e=this,f=c.once(function(){e.off(a,f),b.apply(this,arguments)});return f._callback=b,this.on(a,f,d)},off:function(a,b,d){var e,f,h,i,j,k,l,m;if(!this._events||!g(this,"off",a,[b,d]))return this;if(!a&&!b&&!d)return this._events=void 0,this;for(i=a?[a]:c.keys(this._events),j=0,k=i.length;k>j;j++)if(a=i[j],h=this._events[a]){if(this._events[a]=e=[],b||d)for(l=0,m=h.length;m>l;l++)f=h[l],(b&&b!==f.callback&&b!==f.callback._callback||d&&d!==f.context)&&e.push(f);e.length||delete this._events[a]}return this},offContext:function(a){this.off(null,null,a)},trigger:function(a){if(!this._events)return this;var b=d.call(arguments,1);if(!g(this,"trigger",a,b))return this;var c=this._events[a],e=this._events.all;return c&&h(c,b),e&&h(e,arguments),this},stopListening:function(a,b,d){var e=this._listeningTo;if(!e)return this;var f=!b&&!d;d||"object"!=typeof b||(d=this),a&&((e={})[a._listenId]=a);for(var g in e)a=e[g],a.off(b,d,this),(f||c.isEmpty(a._events))&&delete this._listeningTo[g];return this}},f=/\s+/,g=function(a,b,c,d){if(!c)return!0;if("object"==typeof c){for(var e in c)a[b].apply(a,[e,c[e]].concat(d));return!1}if(f.test(c)){for(var g=c.split(f),h=0,i=g.length;i>h;h++)a[b].apply(a,[g[h]].concat(d));return!1}return!0},h=function(a,b){var c,d=-1,e=a.length,f=b[0],g=b[1],h=b[2];switch(b.length){case 0:for(;++d<e;)(c=a[d]).callback.call(c.ctx);return;case 1:for(;++d<e;)(c=a[d]).callback.call(c.ctx,f);return;case 2:for(;++d<e;)(c=a[d]).callback.call(c.ctx,f,g);return;case 3:for(;++d<e;)(c=a[d]).callback.call(c.ctx,f,g,h);return;default:for(;++d<e;)(c=a[d]).callback.apply(c.ctx,b);return}},i={listenTo:"on",listenToOnce:"once"};c.each(i,function(a,b){e[b]=function(b,d,e){var f=this._listeningTo||(this._listeningTo={}),g=b._listenId||(b._listenId=c.uniqueId("l"));return f[g]=b,e||"object"!=typeof d||(e=this),b[a](d,e,this),this}}),a.Events=e,a.createEventBus=function(b){return b=b||{},c.assign(b,a.Events)}}(b),function(a){"use strict";function b(a){this.id=g++,this.mergedIds={},this.addins=[a],this.order=c.isNumber(a.order)?a.order:0,this.dependsOnClusters={},this.activeAddin=a}function d(a){var b,c,d;for(c=1;c<arguments.length;c++)for(d=arguments[c],b=0;b<d.length;b++)if(d[b].containsAddin(a))return d[b];return null}function e(a){var e,f,g,h,i,j=[],k=null,l=null;for(e=c.map(a,function(a){return new b(a)});e.length>0;)if(f=e.pop(),h=f.activeAddin,c.isString(h.order))for(i=h.order.split(","),g=0;g<i.length;g++)if(0===c.indexOf(i[g],">"))if(1===c.indexOf(i[g],">",1)){if(k=i[g].substring(2),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for >> dependency");if(l.id===f.id&&!l.verifyOrder(k,h.id))throw new Error("Could not find appropriate order for "+k+" and "+h.id);f.dependsOnClusters[l.id]=!0,c.includes(j,f)||j.push(f)}else{if(g!==i.length-1)throw new Error("> dependency must be last in "+h.order+" at "+h.id);if(k=i[g].substring(1),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for > dependency");if(l.id!==f.id){if(l.last().id===k){if(l.dependsOnClusters[f.id])throw new Error("Could not find appropriate order for "+k+" and "+h.id);l.mergeToEnd(f),c.remove(j,f);break}throw new Error("Could not fulfill > dependency for "+k+" because "+l.last().id+" already has the same dependency")}if(!l.verifyOrder(k,h.id,!0))throw new Error("Could not find appropriate order for "+k+" and "+h.id);c.includes(j,f)||j.push(f)}else{if(0!==c.indexOf(i[g],"<"))throw new Error("order must begin with <, <<, >, >> or be a number");if(1===c.indexOf(i[g],"<",1)){if(k=i[g].substring(2),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for << dependency");if(l.id===f.id&&!l.verifyOrder(h.id,k))throw new Error("Could not find appropriate order for "+k+" and "+h.id);l.dependsOnClusters[f.id]=!0,c.includes(j,f)||j.push(f)}else{if(g!==i.length-1)throw new Error("< dependency must be last in "+h.order+" at "+h.id);if(k=i[g].substring(1),l=d(k,e,j,[f]),null===l)throw new Error("Could not find cluster with id "+k+" for < dependency");if(l.id!==f.id){if(l.first().id===k){if(f.dependsOnClusters[l.id])throw new Error("Could not find appropriate order for "+k+" and "+h.id);l.mergeToFront(f),c.remove(j,f);break}throw new Error("Could not fulfill < dependency for "+k+" because "+l.first().id+" already has the same dependency")}if(!l.verifyOrder(h.id,k,!0))throw new Error("Could not find appropriate order for "+k+" and "+h.id);c.includes(j,f)||j.push(f)}}else{if(!c.isNumber(h.order))throw new Error("order must begin with <, <<, >, >> or be a number");j.push(f)}return j}function f(a){for(var b,d,e,f,g,h=[],i=[],j=c.clone(a),k=[];j.length>0;){for(g=j.length,k=[],i=[],b=0;b<j.length;b++)0===c.keys(j[b].dependsOnClusters).length?k.push(j[b]):i.push(j[b]);for(b=0;b<k.length;b++)for(f=c.keys(k[b].mergedIds),f.push(String(k[b].id)),e=0;e<f.length;e++)for(d=0;d<i.length;d++)delete i[d].dependsOnClusters[f[e]];for(k=c.sortBy(k,"order"),b=0;b<k.length;b++)for(d=0;d<k[b].addins.length;d++)h.push(k[b].addins[d]);if(j=i,g===j.length)throw new Error("Circular dependency detected in topological sort")}return h}var g=0;b.prototype.containsAddin=function(a){return-1!==c.findIndex(this.addins,{id:a})},b.prototype.verifyOrder=function(a,b,d){if(a===b)return!1;var e=c.findIndex(this.addins,{id:a});if(-1===e)throw new Error("Could not find addin with id "+a+" in cluster "+this.id);var f=c.findIndex(this.addins,{id:b});if(-1===f)throw new Error("Could not find addin with id "+b+" in cluster "+this.id);var g=f-e;return d?1===g:g>0},b.prototype.first=function(){return this.addins[0]},b.prototype.last=function(){return this.addins[this.addins.length-1]},b.prototype.mergeToEnd=function(a){var b;for(b=0;b<a.addins.length;b++)this.addins.push(a.addins[b]);this.mergedIds[a.id]=!0,this.mergedIds=c.assign(this.mergedIds,a.mergedIds),this.dependsOnClusters=c.assign(this.dependsOnClusters,a.dependsOnClusters)},b.prototype.mergeToFront=function(a){var b;for(b=a.addins.length-1;b>=0;b--)this.addins.unshift(a.addins[b]);this.mergedIds[a.id]=!0,this.mergedIds=c.assign(this.mergedIds,a.mergedIds),this.dependsOnClusters=c.assign(this.dependsOnClusters,a.dependsOnClusters)},a.utils||(a.utils={}),a.utils.topologicalSort=function(b){var c=a.utils.topologicalSort._formSortClusters(b);return a.utils.topologicalSort._sortClusters(c)},a.utils.topologicalSort._formSortClusters=e,a.utils.topologicalSort._sortClusters=f}(b),function(a){"use strict";function b(a,d){if(this.data=null,this.depth=d,c.isEmpty(a))throw new Error("can not evaluate an empty expression");a=a.trim();for(var e,f=!1;!f;)e=this.analyzeExpression(a),e.parenthesesExpression?a=a.substring(1,a.length-1):f=!0;if(e.unaryOperator){var g=new b(e.expression,this.depth+1);this.data=this.createUnaryNotNodeData(g)}else if(e.literal)this.data=this.createLiteralNodeData(e.literal);else{if(!e.binaryOperator)throw new Error("could not analyze expression: "+a);this.data=this.createBinaryOperandNodeData(new b(e.leftOperand,this.depth+1),new b(e.rightOperand,this.depth+1),e.binaryOperator)}}function d(){this.expresionTreeRoot=null}var e="(",f=")",g="!",h="|",i="&";b.prototype.analyzeExpression=function(a){for(var b,c=0,d=0,j=null,k=0,l=0,m=a.length;m>l;l++)if(b=a[l],b===e?c++:b===f&&d++,!(this.isWhiteSpaceChar(b)||c>d))if(c===d&&this.isBinaryOperand(b))(!j||j&&j===i&&b===h)&&(j=b,k=l);else if(d>c)throw new Error("mismatch of parentheses");if(null!==j){var n=a.substring(0,k).trim(),o=a.substring(k+1,a.length+1).trim();if(!n||!o)throw new Error("one or more operands are missing in expression: "+a);return{leftOperand:n,binaryOperator:j,rightOperand:o}}if(a[0]===e){if(c===d){if(a[a.length-1]===f)return{parenthesesExpression:!0};throw new Error("operator is missing between two operands")}throw c>d?new Error("unclosed parentheses"):new Error("mismatch of parentheses")}if(a[0]===g)return{unaryOperator:g,expression:a.substring(1,a.length+1)};if(0===c)return{literal:a};throw new Error("should not have happened. expresion does not fall into any one of the patterns")},b.prototype.isBinaryOperand=function(a){return a===h||a===i},b.prototype.isWhiteSpaceChar=function(a){return a!==a.trim()},b.prototype.createUnaryNotNodeData=function(a){return{operator:g,child:a,evaluate:function(b){return b.not(a.evaluate(b))}}},b.prototype.createLiteralNodeData=function(a){return{literal:a,evaluate:function(b){var c=b.literal(a);if(null===c||void 0===c)throw new Error("could not resolve literal: "+a);return c}}},b.prototype.createBinaryOperandNodeData=function(a,b,c){return{operator:c,leftChildNode:a,rightChildNode:b,evaluate:function(c){return this.operator===h?c.or(a.evaluate(c),b.evaluate(c)):this.operator===i?c.and(a.evaluate(c),b.evaluate(c)):void 0}}},b.prototype.evaluate=function(a){return this.data.evaluate(a)},d.prototype.parse=function(a){this.expresionTreeRoot=new b(a,0);var c=this.expresionTreeRoot;return function(a){return c.evaluate(a)}},d.prototype.evaluate=function(a,b){if(!b)throw new Error("context was not supplied");return this.parse(a)(b)},a.utils||(a.utils={}),a.utils.BooleanPhraseParser=d}(b),function(a){"use strict";function b(){return c.isFunction(a.buildServices)?(a.vent.trigger("before:buildServices"),a.buildServices().then(function(){a.vent.trigger("after:buildServices")})):Promise.resolve()}function d(){var b=a.build(a.systemPaths.commands);c.forEach(b,function(b){a.addCommand(b,!0)})}a.systemPaths={prefix:"subdivision"},a.vent=a.createEventBus(),a.start=function(){return a.vent.trigger("before:start"),a.defaultManifest&&(a.vent.trigger("before:readDefaultManifest"),a.readManifest(a.defaultManifest),a.vent.trigger("after:readDefaultManifest")),a.$generateBuilders(),b().then(function(){d()}).then(function(){a.vent.trigger("after:start")})}}(b),function(a){"use strict";function b(a){this.name=a,this.nodes={},this.addins=[]}var d,e="/";b.prototype.addAddin=function(a){this.addins.push(a)},a.registry={$defaultOrder:100,$getNode:function(e,f){c.isString(e)&&(e=a.registry.breakPath(e));var g,h=d;for(g=0;g<e.length;g++){if(!h.nodes[e[g]]){if(!f)return null;h.nodes[e[g]]=new b(e[g])}h=h.nodes[e[g]]}return h},verifyAxis:function(a){return c.isString(a)?c.isEmpty(a)||c.indexOf(a,e)>=0?!1:!0:!1},joinPath:function(){if(0===arguments.length)return"";if(arguments[0]instanceof Array)return a.registry.joinPath.apply(this,c.flatten(arguments[0]));var b=Array.prototype.slice.call(arguments,0),d=[];return c.forEach(b,function(b){var c,e=a.registry.breakPath(b);for(c=0;c<e.length;c++)d.push(e[c])}),0===d.length?"":d.join(e)},breakPath:function(b){if(!c.isString(b))throw new Error("path must be a string "+JSON.stringify(b));if(""===b)return[];var d=b.split(e);return c.forEach(d,function(b){if(!a.registry.verifyAxis(b))throw new Error("Invalid axis "+b)}),d},pathExists:function(a){var b=this.$getNode(a,!1);return null!==b},getSubPaths:function(a){var b=this.$getNode(a,!1);return null!==b?c.keys(b.nodes):null},$clear:function(){d=new b("")}},a.registry.$clear()}(b),function(a){"use strict";a.defaultManifest={paths:[]}}(b),function(a){"use strict";var b=0;a.Addin=function(c){return a.Addin.$internalConstructor("addin",b++,c)},a.Addin.$internalConstructor=function(a,b,d){d=c.isFunction(d)?d():d||{};var e=c.assign({},d);return e.id=e.id?String(e.id):a+b,e.order=e.order||0,e},a.addAddin=function(b,c){if(void 0===b||null===b)throw new Error("path was not defined for addin "+JSON.stringify(c));var d=a.registry.$getNode(b,!0);c&&d.addAddin(c)},a.getAllAddins=function(b,c){var d=a.registry.$getNode(b,!1);return null===d?[]:c?d.addins:a.utils.topologicalSort(d.addins)},a.getAddins=function(b,d,e){var f,g=a.getAllAddins(b,e);return g=c.filter(g,function(b){return b.hasOwnProperty("isEnabled")?c.isBoolean(b.isEnabled)?b.isEnabled:c.isFunction(b.isEnabled)?b.isEnabled():c.isString(b.isEnabled)&&a.Condition?(f=a.getCondition(b.isEnabled),void 0===f&&(f=new a.Condition({isValid:b.isEnabled})),f.isValid(b)):!1:!0}),void 0===d?c.clone(g):c.filter(g,d)}}(b),function(a){"use strict";function b(c,d,e,f){var g=a.getBuilder(c);return g.preBuildTarget&&(d=b(g.preBuildTarget,d,e,f)),g.build(d,e,f)}function d(b,c,e,f){try{var g=a.getBuilder(b),h=Promise.resolve(c);return g.preBuildTarget&&(h=d(g.preBuildTarget,c,e,f)),h.then(function(a){return g.build(a,e,f)})}catch(i){return Promise.reject(i)}}var e,f,g=0;a.Builder=function(b){var d=a.Addin.$internalConstructor("builder",g++,b);if(!c.isFunction(d.build))throw new Error('Builder options must contain the "build" function '+JSON.stringify(b));return d.target=void 0===d.target?"":d.target,d},a.systemPaths.builders=a.registry.joinPath(a.systemPaths.prefix,"builders"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{id:"subdivision.defaultBuilder",type:"subdivision.builder",target:null,order:a.registry.$defaultOrder,build:function(a){return c.cloneDeep(a)}}]}),a.addBuilder=function(b,c){var d=new a.Builder(b);return null===d.target?!f||c?(f=d,!0):!1:!e.hasOwnProperty(d.target)||c?(e[d.target]=d,!0):!1},a.getBuilder=function(a){if(null===a&&f)return f;if(e.hasOwnProperty(a))return e[a];if(f)return f;throw new Error('No builder of type "'+a+'" was defined and no default builder was registered')},a.build=function(d,e,f,g){var h=a.getAddins(d,f,g);return 0===h.length?h:c.map(h,function(a){return b(a.type,a,e,{path:d})})},a.build.async=function(b,e,f,g){var h=a.getAddins(b,f,g);if(0===h.length)return Promise.resolve(h);var i=c.map(h,function(a){return d(a.type,a,e,{path:b})});return Promise.all(i)},a.buildAddin=function(a,c){return b(a.type,a,c,{path:null})},a.buildAddin.async=function(a,b){return d(a.type,a,b,{path:null})},a.buildTree=function(d,e){var f=a.getAddins(d);return 0===f.length?f:c.map(f,function(c){var f=b(c.type,c,e,{path:d}),g=c.itemsProperty||"$items";return f[g]=a.buildTree(a.registry.joinPath(d,c.id),e),f})},a.$generateBuilders=function(){a.$clearBuilders();var b=a.getAddins(a.systemPaths.builders,{target:null});b.length>0&&(f=new a.Builder(b[0])),b=a.getAddins(a.systemPaths.builders),c.forEach(b,function(b){a.addBuilder(b)})},a.$clearBuilders=function(){e={},f=null},a.$clearBuilders(),Object.defineProperty(a,"builders",{enumerable:!0,configurable:!1,get:function(){return c.clone(e)}})}(b),function(a){"use strict";function b(a){return a?b(a.$next).then(function(){var b;return a.hasOwnProperty("initialize")&&c.isFunction(a.initialize)&&(b=a.initialize()),Promise.resolve(b)}):Promise.resolve()}var d;a.Service=function(b,d){var e=Object.create(d||{});return c.isFunction(b)&&(b=b()),b=b||{},e=c.assign(e,{$vent:a.createEventBus(),$next:d?d:void 0},b)},a.systemPaths.services=a.registry.joinPath(a.systemPaths.prefix,"services"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.service",id:"subdivision.serviceBuilder",order:a.registry.$defaultOrder,build:function(b){if(c.isString(b.name)&&!c.isEmpty(b.name))return a.addService(b.name,b.content,b.override);throw new Error("Service name must be defined "+JSON.stringify(b))}}]}),a.getService=function(a){return d[a]},a.addService=function(b,c,e){b=String(b).trim();var f;e||(f=a.getService(b));var g=new a.Service(c,f);return d[b]=g,g.$name=b,g},a.$clearServices=function(){d={}},a.buildServices=function(){a.$clearServices();var d=a.build(a.systemPaths.services),e=new Set;return c.reduce(d,function(c,d){return e.has(d.$name)?c:(e.add(d.$name),a.vent.trigger("before:service:initialized",d.$name),c.then(function(){return b(a.getService(d.$name)).then(function(){a.vent.trigger("after:service:initialized",d.$name,a.getService(d.$name))})}))},Promise.resolve())},Object.defineProperty(a,"services",{enumerable:!0,configurable:!1,get:function(){return c.clone(d)}})}(b),function(a){"use strict";var b=0,d={};a.Command=function(d){d=d||{};var e=a.Addin.$internalConstructor("command",b++,d);if(e.name=d.name||e.id,!c.isFunction(e.execute))throw new Error('Command options must contain the "execute" function '+JSON.stringify(d));return e.hasOwnProperty("isValid")||(e.isValid=!0),e.hasOwnProperty("canExecute")||(e.canExecute=a.Command.$canExecute),e},a.Command.$canExecute=function(){var b,d=!0;this.hasOwnProperty("condition")&&(b=this.condition,c.isString(b)&&(b=a.getCondition(b),void 0===b&&(b=new a.Condition({isValid:this.condition}))),d=b.isValid(this));var e=!0;return this.hasOwnProperty("isValid")&&(e=c.isFunction(this.isValid)?this.isValid():Boolean(this.isValid)),d&&e},a.systemPaths.commands=a.registry.joinPath(a.systemPaths.prefix,"commands"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.command",id:"subdivision.commandBuilder",order:a.registry.$defaultOrder,build:function(b){return new a.Command(b)}}]}),a.getCommand=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");return d[a]},a.addCommand=function(b,e){var f=new a.Command(b),g=f.name;if(void 0===g||null===g)throw new Error("name must not be undefined or null");return d[g]&&!e?!1:(a.removeCommand(g),d[g]=f,c.isFunction(f.initialize)&&f.initialize(),!0)},a.removeCommand=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");d[a]&&c.isFunction(d[a].destroy)&&d[a].destroy(),d[a]=void 0},a.$clearCommands=function(){d={}},Object.defineProperty(a,"commands",{enumerable:!0,configurable:!1,get:function(){return c.clone(d)}})}(b),function(a){"use strict";var b=0,d={};a.Condition=function(d){d=d||{};var e=a.Addin.$internalConstructor("condition",b++,d);if(e.name=d.name||e.id,c.isString(e.isValid)){var f=e.isValid;e.isValid=function(){var b=new a.utils.BooleanPhraseParser,c=a.Condition.$buildContext(),d=b.evaluate(f,c);return d.isValid()}}if(!c.isFunction(e.isValid))throw new Error("A condition must have an isValid function "+e.id);return e},a.Condition.$buildContext=function(){var b=a.build(a.systemPaths.conditionOperations,null,{literal:"!"})[0],c=a.build(a.systemPaths.conditionOperations,null,{literal:"&"})[0],d=a.build(a.systemPaths.conditionOperations,null,{literal:"|"})[0];if(b&&c&&d)return{not:b.generator,and:c.generator,or:d.generator,literal:function(b){return a.getCondition(b)}};throw new Error('Condition operators for "not", "and", "or" must exist')},a.systemPaths.conditions=a.registry.joinPath(a.systemPaths.prefix,"conditions"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.condition",id:"subdivision.conditionBuilder",order:a.registry.$defaultOrder,build:function(b){var c=new a.Condition(b);return c}}]}),a.getCondition=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");return d[a]},a.addCondition=function(b,e){var f=new a.Condition(b),g=f.name;return d[g]&&!e?!1:(a.removeCondition(g),d[g]=f,c.isFunction(f.initialize)&&f.initialize(),!0)},a.removeCondition=function(a){if(void 0===a||null===a)throw new Error("name must not be undefined or null");d[a]&&c.isFunction(d[a].destroy)&&d[a].destroy(),d[a]=void 0},a.$clearConditions=function(){d={}},a.systemPaths.conditionOperations=a.registry.joinPath(a.systemPaths.prefix,"conditionOperations"),a.Condition.$conditionOperationBuilder={target:"subdivision.conditionOperation",id:"subdivision.conditionOperationBuilder",order:a.registry.$defaultOrder,build:function(a){return{literal:a.literal,generator:a.generator}}},a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[a.Condition.$conditionOperationBuilder]}),a.defaultManifest.paths.push({path:a.systemPaths.conditionOperations,addins:[{id:"NotConditionOperation",literal:"!",type:"subdivision.conditionOperation",generator:function(a){return{isValid:function(){if(c.isFunction(a.isValid))return!Boolean(a.isValid());throw new Error('Cannot evaluate "!" operation because the target has no isValid function '+JSON.stringify(a))}}}},{id:"OrConditionOperation",literal:"|",type:"subdivision.conditionOperation",generator:function(a,b){return{isValid:function(){if(!c.isFunction(a.isValid))throw new Error('Cannot evaluate "|" operation because the first target has no isValid function '+JSON.stringify(a));if(!c.isFunction(b.isValid))throw new Error('Cannot evaluate "|" operation because the second target has no isValid function '+JSON.stringify(b));return Boolean(a.isValid())||Boolean(b.isValid())}}}},{id:"AndConditionOperation",literal:"&",type:"subdivision.conditionOperation",generator:function(a,b){return{isValid:function(){if(!c.isFunction(a.isValid))throw new Error('Cannot evaluate "&" operation because the first target has no isValid function '+JSON.stringify(a));if(!c.isFunction(b.isValid))throw new Error('Cannot evaluate "&" operation because the second target has no isValid function '+JSON.stringify(b));return Boolean(a.isValid())&&Boolean(b.isValid())}}}}]}),Object.defineProperty(a,"conditions",{enumerable:!0,configurable:!1,get:function(){return c.clone(d)}})}(b),function(a){"use strict";var b;a.systemPaths.values=a.registry.joinPath(a.systemPaths.prefix,"values"),a.defaultManifest.paths.push({path:a.systemPaths.builders,addins:[{target:"subdivision.value",id:"subdivision.valueBuilder",order:a.registry.$defaultOrder,build:function(b){if(c.isNil(b.name))throw new Error("Value name must be defined "+JSON.stringify(b));if(!b.hasOwnProperty("value"))throw new Error("Value must have a value property "+JSON.stringify(b));a.addValue(b.name,b.value,!0)}}]}),a.getValue=function(a){return b[a]},a.addValue=function(a,d,e){if(c.isNil(a))throw new Error("Value name must be defined");if(!e&&b.hasOwnProperty(a))throw new Error("A value with the name "+a+" already exists");b[a]=d},a.$clearValues=function(){b={}},a.buildValues=function(){a.vent.trigger("before:values:built"),a.$clearValues(),a.build(a.systemPaths.values),a.vent.trigger("after:values:built")},Object.defineProperty(a,"values",{enumerable:!0,configurable:!1,get:function(){return c.clone(b)}})}(b),function(a){"use strict";a.readManifest=function(b){c.forEach(b.paths,function(b){c.forEach(b.addins,function(c){a.addAddin(b.path,new a.Addin(c))})})}}(b)}); |
{ | ||
"name": "subdivision", | ||
"version": "0.3.4", | ||
"version": "0.4.0", | ||
"description": "A simple modularization layer for your JavaScript application", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -25,2 +25,4 @@ subdivision - A simple library for building highly decoupled and modular web applications. | ||
NOTE: Until version 1.x.x please use ~[version] in your package.json and not ^[version] | ||
#### Browser | ||
@@ -172,7 +174,11 @@ | ||
#### subdivision.getAddins(path, searchCriteria, skipSort) -> [Addin] | ||
Returns an array containing all the addins in the given _path_ that match the _searchCriteria_. If _searchCriteria_ is | ||
````undefined````, returns all the addins in the path. Set _skipSort_ to true if you don't want to sort the returned addins by | ||
Returns an array containing all the addins in the given _path_ that match the _searchCriteria_ and are not disabled via the | ||
_isEnabled_ property. If _searchCriteria_ is ````undefined````, returns all the addins in the path. Set _skipSort_ to true if you don't want to sort the returned addins by | ||
order (more on ordering addins in the next section). The syntax for the _searchCriteria_ is determined by the lodash | ||
[filter function](https://lodash.com/docs#filter) as the _predicate_ argument. | ||
You may specify the _isEnabled_ property to be either a boolean, a function, or a Condition string (see documentation for Conditions below). | ||
If a function is provided then it will be invokes with the addin as its _this_ variable. If a string is provided then a condition | ||
with the given name will be used. Complex condition expressions are supported. | ||
```js | ||
@@ -188,2 +194,21 @@ subdivision.addAddin('aaa',new subdivision.Addin({name:"Bob"})); | ||
```js | ||
subdivision.addAddin('aaa',new subdivision.Addin({name:"Bob",isEnabled:false})); | ||
subdivision.addAddin('aaa',new subdivision.Addin({name:"Alice",isEnabled:function(){ | ||
return true; | ||
})); //[] | ||
subdivision.addAddin('aaa',new subdivision.Addin({name:"Matt",isEnabled:"condition_that_returns_true")); | ||
subdivision.getAddins('aaa'); //[{name:"Alice"}, {name:"Matt"}] | ||
``` | ||
#### subdivision.getAllAddins(path, skipSort) -> [Addin] | ||
Returns an array containing all the addins in the given _path_ regardless of any filtering or disabling. | ||
Set _skipSort_ to true if you don't want to sort the returned addins by order (more on ordering addins in the next section) | ||
```js | ||
subdivision.addAddin('aaa',new subdivision.Addin({name:"Bob"})); | ||
subdivision.addAddin('aaa',new subdivision.Addin({name:"Alice"})); | ||
subdivision.getAllAddins('aaa'); //[{name:"Bob" ...},{name:"Alice" ...}] | ||
``` | ||
## Topological Sort | ||
@@ -526,2 +551,5 @@ For each addin that goes into the registry we define an ````order```` property. This field is used to sort the addins within | ||
are complete. | ||
When subdivision starts two events are triggered on the main event bus (````subdivision.vent````). The _before:start_ event is | ||
triggered right after the call to ````start()```` and before anything is executed while the _after:start_ event is triggered once | ||
everything is initialized and subdivision is ready to run. | ||
@@ -858,2 +886,10 @@ ## Optional Concepts | ||
### 0.3.4 -> 0.4.0 | ||
* Added the _before:start_ and _after:start_ events on the subdivision message bus | ||
* **POSSIBLY BREAKING** Added a new property _isEnabled_ to addins which allows you to exclude the addin from build commands. | ||
* Added ````subdivision.getAllAddins```` that retrieves all the addins without any kind of filtering. | ||
### 0.3.3 -> 0.3.4 | ||
@@ -860,0 +896,0 @@ |
@@ -15,2 +15,4 @@ describe('Addin', function () { | ||
subdivision.registry.$clear(); | ||
subdivision.$clearBuilders(); | ||
subdivision.$clearConditions(); | ||
}); | ||
@@ -60,6 +62,6 @@ | ||
it('should throw if path was undefined', function(){ | ||
expect(function(){ | ||
subdivision.addAddin(); | ||
}).to.throw('path was not defined for addin'); | ||
it('should throw if path was undefined', function () { | ||
expect(function () { | ||
subdivision.addAddin(); | ||
}).to.throw('path was not defined for addin'); | ||
}); | ||
@@ -81,2 +83,10 @@ }); | ||
it('should get all addins of a node with the dedicated function', function () { | ||
var addin1 = new subdivision.Addin({order: 1}); | ||
var addin2 = new subdivision.Addin({order: 2, isEnabled: false}); | ||
subdivision.addAddin('ab/cd', addin1); | ||
subdivision.addAddin('ab/cd', addin2); | ||
expect(subdivision.getAllAddins('ab/cd')).to.be.eql([addin1, addin2]); | ||
}); | ||
it('should get all addins of a node with a specific property', function () { | ||
@@ -105,2 +115,86 @@ var addin1 = new subdivision.Addin({id: '1'}); | ||
}); | ||
describe('isEnabled flag', function () { | ||
it('should disable an addin with boolean', function () { | ||
var addin1 = new subdivision.Addin({isEnabled: false}); | ||
var addin2 = new subdivision.Addin({isEnabled: true}); | ||
subdivision.addAddin('a', addin1); | ||
subdivision.addAddin('a', addin2); | ||
expect(subdivision.getAddins('a')).to.be.eql([addin2]); | ||
}); | ||
it('should disable addins with function', function () { | ||
var addin1 = new subdivision.Addin({ | ||
isEnabled: function () { | ||
return false; | ||
} | ||
}); | ||
var addin2 = new subdivision.Addin({ | ||
isEnabled: function () { | ||
return true; | ||
} | ||
}); | ||
subdivision.addAddin('a', addin1); | ||
subdivision.addAddin('a', addin2); | ||
expect(subdivision.getAddins('a')).to.be.eql([addin2]); | ||
}); | ||
it('should disable addins with string', function () { | ||
subdivision.addCondition({ | ||
name: 'falseCondition', | ||
isValid: function () { | ||
return false; | ||
} | ||
}); | ||
subdivision.addCondition({ | ||
name: 'trueCondition', | ||
isValid: function () { | ||
return true; | ||
} | ||
}); | ||
var addin1 = new subdivision.Addin({ | ||
isEnabled: 'falseCondition' | ||
}); | ||
var addin2 = new subdivision.Addin({ | ||
isEnabled: 'trueCondition' | ||
}); | ||
subdivision.addAddin('a', addin1); | ||
subdivision.addAddin('a', addin2); | ||
expect(subdivision.getAddins('a')).to.be.eql([addin2]); | ||
}); | ||
it('should disable addins with complex string condition', function () { | ||
subdivision.readManifest(subdivision.defaultManifest); | ||
subdivision.$generateBuilders(); | ||
subdivision.addCondition({ | ||
name: 'falseCondition', | ||
isValid: function () { | ||
return false; | ||
} | ||
}); | ||
subdivision.addCondition({ | ||
name: 'trueCondition', | ||
isValid: function () { | ||
return true; | ||
} | ||
}); | ||
var addin1 = new subdivision.Addin({ | ||
isEnabled: 'falseCondition & trueCondition' | ||
}); | ||
var addin2 = new subdivision.Addin({ | ||
isEnabled: 'trueCondition | trueCondition' | ||
}); | ||
subdivision.addAddin('a', addin1); | ||
subdivision.addAddin('a', addin2); | ||
expect(subdivision.getAddins('a')).to.be.eql([addin2]); | ||
}); | ||
}); | ||
}); |
@@ -47,3 +47,3 @@ describe('App', function () { | ||
name: 'cow', | ||
execute: function(){ | ||
execute: function () { | ||
} | ||
@@ -64,3 +64,3 @@ } | ||
done(); | ||
}, function (error) { | ||
}).catch(function (error) { | ||
done(error); | ||
@@ -70,3 +70,60 @@ }); | ||
}); | ||
}) | ||
; | ||
it('should trigger start events when subdivision starts', function (done) { | ||
subdivision.readManifest(subdivision.defaultManifest); | ||
subdivision.start().then(function () { | ||
expect(subdivision.vent.trigger.calledWith('before:start')).to.be.true; | ||
expect(subdivision.vent.trigger.calledWith('after:start')).to.be.true; | ||
done(); | ||
}).catch(function (error) { | ||
done(error); | ||
}); | ||
}); | ||
it('should start subdivision if no buildServices is defined', function () { | ||
var temp = subdivision.buildServices; | ||
subdivision.readManifest(subdivision.defaultManifest); | ||
subdivision.readManifest({ | ||
paths: [ | ||
{ | ||
path: subdivision.systemPaths.services, | ||
addins: [ | ||
{ | ||
type: 'subdivision.service', | ||
name: 'cow', | ||
content: { | ||
hello: 'world' | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
path: subdivision.systemPaths.commands, | ||
addins: [ | ||
{ | ||
type: 'subdivision.command', | ||
name: 'cow', | ||
execute: function () { | ||
} | ||
} | ||
] | ||
} | ||
] | ||
}); | ||
subdivision.buildServices = null; | ||
subdivision.start().then(function () { | ||
expect(subdivision.vent.trigger.calledWith('before:buildServices')).to.be.false; | ||
expect(subdivision.vent.trigger.calledWith('after:buildServices')).to.be.false; | ||
var service = subdivision.getService('cow'); | ||
expect(service).to.be.undefined; | ||
done(); | ||
}).catch(function (error) { | ||
done(error); | ||
}); | ||
subdivision.buildServices = temp; | ||
}); | ||
}); |
@@ -221,3 +221,3 @@ describe('Condition', function () { | ||
var result = subdivision.build(subdivision.systemPaths.conditionOperations,{}, {literal: 'aaa'}); | ||
var result = subdivision.build(subdivision.systemPaths.conditionOperations, {}, {literal: 'aaa'}); | ||
expect(result.length).to.be.equal(1); | ||
@@ -224,0 +224,0 @@ expect(result[0].literal).to.be.equal('aaa'); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
504110
8243
948