Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
1) thoughts about how to adopt the principles of aspect oriented programming to JavaScripts dynamic and functional nature.2) point (1) now gets accompanied by a working implementation - "modification.ao.js" - of an aspect oriented system as proof of concept.3) there is a working "logging" example now too as always if one needs to justify the exi…

roughly sketched

  • runtime based only and not using any kind of JavaScript "transpilers" or JavaScript build tools for "code weaving" as in e.g. AspectJ.
  • thus being forced focusing on what ES3 language core does provide.
  • implementation of prototypal method modifiers e.g. Function.prototype.before, Function.prototype.after, Function.prototype.around as minimal set of a kind of an AOP base that already supports library / framework agnostic modification of function based control flow by just wrapping additional behaviors / advice handlers around existing methods / functions.
  • clarify role of Joinpoint, Pointcut, Advice, Aspect; especially from this point of view of what makes them distinct from existing approaches in compiled and/or non dynamic and/or non functional programming languages.

  • no need of a pointcut specific language but methods as filters in order to define pointcuts that access/collect joinpoints.
  • maybe support for accumulating joinpoints in a way similar to a pointcut's definition by just providing a filter method.
  • maybe even consider dropping the AOP paradigm of supporting an "oblivious" system thus allowing to mark/flag methods as joinpoints from within any JavaScript source code - think in ways of e.g. Function.prototype.(un)markJoinpoint.

Joinpoint

  • A Joinpoint in JavaScript always needs to feature both a method that is bound to an object and this very object itself (regardless of either this couple is locally scoped or not). One might even think about a label that optionally gets assigned to a joinpoint.
  • Thus a joinpoint will be constructed at least by a method and this method's target object.

Pointcut

  • A Pointcut in JavaScript always should be able to return a collection of joinpoints that are filtered according to certain criteria.
  • Thus a pointcut explicitly will be constructed by its filter method.

Advice

  • An Advice in JavaScript always should feature both a method that defines behavior (or could be seen as advice handler) and a named qualifier or type e.g. before, after, around(, afterReturning, afterThrowing).
  • Thus an advice will be constructed by a type and a method that gets associated with that type.

Aspect

  • An Aspect in JavaScript needs to feature just a sole function that folds advices and pointcuts within it's function body.

additional notes

  • In order to take advantage of JavaScripts dynamic nature it should be allowed to alter the whole system's control flow at any time from any point e.g.
    • advices do alter the system's control flow just by calling one of every advices two methods either confirm or reject / deny.
    • add or remove joinpoints, pointcuts, advices regardless of how many aspects are currently confirmed or rejected.
(function(r,j){var b,c=this;b=c.Object;var e=b.prototype,k=c.Array.prototype,d=c.RegExp.prototype,s=c.String.prototype,t=e.toString,u=e.valueOf,v=d.compile,g=/(?:)/;""+g.compile("(?:)","")!==""+g&&(d.compile=function(){v.apply(this,arguments);return this});var e=function(a){return["^\\[object\\s+",a,"\\]$"].join("")},m=function(a){return t.call(a)},w=e("String"),n=function(a){return void 0===a||null===a?a:u.call(a).valueOf()},f=function(a){return"function"==typeof a&&"function"==typeof a.call&&"function"==typeof a.apply},l=function(a){return g.compile(w).test(m(a))},d=function(a,b){return new c.ReferenceError(["A valid implementation of ",a," is missing.\n\nPlease provide the basic shims of ES5. Have a look at e.g.\nhttps://github.com/kriskowal/es5-shim/blob/master/es5-shim.js",b].join(""))};if(!f(b.keys))throw d("[Object.keys]","#L542");if(!f(s.trim))throw d("[String.prototype.trim]","#L899");if(!f(k.indexOf))throw d("[Array.prototype.indexOf]","#L479");if(!f(k.forEach))throw d("[Array.prototype.forEach]","#L238");if(!f(k.reduce))throw d("[Array.prototype.reduce]","#L382");var p=b.keys,x=c.parseFloat,y={global:c,objects:{regX:g},methods:{noop:function(){}},helpers:{compareTypes:function(a,b,c){c=f(c)&&c||n;var d,e;return(d=c(a))>(e=c(b))&&1||d<e&&-1||(d===e?0:void 0)},createClassSignaturePattern:e,protectBehaviorFromInstantiation:function(a,c){if(c instanceof a)throw new TypeError("Traits and Mixins always need to be applied onto objects but never get instantiated.");}},introspective:{isFunction:f,isString:l,baseValueOf:n,getClassSignature:m}},h={},q=function(a){return h[l(a)&&a.trim()||""]};j=j||c;b=function(a,b){a=l(a)&&a.trim()||"";var d=f(b)&&b(q,c,y);if(d&&a)return h[a]=d};b.all=function(){return p(h)};b.all.size=function(){return p(h).length};b.require=q;(function(){this.first=function(){return this()[0]};this.last=function(){var a;return(a=this())[a.length-1]};this.item=function(a){return this()[x(a,10)]}}).call(b.all);return j[r]=b}).call(null,"composable");
composable("components.Introspective_isFunction_isCallable",function(b,e,f){var g=e.Function.prototype,h=function(a){return"function"==typeof a&&"function"==typeof a.call&&"function"==typeof a.apply},j=function(a){var c;if(c=h(a)){var b;try{g.toString.call(a),b=!0}catch(e){b=!1}c=b}if(!c){var d;try{a(),d=!0}catch(f){try{g.call.call(a),d=!0}catch(j){d=!1}}c=d}return c};b=function(){this.isFunction=h;this.isCallable=j};b.apply(f.introspective);return b});
composable("components.Introspective_isArray_isArguments",function(d,b,c){d("components.Introspective_isFunction_isCallable");d=c.introspective;var e=b.Array,j,a=b.Object.prototype.propertyIsEnumerable;try{a.call(null,"length");var l=a,a=function(h,a){return l.call(h,a)}}catch(t){var m=a,a=function(h,a){var b;try{b=m.call(h,a)}catch(c){b=!0}return b}}j=a;var a=c.helpers.createClassSignaturePattern,f=c.objects.regX,n=a("Object"),p=a("Array"),k=a("Arguments"),g=d.getClassSignature;c=d.isFunction;var q=b.isFinite,r=c(e.isArray)&&e.isArray||function(a){return f.compile(p).test(g(a))};if(!(b=c(e.isArguments)&&e.isArguments))b=function(){return f.compile(k).test(g(arguments))}()?function(a){return f.compile(k).test(g(a))}:function(a){return!!a&&f.compile(n).test(g(a))&&"number"==typeof a.length&&q(a.length)&&!j(a,"length")};var s=b;b=function(){this.isArray=r;this.isArguments=s};b.apply(d);return b});
composable("components.Enumerable_toArray",function(a,d,h){a("components.Introspective_isArray_isArguments");a=h.introspective;var e=d.Array.prototype.slice,j=a.isFunction,k=a.isString,n=a.isArguments,p=a.isArray,l=d.isFinite,f=d.document,q=function(){var a,b,g,d=f&&f.forms||[],m=f&&j(f.getElementsByTagName)&&f.getElementsByTagName("")||d;try{b=e.call(d);b=e.call(m);b=e.call(arguments);g=b.join("");if(3!=b.length||"Array.make"!=g)throw Error();b=e.call(g);if(10!==b.length||"."!=b[5])throw Error();a=function(){var a,c=(this||k(this))&&this.length;"number"==typeof c&&l(c)&&(a=[],a.length=c,a=e.call(this));return a}}catch(h){a=function(){var a,c,b=(p(this)||n(this))&&e.call(this)||k(this)&&this.split("")||a;if(!b&&(c=0!==this&&this&&this.length,"number"==typeof c&&l(c)))if(b=[],b.length=c,j(this.item))for(;c--;)a=this.item(c),c in this&&(b[c]=a);else for(;c--;)a=this[c],c in this&&(b[c]=a);return b}}b=g=d=m=null;return a}("Array",".","make");return function(){this.toArray=q}});
composable("composites.Array_make",function(b,c,d){var a={},e=b("components.Enumerable_toArray").call(a)||a.toArray;c.Array.make=d.helpers.makeArray=function(a){return e.call(a)}});
composable("components.Introspective_typeDetection_core",function(c,l,j){c("components.Introspective_isFunction_isCallable");c("components.Introspective_isArray_isArguments");c=j.introspective;var x=c.isFunction,y=c.isCallable,z=c.isArray,A=c.isArguments,m=c.isString,B=c.baseValueOf,h=j.helpers.createClassSignaturePattern,f=function(a){return["(?:^",a,":)|(?:^",a,"$)|(?:\\[",a,":\\s*name\\:\\s*",a,")"].join("")},b=j.objects.regX,C=h("Boolean"),D=h("Number"),E=h("Object"),F=h("RegExp"),G=h("Date"),H=h("Error"),I=f("Error"),J=f("EvalError"),K=f("RangeError"),L=f("ReferenceError"),M=f("SyntaxError"),N=f("TypeError"),O=f("URIError"),g=c.getClassSignature,d,P=l.Error.prototype.toString;d=function(a){return P.call(a)};var n=l.isFinite,Q=function(a){return void 0===a},R=function(a){return void 0!==a},S=function(a){return null===a},T=function(a){return null!==a},p=function(a){return!a&&(void 0===a||null===a)},k=function(a){return void 0!==a&&null!==a},q=function(a){return"string"==typeof a||"number"==typeof a||"boolean"==typeof a},U=function(a){return q(a)||p(a)},r=function(a){return a&&("object"==typeof a||"function"==typeof a)},s=function(a){return k(a)&&"function"==typeof a.constructor},V=function(a){return r(a)&&"function"!=typeof a.constructor},t=function(a){return b.compile(C).test(g(a))},u=function(a){return"boolean"==typeof a},W=function(a){return t(a)&&!u(a)},v=function(a){return b.compile(D).test(g(a))&&"number"!=typeof a},X=function(a){return"number"==typeof a},Y=function(a){return("number"==typeof a||v(a))&&n(a)},w=function(a){return"string"==typeof a},Z=function(a){return m(a)&&!w(a)},$=function(a){return k(a)&&"number"==typeof a.length&&n(a.length)&&0<=a.length},aa=function(a){return s(a)&&b.compile(E).test(g(a))},ba=function(a){return b.compile(F).test(g(a))},ca=function(a){return b.compile(G).test(g(a))},e=function(a){return b.compile(H).test(g(a))},da=function(a){return e(a)&&(b.compile(I).test(d(a))||"Error"===a.name)},ea=function(a){return e(a)&&(b.compile(J).test(d(a))||"EvalError"===a.name)},fa=function(a){return e(a)&&(b.compile(K).test(d(a))||"RangeError"===a.name)},ga=function(a){return e(a)&&(b.compile(L).test(d(a))||"ReferenceError"===a.name)},ha=function(a){return e(a)&&(b.compile(M).test(d(a))||"SyntaxError"===a.name)},ia=function(a){return e(a)&&(b.compile(N).test(d(a))||"TypeError"===a.name)},ja=function(a){return e(a)&&(b.compile(O).test(d(a))||"URIError"===a.name)};return function(){this.isUndefined=Q;this.isDefined=R;this.isNull=S;this.isNotNull=T;this.isUndefinedOrNull=p;this.isNeitherUndefinedNorNull=k;this.isPrimitive=q;this.isValue=U;this.isObject=r;this.isNative=s;this.isAlien=V;this.isBoolean=t;this.isBooleanValue=u;this.isBooleanObject=W;this.isNumber=Y;this.isNumberValue=X;this.isNumberObject=v;this.isString=m;this.isStringValue=w;this.isStringObject=Z;this.isArray=z;this.isArguments=A;this.isListLike=$;this.isObjectObject=aa;this.isFunction=x;this.isCallable=y;this.isRegExp=ba;this.isDate=ca;this.isError=e;this.isGenericError=da;this.isEvalError=ea;this.isRangeError=fa;this.isReferenceError=ga;this.isSyntaxError=ha;this.isTypeError=ia;this.isURIError=ja;this.baseValueOf=B;this.getClassSignature=g}});
composable("environment",function(a,c,b){a=function(){};a.prototype=b;return new a});
composable("environment_extended_introspective_core",function(a){var b=a("environment");a("components.Introspective_typeDetection_core").call(b.introspective);return b});
composable("components.Enumerable_first_last",function(){return function(){this.first=function(){return this[0]};this.last=function(){return this[this.length-1]}}});
composable("components.Enumerable_first_last_item",function(c,a){var b=a.parseFloat;return function(){this.first=function(){return this[0]};this.last=function(){return this[this.length-1]};this.item=function(a){return this[b(a,10)]}}});
composable("components.Enumerable_first_last_item_listWrapper",function(d,b){var c=b.parseFloat;return function(a){this.first=function(){return a[0]};this.last=function(){return a[a.length-1]};this.item=function(b){return a[c(b,10)]}}});
composable("components.Enumerable_first_last_item_listGetterShorthands",function(d,b){var c=b.parseFloat;return function(){this.first=function(){return this()[0]};this.last=function(){var a;return(a=this())[a.length-1]};this.item=function(a){return this()[c(a,10)]}}});
composable("components.Allocable",function(a,b,c){a("composites.Array_make");var d=a("components.Enumerable_first_last_item_listWrapper");a=b.Array;b=c.introspective.isFunction;var e=b(a.make)&&a.make||c.helpers.makeArray;return function(a){this.valueOf=this.toArray=function(){return e(a)};this.toString=function(){return""+a};this.size=function(){return a.length};d.call(this,a)}});
composable("components.Allocable_all",function(a,b,c){a("composites.Array_make");var d=a("components.Enumerable_first_last_item_listGetterShorthands");a=b.Array;b=c.introspective.isFunction;var e=b(a.make)&&a.make||c.helpers.makeArray;return function(a){this.all=function(){return e(a)};this.all.size=function(){return a.length};d.call(this.all)}});
composable("components.Controllable_Advice_before_after_around",function(k,n,l){k("components.Introspective_isFunction_isCallable");k=l.introspective;var e=k.isFunction,m=k.isCallable,c=function(b){return!b&&(void 0===b||null===b)?null:b};return function(){this.before=function(b,f,g){var a;if(a=e(b))if(a=e(this)){var h=this,d=c(f),j=c(g);a=function(){var a=arguments;b.call(d,a,j);return h.apply(d,a)}}return a||this};this.after=function(b,f,g){var a;if(a=e(this))if(a=e(b)){var h=this,d=c(f),j=c(g);a=function(){var a,c=arguments;a=h.apply(d,c);b.call(d,c,a,j);return a}}return a||this};this.around=function(b,f,g){var a;if(a=m(this))if(a=e(b)){var h=this,d=c(f),j=c(g);a=function(){return b.call(d,h,b,arguments,d,j)}}return a||this}}});
//deprecated//composable("components.Controllable_Advice_before_after_around",function(e,k,h){e("components.Introspective_isFunction_isCallable");e=h.introspective;var b=e.isFunction,j=e.isCallable,f=function(a,c,d){return function(){var b=arguments;a.apply(d,b);return c.apply(d,b)}},g=function(a){return!a&&(void 0===a||null===a)?null:a};return function(){this.before=function(a,c){return b(a)&&b(this)&&f(a,this,g(c))||this};this.after=function(a,c){return b(this)&&b(a)&&f(this,a,g(c))||this};this.around=function(a,c){var d;if(d=j(this))if(d=b(a)){var e=this,f=g(c);d=function(){return a.call(f,e,a,arguments,f)}}return d||this}}});
composable("composites.Function_isFunction_isCallable",function(a,b){a("components.Introspective_isFunction_isCallable").call(b.Function)});
composable("",function(a,b){a("components.Introspective_isArray_isArguments").call(b.Array)});
composable("",function(a,b){a("components.Enumerable_first_last").call(b.Array.prototype)});
composable("composites.Function_modifiers_Advice_before_after_around",function(a,b){a("components.Controllable_Advice_before_after_around").call(b.Function.prototype)});
composable("components.Observable_SignalsAndSlots",function(h,c,p){h("composites.Array_make");h=c.Array;var r=c.Date;c=p.introspective;var s=c.isFunction,n=c.isCallable,f=c.isString,t=s(h.make)&&h.make||p.helpers.makeArray,q=function(a,g){this.constructor=q;this.target=a;this.type=g;this.timeStamp=new r},m=function(a,g,f){var d=new q(a,g);this.constructor=m;this.handleEvent=function(a){a&&"object"==typeof a?(a.target=d.target,a.type=d.type,a.timeStamp=d.timeStamp):a={target:d.target,type:d.type,timeStamp:d.timeStamp};f(a)};this.getType=function(){return g};this.getHandler=function(){return f}};return function(a){a="object"==typeof a&&a||{};var g={},c="addEventListener",d="removeEventListener",k="hasEventListener",l="dispatchEvent",h=function(j,a){var b=g[j],e=!1;if(b){var c=b.handlers,b=b.listeners,f=c.indexOf(a);0<=f&&(c.splice(f,1),b.splice(f,1),e=!0)}return e},c=f(a[c])&&a[c]||c,d=f(a[d])&&a[d]||d,k=f(a[k])&&a[k]||k,l=f(a[l])&&a[l]||l;this[c]=function(j,a){var b;if(j&&f(j)&&n(a)){var e=g[j];b=new m(this,j,a);if(e){var c=e.handlers,e=e.listeners,d=c.indexOf(a);-1==d?(c.push(b.getHandler()),e.push(b)):b=e[d]}else e=g[j]={},e.handlers=[b.getHandler()],e.listeners=[b]}return b};this[d]=function(a,c){return f(a)&&n(c)&&h(a,c)||a instanceof m&&h(a.getType(),a.getHandler())||!1};this[k]=function(a,c){var b;if(!(b=f(a)&&n(c)&&(g[a]||!1)&&0<=g[a].handlers.indexOf(c))){if(b=a instanceof m){b=a.getType();var e=a.getHandler();b=(g[b]||!1)&&0<=g[b].handlers.indexOf(e)}b=b||!1}return b};this[l]=function(a){var c=!1,b=a&&"object"==typeof a&&f(a.type)&&a.type||f(a)&&a;if(b=b&&g[b]){var e=(b=b.listeners&&t(b.listeners))&&b.length||0,d=-1;if(1<=e){for(;++d<e;)b[d].handleEvent(a);c=!0}}return c}}});
composable("modification.ao",function(k,f,h){k("composites.Function_modifiers_Advice_before_after_around");h=k("environment");var E=k("components.Allocable_all");k=k("components.Observable_SignalsAndSlots");var l=h.introspective.isUndefined,c=h.introspective.isFunction,ka=h.introspective.isObject,m=h.introspective.isStringValue,la=f.Math.random,ma=h.helpers.makeArray,F=function(c,a){for(var b=-1,j=c.length;++b<j;)a(c[b],b,c)&&(c.splice(b,1),--b,--j)},N=function(c,a){for(var b,j=-1,d=c.length;++j<d;)if(a(c[j],j,c)){b=c[j];break}return b},g=function(c){return m(c)&&c.trim()||""},O=f.uuid&&c(f.uuid.v4)&&f.uuid.v4||function a(b){return b?(b^16*la()>>b/4).toString(16):([1E7]+-1E3+-4E3+-8E3+-1E11).replace(/[018]/g,a)},W,G,H="on",X=function(){return"off"==H},P,Q;f=function(){P();Q()};var e={};k.call(e,{addEventListener:"on",removeEventListener:"off",dispatchEvent:"emit"});var t,u=[],R=function(a){this.getLabel=function(){return a.label};this.getTarget=function(){return a.target};this.getMethodName=function(){return a.methodName};this.getBaseMethod=function(){return a.baseMethod}};R.prototype.equals=function(a){return v(this)&&v(a)&&this===a||w(this)&&w(a)&&this.getBaseMethod()===a.getBaseMethod()&&this.getMethodName()===a.getMethodName()&&this.getTarget()===a.getTarget()&&this.getLabel()===a.getLabel()};var v=function(a){return a instanceof R},w=function(a){return a&&"object"==typeof a&&c(a.getLabel)&&c(a.getTarget)&&c(a.getMethodName)&&c(a.getBaseMethod)},Y=function(a){return a&&"object"==typeof a&&ka(a.target)&&m(a.methodName)&&c(a.target[a.methodName])},Z=function(a){var b=a.getBaseMethod(),j=a.getMethodName(),d=a.getTarget(),c=a.getLabel();return function(a){return a.getBaseMethod()===b&&a.getMethodName()===j&&a.getTarget()===d&&a.getLabel()===c}},$=function(a){a.baseMethod=a.target[a.methodName];a.label=g(a.label);return new R(a)};t={add:function(a){var b;if(Y(a))b=$(a);else if(v(a)||w(a))b=a;b&&!u.some(Z(b))&&(u.push(b),e.emit({type:"joinpoint:add",joinpoint:b}));return b},remove:function(a){var b;if(Y(a))b=$(a);else if(v(a)||w(a))b=a;b&&(a=Z(b),u.some(a)?(F(u,a),e.emit({type:"joinpoint:remove",joinpoint:b})):b=!1);return b},isJoinpoint:v,isJoinpointLike:w};E.call(t,u);var x,n=[],S={},y=function(a){this.getFilter=function(){return a.filter};this.getId=function(){return a.id}};y.prototype.equals=function(a){return p(this)&&p(a)&&this===a||q(this)&&q(a)&&this.getFilter()===a.getFilter()&&this.getId()===a.getId()};y.prototype.getJoinpoints=function(){return(p(this)||q(this))&&t.all().filter(this.getFilter())||[]};var p=function(a){return a instanceof y},q=function(a){return a&&"object"==typeof a&&c(a.getFilter)&&c(a.getId)},aa=function(a){var b=a.getFilter(),c=a.getId();return function(a){return a.getFilter()===b&&a.getId()===c}},ba=function(a){var b;m(a)&&(b=S[a]);return b},I=function(a){var b,c=g(a.id),d=ba(c);if(d)b=d.getFilter()===a.filter?d:!1;else{var e=a.filter;(d=N(n,function(a){return a.getFilter()===e}))&&(b=d.getId()===c?d:!1)}return b};x={getById:ba,add:function(a){var b;a&&"object"==typeof a&&c(a.filter)?(b=I(a),l(b)&&(a.id=g(a.id)||O(),b=new y(a))):p(a)?b=a:q(a)&&(b=I({filter:a.getFilter(),id:a.getId()}),l(b)&&(a={filter:a.getFilter(),id:a.getId()},b=new y(a)));b&&!n.some(aa(b))&&(n.push(b),S[b.getId()]=b,e.emit({type:"pointcut:add",pointcut:b}));return b},remove:function(a){var b;if(a&&"object"==typeof a&&c(a.filter))b=I(a);else if(p(a)||q(a))b=I({filter:a.getFilter(),id:a.getId()});b&&(a=aa(b),n.some(a)?(F(n,a),delete S[b.getId()],e.emit({type:"pointcut:remove",pointcut:b})):b=!1);return b},isPointcut:p,isPointcutLike:q};E.call(x,n);var z,r=[],T={},J={AROUND:"around",BEFORE:"before",AFTER:"after",AFTERTHROWING:"afterThrowing",AFTERRETURNING:"afterReturning"},K=function(a){this.getHandler=function(){return a.handler};this.getType=function(){return a.type};this.getId=function(){return a.id}};K.prototype.equals=function(a){return A(this)&&A(a)&&this===a||B(this)&&B(a)&&this.getHandler()===a.getHandler()&&this.getType()===a.getType()&&this.getId()===a.getId()};var A=function(a){return a instanceof K},B=function(a){var b;if(b=a)if(b="object"==typeof a)if(b=c(a.getHandler))if(b=c(a.getType))b=a.getType(),b=m(b)&&J[b.toUpperCase()]===b&&c(a.getId);return b},ca=function(a){return a&&"object"==typeof a&&c(a.handler)&&(J[g(a.type).toUpperCase()]||"")},da=function(a){var b=a.getHandler(),c=a.getType(),d=a.getId();return function(a){return a.getHandler()===b&&a.getType()===c&&a.getId()===d}},ea=function(a){var b;m(a)&&(b=T[a]);return b},U=function(a){var b,c=g(a.id),d=ea(c);a.type=J[g(a.type).toUpperCase()]||"";if(d)b=d.getHandler()===a.handler&&d.getType()===a.type?d:!1;else{var e=a.handler,f=a.type;(d=N(r,function(a){return a.getHandler()===e&&a.getType()===f}))&&(b=d.getId()===c?d:!1)}return b},fa=function(a){return U({handler:a.getHandler(),type:a.getType(),id:a.getId()})};z={getById:ea,add:function(a){var b;ca(a)?(b=U(a),l(b)&&(a.type=J[g(a.type).toUpperCase()]||"",a.id=g(a.id)||O(),b=new K(a))):A(a)?b=a:B(a)&&(b=fa(a),l(b)&&(a={handler:a.getHandler(),type:a.getType(),id:a.getId()},b=new K(a)));b&&!r.some(da(b))&&(r.push(b),T[b.getId()]=b,e.emit({type:"advice:add",advice:b}));return b},remove:function(a){var b;if(ca(a))b=U(a);else if(A(a)||B(a))b=fa(a);b&&(a=da(b),r.some(a)?(F(r,a),delete T[b.getId()],e.emit({type:"advice:remove",advice:b})):b=!1);return b},isAdvice:A,isAdviceLike:B};E.call(z,r);var s=[],V={},L=function(a){var b=this,c="deny",d="deny",f=function(){c=""},g=[],h=a.handler;h(function(a,b){var c=z.add(a),d=x.add(b);na(c)&&(oa(d)&&!g.some(pa(c,d)))&&g.push({advice:c,pointcut:d})},W);b.getLinkList=function(){return ma(g)};b.getHandler=function(){return h};b.getId=function(){return a.id};b.deny=function(){this===b&&!b.isDenied()&&(e.off("system:restore",f),d=c="deny",ga(),G.all().forEach(ha))};b.confirm=function(){this===b&&!b.isConfirmed()&&(X()?(c="",d="confirm"):(b.getLinkList().forEach(function(a){var b=a.advice;a=a.pointcut;var c=b.getType(),d=b.getHandler();a.getJoinpoints().forEach(function(a){var b=a.getTarget(),e=a.getMethodName();b[e]=b[e][c](d,b,a)})}),d=c="confirm",e.on("system:restore",f)))};b.isReconfirm=function(){return this===b&&"confirm"!=c&&"confirm"==d};b.isConfirmed=function(){return this===b&&"confirm"==c&&"confirm"==d};b.isDenied=function(){return this===b&&"deny"==c&&"deny"==d}};L.prototype.equals=function(a){return C(this)&&C(a)&&this===a||D(this)&&D(a)&&this.getHandler()===a.getHandler()&&this.getId()===a.getId()};var oa=x.isPointcut,na=z.isAdvice,C=function(a){return a instanceof L},D=function(a){return a&&"object"==typeof a&&c(a.getLinkList)&&c(a.getHandler)&&c(a.getId)&&c(a.deny)&&c(a.confirm)&&c(a.isConfirmed)},ia=function(a){var b=a.getHandler(),c=a.getId();return function(a){return a.getHandler()===b&&a.getId()===c}},pa=function(a,b){return function(c){return c.advice===a&&c.pointcut===b}},ha=function(a){a.isReconfirm()&&a.confirm()},ga=function(){t.all().forEach(function(a){var b=a.getTarget(),c=a.getMethodName();a=a.getBaseMethod();b[c]=a});e.emit("system:restore")},ja=function(a){var b;m(a)&&(b=V[a]);return b},M=function(a){var b,c=g(a.id),d=ja(c);if(d)b=d.getHandler()===a.handler?d:!1;else{var e=a.handler;(d=N(s,function(a){return a.getHandler()===e}))&&(b=d.getId()===c?d:!1)}return b};P=function(){H="off";ga()};Q=function(){H="on";G.all().forEach(ha)};h={getById:ja,add:function(a){var b;a&&"object"==typeof a&&c(a.handler)?(b=M(a),l(b)&&(a.id=g(a.id)||O(),b=new L(a))):C(a)?b=a:D(a)&&(b=M({handler:a.getHandler(),id:a.getId()}),l(b)&&(a={handler:a.getHandler(),id:a.getId()},b=new L(a)));b&&!s.some(ia(b))&&(s.push(b),V[b.getId()]=b,e.emit({type:"aspect:add",aspect:b}));return b},remove:function(a){var b;if(a&&"object"==typeof a&&c(a.handler))b=M(a);else if(C(a)||D(a))b=M({handler:a.getHandler(),id:a.getId()});b&&(a=ia(b),s.some(a)?(F(s,a),delete V[b.getId()],e.emit({type:"aspect:remove",aspect:b})):b=!1);return b},isAspect:C,isAspectLike:D};E.call(h,s);G=h;e.on("joinpoint:add",f);e.on("joinpoint:remove",f);e.on("pointcut:add",f);e.on("pointcut:remove",f);e.on("advice:add",f);e.on("advice:remove",f);e.on("aspect:add",f);e.on("aspect:remove",f);return W={Joinpoint:t,Pointcut:x,Advice:z,Aspect:G,isOff:X,isOn:function(){return"on"==H},off:P,on:Q,reboot:f}});
composable("modification.ao", function (require, global, environment) {
"use strict";
require("composites.Function_modifiers_Advice_before_after_around");
environment = require("environment");
var
Allocable_all = require("components.Allocable_all"),
Observable = require("components.Observable_SignalsAndSlots"),
isUndefined = environment.introspective.isUndefined,
isFunction = environment.introspective.isFunction,
isObject = environment.introspective.isObject,
isStringValue = environment.introspective.isStringValue,
math_random = global.Math.random,
makeArray = environment.helpers.makeArray,
mutateArray_removeItemsByFilter = function (arr, filter) {
var
idx = -1,
len = arr.length
;
while (++idx < len) {
if (filter(arr[idx], idx, arr)) {
arr.splice(idx, 1);
--idx;
--len;
}
}
},
array_getItemByFilter = function(arr, filter) {
var
item,
idx = -1,
len = arr.length
;
while (++idx < len) {
if (filter(arr[idx], idx, arr)) {
item = arr[idx];
break;
}
}
return item;
},
getSanitizedIdentifier = function (identifier) {
return (isStringValue(identifier) && identifier.trim()) || "";
},
createId = (
/* [https://github.com/broofa/node-uuid] - Robert Kieffer */
(global.uuid && isFunction(global.uuid.v4) && global.uuid.v4)
/* [https://gist.github.com/jed/982883] - Jed Schmidt */
|| function b(a){return a?(a^math_random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
),
AspectOrientedModule, // control flow modifying module of an Aspect Oriented DSL
Joinpoint,
Pointcut,
Advice,
Aspect,
systemState = "on", // "off"
isSystemOff = function () {return (systemState == "off");},
isSystemOn = function () {return (systemState == "on");},
systemOff, //:Function(scoped)
systemOn, //:Function(scoped)
rebootSystem = function () {
systemOff();
systemOn();
},
EventProxy = {}
;
Observable.call(EventProxy, { // ++ OBSERVABLE API CONFIGURATION ++
addEventListener : "on", // "addListener" - "addObserver"
removeEventListener : "off", // "removeListener" - "removeObserver"
//hasEventListener : "hasListener", // "hasListener" - "hasObserver"
dispatchEvent : "emit" // "dispatch" - "triggerEvent"
});
Joinpoint = (function () {
var
module,
joinpointList = [],
Constructor = function (config) {
var joinpoint = this;
joinpoint.getLabel = function () {
return config.label;
};
joinpoint.getTarget = function () {
return config.target;
};
joinpoint.getMethodName = function () {
return config.methodName;
};
joinpoint.getBaseMethod = function () {
return config.baseMethod;
};
}
;
Constructor.prototype.equals = function (type) {
var joinpoint = this;
return (
(isJoinpoint(joinpoint) && isJoinpoint(type) && (joinpoint === type))
|| (
isJoinpointLike(joinpoint) && isJoinpointLike(type)
&& (joinpoint.getBaseMethod() === type.getBaseMethod())
&& (joinpoint.getMethodName() === type.getMethodName())
&& (joinpoint.getTarget() === type.getTarget())
&& (joinpoint.getLabel() === type.getLabel())
)
);
};
var
isJoinpoint = function (type) {
return (type instanceof Constructor);
},
isJoinpointLike = function (type) {
return (
type && (typeof type == "object")
&& isFunction(type.getLabel) && isFunction(type.getTarget)
&& isFunction(type.getMethodName) && isFunction(type.getBaseMethod)
);
},
isJoinpointConfig = function (type) {
return (
type && (typeof type == "object")
&& isObject(type.target) && isStringValue(type.methodName)
&& isFunction(type.target[type.methodName])
);
},
makeFilter_equalsJoinpoint = function (joinpoint) {
var
baseMethod = joinpoint.getBaseMethod(), // generated
methodName = joinpoint.getMethodName(), // required
target = joinpoint.getTarget(), // required
label = joinpoint.getLabel() // fallback
;
return function/* equalsJoinpoint */(item/*, idx, list*/) {
return (
(item.getBaseMethod() === baseMethod) && (item.getMethodName() === methodName)
&& (item.getTarget() === target) && (item.getLabel() === label)
);
};
},
createJoinpoint = function (config) {
config.baseMethod = config.target[config.methodName];
config.label = getSanitizedIdentifier(config.label);
return (new Constructor(config));
},
addJoinpoint = function (configOrJoinpoint) {
var joinpoint;
if (isJoinpointConfig(configOrJoinpoint)) {
joinpoint = createJoinpoint(configOrJoinpoint);
} else if (isJoinpoint(configOrJoinpoint) || isJoinpointLike(configOrJoinpoint)) {
joinpoint = configOrJoinpoint;
}
if (joinpoint && !joinpointList.some(makeFilter_equalsJoinpoint(joinpoint))) {
// addJoinpoint
joinpointList.push(joinpoint);
EventProxy.emit({
type : "joinpoint:add",
joinpoint : joinpoint
});
}
return joinpoint;
},
removeJoinpoint = function (configOrJoinpoint) {
var joinpoint;
if (isJoinpointConfig(configOrJoinpoint)) {
joinpoint = createJoinpoint(configOrJoinpoint);
} else if (isJoinpoint(configOrJoinpoint) || isJoinpointLike(configOrJoinpoint)) {
joinpoint = configOrJoinpoint;
}
if (joinpoint) {
var equalsJoinpoint = makeFilter_equalsJoinpoint(joinpoint);
if (joinpointList.some(equalsJoinpoint)) {
// this approach keeps the list reference that was passed into the privileged "Allocable_all" Trait Module.
mutateArray_removeItemsByFilter(joinpointList, equalsJoinpoint);
EventProxy.emit({
type : "joinpoint:remove",
joinpoint : joinpoint
});
} else {
joinpoint = false;
}
equalsJoinpoint = null;
}
return joinpoint;
}
;
module = {
add : addJoinpoint,
remove : removeJoinpoint,
isJoinpoint : isJoinpoint,
isJoinpointLike : isJoinpointLike
};
Allocable_all.call(module, joinpointList);
return module;
}());
Pointcut = (function () {
var
module,
pointcutList = [],
pointcutMap = {},
Constructor = function (config) {
var pointcut = this;
pointcut.getFilter = function () {
return config.filter;
};
pointcut.getId = function () {
return config.id;
};
}
;
Constructor.prototype.equals = function (type) {
var pointcut = this;
return (
(isPointcut(pointcut) && isPointcut(type) && (pointcut === type))
|| (
isPointcutLike(pointcut) && isPointcutLike(type)
&& (pointcut.getFilter() === type.getFilter())
&& (pointcut.getId() === type.getId())
)
);
};
Constructor.prototype.getJoinpoints = function () {
var pointcut = this;
return ((isPointcut(pointcut) || isPointcutLike(pointcut)) && Joinpoint.all().filter(pointcut.getFilter())) || [];
};
var
isPointcut = function (type) {
return (type instanceof Constructor);
},
isPointcutLike = function (type) {
return (type && (typeof type == "object") && isFunction(type.getFilter) && isFunction(type.getId));
},
isPointcutConfig = function (type) {
return (type && (typeof type == "object") && isFunction(type.filter));
},
makeFilter_isPointcutFilter = function (filter) {
return function/* isPointcutFilter */(item/*, idx, list*/) {
return (item.getFilter() === filter);
};
},
makeFilter_equalsPointcut = function (pointcut) {
var
filter = pointcut.getFilter(), // required
id = pointcut.getId() // required
;
return function/* equalsPointcut */(item/*, idx, list*/) {
return ((item.getFilter() === filter) && (item.getId() === id));
};
},
getPointcutById = function (id) {
var pointcut;
if (isStringValue(id)) {
pointcut = pointcutMap[id];
}
return pointcut;
},
getPointcutByConfig = function (config) {
var
pointcut,
id = getSanitizedIdentifier(config.id),
pc = getPointcutById(id) // pointcutMap[id]
;
if (pc) {
pointcut = (pc.getFilter() === config.filter) ? pc : false;
} else {
var isPointcutFilter = makeFilter_isPointcutFilter(config.filter);
pc = array_getItemByFilter(pointcutList, isPointcutFilter);
if (pc) {
pointcut = (pc.getId() === id) ? pc : false;
}
isPointcutFilter = null;
}
return pointcut; // :Pointcut|false|undefined
},
getPointcutByReference = function (pointcut) {
return getPointcutByConfig({
filter : pointcut.getFilter(),
id : pointcut.getId()
}); // :Pointcut|false|undefined
},
createPointcut = function (config) {
return (new Constructor(config));
},
addPointcut = function (configOrPointcut) {
var config, pointcut;
if (isPointcutConfig(configOrPointcut)) {
config = configOrPointcut;
pointcut = getPointcutByConfig(config); // :Pointcut|false|undefined
if (isUndefined(pointcut)) {
config.id = (getSanitizedIdentifier(config.id) || createId());
pointcut = createPointcut(config); // :Pointcut
}
} else if (isPointcut(configOrPointcut)) {
pointcut = configOrPointcut; // :Pointcut
} else if (isPointcutLike(configOrPointcut)) {
pointcut = getPointcutByReference(configOrPointcut); // :Pointcut|false|undefined
if (isUndefined(pointcut)) {
pointcut = createPointcut({
filter : configOrPointcut.getFilter(),
id : configOrPointcut.getId()
}); // :Pointcut
}
}
if (pointcut && !pointcutList.some(makeFilter_equalsPointcut(pointcut))) {
// addPointcut
pointcutList.push(pointcut);
pointcutMap[pointcut.getId()] = pointcut;
EventProxy.emit({
type : "pointcut:add",
pointcut : pointcut
});
}
return pointcut; // :Pointcut|false|undefined
},
removePointcut = function (configOrPointcut) {
var pointcut;
if (isPointcutConfig(configOrPointcut)) {
pointcut = getPointcutByConfig(configOrPointcut); // :Pointcut|false|undefined
} else if (isPointcut(configOrPointcut) || isPointcutLike(configOrPointcut)) {
pointcut = getPointcutByReference(configOrPointcut); // :Pointcut|false|undefined
}
if (pointcut) {
var equalsPointcut = makeFilter_equalsPointcut(pointcut);
if (pointcutList.some(equalsPointcut)) {
// this approach keeps the list reference that was passed into the privileged "Allocable_all" Trait Module.
mutateArray_removeItemsByFilter(pointcutList, equalsPointcut);
delete pointcutMap[pointcut.getId()];
EventProxy.emit({
type : "pointcut:remove",
pointcut : pointcut
});
} else {
pointcut = false;
}
equalsPointcut = null;
}
return pointcut;
}
;
module = {
getById : getPointcutById,
add : addPointcut,
remove : removePointcut,
isPointcut : isPointcut,
isPointcutLike : isPointcutLike
};
Allocable_all.call(module, pointcutList);
return module;
}());
Advice = (function () {
var
module,
adviceList = [],
adviceMap = {},
adviceTypeCheckList = {
"AROUND" : "around",
"BEFORE" : "before",
"AFTER" : "after",
"AFTERTHROWING" : "afterThrowing",
"AFTERRETURNING" : "afterReturning"
},
Constructor = function (config) {
var advice = this;
advice.getHandler = function () {
return config.handler;
};
advice.getType = function () {
return config.type;
};
advice.getId = function () {
return config.id;
};
}
;
Constructor.prototype.equals = function (type) {
var advice = this;
return (
(isAdvice(advice) && isAdvice(type) && (advice === type))
|| (
isAdviceLike(advice) && isAdviceLike(type)
&& (advice.getHandler() === type.getHandler())
&& (advice.getType() === type.getType())
&& (advice.getId() === type.getId())
)
);
};
var
getSanitizedAdviceType = function (adviceType) {
return adviceTypeCheckList[getSanitizedIdentifier(adviceType).toUpperCase()] || "";
},
isValidAdviceType = function (adviceType) {
return (isStringValue(adviceType) && (adviceTypeCheckList[adviceType.toUpperCase()] === adviceType));
},
isAdvice = function (type) {
return (type instanceof Constructor);
},
isAdviceLike = function (type) {
return (
type && (typeof type == "object")
&& isFunction(type.getHandler) && isFunction(type.getType)
&& isValidAdviceType(type.getType()) && isFunction(type.getId)
);
},
isAdviceConfig = function (type) {
return (
type && (typeof type == "object")
&& isFunction(type.handler) && getSanitizedAdviceType(type.type)
);
},
makeFilter_equalsBehavior = function (handler, type) {
return function/* equalsBehavior */(item/*, idx, list*/) {
return ((item.getHandler() === handler) && (item.getType() === type));
};
},
makeFilter_equalsAdvice = function (advice) {
var
handler = advice.getHandler(), // required
type = advice.getType(), // required
id = advice.getId() // required
;
return function/* equalsAdvice */(item/*, idx, list*/) {
return ((item.getHandler() === handler) && (item.getType() === type) && (item.getId() === id));
};
},
getAdviceById = function (id) {
var advice;
if (isStringValue(id)) {
advice = adviceMap[id];
}
return advice;
},
getAdviceByConfig = function (config) {
var
advice,
id = getSanitizedIdentifier(config.id),
av = getAdviceById(id) // adviceMap[id]
;
config.type = getSanitizedAdviceType(config.type);
if (av) {
advice = ((av.getHandler() === config.handler) && (av.getType() === config.type)) ? av : false;
} else {
var equalsBehavior = makeFilter_equalsBehavior(config.handler, config.type);
av = array_getItemByFilter(adviceList, equalsBehavior);
if (av) {
advice = (av.getId() === id) ? av : false;
}
equalsBehavior = null;
}
return advice; // :Advice|false|undefined
},
getAdviceByReference = function (advice) {
return getAdviceByConfig({
handler : advice.getHandler(),
type : advice.getType(),
id : advice.getId()
}); // :Advice|false|undefined
},
createAdvice = function (config) {
return (new Constructor(config));
},
addAdvice = function (configOrAdvice) {
var config, advice;
if (isAdviceConfig(configOrAdvice)) {
config = configOrAdvice;
advice = getAdviceByConfig(config); // :Advice|false|undefined
if (isUndefined(advice)) {
config.type = getSanitizedAdviceType(config.type);
config.id = (getSanitizedIdentifier(config.id) || createId());
advice = createAdvice(config); // :Advice
}
} else if (isAdvice(configOrAdvice)) {
advice = configOrAdvice; // :Advice
} else if (isAdviceLike(configOrAdvice)) {
advice = getAdviceByReference(configOrAdvice); // :Advice|false|undefined
if (isUndefined(advice)) {
advice = createAdvice({
handler : configOrAdvice.getHandler(),
type : configOrAdvice.getType(),
id : configOrAdvice.getId()
}); // :Advice
}
}
if (advice && !adviceList.some(makeFilter_equalsAdvice(advice))) {
// addAdvice
adviceList.push(advice);
adviceMap[advice.getId()] = advice;
EventProxy.emit({
type : "advice:add",
advice : advice
});
}
return advice; // :Advice|false|undefined
},
removeAdvice = function (configOrAdvice) {
var advice;
if (isAdviceConfig(configOrAdvice)) {
advice = getAdviceByConfig(configOrAdvice); // :Advice|false|undefined
} else if (isAdvice(configOrAdvice) || isAdviceLike(configOrAdvice)) {
advice = getAdviceByReference(configOrAdvice); // :Advice|false|undefined
}
if (advice) {
var equalsAdvice = makeFilter_equalsAdvice(advice);
if (adviceList.some(equalsAdvice)) {
// this approach keeps the list reference that was passed into the privileged "Allocable_all" Trait Module.
mutateArray_removeItemsByFilter(adviceList, equalsAdvice);
delete adviceMap[advice.getId()];
EventProxy.emit({
type : "advice:remove",
advice : advice
});
} else {
advice = false;
}
equalsAdvice = null;
}
return advice;
}
;
module = {
getById : getAdviceById,
add : addAdvice,
remove : removeAdvice,
isAdvice : isAdvice,
isAdviceLike : isAdviceLike
};
Allocable_all.call(module, adviceList);
return module;
}());
Aspect = (function () {
var
module,
aspectList = [],
aspectMap = {},
Constructor = function (config) {
var
aspect = this,
confirmationState = {
current: "deny",
nominal: "deny"
},
markForReconfirmation = function () {
confirmationState.current = "";
},
linkList = [],
linkAdviceToPointcut = function (configOrAdvice, configOrPointcut) {
injectLinkIntoAspect(linkList, configOrAdvice, configOrPointcut);
},
handler = config.handler
;
handler(linkAdviceToPointcut, AspectOrientedModule); // Aspect Handler Arguments (API)
aspect.getLinkList = function () {
return makeArray(linkList);
};
aspect.getHandler = function () {
return handler;
};
aspect.getId = function () {
return config.id;
};
aspect.deny = function () {
if ((this === aspect) && !aspect.isDenied()) {
denyAspect(/*aspect, */confirmationState, markForReconfirmation);
}
};
aspect.confirm = function () {
if ((this === aspect) && !aspect.isConfirmed()) {
confirmAspect(aspect, confirmationState, markForReconfirmation);
}
};
aspect.isReconfirm = function () {
return ((this === aspect) && (confirmationState.current != "confirm") && (confirmationState.nominal == "confirm"));
};
aspect.isConfirmed = function () {
return ((this === aspect) && (confirmationState.current == "confirm") && (confirmationState.nominal == "confirm"));
};
aspect.isDenied = function () {
return ((this === aspect) && (confirmationState.current == "deny") && (confirmationState.nominal == "deny"));
};
}
;
Constructor.prototype.equals = function (type) {
var aspect = this;
return (
(isAspect(aspect) && isAspect(type) && (aspect === type))
|| (
isAspectLike(aspect) && isAspectLike(type)
&& (aspect.getHandler() === type.getHandler())
&& (aspect.getId() === type.getId())
)
);
};
var
isPointcut = Pointcut.isPointcut,
isAdvice = Advice.isAdvice,
isAspect = function (type) {
return (type instanceof Constructor);
},
isAspectLike = function (type) {
return (
type && (typeof type == "object")
&& isFunction(type.getLinkList) && isFunction(type.getHandler) && isFunction(type.getId)
&& isFunction(type.deny) && isFunction(type.confirm) && isFunction(type.isConfirmed)
);
},
isAspectConfig = function (type) {
return (type && (typeof type == "object") && isFunction(type.handler));
},
makeFilter_isAspectHandler = function (handler) {
return function/* isAspectHandler */(item/*, idx, list*/) {
return (item.getHandler() === handler);
};
},
makeFilter_equalsAspect = function (aspect) {
var
handler = aspect.getHandler(), // required
id = aspect.getId() // required
;
return function/* equalsAspect */(item/*, idx, list*/) {
return ((item.getHandler() === handler) && (item.getId() === id));
};
},
makeFilter_equalsAspectLink = function (advice, pointcut) {
return function/* equalsAspectLink */(item/*, idx, list*/) {
return ((item.advice === advice) && (item.pointcut === pointcut));
};
},
injectLinkIntoAspect = function (linkList, configOrAdvice, configOrPointcut) {
var
advice = Advice.add(configOrAdvice),
pointcut = Pointcut.add(configOrPointcut)
;
if (isAdvice(advice) && isPointcut(pointcut) && !linkList.some(makeFilter_equalsAspectLink(advice, pointcut))) {
linkList.push({
advice : advice,
pointcut : pointcut
});
}
},
isConfirmedAspect = function (aspect/*, idx, list*/) {
return aspect.isConfirmed();
},
reconfirmAspect = function (aspect/*, idx, list*/) {
aspect.isReconfirm() && aspect.confirm();
},
restoreInitialSystemState = function () {
//if (Aspect.all().some(isConfirmedAspect)) { // only in case of finding at least one "confirmed" aspect.
Joinpoint.all().forEach(function (joinpoint/*, idx, list*/) {
restoreJoinpoint(joinpoint.getTarget(), joinpoint.getMethodName(), joinpoint.getBaseMethod());
});
EventProxy.emit("system:restore"/*initialstate*/); // triggers the internal current confirmation state of each
//} // aspect to be set to anything different from "confirm" -
}, // thus switching each aspect into its "isReconfirm" mode.
reinitializeSystemState = function () {
Aspect.all().forEach(reconfirmAspect);
},
restoreJoinpoint = function (methodTarget, methodName, baseMethod) {
methodTarget[methodName] = baseMethod;
},
modifyJoinpoint = function (methodTarget, methodName, adviceType, adviceHandler, joinpoint) {
methodTarget[methodName] = methodTarget[methodName][adviceType](adviceHandler, methodTarget, joinpoint);
//console.warn = console.warn.before(function () {console.log("before warn", arguments);}, console);
},
joinAdviceAndPointcut = function (advice, pointcut) {
var
adviceType = advice.getType(),
adviceHandler = advice.getHandler()
;
pointcut.getJoinpoints().forEach(function (joinpoint/*, idx, list*/) {
modifyJoinpoint(joinpoint.getTarget(), joinpoint.getMethodName(), adviceType, adviceHandler, joinpoint);
});
},
confirmAspect = function (aspect, confirmationState, eventHandler) {
if (isSystemOff()) {
confirmationState.current = "";
confirmationState.nominal = "confirm";
} else {
aspect.getLinkList().forEach(function (link/*, idx, list*/) {
joinAdviceAndPointcut(link.advice, link.pointcut);
});
confirmationState.current = "confirm";
confirmationState.nominal = "confirm";
EventProxy.on("system:restore"/*initialstate*/, eventHandler);
}
},
denyAspect = function (/*aspect, */confirmationState, eventHandler) {
EventProxy.off("system:restore"/*initialstate*/, eventHandler);
confirmationState.current = "deny";
confirmationState.nominal = "deny";
restoreInitialSystemState();
reinitializeSystemState();
},
getAspectById = function (id) {
var aspect;
if (isStringValue(id)) {
aspect = aspectMap[id];
}
return aspect;
},
getAspectByConfig = function (config) {
var
aspect,
id = getSanitizedIdentifier(config.id),
as = getAspectById(id) // aspectMap[id]
;
if (as) {
aspect = (as.getHandler() === config.handler) ? as : false;
} else {
var isAspectHandler = makeFilter_isAspectHandler(config.handler);
as = array_getItemByFilter(aspectList, isAspectHandler);
if (as) {
aspect = (as.getId() === id) ? as : false;
}
isAspectHandler = null;
}
return aspect; // :Aspect|false|undefined
},
getAspectByReference = function (aspect) {
return getAspectByConfig({
handler : aspect.getHandler(),
id : aspect.getId()
}); // :Aspect|false|undefined
},
createAspect = function (config) {
return (new Constructor(config));
},
addAspect = function (configOrAspect) {
var config, aspect;
if (isAspectConfig(configOrAspect)) {
config = configOrAspect;
aspect = getAspectByConfig(config); // :Aspect|false|undefined
if (isUndefined(aspect)) {
config.id = (getSanitizedIdentifier(config.id) || createId());
aspect = createAspect(config); // :Aspect
}
} else if (isAspect(configOrAspect)) {
aspect = configOrAspect; // :Aspect
} else if (isAspectLike(configOrAspect)) {
aspect = getAspectByReference(configOrAspect); // :Aspect|false|undefined
if (isUndefined(aspect)) {
aspect = createAspect({
handler : configOrAspect.getHandler(),
id : configOrAspect.getId()
}); // :Aspect
}
}
if (aspect && !aspectList.some(makeFilter_equalsAspect(aspect))) {
// addAspect
aspectList.push(aspect);
aspectMap[aspect.getId()] = aspect;
EventProxy.emit({
type : "aspect:add",
aspect : aspect
});
}
return aspect; // :Aspect|false|undefined
},
removeAspect = function (configOrAspect) {
var aspect;
if (isAspectConfig(configOrAspect)) {
aspect = getAspectByConfig(configOrAspect); // :Aspect|false|undefined
} else if (isAspect(configOrAspect) || isAspectLike(configOrAspect)) {
aspect = getAspectByReference(configOrAspect); // :Aspect|false|undefined
}
if (aspect) {
var equalsAspect = makeFilter_equalsAspect(aspect);
if (aspectList.some(equalsAspect)) {
// this approach keeps the list reference that was passed into the privileged "Allocable_all" Trait Module.
mutateArray_removeItemsByFilter(aspectList, equalsAspect);
delete aspectMap[aspect.getId()];
EventProxy.emit({
type : "aspect:remove",
aspect : aspect
});
} else {
aspect = false;
}
equalsAspect = null;
}
return aspect;
}
;
systemOff = function () {
systemState = "off";
restoreInitialSystemState();
};
systemOn = function () {
systemState = "on";
reinitializeSystemState();
};
module = {
getById : getAspectById,
add : addAspect,
remove : removeAspect,
isAspect : isAspect,
isAspectLike : isAspectLike
};
Allocable_all.call(module, aspectList);
return module;
}());
EventProxy.on("joinpoint:add", rebootSystem);
EventProxy.on("joinpoint:remove", rebootSystem);
EventProxy.on("pointcut:add", rebootSystem);
EventProxy.on("pointcut:remove", rebootSystem);
EventProxy.on("advice:add", rebootSystem);
EventProxy.on("advice:remove", rebootSystem);
EventProxy.on("aspect:add", rebootSystem);
EventProxy.on("aspect:remove", rebootSystem);
AspectOrientedModule = {
Joinpoint : Joinpoint,
Pointcut : Pointcut,
Advice : Advice,
Aspect : Aspect,
isOff : isSystemOff,
isOn : isSystemOn,
off : systemOff,
on : systemOn,
reboot : rebootSystem
};
return AspectOrientedModule;
});
/**
* as for use with [twitter.com],
*
* if one tries scanning and logging the global namespace/object
* twitter.com prevents logging by overwriting [global.console] features
*
* the approach beneath kind of recovers [global.console.log] and [global.console.warn]
*
* just open a console window for the not closed minified "proxy" window as well
* and place it right to the console window of the browser that runs twitter.com
* (you don't need though, but see what happens / not happens).
*/
var win = window.open("","","");
win.resizeTo(0,0);
win.moveTo(0,0);
window.console.log = (function (loacal_console, remote_console) {
return function () {
remote_console.log.apply(loacal_console, arguments);
remote_console.log.apply(remote_console, arguments);
};
}(window.console, win.console));
window.console.warn = (function (loacal_console, remote_console) {
return function () {
remote_console.warn.apply(loacal_console, arguments);
remote_console.warn.apply(remote_console, arguments);
};
}(window.console, win.console));
//win.close();
//delete window.win;
var
ao = composable.require("modification.ao"),
JP = ao.Joinpoint,
PC = ao.Pointcut,
AV = ao.Advice,
AS = ao.Aspect
;
(function (require, global, rootName) {
var
scanTarget = global[rootName],
Object = global.Object,
env = require("environment"),
//env_helpers = env.helpers,
env_introspective = env.introspective,
isObjectObject = env_introspective.isObjectObject,
//isObject = env_introspective.isObject,
//isArray = env_introspective.isArray,
isFunction = env_introspective.isFunction,
//isCallable = env_introspective.isCallable,
ao = require("modification.ao"),
JP = ao.Joinpoint,
PC = ao.Pointcut,
AV = ao.Advice,
AS = ao.Aspect
;
var globallyAccessibleMethodsMap = Object.keys(scanTarget).reduce(function (scopedCollector, key) {
var
collect = arguments.callee,
target = scopedCollector.target,
list = scopedCollector.list,
path = scopedCollector.path,
methods = scopedCollector.scanned.methods,
objects = scopedCollector.scanned.objects,
type
//type = target[key]
;
try {
type = target[key];
} catch (exc) {
console.warn([exc.message, key, target]);
type = null;
}
scopedCollector.path = [path, ".", key].join("");
if (isFunction(type)) { // if (typeof type == "function") {
if (methods.indexOf(type) == -1) {
methods.push(type);
list.push({
"label" : scopedCollector.path,
"methodName" : key,
"target" : target
});
scopedCollector.target = type;
scopedCollector = Object.keys(type).reduce(collect, scopedCollector);
scopedCollector.target = target;
}
} else if (isObjectObject(type)) { // else if (type && (typeof type == "object")) {
if (objects.indexOf(type) == -1) {
objects.push(type);
scopedCollector.target = type;
scopedCollector = Object.keys(type).reduce(collect, scopedCollector);
scopedCollector.target = target;
}
}
scopedCollector.path = path;
return scopedCollector;
}, {
"target" : scanTarget,
"list" : [],
"path" : rootName,
"scanned" : {
"methods" : [],
"objects" : []
}
});
globallyAccessibleMethodsMap.list.forEach(function (protoJoinpoint) {
// JP.add({
// label : protoJoinpoint.label,
// methodName : protoJoinpoint.methodName,
// target : protoJoinpoint.target
// });
JP.add(protoJoinpoint);
});
return globallyAccessibleMethodsMap;
}(window.composable.require, window, "window"));
JP.all().sort(function (a, b) {
return (a.getLabel() < b.getLabel()) ? -1 : ((a.getLabel() > b.getLabel()) ? 1 : 0);
}).forEach(function (jp/*, idx, list*/) {
console.log(jp.getLabel());
});
console.log(["JP.all.size()", JP.all.size()]);
/**
* working AO system example that needs to be run
* within the console of a google chrome browser
* that runs [twitter.com]
*/
var av__log_before = AV.add({
id : "log_before",
type : "before",
handler : function (argsArray, pointcut) {
if (pointcut) {
var
label = pointcut.getLabel(),
target = pointcut.getTarget(),
methodName = pointcut.getMethodName()
;
console.log([label, methodName, (target === this), argsArray, this]);
} else {
console.log([this.name, argsArray, this]);
}
}
});
var pc__app_data = PC.add({
id : "app_data",
filter : function (jp) {
return (jp.getLabel().indexOf("window.loadrunner.Module.exports.app/data/") >= 0);
}
});
var pc__all_apps = PC.add({
id : "all_apps",
filter : function (jp) {
return (jp.getLabel().indexOf("window.loadrunner.Module.exports.app") >= 0);
}
});
var as__log__app_data = AS.add({
id : "log__app_data",
handler : function (linkAdviceToPointcut, aoSystem) {
linkAdviceToPointcut(av__log_before, pc__app_data);
}
});
var as__log__all_apps = AS.add({
id : "log__all_apps",
handler : function (linkAdviceToPointcut, aoSystem) {
linkAdviceToPointcut(av__log_before, pc__all_apps);
}
});
as__log__app_data.confirm();
as__log__all_apps.confirm();
/**
* play around - stepwise do:
*
* > as__log__all_apps.deny();
* > // ... see what happens ...
* > as__log__app_data.deny();
* > // ... ...
* > as__log__app_data.confirm();
* > // ... ...
* > ao.off()
* > // ... ...
* > as__log__all_apps.confirm();
* > // ... ...
* > ao.on()
* > // ... ...
* > ...
* > ...
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.