Last active
August 25, 2023 08:23
-
-
Save petsel/3a598704149e00541db0ff9790146c4a to your computer and use it in GitHub Desktop.
Just Another "Trait Composition Language" Library for ECMAScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// | |
// Just Another "Trait Composition Language" Library for ECMAScript | |
// | |
// | |
(function (global) { // module (pattern). | |
"use strict"; | |
var | |
Function = global.Function, | |
Object = global.Object, | |
Array = global.Array, | |
RegExp = global.RegExp, | |
Number = global.Number, | |
Math = global.Math, | |
JSON = global.JSON, | |
TypeError = global.TypeError, | |
ReferenceError = global.ReferenceError, | |
SyntaxError = global.SyntaxError, | |
functionPrototype = Function.prototype, | |
objectPrototype = Object.prototype, | |
arrayPrototype = Array.prototype, | |
useRootPrototype = UseRoot.prototype, | |
traitsLinkPrototype = ApplyLink_fromTraits.prototype, | |
behaviorLinkPrototype = ApplyLink_singleBehavior.prototype, | |
functionPrototypeToString = functionPrototype.toString, | |
objectPrototypeValueOf = objectPrototype.valueOf, | |
objectPrototypeToString = objectPrototype.toString, | |
arrayPrototypeSlice = arrayPrototype.slice, | |
TYPE_OF__FUNCTION_TYPE = (typeof Function), | |
PATTERN__FUNCTION_CLASS = createClassSignaturePattern("Function"), | |
PATTERN__OBJECT_CLASS = createClassSignaturePattern("Object"), | |
PATTERN__ARRAY_CLASS = createClassSignaturePattern("Array"), | |
PATTERN__ARGUMENTS_CLASS = createClassSignaturePattern("Arguments"), | |
PATTERN__STRING_CLASS = createClassSignaturePattern("String"), | |
PATTERN__GENERATOR_CLASS = createClassSignaturePattern("GeneratorFunction"), | |
PATTERN__ARROW_SIGNATURE = "\\([^)]*\\)\\s+=>\\s+\\(", | |
PATTERN__BASE_TYPE_NAME = "^function\\s+([^(]+)\\(", | |
PATTERN__DOM_INTERFACES = "^(?:Node|CharacterData|Event|DOMError|DOMException|DOMImplementation|DOMStringList|DOMTokenList|EventTarget|HTMLCollection|MutationObserver|MutationRecord|NodeFilter|NodeIterator|NodeList|Range|TreeWalker|URL|Document)$", | |
PATTERN__HTML_INTERFACES = "^(?:HTMLElement|HTMLMediaElement|Element)$", | |
PATTERN__OTHER_INTERFACES = "^(?:CanvasRenderingContext2D|CanvasGradient|CanvasPattern|TextMetrics|ImageData|DOMStringMap|MediaError|HTMLCollection|NodeList)$", | |
PATTERN__BUILD_IN_TYPES = "^(?:Array|ArrayBuffer|AsyncFunction|Atomics|Boolean|DataView|Date|Error|EvalError|Float32Array|Float64Array|Function|Generator|GeneratorFunction|Int16Array|Int32Array|Int8Array|InternalError|Collator|DateTimeFormat|NumberFormat|Iterator|Map|Number|Object|Promise|Proxy|RangeError|ReferenceError|RegExp|Bool16x8|Bool32x4|Bool64x2|Bool8x16|Float32x4|Float64x2|Int16x8|Int32x4|Int8x16|Uint16x8|Uint32x4|Uint8x16|Set|SharedArrayBuffer|StopIteration|String|Symbol|SyntaxError|TypeError|TypedArray|URIError|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|WeakMap|WeakSet)$", | |
TEST_CALL_REFERENCE = {}, | |
// TYPE__APPLICABLE_FUNCTION = "applicable-function", | |
// TYPE__BUILDIN_CONSTRUCTOR = "buildin-constructor", | |
// TYPE__CLASS_CONSTRUCTOR = "class-constructor", | |
// TYPE__ARROW_FUNCTION = "arrow-function", | |
// TYPE__GENERATOR_FUNCTION = "generator-function", | |
// TYPE__INTERFACE_TYPE = "interface-type", | |
// | |
// //TYPE__GENERATOR_METHOD = "generator-method", | |
// //TYPE__INSTANCE_METHOD = "instance-method", | |
CHAINING_RULES_TABLE = { // {<currentCalleeName> : { "recentCalleeName" | ["recentCalleeName"[, "recentCalleeName"[, …]]] }} | |
"without" : ["apply", "applyTraits"], | |
"as" : ["apply", "applyBehavior"], | |
"after" : ["apply", "applyBehavior", "after", "before"], | |
"before" : ["apply", "applyBehavior", "after", "before"], | |
"apply" : ["apply", "applyBehavior", "applyTraits", "without", "as", "after", "before", "use"], | |
"applyTraits" : ["apply", "applyBehavior", "applyTraits", "without", "as", "after", "before", "use"], | |
"applyBehavior" : ["apply", "applyBehavior", "applyTraits", "without", "as", "after", "before", "use"] | |
}, | |
RULE_TYPE_COPY_TABLE = { | |
"beforeWrap" : copyTraitCompositionRule_beforeAfterWrap, | |
"afterWrap" : copyTraitCompositionRule_beforeAfterWrap, | |
"beforeApply" : copyTraitCompositionRule_beforeAfterApply, | |
"afterApply" : copyTraitCompositionRule_beforeAfterApply, | |
"without" : copyTraitCompositionRule_without, | |
"as" : copyTraitCompositionRule_as | |
}, | |
RULE_TYPE_EXECUTE_TABLE = { | |
"beforeWrap" : applyTraitCompositionRule_beforeWrap, | |
"afterWrap" : applyTraitCompositionRule_afterWrap, | |
"beforeApply" : applyTraitCompositionRule_beforeApply, | |
"afterApply" : applyTraitCompositionRule_afterApply, | |
"without" : applyTraitCompositionRule_without, | |
"as" : applyTraitCompositionRule_as | |
}, | |
propertyIsEnumerable = (function (propertyIsEnumerable) { | |
try { | |
propertyIsEnumerable.call(null, "length"); | |
propertyIsEnumerable = (function (is_enumerable, NULL_VALUE) { | |
return function (type, key) { | |
return ((type != NULL_VALUE) && is_enumerable.call(type, key)); | |
}; | |
}(propertyIsEnumerable, null)); | |
} catch (exc) { // [exc]::[Error] | |
propertyIsEnumerable = (function (is_enumerable, NULL_VALUE) { | |
return function (type, key) { | |
var isEnum = (type != NULL_VALUE); | |
if (isEnum) { | |
try { | |
isEnum = is_enumerable.call(type, key); | |
} catch (exc) { | |
//isEnum = false; | |
isEnum = true; /* due to [propertyIsEnumerable]'s special internal use within client/js-engine specific [isArgumentsArray] method */ | |
} | |
} | |
return isEnum; | |
}; | |
}(propertyIsEnumerable, null)); | |
} | |
return propertyIsEnumerable; | |
}(objectPrototype.propertyIsEnumerable)), | |
getPrototypeOf = (isFunction(Object.getPrototypeOf) && Object.getPrototypeOf) || function (type) { | |
var | |
protoType, // not the best "shamming" of … | |
proto = (type && type.__proto__); // | |
// … `Object.getPrototypeOf` … | |
if (proto || (proto === null)) { // | |
// … but feasible enough. | |
protoType = proto; // | |
// | |
} else if (isFunctionObject(type.constructor)) { // - return best guess | |
// of an object's | |
protoType = type.constructor.prototype; // prototype. | |
// | |
} else if (type instanceof Object) { // | |
// | |
protoType = objectPrototype; // | |
} else { // | |
protoType = null; // | |
} // | |
return protoType; // | |
}, | |
// @COMMEND - think about how to categorize and how to deal with non callable objects | |
// that pretend to be (ordinary) callable and/or applicable function types. | |
// | |
// Arrow Function :: fctArrow = (() => (function(){}) | |
// - is a function type. | |
// - can not serve as constructor. | |
// - inherits the Function prototype. | |
// Generator Function :: fctGenerator = (function*(){}) | |
// - is a function type. | |
// - can not serve as constructor. | |
// - does feature the `prototype` object. | |
// - inherits the Generator prototype. | |
// CLass Constructor Function :: class Foo { constructor() {} } | |
// - is a function type. | |
// - does serve as constructor only. | |
// - can not be invoked without new operator. | |
// - does feature the `prototype` object. | |
// Ordinary Function | |
// - callable in any way. | |
// - does feature the `prototype` object. | |
// - inherits the Function prototype. | |
// | |
// see - [https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model] | |
// DOM interfaces: | |
// ["Attr", "CharacterData", "ChildNode", "Comment", "CustomEvent", "Document", "DocumentFragment", "DocumentType", | |
// "DOMError", "DOMException", "DOMImplementation", "DOMString", "DOMTimeStamp"/*, "DOMSettableTokenList"*/, "DOMStringList", | |
// "DOMTokenList", "Element", "Event", "EventTarget", "HTMLCollection", "MutationObserver", "MutationRecord", | |
// "Node", "NodeFilter", "NodeIterator", "NodeList", "ParentNode", "ProcessingInstruction", "Range", "Text", | |
// "TreeWalker", "URL", "Window", "Worker", "XMLDocument"] | |
// | |
// DOM interface prototypes: | |
// ["Node", "CharacterData", "Event", "EventTarget", "Document"] // "function () {}" | |
// | |
// DOM interface types and prototypes: | |
// ["Node", "CharacterData", "Event", "DOMError", "DOMException", "DOMImplementation", "DOMStringList", "DOMTokenList", | |
// "EventTarget", "HTMLCollection", "MutationObserver", "MutationRecord", "NodeFilter", "NodeIterator", "NodeList", | |
// "Range", "TreeWalker", "URL", "Document"] | |
// HTML element interfaces: | |
// ["HTMLAnchorElement"/*, "HTMLAppletElement"*/, "HTMLAreaElement", "HTMLAudioElement", "HTMLBaseElement", "HTMLBodyElement", | |
// "HTMLBRElement", "HTMLButtonElement", "HTMLCanvasElement", "HTMLDataElement", "HTMLDataListElement", "HTMLDialogElement"/*, | |
// "HTMLDirectoryElement"*/, "HTMLDivElement", "HTMLDListElement", "HTMLElement", "HTMLEmbedElement", "HTMLFieldSetElement", | |
// "HTMLFontElement", "HTMLFormElement"/*, "HTMLFrameElement"*/, "HTMLFrameSetElement", "HTMLHeadElement", "HTMLHeadingElement", | |
// "HTMLHtmlElement", "HTMLHRElement", "HTMLIFrameElement", "HTMLImageElement", "HTMLInputElement", "HTMLKeygenElement", | |
// "HTMLLabelElement", "HTMLLegendElement", "HTMLLIElement", "HTMLLinkElement", "HTMLMapElement", "HTMLMediaElement"/*, | |
// "HTMLMenuElement"*/, "HTMLMetaElement", "HTMLMeterElement", "HTMLModElement", "HTMLObjectElement", "HTMLOListElement", | |
// "HTMLOptGroupElement", "HTMLOptionElement", "HTMLOutputElement", "HTMLParagraphElement", "HTMLParamElement", "HTMLPreElement", | |
// "HTMLProgressElement", "HTMLQuoteElement", "HTMLScriptElement", "HTMLSelectElement", "HTMLSourceElement", "HTMLSpanElement", | |
// "HTMLStyleElement", "HTMLTableElement", "HTMLTableCaptionElement", "HTMLTableCellElement", "HTMLTableDataCellElement", | |
// "HTMLTableHeaderCellElement", "HTMLTableColElement", "HTMLTableRowElement", "HTMLTableSectionElement", "HTMLTextAreaElement", | |
// "HTMLTimeElement", "HTMLTitleElement", "HTMLTrackElement", "HTMLUListElement", "HTMLUnknownElement", "HTMLVideoElement"] | |
// | |
// HTML element interface prototypes: | |
// ["HTMLElement", "HTMLMediaElement", "Element"] | |
// | |
// HTML element interface types and prototypes: | |
// ["HTMLElement", "HTMLMediaElement", "Element"] | |
// Other interfaces: | |
// ["CanvasRenderingContext2D", "CanvasGradient", "CanvasPattern", "TextMetrics", "ImageData", "CanvasPixelArray", | |
// "NotifyAudioAvailableEvent"/*, "HTMLAllCollection"*/, "HTMLFormControlsCollection", "HTMLOptionsCollection"/*, | |
// "HTMLPropertiesCollection"*/, "DOMStringMap", "RadioNodeList", "MediaError"] | |
// | |
// Other interface prototypes: | |
// ["HTMLCollection", "NodeList"] // "function () {}" | |
// | |
// Other interface types and prototypes: | |
// ["CanvasRenderingContext2D", "CanvasGradient", "CanvasPattern", "TextMetrics", "ImageData", "HTMLCollection", | |
// "DOMStringMap", "NodeList", "MediaError"] | |
// test: | |
// [/* (interface) key list */].reduce(function (collector, key) { | |
// debugger; | |
// var | |
// classSignature, | |
// protoType, | |
// type = window[key]; | |
// | |
// if (typeof type == "function") { | |
// protoType = Object.getPrototypeOf(type); | |
// classSignature = Function.prototype.toString.call(protoType); | |
// | |
// //if (classSignature == "function () {}") { | |
// // classSignature = Function.prototype.toString.call(type); | |
// //} | |
// if (!(classSignature in collector.index)) { | |
// collector.index[classSignature] = null; | |
// collector.list.push(classSignature); | |
// } | |
// } | |
// return collector | |
// | |
// }, {index: {}, list: []}).list; | |
isFiniteNumber = Number.isFinite, | |
isArguments = (isFunction(Array.isArguments) && Array.isArguments) || (function () { | |
function isArguments(type) { | |
return RegExp(PATTERN__ARGUMENTS_CLASS).test(classSignatureOf(type)); | |
} | |
if (!isArguments(arguments)) { | |
isArguments = function (type) { | |
return (isObjectObject(type) && (typeof type.length == "number") && isFiniteNumber(type.length) && !propertyIsEnumerable(type, "length")); | |
//return (isObjectObject(type) && (typeof type.length == "number") && isFiniteNumber(type.length) && !propertyIsEnumerable(type, "length") && (typeof type.callee == "function")); | |
}; | |
} | |
return isArguments; | |
}()), | |
array_from = (isFunction(Array.from) && Array.from) || function (listType) { | |
return arrayPrototypeSlice.call(listType); | |
}, | |
array_flatten = function flatten (list) { | |
list = (isArguments(list) && array_from(list)) || list; | |
if (isArray(list)) { | |
list = list.reduce(function (collector, item) { | |
return collector.concat(flatten(item)); | |
}, []); | |
} | |
return list; | |
}, | |
object_keys = Object.keys, | |
object_assign = (isFunction(Object.assign) && Object.assign) || function (target, source) { | |
object_keys(source).forEach(function (key) { // | |
// - simplified (just | |
target[key] = source[key]; // a single source) | |
}); // 'assign' fallback. | |
return target; // | |
}, | |
math_min = Math.min, | |
noop = (function () {}), | |
console; | |
console = (((console = global.console) && isFunction(console.warn) && isFunction(console.log)) && console) || { | |
error : noop, | |
warn : noop, | |
log : noop | |
}; | |
// function tryConstruct(type, argumentsArray) { // not for e.g. arrow functions. | |
// var | |
// argumentsLength = (argumentsArray && (isArray(argumentsArray) || isArguments(argumentsArray)) && argumentsArray.length) || 0; | |
// | |
// if (argumentsLength == 0) { | |
// (new type); | |
// } else if (argumentsLength == 1) { | |
// (new type(argumentsArray[0])); | |
// } else if (argumentsLength == 2) { | |
// (new type(argumentsArray[0], argumentsArray[1])); | |
// } else if (argumentsLength == 3) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2])); | |
// } else if (argumentsLength == 4) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3])); | |
// } else if (argumentsLength == 5) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4])); | |
// } else if (argumentsLength == 6) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5])); | |
// } else if (argumentsLength == 7) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6])); | |
// } else if (argumentsLength == 8) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6], argumentsArray[7])); | |
// } else if (argumentsLength == 9) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6], argumentsArray[7], argumentsArray[8])); | |
// } else if (argumentsLength == 10) { | |
// (new type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6], argumentsArray[7], argumentsArray[8], argumentsArray[9])); | |
// } | |
// } | |
// function tryDirectCall(type, argumentsArray) { // not for e.g. class constructor functions. | |
// var | |
// argumentsLength = (argumentsArray && (isArray(argumentsArray) || isArguments(argumentsArray)) && argumentsArray.length) || 0; | |
// | |
// if (argumentsLength == 0) { | |
// type(); | |
// } else if (argumentsLength == 1) { | |
// type(argumentsArray[0]); | |
// } else if (argumentsLength == 2) { | |
// type(argumentsArray[0], argumentsArray[1]); | |
// } else if (argumentsLength == 3) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2]); | |
// } else if (argumentsLength == 4) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3]); | |
// } else if (argumentsLength == 5) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4]); | |
// } else if (argumentsLength == 6) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5]); | |
// } else if (argumentsLength == 7) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6]); | |
// } else if (argumentsLength == 8) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6], argumentsArray[7]); | |
// } else if (argumentsLength == 9) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6], argumentsArray[7], argumentsArray[8]); | |
// } else if (argumentsLength == 10) { | |
// type(argumentsArray[0], argumentsArray[1], argumentsArray[2], argumentsArray[3], argumentsArray[4], argumentsArray[5], argumentsArray[6], argumentsArray[7], argumentsArray[8], argumentsArray[9]); | |
// } | |
// } | |
// | |
// function canConstruct(type, argumentsArray) { // not for e.g. arrow functions. | |
// var | |
// isAllowConstruct = true; | |
// | |
// try { | |
// tryConstruct(type, argumentsArray); | |
// | |
// } catch (exception) { | |
// | |
// isAllowConstruct = false; | |
// } | |
// return isAllowConstruct; | |
// } | |
// function isCallable(type, argumentsArray) { // not for e.g. class constructor functions. | |
// var | |
// isAllowDirectCall = true; | |
// | |
// try { | |
// tryDirectCall(type, argumentsArray); | |
// //functionPrototype.call.apply(type, argumentsArray); // merciless. | |
// | |
// } catch (exception) { | |
// | |
// isAllowDirectCall = false; | |
// } | |
// return isAllowDirectCall; | |
// } | |
// | |
// function isOrdinaryFunction(type, argumentsArray) { | |
// return ( | |
// isFunction(type) | |
// | |
// && !isGeneratorFunction(type) | |
// | |
// && isCallable(type, argumentsArray) // - not for e.g. class constructor functions. | |
// && canConstruct(type, argumentsArray) // - not for e.g. arrow functions. | |
// | |
// && !isBuildInConstructor(type) | |
// ); | |
// } | |
// class FooClass { constructor() {} } | |
// var | |
// fctArrow = (() => ( this )), | |
// fctBuildInConstructor = Object, | |
// fctDomElementConstructor = Node, | |
// fctGenerator = (function*(){}), | |
// fctOrdinary = function(){}; | |
// | |
// Object.prototype.toString.call(fctArrow); // "[object Function]" | |
// Object.prototype.toString.call(fctBuildInConstructor); // "[object Function]" | |
// Object.prototype.toString.call(fctDomElementConstructor); // "[object Function]" | |
// Object.prototype.toString.call(FooClass); // "[object Function]" | |
// Object.prototype.toString.call(fctGenerator); // "[object GeneratorFunction]" | |
// Object.prototype.toString.call(fctOrdinary); // "[object Function]" | |
// | |
// isFunctionObject(fctArrow); // true | |
// isFunctionObject(fctBuildInConstructor); // true | |
// isFunctionObject(fctDomElementConstructor); // true | |
// isFunctionObject(FooClass); // false | |
// isFunctionObject(fctGenerator); // false | |
// isFunctionObject(fctOrdinary); // true | |
// | |
// isFunction(fctArrow); // true | |
// isFunction(fctBuildInConstructor); // true | |
// isFunction(fctDomElementConstructor); // true | |
// isFunction(FooClass); // true | |
// isFunction(fctGenerator); // true | |
// isFunction(fctOrdinary); // true | |
// | |
// isFunctionType(fctArrow); // true | |
// isFunctionType(fctBuildInConstructor); // true | |
// isFunctionType(fctDomElementConstructor); // true | |
// isFunctionType(FooClass); // true | |
// isFunctionType(fctGenerator); // true | |
// isFunctionType(fctOrdinary); // true | |
// | |
// isCallable(fctArrow); // true | |
// isCallable(fctBuildInConstructor); // true | |
// isCallable(fctDomElementConstructor); // false | |
// isCallable(FooClass); // false | |
// isCallable(fctGenerator); // true | |
// isCallable(fctOrdinary); // true | |
// | |
// canConstruct(fctArrow); // false | |
// canConstruct(fctBuildInConstructor); // true | |
// canConstruct(fctDomElementConstructor); // false | |
// canConstruct(FooClass); // true | |
// canConstruct(fctGenerator); // false | |
// canConstruct(fctOrdinary); // true | |
// | |
// isOrdinaryFunction(fctArrow); // false | |
// isOrdinaryFunction(fctBuildInConstructor); // false | |
// isOrdinaryFunction(fctDomElementConstructor); // false | |
// isOrdinaryFunction(FooClass); // false | |
// isOrdinaryFunction(fctGenerator); // false | |
// isOrdinaryFunction(fctOrdinary); // true | |
function createClassSignaturePattern(internalClassName) { | |
return ["^\\[object\\s+", internalClassName, "\\]$"].join(""); | |
} | |
function getBaseTypeName(type) { | |
var | |
result = RegExp(PATTERN__BASE_TYPE_NAME).exec(functionTypeSignatureOf(type)); | |
return (result && result[1]); | |
} | |
function getSanitizedTarget(target) { | |
return ((target != null) && target) || null; | |
} | |
function baseValueOf(type) { | |
return ((type == null) ? type : objectPrototypeValueOf.call(type).valueOf()); | |
} | |
function classSignatureOf(type) { | |
return objectPrototypeToString.call(type); | |
} | |
function functionTypeSignatureOf(type) { | |
return functionPrototypeToString.call(type); | |
} | |
function isFunctionType(type) { | |
return (typeof type == TYPE_OF__FUNCTION_TYPE); | |
} | |
function isFunction(type) { | |
return ( | |
isFunctionType(type) | |
&& (typeof type.call == TYPE_OF__FUNCTION_TYPE) | |
&& (typeof type.apply == TYPE_OF__FUNCTION_TYPE) | |
); | |
} | |
function isFunctionObject(type) { | |
return RegExp(PATTERN__FUNCTION_CLASS).test(classSignatureOf(type)); | |
} | |
function isObjectObject(type) { | |
return RegExp(PATTERN__OBJECT_CLASS).test(classSignatureOf(type)); | |
} | |
// function isObject(type) { | |
// return (!!type && (isObjectObject(type) || isFunction(type))); | |
// } | |
function isArray(type) { | |
return RegExp(PATTERN__ARRAY_CLASS).test(classSignatureOf(type)); | |
} | |
function isString(type) { | |
return RegExp(PATTERN__STRING_CLASS).test(classSignatureOf(type)); | |
} | |
function isTypeOrExtendedType(type, regXPattern) { | |
var | |
regX = RegExp(regXPattern); | |
return ( | |
regX.test(getBaseTypeName(type)) | |
|| regX.test(getBaseTypeName(getPrototypeOf(type))) | |
); | |
} | |
function isDOMInterfaceType(type) { | |
return isTypeOrExtendedType(type, PATTERN__DOM_INTERFACES); | |
} | |
function isHTMLElementInterfaceType(type) { | |
return isTypeOrExtendedType(type, PATTERN__HTML_INTERFACES); | |
} | |
function isOtherInterfaceType(type) { | |
return isTypeOrExtendedType(type, PATTERN__OTHER_INTERFACES); | |
} | |
function isInterfaceType(type) { | |
return ( | |
isDOMInterfaceType(type) | |
|| isHTMLElementInterfaceType(type) | |
|| isOtherInterfaceType(type) | |
); | |
} | |
function isBuildInConstructor(type) { | |
return RegExp(PATTERN__BUILD_IN_TYPES).test(getBaseTypeName(type)); | |
//return RegExp(PATTERN__BUILD_IN_TYPES).test(type.name); // not reliable enough. | |
} | |
function isClassConstructorSignature(functionTypeSignature) { | |
return RegExp("^class\\s+").test(functionTypeSignature); | |
} | |
function isArrowFunctionSignature(functionTypeSignature) { | |
return RegExp(PATTERN__ARROW_SIGNATURE).test(functionTypeSignature); | |
} | |
function isGeneratorFunction(type) { | |
return RegExp(PATTERN__GENERATOR_CLASS).test(classSignatureOf(type)); | |
} | |
// function isArrowFunction(type) { | |
// return (isFunctionType(type) && isArrowFunctionSignature(functionTypeSignatureOf(type))); | |
// } | |
// function getBestGuessForFunctionType (type) { | |
// var | |
// functionType = "none", | |
// typeSignature = ""; | |
// | |
// if (isFunctionType(type)) { | |
// if (isGeneratorFunction(type)) { | |
// | |
// functionType = TYPE__GENERATOR_FUNCTION; | |
// } else { | |
// typeSignature = functionTypeSignatureOf(type); | |
// | |
// if (isArrowFunctionSignature(typeSignature)) { | |
// | |
// functionType = TYPE__ARROW_FUNCTION; | |
// | |
// } else if ( | |
// RegExp/* named class */("^class\\s+" + type.name + "\\s+\\{").test(typeSignature) | |
// || RegExp/* named extended class */("^class\\s+" + type.name + "\\s+extends\\s+[^\\{]+(?:\\s+|\\)\\s*)\\{").test(typeSignature) | |
// || RegExp/* anonymous "mixin" class */("^class\\s+extends\\s+[^\\{]+\\s+\\{").test(typeSignature) | |
// || RegExp/* anonymous class */("^class\\s+\\{").test(typeSignature) | |
// | |
// ) { | |
// functionType = TYPE__CLASS_CONSTRUCTOR; | |
// | |
// } else if (isFunction(type)) { | |
// if (isBuildInConstructor(type)) { | |
// | |
// functionType = TYPE__BUILDIN_CONSTRUCTOR; | |
// | |
// } else if (isInterfaceType(type)) { | |
// | |
// functionType = TYPE__INTERFACE_TYPE; | |
// } else { | |
// functionType = TYPE__APPLICABLE_FUNCTION; | |
// } | |
// } | |
// } | |
// } | |
// return functionType; | |
// } | |
// | |
// function isApplicableFunction(type) { | |
// // there also is an implementation of `function isApplicableType(type) { … }` | |
// return (getBestGuessForFunctionType(type) === TYPE__APPLICABLE_FUNCTION); | |
// } | |
// function isClassConstructor(type) { | |
// return (getBestGuessForFunctionType(type) === TYPE__CLASS_CONSTRUCTOR); | |
// } | |
function isApplicableFunction(type) { | |
var | |
typeSignature; | |
return ( | |
isFunction(type) | |
&& !isGeneratorFunction(type) | |
&& (typeSignature = functionTypeSignatureOf(type)) | |
&& !isArrowFunctionSignature(typeSignature) | |
&& !isClassConstructorSignature(typeSignature) | |
&& !isBuildInConstructor(type) | |
&& !isInterfaceType(type) | |
); | |
} | |
function isClassConstructor(type) { | |
return ( | |
isFunction(type) | |
&& isClassConstructorSignature(functionTypeSignatureOf(type)) | |
); | |
} | |
// function isClassConstructor(type) { | |
// var typeSignature = ""; | |
// return ( | |
// isFunction(type) | |
// && (typeSignature = functionTypeSignatureOf(type)) | |
// | |
// && isClassConstructorSignature(typeSignature) | |
// && ( | |
// RegExp/* named class */("^class\\s+" + type.name + "\\s+\\{").test(typeSignature) | |
// || RegExp/* named extended class */("^class\\s+" + type.name + "\\s+extends\\s+[^\\{]+(?:\\s+|\\)\\s*)\\{").test(typeSignature) | |
// || RegExp/* anonymous "mixin" class */("^class\\s+extends\\s+[^\\{]+\\s+\\{").test(typeSignature) | |
// || RegExp/* anonymous class */("^class\\s+\\{").test(typeSignature) | |
// ) | |
// ); | |
// } | |
function isValidChaining(recentCalleeName, currentCalleeName) { | |
// CHAINING_RULES_TABLE : { | |
// "without" : ["apply", "applyTraits"], | |
// "as" : ["apply", "applyBehavior"], | |
// "after" : ["apply", "applyBehavior", "after", "before"], | |
// "before" : ["apply", "applyBehavior", "after", "before"], | |
// "apply" : ["without", "as", "after", "before", "use"] | |
// } | |
var | |
tableValue = CHAINING_RULES_TABLE[currentCalleeName]; | |
return (!!tableValue && (tableValue.indexOf(recentCalleeName) >= 0)); | |
} | |
function composeHandler_before(proceed, before, target) { // compose wrapping before handler. | |
return function beforeHandler () { | |
var | |
argsArray = arguments; | |
before.apply(target, argsArray); | |
return proceed.apply(target, argsArray); | |
}; | |
} | |
function composeHandler_after(proceed, after, target) { // compose wrapping after handler. | |
return function afterHandler () { | |
var | |
argsArray = arguments, | |
returnValue = proceed.apply(target, argsArray); | |
after.apply(target, argsArray); | |
return returnValue; | |
}; | |
} | |
function composeHandler_statefulBefore(proceed, before, target, payloadList) { // compose stateful before handler. | |
return function statefulBeforeHandler () { | |
var | |
argsArray = arguments; | |
before.call(target, argsArray, payloadList); | |
return proceed.apply(target, argsArray); | |
}; | |
} | |
function composeHandler_statefulAfter(proceed, after, target, payloadList) { // compose stateful after handler. | |
return function statefulAfterHandler () { | |
var | |
argsArray = arguments, | |
returnValue = proceed.apply(target, argsArray); | |
after.call(target, argsArray, payloadList); | |
return returnValue; | |
}; | |
} | |
function composeHandler_afterReturning(proceed, after, target, payloadList) { // compose afterReturning handler. | |
return function afterReturningHandler () { | |
var | |
argsArray = arguments, | |
returnValue = proceed.apply(target, argsArray); | |
after.call(target, returnValue, argsArray, payloadList); | |
return returnValue; | |
}; | |
} | |
function composeHandler_afterThrowing(proceed, after, target, payloadList) { // compose afterThrowing handler. | |
return function afterThrowingHandler () { | |
var | |
argsArray = arguments, | |
returnValue; | |
try { | |
returnValue = proceed.apply(target, argsArray); | |
} catch (exception) { | |
after.call(target, exception, argsArray, payloadList); | |
} | |
return returnValue; | |
}; | |
} | |
function composeHandler_afterFinally(proceed, after, target, payloadList) { // compose afterFinally handler. | |
return function afterFinallyHandler () { | |
var | |
argsArray = arguments, | |
returnValue, | |
errorValue; | |
try { | |
returnValue = proceed.apply(target, argsArray); | |
} catch (exception) { | |
errorValue = exception; | |
} | |
after.call(target, (errorValue || returnValue), argsArray, payloadList); // finally | |
return returnValue; | |
}; | |
} | |
function composeHandler_around(intercepted, intercepting, target, payloadList) { // compose around handler. | |
return function aroundHandler () { | |
return intercepting/*Behavior*/.call(target, intercepted/*Proceed*/, intercepting/*Behavior*/, arguments, payloadList); | |
}; | |
} | |
function createMethodModifier_before(methodName, behavior) { | |
return function beforeModifier () { // - basic wrapping 'before' modifier | |
var // that does not touch a callback's | |
target = this, // arguments signature. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_before(proceed, behavior, target); | |
}; | |
} | |
function createMethodModifier_after(methodName, behavior) { | |
return function afterModifier () { // - basic wrapping 'after' modifier | |
var // that does not touch a callback's | |
target = this, // arguments signature. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_after(proceed, behavior, target); | |
}; | |
} | |
function createMethodModifier_before_stateful(methodName, behavior) { | |
return function statefulBeforeModifier (payloadList) { // - channeling the `applicator`'s transformed | |
var // arguments array in order to enable method | |
target = this, // modification for stateful traits too. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_statefulBefore(proceed, behavior, target, payloadList); | |
}; | |
} | |
function createMethodModifier_after_stateful(methodName, behavior) { | |
return function statefulAfterModifier (payloadList) { // - channeling the `applicator`'s transformed | |
var // arguments array in order to enable method | |
target = this, // modification for stateful traits too. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_statefulAfter(proceed, behavior, target, payloadList); | |
}; | |
} | |
function createMethodModifier_afterReturning(methodName, behavior) { | |
return function afterReturningModifier (payloadList) { // - channeling the `applicator`'s transformed | |
var // arguments array in order to enable method | |
target = this, // modification for stateful traits too. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_afterReturning(proceed, behavior, target, payloadList); | |
}; | |
} | |
function createMethodModifier_afterThrowing(methodName, behavior) { | |
return function afterThrowingModifier (payloadList) { // - channeling the `applicator`'s transformed | |
var // arguments array in order to enable method | |
target = this, // modification for stateful traits too. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_afterThrowing(proceed, behavior, target, payloadList); | |
}; | |
} | |
function createMethodModifier_afterFinally(methodName, behavior) { | |
return function afterFinallyModifier (payloadList) { // - channeling the `applicator`'s transformed | |
var // arguments array in order to enable method | |
target = this, // modification for stateful traits too. | |
proceed = target[methodName]; | |
if (!isApplicableFunction(proceed)) { | |
proceed = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_afterFinally(proceed, behavior, target, payloadList); | |
}; | |
} | |
function createMethodModifier_around(methodName, intercepting/*Behavior*/) { | |
return function aroundModifier (payloadList) { // - channeling the `applicator`'s transformed | |
var // arguments array in order to enable method | |
target = this, // modification for stateful traits too. | |
intercepted/*Proceed*/ = target[methodName]; | |
if (!isApplicableFunction(intercepted)) { | |
intercepted = noop; | |
} | |
// in case <methodName> did not exist before, it always will be created instead of being modified. | |
target[methodName] = composeHandler_around(intercepted/*Proceed*/, intercepting/*Behavior*/, target, payloadList); | |
}; | |
} | |
function recordTraitCompositionRule_beforeWrap(traitSetup, trait, methodName) { | |
traitSetup.useTraits.rules.push(new TraitCompositionRule({ | |
type : "beforeWrap", | |
trait : trait, | |
methodName : methodName | |
})); | |
} | |
function recordTraitCompositionRule_afterWrap(traitSetup, trait, methodName) { | |
traitSetup.useTraits.rules.push(new TraitCompositionRule({ | |
type : "afterWrap", | |
trait : trait, | |
methodName : methodName | |
})); | |
} | |
function recordTraitCompositionRule_beforeApply(traitSetup, trait, fromTrait, methodName) { | |
traitSetup.useTraits.rules.push(new TraitCompositionRule({ | |
type : "beforeApply", | |
trait : trait, | |
fromTrait : fromTrait, | |
methodName : methodName | |
})); | |
} | |
function recordTraitCompositionRule_afterApply(traitSetup, trait, fromTrait, methodName) { | |
traitSetup.useTraits.rules.push(new TraitCompositionRule({ | |
type : "afterApply", | |
trait : trait, | |
fromTrait : fromTrait, | |
methodName : methodName | |
})); | |
} | |
function recordTraitCompositionRule_without(traitSetup, traitList, methodNameList) { | |
traitSetup.useTraits.rules.push(new TraitCompositionRule({ | |
type : "without", | |
traitList : traitList, | |
methodNameList : methodNameList | |
})); | |
} | |
function recordTraitCompositionRule_as(traitSetup, trait, methodName, methodAlias) { | |
traitSetup.useTraits.rules.push(new TraitCompositionRule({ | |
type : "as", | |
trait : trait, | |
methodName : methodName, | |
methodAlias : methodAlias | |
})); | |
} | |
function recordTraitCompositionRule_applyTraits(traitSetup, traitList) { | |
recordTraitCompositionRule_without(traitSetup, traitList, []); | |
} | |
function recordTraitCompositionRule_applyBehavior(traitSetup, trait, methodName) { | |
recordTraitCompositionRule_as(traitSetup, trait, methodName, methodName); | |
} | |
function getSanitizedMethodNameList(argsArray) { | |
return array_flatten(array_from(argsArray)).reduce(function (list, methodName) { | |
if (isString(methodName)) { | |
list.push(baseValueOf(methodName)) | |
} | |
return list; | |
}, []); | |
} | |
function prototypal_applyFromTraitsWithout(/* ["methodName" [, "methodName"] [, …]] */) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFromTraitsWithout +++"); } | |
var | |
invalidChainingMessage, | |
currentCalleeName = "without", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
methodNameList, | |
valueOfApplyLink, | |
useRoot, | |
applyLink = this; | |
if (isApplyLink_fromTraits(applyLink)) { | |
valueOfApplyLink = applyLink.valueOf(); | |
useRoot = valueOfApplyLink.parentLink; | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
methodNameList = getSanitizedMethodNameList(arguments); | |
if (methodNameList.length >= 1) { | |
chainData.recentCalleeName = currentCalleeName; | |
recordTraitCompositionRule_without(traitSetup, valueOfApplyLink.traitList, methodNameList); | |
} else { | |
throw(new TypeError("Not even a single <String> type was passed to 'without' as to be excluded method name.")); | |
} | |
} else { | |
invalidChainingMessage = ["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""); | |
if (recentCalleeName == "applyBehavior") { | |
throw(new SyntaxError([invalidChainingMessage, " in case of excluding one or more certain behaviors."].join(""))); | |
} else { | |
throw(new SyntaxError(invalidChainingMessage)); | |
} | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'use'.")); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'apply'.")); | |
} | |
// console.log("'without' - traitSetup : ", traitSetup); | |
return useRoot; | |
} | |
function prototypal_applyFromTraitAs(methodAlias) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFromTraitAs +++"); } | |
var | |
invalidChainingMessage, | |
currentCalleeName = "as", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
fromTrait, | |
methodName, | |
valueOfApplyLink, | |
useRoot, | |
applyLink = this; | |
if (isApplyLink_singleBehavior(applyLink)) { | |
valueOfApplyLink = applyLink.valueOf(); | |
useRoot = valueOfApplyLink.parentLink; | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
if (isString(methodAlias = baseValueOf(methodAlias))) { | |
fromTrait = valueOfApplyLink.trait; | |
methodName = valueOfApplyLink.methodName; | |
if (methodName !== methodAlias) { | |
chainData.recentCalleeName = currentCalleeName; | |
recordTraitCompositionRule_as(traitSetup, fromTrait, methodName, methodAlias); | |
} else { | |
throw(new TypeError("Using identical method names in case of aliasing is considered to be a rule violating contradiction.")); | |
} | |
} else { | |
throw(new TypeError("'as(<String>)' excepts as its sole argument just a 'String' type.")); | |
} | |
} else { | |
invalidChainingMessage = ["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""); | |
if (recentCalleeName == "applyTraits") { | |
throw(new SyntaxError([invalidChainingMessage, " in case of aliasing just a certain behavior."].join(""))); | |
} else { | |
throw(new SyntaxError(invalidChainingMessage)); | |
} | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'use'.")); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'apply'.")); | |
} | |
// console.log("'as' - traitSetup : ", traitSetup); | |
return useRoot; | |
} | |
function prototypal_applyFromTraitBefore(trait) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFromTraitBefore +++"); } | |
var | |
currentCalleeName = "before", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
traitList, | |
dummyType, | |
fromTrait, | |
methodName, | |
valueOfUseRoot, | |
valueOfApplyLink, | |
useRoot, | |
applyLink = this; | |
if (isApplyLink_singleBehavior(applyLink)) { | |
valueOfApplyLink = applyLink.valueOf(); | |
useRoot = valueOfApplyLink.parentLink; | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
if (isApplicableType(trait)) { | |
valueOfUseRoot = useRoot.valueOf(); | |
traitList = valueOfUseRoot.traitList; | |
if (traitList.indexOf(trait) >= 0) { | |
fromTrait = valueOfApplyLink.trait; | |
if (fromTrait !== trait) { | |
methodName = valueOfApplyLink.methodName; | |
dummyType = {}; | |
trait.call(dummyType); | |
if (isApplicableFunction(dummyType[methodName])) { | |
dummyType = null; | |
chainData.recentCalleeName = currentCalleeName; | |
recordTraitCompositionRule_beforeApply(traitSetup, trait, fromTrait, methodName); | |
} else { | |
throw(new ReferenceError(["Please consider applying", " '", methodName, "' ", "directly. This expected behavior has not been implemented by the trait that got passed to 'before'."].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Passing identical trait references to both 'apply' and 'before' is a contradiction that violates the composition rules.")); | |
} | |
} else { | |
throw(new TypeError("Any trait passed to 'before' has to be registered before via 'use'.")); | |
} | |
} else { | |
throw(new TypeError("'before(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.")); | |
} | |
} else { | |
throw(new SyntaxError(["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'use'.")); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'apply'.")); | |
} | |
// console.log("'before' - traitSetup : ", traitSetup); | |
// console.log("'before' - traitList : ", traitList); | |
return useRoot; | |
} | |
function prototypal_applyFromTraitAfter(trait) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFromTraitAfter +++"); } | |
var | |
currentCalleeName = "after", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
traitList, | |
dummyType, | |
fromTrait, | |
methodName, | |
valueOfUseRoot, | |
valueOfApplyLink, | |
useRoot, | |
applyLink = this; | |
if (isApplyLink_singleBehavior(applyLink)) { | |
valueOfApplyLink = applyLink.valueOf(); | |
useRoot = valueOfApplyLink.parentLink; | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
if (isApplicableType(trait)) { | |
valueOfUseRoot = useRoot.valueOf(); | |
traitList = valueOfUseRoot.traitList; | |
if (traitList.indexOf(trait) >= 0) { | |
fromTrait = valueOfApplyLink.trait; | |
if (fromTrait !== trait) { | |
methodName = valueOfApplyLink.methodName; | |
dummyType = {}; | |
trait.call(dummyType); | |
if (isApplicableFunction(dummyType[methodName])) { | |
dummyType = null; | |
chainData.recentCalleeName = currentCalleeName; | |
recordTraitCompositionRule_afterApply(traitSetup, trait, fromTrait, methodName); | |
} else { | |
throw(new ReferenceError(["Please consider applying", " '", methodName, "' ", "directly. This expected behavior has not been implemented by the trait that got passed to 'after'."].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Passing identical trait references to both 'apply' and 'after' is a contradiction that violates the composition rules.")); | |
} | |
} else { | |
throw(new TypeError("Any trait passed to 'after' has to be registered before via 'use'.")); | |
} | |
} else { | |
throw(new TypeError("'after(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.")); | |
} | |
} else { | |
throw(new SyntaxError(["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'use'.")); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'apply'.")); | |
} | |
// console.log("'after' - traitSetup : ", traitSetup); | |
// console.log("'after' - traitList : ", traitList); | |
return useRoot; | |
} | |
function prototypal_applyFromTraitBefore_viaUseRoot(trait) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFromTraitBefore_viaUseRoot +++"); } | |
var | |
currentCalleeName = "before", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
traitList, | |
dummyType, | |
fromTrait, | |
methodName, | |
valueOfUseRoot, | |
valueOfApplyLink, | |
applyLink, | |
useRoot = this; | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
if (isApplicableType(trait)) { | |
valueOfUseRoot = useRoot.valueOf(); | |
traitList = valueOfUseRoot.traitList; | |
if (traitList.indexOf(trait) >= 0) { | |
applyLink = useRoot.getChild(); | |
valueOfApplyLink = applyLink.valueOf(); | |
fromTrait = valueOfApplyLink.trait; | |
if (fromTrait !== trait) { | |
methodName = valueOfApplyLink.methodName; | |
dummyType = {}; | |
trait.call(dummyType); | |
if (isApplicableFunction(dummyType[methodName])) { | |
dummyType = null; | |
chainData.recentCalleeName = currentCalleeName; | |
recordTraitCompositionRule_beforeWrap(traitSetup, trait, methodName); | |
} else { | |
throw(new ReferenceError(["Please consider applying", " '", methodName, "' ", "directly. This expected behavior has not been implemented by the trait that got passed to 'before'."].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Passing identical trait references to both 'apply' and 'before' is a contradiction that violates the composition rules.")); | |
} | |
} else { | |
throw(new TypeError("Any trait passed to 'before' has to be registered before via 'use'.")); | |
} | |
} else { | |
throw(new TypeError("'before(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.")); | |
} | |
} else { | |
throw(new SyntaxError(["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'use'.")); | |
} | |
return useRoot; | |
} | |
function prototypal_applyFromTraitAfter_viaUseRoot(trait) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFromTraitAfter_viaUseRoot +++"); } | |
var | |
currentCalleeName = "after", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
traitList, | |
dummyType, | |
fromTrait, | |
methodName, | |
valueOfUseRoot, | |
valueOfApplyLink, | |
applyLink, | |
useRoot = this; | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
if (isApplicableType(trait)) { | |
valueOfUseRoot = useRoot.valueOf(); | |
traitList = valueOfUseRoot.traitList; | |
if (traitList.indexOf(trait) >= 0) { | |
applyLink = useRoot.getChild(); | |
valueOfApplyLink = applyLink.valueOf(); | |
fromTrait = valueOfApplyLink.trait; | |
if (fromTrait !== trait) { | |
methodName = valueOfApplyLink.methodName; | |
dummyType = {}; | |
trait.call(dummyType); | |
if (isApplicableFunction(dummyType[methodName])) { | |
dummyType = null; | |
chainData.recentCalleeName = currentCalleeName; | |
recordTraitCompositionRule_afterWrap(traitSetup, trait, methodName); | |
} else { | |
throw(new ReferenceError(["Please consider applying", " '", methodName, "' ", "directly. This expected behavior has not been implemented by the trait that got passed to 'after'."].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Passing identical trait references to both 'apply' and 'after' is a contradiction that violates the composition rules.")); | |
} | |
} else { | |
throw(new TypeError("Any trait passed to 'after' has to be registered before via 'use'.")); | |
} | |
} else { | |
throw(new TypeError("'after(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.")); | |
} | |
} else { | |
throw(new SyntaxError(["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""))); | |
} | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'use'.")); | |
} | |
return useRoot; | |
} | |
function getApplyLinkFrom_registerSingleBehavior(useRoot, trait, methodName) { | |
var | |
currentCalleeName = "applyBehavior", | |
traitSetup = useRoot.getSetup(), | |
useTraitList = useRoot.valueOf().traitList, | |
dummyType, | |
applyLink; | |
if (useTraitList.indexOf(trait) >= 0) { | |
dummyType = {}; | |
trait.call(dummyType); | |
if (isApplicableFunction(dummyType[methodName])) { | |
dummyType = null; | |
traitSetup.chainData.recentCalleeName = currentCalleeName; | |
applyLink = createApplyLink_singleBehavior(useRoot, trait, methodName); | |
useRoot.putChild(applyLink); | |
} else { | |
throw(new ReferenceError(["The requested", " '", methodName, "' ", "method has not been implemented by the trait that got passed to 'apply'."].join(""))); | |
} | |
} else { | |
throw(new TypeError("Any trait that got passed to 'apply' needs to be registered before via 'use'.")); | |
} | |
return applyLink; | |
} | |
function getApplyLinkFrom_registerEachTrait(useRoot, traitList) { | |
var | |
currentCalleeName = "applyTraits", | |
traitSetup = useRoot.getSetup(), | |
useTraitList = useRoot.valueOf().traitList, | |
applyLink; | |
if (isEveryTraitRegisteredViaUse(traitList, useTraitList)) { | |
traitSetup.chainData.recentCalleeName = currentCalleeName; | |
applyLink = createApplyLink_fromTraits(useRoot, traitList); | |
useRoot.putChild(applyLink); | |
} else { | |
throw(new TypeError("Any trait that got passed to 'apply' needs to be registered before via 'use'.")); | |
} | |
return applyLink; | |
} | |
function isEveryTraitRegisteredViaUse(traitList, useTraitList) { | |
return traitList.every(function (trait) { | |
return (useTraitList.indexOf(trait) >= 0); | |
}); | |
} | |
function isArgumentsSignature_applyFromEachTrait(argsArray) { | |
return array_from(argsArray).every(isApplicableType); | |
} | |
function chaining_applyFromAllTraitsWithoutBehaviors(/* ["methodName" [, "methodName"] [, …]] */) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ chaining_applyFromAllTraitsWithoutBehaviors +++"); } | |
var | |
useRoot = this, | |
applyLink, | |
traitSetup = useRoot.getSetup(), | |
traitList = useRoot.valueOf().traitList; | |
terminating_applyFrom(useRoot, traitSetup, traitSetup.chainData.recentCalleeName); | |
applyLink = getApplyLinkFrom_registerEachTrait(useRoot, traitList); | |
return prototypal_applyFromTraitsWithout.apply(applyLink, arguments); | |
} | |
function chaining_applyFromAllTraits() { | |
//try { throw(new Error); } catch (exc) { console.error("+++ chaining_applyFromAllTraits +++"); } | |
var | |
useRoot = this, | |
traitSetup = useRoot.getSetup(), | |
traitList = useRoot.valueOf().traitList; | |
terminating_applyFrom(useRoot, traitSetup, traitSetup.chainData.recentCalleeName); | |
return getApplyLinkFrom_registerEachTrait(useRoot, traitList); | |
} | |
function chaining_applyFrom(/* [<Trait>, "methodName"] | [<Trait> [, <Trait>] [, …]] */) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ chaining_applyFrom +++"); } | |
var | |
invalidChainingMessage, | |
currentCalleeName = "apply", | |
recentCalleeName, | |
chainData, | |
traitSetup, | |
applyLink, | |
useRoot = this, | |
argsList = array_from(arguments); | |
if (isUseRoot(useRoot)) { | |
traitSetup = useRoot.getSetup(); | |
chainData = traitSetup.chainData; | |
recentCalleeName = chainData.recentCalleeName; | |
terminating_applyFrom(useRoot, traitSetup, recentCalleeName); | |
invalidChainingMessage = ["… invalid chaining of '", recentCalleeName, "().", currentCalleeName, "()'"].join(""); | |
if (isValidChaining(recentCalleeName, currentCalleeName)) { | |
if (isApplicableType(argsList[0])) { // - is arguments signature … | |
if (isString(argsList[1])) { // … "apply a single behavior"? | |
if (isValidChaining(recentCalleeName, "applyBehavior")) { | |
applyLink = getApplyLinkFrom_registerSingleBehavior(useRoot, argsList[0], baseValueOf(argsList[1])); | |
} else { | |
throw(new SyntaxError([invalidChainingMessage, " in case of applying just a certain behavior."].join(""))); | |
} | |
} else if (isArgumentsSignature_applyFromEachTrait(argsList)) { | |
if (isValidChaining(recentCalleeName, "applyTraits")) { | |
applyLink = getApplyLinkFrom_registerEachTrait(useRoot, argsList); | |
} else { | |
throw(new SyntaxError([invalidChainingMessage, " in case of applying from one or more traits."].join(""))); | |
} | |
} else { | |
throw(new TypeError("'apply(…)' excepts either, as its 2nd delimiting argument, just a 'String' type or exclusively one or more 'Trait' and 'Function' types.")); | |
} | |
} else { | |
throw(new TypeError("'apply(<Trait|Function>, …)' excepts as its 1st argument explicitly either a 'Trait' or a 'Function' type.")); | |
} | |
} else { | |
throw(new SyntaxError(invalidChainingMessage)); | |
} | |
} else { | |
throw(new ReferenceError("'use(…).apply(…)' only works within a validly chained context, please do not try spoofing the latter.")); | |
} | |
return applyLink; | |
} | |
function prototypal_applyFrom(/* [<Trait>, "methodName"] | [<Trait> [, <Trait>] [, …]] */) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ prototypal_applyFrom +++"); } | |
var | |
valueOfApplyLink, | |
useRoot, | |
applyLink = this; | |
if (isApplyLink_fromTraits(applyLink) || isApplyLink_singleBehavior(applyLink)) { | |
valueOfApplyLink = applyLink.valueOf(); | |
useRoot = valueOfApplyLink.parentLink; | |
applyLink = chaining_applyFrom.apply(useRoot, arguments); | |
} else { | |
throw(new ReferenceError("Please do not spoof the context of 'apply'.")); | |
} | |
// console.log("'without' - traitSetup : ", traitSetup); | |
return applyLink; | |
} | |
function terminating_applyFrom(useRoot, traitSetup, recentCalleeName) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ terminating_applyFrom +++"); } | |
var | |
recentApplyLink, | |
valueOfApplyLink; | |
if ( | |
!!useRoot | |
&& !traitSetup.chainData.isTerminated | |
&& !!(recentApplyLink = useRoot.getChild()) | |
&& !!(valueOfApplyLink = recentApplyLink.valueOf()) | |
) { | |
if ((recentCalleeName == "applyTraits") && isApplyLink_fromTraits(recentApplyLink)) { | |
recordTraitCompositionRule_applyTraits(traitSetup, valueOfApplyLink.traitList); | |
} else if ((recentCalleeName == "applyBehavior") && isApplyLink_singleBehavior(recentApplyLink)) { | |
recordTraitCompositionRule_applyBehavior(traitSetup, valueOfApplyLink.trait, valueOfApplyLink.methodName); | |
} | |
} | |
traitSetup.chainData.recentCalleeName = "apply"; | |
} | |
function ApplyLink_singleBehavior(state) { | |
var | |
link = this; | |
link.valueOf = function () { | |
//return object_assign({}, state); | |
return copyApplyLinkState_singleBehavior(state); | |
}; | |
link.toString = function () { | |
return [ | |
"ApplyLink::singleBehavior :: ", | |
JSON.stringify(state) | |
].join(""); | |
}; | |
return link; | |
} | |
behaviorLinkPrototype.as = prototypal_applyFromTraitAs; // - aliasing a method name that is going to be or already has been overwritten. | |
behaviorLinkPrototype.after = prototypal_applyFromTraitAfter; | |
behaviorLinkPrototype.before = prototypal_applyFromTraitBefore; | |
behaviorLinkPrototype.apply = prototypal_applyFrom; | |
function copyApplyLinkState_singleBehavior(state) { | |
return { | |
trait : state.trait, | |
methodName: state.methodName, | |
parentLink: state.parentLink | |
}; | |
} | |
function createApplyLink_singleBehavior(parentLink, trait, methodName) { | |
var | |
initialState = { // - though 'link' | |
trait : trait, // is redundant | |
methodName: methodName, // here, it stays | |
parentLink: parentLink // that way for | |
}, // a better | |
link = (new ApplyLink_singleBehavior(initialState)); // readability. | |
return link; | |
} | |
function isApplyLink_singleBehavior(type) { | |
var value; | |
return ( | |
(type != null) | |
&& ( | |
(type instanceof ApplyLink_singleBehavior) | |
|| ( | |
isApplicableFunction(type.as) | |
&& isApplicableFunction(type.after) | |
&& isApplicableFunction(type.before) | |
&& isApplicableFunction(type.valueOf) | |
&& (value = type.valueOf()) | |
&& isApplicableType(value.trait) | |
&& isString(value.methodName) | |
&& isUseRoot(value.parentLink) | |
) | |
) | |
); | |
} | |
function ApplyLink_fromTraits(state) { | |
var | |
link = this; | |
link.valueOf = function () { | |
//return object_assign({}, state); | |
return copyApplyLinkState_fromTraits(state); | |
}; | |
link.toString = function () { | |
return [ | |
"ApplyLink::fromTraits :: ", | |
JSON.stringify(state) | |
].join(""); | |
}; | |
return link; | |
} | |
traitsLinkPrototype.without = prototypal_applyFromTraitsWithout; // - except for the excluded behavior, stepwise merge | |
// and apply the behavior of each registered trait. | |
traitsLinkPrototype.apply = prototypal_applyFrom; | |
function copyApplyLinkState_fromTraits(state) { | |
return { | |
traitList : state.traitList, | |
parentLink: state.parentLink | |
}; | |
} | |
function createApplyLink_fromTraits(parentLink, traitList) { | |
var | |
initialState = { // - though 'link' is | |
traitList : traitList, // redundant here, | |
parentLink: parentLink // it stays that way | |
}, // for a better | |
link = (new ApplyLink_fromTraits(initialState)); // readability. | |
return link; | |
} | |
function isApplyLink_fromTraits(type) { | |
var value; | |
return ( | |
(type != null) | |
&& ( | |
(type instanceof ApplyLink_fromTraits) | |
|| ( | |
isApplicableFunction(type.without) | |
&& isApplicableFunction(type.valueOf) | |
&& (value = type.valueOf()) | |
&& isArray(value.traitList) | |
&& isUseRoot(value.parentLink) | |
) | |
) | |
); | |
} | |
function UseRoot(state, traitSetup) { | |
var | |
child = null, | |
link = this; | |
link.getSetup = function () { | |
return traitSetup; | |
}; | |
link.deleteChild = function () { | |
child = null; | |
}; | |
link.putChild = function (applyLink) { | |
child = applyLink; | |
}; | |
link.getChild = function () { | |
return child; | |
}; | |
link.valueOf = function () { | |
return copyUseRootState(state); | |
}; | |
link.toString = function () { | |
return [ | |
"UseRoot :: ", | |
JSON.stringify(state) | |
].join(""); | |
}; | |
link.apply = chaining_applyFrom.bind(link); | |
link.apply.all = chaining_applyFromAllTraits.bind(link); | |
link.apply.all.without = chaining_applyFromAllTraitsWithoutBehaviors.bind(link); | |
return link; | |
} | |
useRootPrototype.after = prototypal_applyFromTraitAfter_viaUseRoot; | |
useRootPrototype.before = prototypal_applyFromTraitBefore_viaUseRoot; | |
function copyUseRootState(state) { | |
return { | |
traitList: array_from(state.traitList) | |
}; | |
} | |
function createUseRoot(traitReferenceList, traitSetup) { | |
//try { throw(new Error); } catch (exc) { console.error("+++ createUseRoot +++"); } | |
var | |
initialState = { // - though 'link' | |
traitList: traitReferenceList // is redundant | |
}, // here, it stays | |
link = (new UseRoot(initialState, traitSetup)); // that way for | |
// a better | |
return link; // readability. | |
} | |
function isUseRoot(type) { | |
var value; | |
return ( | |
(type != null) | |
&& ( | |
(type instanceof UseRoot) | |
|| ( | |
isApplicableFunction(type.apply) | |
&& isApplicableFunction(type.valueOf) | |
&& isApplicableFunction(type.getSetup) | |
&& (value = type.valueOf()) | |
&& isArray(value.traitList) | |
&& (value = type.getSetup()) | |
&& isObjectObject(value) | |
) | |
) | |
); | |
} | |
function handleApplicatorSetup_modifyBefore(methodName, behaviorBefore) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorBefore)) { | |
modifierList.push(createMethodModifier_before(methodName, behaviorBefore)); | |
// console.log("setup :: applicator.before - [methodName, behaviorBefore, modifierList] : ", methodName, behaviorBefore, modifierList); | |
} else { | |
throw(new TypeError("'before(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'before(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyBefore_statefully(methodName, behaviorBefore) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorBefore)) { | |
modifierList.push(createMethodModifier_before_stateful(methodName, behaviorBefore)); | |
// console.log("setup :: applicator.before.stateful - [methodName, behaviorBefore, modifierList] : ", methodName, behaviorBefore, modifierList); | |
} else { | |
throw(new TypeError("'before.stateful(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'before.stateful(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyAfter(methodName, behaviorAfter) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorAfter)) { | |
modifierList.push(createMethodModifier_after(methodName, behaviorAfter)); | |
// console.log("setup :: applicator.after - [methodName, behaviorAfter, modifierList] : ", methodName, behaviorAfter, modifierList); | |
} else { | |
throw(new TypeError("'after(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'after(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyAfter_statefully(methodName, behaviorAfter) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorAfter)) { | |
modifierList.push(createMethodModifier_after_stateful(methodName, behaviorAfter)); | |
// console.log("setup :: applicator.after.stateful - [methodName, behaviorAfter, modifierList] : ", methodName, behaviorAfter, modifierList); | |
} else { | |
throw(new TypeError("'after.stateful(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'after.stateful(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyAfterReturning(methodName, behaviorAfter) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorAfter)) { | |
modifierList.push(createMethodModifier_afterReturning(methodName, behaviorAfter)); | |
// console.log("setup :: applicator.afterReturning - [methodName, behaviorAfter, modifierList] : ", methodName, behaviorAfter, modifierList); | |
} else { | |
throw(new TypeError("'afterReturning(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'afterReturning(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyAfterThrowing(methodName, behaviorAfter) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorAfter)) { | |
modifierList.push(createMethodModifier_afterThrowing(methodName, behaviorAfter)); | |
// console.log("setup :: applicator.afterThrowing - [methodName, behaviorAfter, modifierList] : ", methodName, behaviorAfter, modifierList); | |
} else { | |
throw(new TypeError("'afterThrowing(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'afterThrowing(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyAfterFinally(methodName, behaviorAfter) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorAfter)) { | |
modifierList.push(createMethodModifier_afterFinally(methodName, behaviorAfter)); | |
// console.log("setup :: applicator.afterFinally - [methodName, behaviorAfter, modifierList] : ", methodName, behaviorAfter, modifierList); | |
} else { | |
throw(new TypeError("'afterFinally(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'afterFinally(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_modifyAround(methodName, behaviorAround) { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
modifierList = applicator.modifiers; | |
applicator.canRequire = false; | |
if (isString(methodName)) { | |
if (isApplicableFunction(behaviorAround)) { | |
modifierList.push(createMethodModifier_around(methodName, behaviorAround)); | |
// console.log("setup :: applicator.around - [methodName, behaviorAround, modifierList] : ", methodName, behaviorAround, modifierList); | |
} else { | |
throw(new TypeError("'around(…, <Function>)' excepts as its 2nd argument just a 'Function' type.")); | |
} | |
} else { | |
throw(new TypeError("'around(<String>, …)' excepts as its 1st argument just a 'String' type.")); | |
} | |
return setupRoot; | |
} | |
function handleApplicatorSetup_requires() { | |
var | |
traitSetup = this, | |
applicator = traitSetup.applicator, | |
setupRoot = applicator.root, | |
canRequire = applicator.canRequire, | |
didRequire = applicator.didRequire, | |
methodNameList; | |
if (canRequire) { | |
applicator.canRequire = false; | |
applicator.didRequire = true; | |
methodNameList = getSanitizedMethodNameList(arguments); | |
if (methodNameList.length >= 1) { | |
applicator.requires = methodNameList; | |
} else { | |
throw(new TypeError("Not even a single <String> type was passed to 'requires' as method name that a trait, at its apply time, expects to be present at least.")); | |
} | |
} else if (didRequire) { | |
throw(new SyntaxError("'requires' can be invoked exactly once, right after having executed a trait's 'applicator' method.")); | |
} else { | |
throw(new SyntaxError("'requires' can not bee invoked after a modifier method, but has to be the direct follower of a trait's 'applicator' method.")); | |
} | |
return setupRoot; | |
} | |
// function handleApplicatorSetup_without() { | |
// var | |
// traitSetup = this, | |
// setupRoot = traitSetup.applicator.root; | |
// | |
// // console.log("setup :: applicator.without - arguments : ", arguments); | |
// | |
// return setupRoot; | |
// } | |
// function handleApplicatorSetup_alias() { | |
// var | |
// traitSetup = this, | |
// setupRoot = traitSetup.applicator.root; | |
// | |
// // console.log("setup :: applicator.alias - arguments : ", arguments); | |
// | |
// return setupRoot; | |
// } | |
function terminateTraitSetupChain(traitSetup) { | |
terminating_applyFrom(traitSetup.useTraits.root, traitSetup, traitSetup.chainData.recentCalleeName); | |
traitSetup.chainData.isTerminated = true; | |
} | |
function prepareSetupLanguage_applicator(applicatorBody) { | |
var | |
traitSetup = this; | |
terminateTraitSetupChain(traitSetup); | |
var | |
applicator = traitSetup.applicator, | |
compositionRules = traitSetup.useTraits.rules, | |
isEmptyRuleList = (compositionRules.length <= 0), | |
isValidRuleList = (isEmptyRuleList || isValidTraitCompositionRuleList(compositionRules)); | |
// console.log("+++ prepareSetupLanguage_applicator +++ [isEmptyRuleList, isValidRuleList] : ", isEmptyRuleList, isValidRuleList); | |
if (!isValidRuleList) { | |
throw(new ReferenceError("The trait composition language's rule set does not result in applicable behavior. This happens e.g. if all behavior has been deleted via 'without'.")); | |
} | |
if (applicatorBody != null) { | |
if (isApplicableFunction(applicatorBody = baseValueOf(applicatorBody))) { | |
applicator.body = applicatorBody; | |
applicatorBody.call(applicator.proxy); // setupProxy | |
// console.log("prepareSetupLanguage_applicator - traitSetup : ", traitSetup); | |
} else { | |
throw(new TypeError("The applicator should either stay empty or receive a sole applicable type like a 'Trait' or a 'Function' type.")); | |
} | |
} else if (isEmptyRuleList && (applicator.modifiers.length <= 0)) { | |
console.warn("The trait descriptor till now did neither receive an applicable function via the 'applicator' method nor any composition rule via 'use(…).apply(…)' nor any method modifier."); | |
} | |
return applicator.root; | |
} | |
function prepareSetupLanguage_useTraits() { | |
var | |
useRoot, | |
traitReferenceList = array_flatten(array_from(arguments)).filter(function (trait) { | |
return isApplicableType(trait); | |
}), | |
traitSetup = this; | |
if (traitReferenceList.length >= 1) { | |
// create the 'use' root of a functional micro DSL (Domain Specific Language) - here a specific Trait Composition Language based on method-chaining. | |
useRoot = createUseRoot(traitReferenceList, traitSetup); | |
} else { | |
throw(new TypeError("Not even a single valid 'Trait' or 'Class' or 'Function' type has been provided to 'use(<Trait|Function>[, …])'.")); | |
} | |
// console.log("prepareSetupLanguage_useTraits - traitSetup : ", traitSetup); | |
// console.log("prepareSetupLanguage_useTraits - useRoot : ", useRoot); | |
return (traitSetup.useTraits.root = useRoot); | |
} | |
function findIndexOfTraitProxyLink(proxyLinkList, trait) { | |
return proxyLinkList.findIndex(function (link) { | |
return (link.trait === trait); | |
}); | |
} | |
function applyTraitCompositionRule_beforeWrap(record, target, proxyLinkList) { | |
var | |
indexOfProceedLink = findIndexOfTraitProxyLink(proxyLinkList, record.trait), | |
proceedLink = proxyLinkList[indexOfProceedLink], | |
proceedProxy = (proceedLink && proceedLink.proxy) || {}, | |
methodName = record.methodName; | |
target[methodName] = composeHandler_before(proceedProxy[methodName], target[methodName], target); | |
record/* = target*/ = proxyLinkList = indexOfProceedLink = proceedLink = proceedProxy = methodName = null; | |
} | |
function applyTraitCompositionRule_afterWrap(record, target, proxyLinkList) { | |
var | |
indexOfProceedLink = findIndexOfTraitProxyLink(proxyLinkList, record.trait), | |
proceedLink = proxyLinkList[indexOfProceedLink], | |
proceedProxy = (proceedLink && proceedLink.proxy) || {}, | |
methodName = record.methodName; | |
target[methodName] = composeHandler_after(proceedProxy[methodName], target[methodName], target); | |
record/* = target*/ = proxyLinkList = indexOfProceedLink = proceedLink = proceedProxy = methodName = null; | |
} | |
function applyTraitCompositionRule_beforeApply(record, target, proxyLinkList) { | |
var | |
indexOfProceedLink = findIndexOfTraitProxyLink(proxyLinkList, record.trait), | |
indexOfBeforeLink = findIndexOfTraitProxyLink(proxyLinkList, record.fromTrait), | |
proceedLink = proxyLinkList[indexOfProceedLink], | |
beforeLink = proxyLinkList[indexOfBeforeLink], | |
proceedProxy = (proceedLink && proceedLink.proxy) || {}, | |
beforeProxy = (beforeLink && beforeLink.proxy) || {}, | |
methodName = record.methodName; | |
if (methodName in target) { // free closure occupied space explicitly. | |
delete target.methodName; | |
} | |
target[methodName] = composeHandler_before(proceedProxy[methodName], beforeProxy[methodName], target); | |
record/* = target*/ = proxyLinkList = indexOfProceedLink = indexOfBeforeLink = proceedLink = beforeLink = proceedProxy = beforeProxy = methodName = null; | |
} | |
function applyTraitCompositionRule_afterApply(record, target, proxyLinkList) { | |
var | |
indexOfProceedLink = findIndexOfTraitProxyLink(proxyLinkList, record.trait), | |
indexOfAfterLink = findIndexOfTraitProxyLink(proxyLinkList, record.fromTrait), | |
proceedLink = proxyLinkList[indexOfProceedLink], | |
afterLink = proxyLinkList[indexOfAfterLink], | |
proceedProxy = (proceedLink && proceedLink.proxy) || {}, | |
afterProxy = (afterLink && afterLink.proxy) || {}, | |
methodName = record.methodName; | |
if (methodName in target) { // free closure occupied space explicitly. | |
delete target.methodName; | |
} | |
target[methodName] = composeHandler_after(proceedProxy[methodName], afterProxy[methodName], target); | |
record/* = target*/ = proxyLinkList = indexOfProceedLink = indexOfAfterLink = proceedLink = afterLink = proceedProxy = afterProxy = methodName = null; | |
} | |
function applyTraitCompositionRule_without(record, target, proxyLinkList) { | |
var | |
traitList = record.traitList, | |
withoutMap = record.methodNameList.reduce(function (map, methodName) { | |
map[methodName] = null; | |
return map; | |
}, {}); | |
traitList.forEach(function (trait) { | |
var | |
indexOfLink = findIndexOfTraitProxyLink(proxyLinkList, trait), | |
link = proxyLinkList[indexOfLink], | |
proxy = (link && link.proxy) || {}; | |
object_keys(proxy).forEach(function (methodName) { | |
if (!(methodName in withoutMap)) { | |
if (methodName in target) { // free closure occupied space explicitly. | |
delete target.methodName; | |
} | |
target[methodName] = (function (proceed, target) { | |
return function () { | |
return proceed.apply(target, arguments); | |
}; | |
}(proxy[methodName], target)); | |
} | |
}); | |
}); | |
record/* = target*/ = proxyLinkList = traitList = withoutMap = null; | |
} | |
function applyTraitCompositionRule_as(record, target, proxyLinkList) { | |
var | |
indexOfLink = findIndexOfTraitProxyLink(proxyLinkList, record.trait), | |
link = proxyLinkList[indexOfLink], | |
proxy = (link && link.proxy) || {}, | |
methodAlias = record.methodAlias, | |
methodName = record.methodName; | |
if (methodAlias in target) { // free closure occupied space explicitly. | |
delete target.methodAlias; | |
} | |
target[methodAlias] = (function (proceed, target) { | |
return function () { | |
return proceed.apply(target, arguments); | |
}; | |
}(proxy[methodName], target)); | |
record/* = target*/ = proxyLinkList = indexOfLink = link = proxy = methodAlias = methodName = null; | |
} | |
function copyTraitCompositionRule_beforeAfterWrap(record) { | |
return { | |
type : record.type, | |
trait : record.trait, | |
methodName : record.methodName | |
}; | |
} | |
function copyTraitCompositionRule_beforeAfterApply(record) { | |
return { | |
type : record.type, | |
trait : record.trait, | |
fromTrait : record.fromTrait, | |
methodName : record.methodName | |
}; | |
} | |
function copyTraitCompositionRule_without(record) { | |
return { | |
type : record.type, | |
traitList : array_from(record.traitList), | |
methodNameList : array_from(record.methodNameList) | |
}; | |
} | |
function copyTraitCompositionRule_as(record) { | |
return { | |
type : record.type, | |
trait : record.trait, | |
methodName : record.methodName, | |
methodAlias : record.methodAlias | |
}; | |
} | |
function copyTraitCompositionRule(record) { | |
return (RULE_TYPE_COPY_TABLE[record.type](record)); | |
} | |
function TraitCompositionRule(record) { | |
this.valueOf = function () { | |
return copyTraitCompositionRule(record) | |
}; | |
} | |
TraitCompositionRule.prototype.execute = function (target, proxyLinkList) { | |
var | |
record = this.valueOf(); | |
(RULE_TYPE_EXECUTE_TABLE[record.type](record, target, proxyLinkList)); | |
//return (RULE_TYPE_EXECUTE_TABLE[record.type](record, target, proxyLinkList)); | |
}; | |
function isValidTraitCompositionRuleList(traitCompositionRuleList) { | |
var | |
isValidList = true; // empty lists are valid. | |
if (traitCompositionRuleList.length >= 1) { | |
var | |
proxy = {}, | |
traitList = fetchTraitListFromCompositionRules(traitCompositionRuleList), | |
proxyLinkList = mapProxyLinkListFromTraitList(traitList); | |
proxyLinkList.forEach(function (link) { | |
var | |
trait = link.trait, | |
proxy = link.proxy; | |
//console.log('getBestGuessForFunctionType(' + trait + ') : ', getBestGuessForFunctionType(trait)); | |
//if (isClassConstructor(trait)) { | |
// applyClassChainDelegatedBehavior(trait, proxy); | |
//} else { | |
trait.call(proxy); | |
// } | |
//deleteEveryNonApplicableSlot(proxy); | |
}); | |
traitCompositionRuleList.forEach(function (traitCompositionRule) { | |
traitCompositionRule.execute(proxy, proxyLinkList); | |
}); | |
isValidList = (object_keys(proxy).length >= 1); | |
} | |
return isValidList; | |
} | |
function deleteEveryNonApplicableSlot(type) { | |
object_keys(type).forEach(function (key) { | |
if (!isApplicableFunction(type[key])) { | |
delete type[key]; | |
} | |
}); | |
} | |
function createTypeFromNoArgument(classConstructor) { | |
return (new classConstructor); | |
} | |
function createTypeFromSingleArgument(classConstructor, args) { | |
return (new classConstructor(args[0])); | |
} | |
function createTypeFromTwoArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1])); | |
} | |
function createTypeFromThreeArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2])); | |
} | |
function createTypeFromFourArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3])); | |
} | |
function createTypeFromFiveArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3], args[4])); | |
} | |
function createTypeFromSixArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3], args[4], args[5])); | |
} | |
function createTypeFromSevenArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6])); | |
} | |
function createTypeFromEightArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])); | |
} | |
function createTypeFromNineArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])); | |
} | |
function createTypeFromTenArguments(classConstructor, args) { | |
return (new classConstructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9])); | |
} | |
function raiseTooManyArgumentsWarning(classConstructor, args) { | |
console.warn("Injecting more than 10 arguments into an applicable class-constructor type is not supported ... ", classConstructor, args); | |
return createTypeFromTenArguments(classConstructor, args); | |
} | |
function createTypeFromClassAndArguments(classConstructor, args) { | |
return (({ | |
0 : createTypeFromNoArgument, | |
1 : createTypeFromSingleArgument, | |
2 : createTypeFromTwoArguments, | |
3 : createTypeFromThreeArguments, | |
4 : createTypeFromFourArguments, | |
5 : createTypeFromFiveArguments, | |
6 : createTypeFromSixArguments, | |
7 : createTypeFromSevenArguments, | |
8 : createTypeFromEightArguments, | |
9 : createTypeFromNineArguments, | |
10: createTypeFromTenArguments, | |
11: raiseTooManyArgumentsWarning | |
}[math_min(args.length, 11)])(classConstructor, args)); | |
} | |
function applyClassChainDelegatedBehavior(classConstructor, type, payloadList) { | |
var | |
//getOwnSymbols = Object.getOwnPropertySymbols, | |
getOwnNames = Object.getOwnPropertyNames, | |
args = payloadList || [], | |
customType = createTypeFromClassAndArguments(classConstructor, args), | |
//protoType, | |
basePrototype = getPrototypeOf({}), | |
__proto__ = getPrototypeOf(customType); | |
function isBoundBehavior(key) { | |
return ((key !== "constructor") && isApplicableFunction(this[key])); | |
} | |
function assignBoundSlot(key) { | |
this.target[key] = this.source[key]; | |
} | |
while (customType && __proto__ && (__proto__ !== basePrototype)) { | |
//classConstructor.call(type); // function based mixin patterns do not work for class constructors | |
// since they always have to be invoked via the `new` operator. | |
deleteEveryNonApplicableSlot(customType); | |
// assigning prototypal behavior directly as a `types` own behavior, ... | |
// ... thus flattening the delegation pattern (bypassing prototypal/implicit delegation via direct/explicit proxy delegation). | |
getOwnNames(__proto__).filter(isBoundBehavior, __proto__).forEach(assignBoundSlot, { source: __proto__, target: type }); | |
// assigning own custom behavior (does overwrite equally named slots that were derived/obtained from `__proto__`). | |
object_assign(type, customType); | |
classConstructor = __proto__.constructor; | |
customType = (isFunctionType(classConstructor) && createTypeFromClassAndArguments(classConstructor, args)); | |
__proto__ = getPrototypeOf(__proto__); | |
} | |
} | |
function checkForRequiredBehavior(type, requiredMethodNameList, payloadList) { | |
var | |
missingMethodNameList; | |
if (payloadList[0] !== TEST_CALL_REFERENCE) { | |
missingMethodNameList = requiredMethodNameList.reduce(function (list, behaviorName) { | |
if (!isApplicableFunction(type[behaviorName])) { | |
list.push(behaviorName); | |
} | |
return list | |
}, []); | |
if (missingMethodNameList.length >= 1) { | |
throw(new TypeError("The type misses following required method(s) … '" + missingMethodNameList.join("', '") + "'.")); | |
} | |
} | |
return missingMethodNameList; | |
} | |
function applyAllMethodModifiers(modifierList, type, payloadList) { | |
modifierList.forEach(function (modifier) { | |
modifier.call(type, payloadList); | |
}) | |
} | |
function withApplicator(applicator) { // - "callable object" features provided | |
var // via function based "applicable" mixin. | |
callableObject = this; | |
callableObject.call = function () { | |
var | |
args = array_from(arguments), | |
target = getSanitizedTarget(args.shift()); | |
applicator.apply(target, args); | |
return target; | |
}; | |
callableObject.apply = function (target, args) { | |
// if (args == null) { // // - sanitize | |
// args = []; // // 'args' in | |
// } else if (!isArguments(args) && !isArray[args]) { // - too forgiving. // order to | |
// args = [args]; // // make it | |
// } // // properly | |
// args = array_from((!!args && args) || []); // - not feasible enough. // applicable. | |
if (args == null) { // - further error handling handling | |
args = []; // is covered by the language core. | |
} | |
target = getSanitizedTarget(target); | |
applicator.apply(target, args); | |
return target; | |
}; | |
return callableObject; | |
} | |
function isWithApplicator(type) { // [isWithApplicator] feature test. | |
return ( | |
(typeof type == "object") | |
&& isApplicableFunction(type.call) | |
&& isApplicableFunction(type.apply) | |
&& isApplicableFunction(type.valueOf) | |
&& isApplicableFunction(type.valueOf()) | |
); | |
} | |
function withApplicatorRequires(requires) { // - mixin for trait type specific `requires` method. | |
var // - if called this method does list all method names | |
callableObject = this; // of behavior an applicator does expect to be accessible | |
// at a trait's apply time. | |
callableObject.requires = function () { | |
return array_from(requires); | |
}; | |
return callableObject; | |
} | |
function withTraitEnumerability(applicator) { // mixin for trait type specific enumerable methods. | |
var | |
trait = this, | |
keys = [], | |
//values = [], // - wanting to know something about a trait's specific behavior is of no use since | |
//entries = [], // all of a traits behavior does 'materialize' at apply time. Thus, especially for | |
// method modifying traits, the final outcome highly depends on the type (the very | |
proxy = {}; // context a trait does 'materialize' upon) a trait gets applied to. | |
applicator.call(proxy, TEST_CALL_REFERENCE); | |
keys = object_keys(proxy).sort(function (a, b) { | |
return (((a < b) && -1) || ((a > b) && 1) || 0); | |
}); | |
// values = keys.map(function (key) { | |
// return proxy[key]; | |
// }); | |
// entries = keys.map(function (key) { | |
// return { | |
// key : key, | |
// value : proxy[key] | |
// }; | |
// }); | |
proxy = null; | |
trait.keys = function () { | |
return array_from(keys); | |
}; | |
// trait.values = function () { | |
// return array_from(values); | |
// }; | |
// trait.entries = function () { | |
// return array_from(entries); | |
// }; | |
return trait; | |
} | |
function Trait(applicator, requires) { // constructor. | |
var // | |
trait = this; // - just for being able falling back | |
// to a more easy to accomplish | |
trait.toString = function () { // [isTraitType] test. | |
return "[object Trait]"; | |
}; | |
trait.valueOf = function () { | |
return applicator; | |
}; | |
// mixing in "applicable" behavior. | |
withApplicator.call(trait, applicator); | |
// mixing in "applicable" behavior. | |
withApplicatorRequires.call(trait, requires); | |
// mixing in in trait type specific enumerable methods. | |
withTraitEnumerability.call(trait, applicator); | |
return trait; | |
} | |
function isTraitType(type) { // [isTraitType] test. | |
return ( | |
!!type | |
&& ( | |
(type instanceof Trait) | |
|| isWithApplicator(type) | |
) | |
); | |
} | |
function isApplicableType(type) { // [isApplicableType] test. | |
return ( | |
isTraitType(type) | |
//|| isClassConstructor(type) // @TODO ... get rid of `isClassConstructor` and check usage of `isApplicableType` ... maybe introduce something like `isTraitTypeSource` | |
|| isApplicableFunction(type) | |
); | |
} | |
function fetchTraitListFromCompositionRules(compositionRules) { | |
return compositionRules.reduce(function (traitList, traitCompositionRule) { | |
var | |
record = traitCompositionRule.valueOf(), | |
trait = record.trait, | |
fromTrait = record.fromTrait; | |
if (trait && (traitList.indexOf(trait) < 0)) { | |
traitList.push(trait); | |
} | |
if (fromTrait && (traitList.indexOf(fromTrait) < 0)) { | |
traitList.push(fromTrait); | |
} | |
(record.traitList || []).forEach(function (trait) { | |
if (traitList.indexOf(trait) < 0) { | |
traitList.push(trait) | |
} | |
}); | |
return traitList; | |
}, []); | |
} | |
function mapProxyLinkListFromTraitList(traitList) { | |
return traitList.map(function (trait) { | |
return { | |
trait: trait, | |
proxy: {} | |
}; | |
}); | |
} | |
function canCreateTrait(traitList, traitCompositionRuleList, applicatorBody, modifierList) { | |
var | |
proxyKeyList = [], | |
proxy = {}, | |
isEmptyRuleList = (traitCompositionRuleList.length <= 0), | |
isValidRuleList = (isEmptyRuleList || isValidTraitCompositionRuleList(traitCompositionRuleList)); | |
// console.log("+++ canCreateTrait +++ [isEmptyRuleList, isValidRuleList] : ", isEmptyRuleList, isValidRuleList); | |
if (!isValidRuleList) { | |
throw(new ReferenceError("The trait composition language's rule set does not result in applicable behavior. This happens e.g. if all behavior has been deleted via 'without'.")); | |
} | |
if (isApplicableFunction(applicatorBody)) { | |
applicatorBody.call(proxy); | |
proxyKeyList = object_keys(proxy); | |
} | |
return [traitList, traitCompositionRuleList, proxyKeyList, modifierList].some(function (list) { return list.length >= 1}); | |
} | |
function createTrait(traitSetup) { // trait factory. | |
var | |
trait, | |
compositionRules = traitSetup.useTraits.rules, | |
applicator = traitSetup.applicator, | |
applicatorBody = applicator.body, | |
requires = applicator.requires, | |
modifiers = applicator.modifiers, | |
traitList = fetchTraitListFromCompositionRules(compositionRules); | |
if (canCreateTrait(traitList, compositionRules, applicatorBody, modifiers)) { | |
applicator = (function (traitList, traitCompositionRuleList, requiredMethodNameList, applicatorBody, modifierList) { | |
return function TraitApplicator () { | |
var // - stateful traits not only might carry state that is generated | |
compositeType = this, // by the applicators code within the closure which gets created | |
payloadList = array_from(arguments), // anyhow at an states apply time, but stateful traits might also | |
// become hosts of state that gets injected into such a closure. | |
proxyLinkList = mapProxyLinkListFromTraitList(traitList); // - ??? | |
// | |
proxyLinkList.forEach(function (link) { // - ??? | |
var // | |
trait = link.trait, // | |
proxy = link.proxy; // | |
// | |
if (isClassConstructor(trait)) { // | |
applyClassChainDelegatedBehavior(trait, proxy, payloadList); // | |
} else { // | |
trait.apply(proxy, payloadList); // | |
} // | |
}); // | |
traitCompositionRuleList.forEach(function (traitCompositionRule) { // - compose at execution time a complex behavioral | |
traitCompositionRule.execute(compositeType, proxyLinkList); // set as result from every provided composition | |
}); // rule, with each created via the composing DSL. | |
checkForRequiredBehavior(compositeType, requiredMethodNameList, payloadList); // - ??? | |
if (isApplicableFunction(applicatorBody)) { // - apply the trait or function object that has been | |
applicatorBody.apply(compositeType, payloadList); // passed to "applicator" from within 'Trait.create'. | |
} | |
applyAllMethodModifiers(modifierList, compositeType, payloadList); // - finally apply all registered method modifications. | |
return compositeType; | |
}; | |
}(traitList, compositionRules, requires, applicatorBody, modifiers)); | |
trait = (new Trait(applicator, requires)); // - trait reference. | |
} | |
return trait; | |
} | |
function triggerCreateTrait(descriptorTemplate) { // factory setup. | |
var | |
requireAndComposeExternalTraitReferences, | |
requireApplicatorAndCreateMethodModifiers, | |
applicatorRoot, | |
traitSetup, | |
trait; | |
if (isApplicableFunction(descriptorTemplate = baseValueOf(descriptorTemplate))) { | |
traitSetup = { // - whilst processing 'descriptorTemplate', | |
chainData : { // sub routines do "write" all necessary | |
// trait configuration data into the | |
isTerminated : false, // corresponding 'traitSetup' slots. | |
recentCalleeName: "use" // | |
}, // - 'createTrait' then, working upon this | |
useTraits : { // data, does assemble a callable object | |
// and wraps it into a <Trait> type. | |
root : null, | |
rules : [] | |
}, | |
applicator: { | |
body : null, | |
proxy : {}, | |
root : {}, | |
modifiers : [], | |
requires : [], | |
canRequire: true, | |
didRequire: false | |
} | |
}; | |
applicatorRoot = traitSetup.applicator.root; | |
//applicatorRoot.without = handleApplicatorSetup_without.bind(traitSetup); | |
//applicatorRoot.alias = handleApplicatorSetup_alias.bind(traitSetup); | |
applicatorRoot.requires = handleApplicatorSetup_requires.bind(traitSetup); | |
applicatorRoot.before = handleApplicatorSetup_modifyBefore.bind(traitSetup); // - basic wrapping, not touching a callback's arguments signature. | |
applicatorRoot.after = handleApplicatorSetup_modifyAfter.bind(traitSetup); // - basic wrapping, not touching a callback's arguments signature. | |
applicatorRoot.before.stateful = handleApplicatorSetup_modifyBefore_statefully.bind(traitSetup); // - modifier already does touch a callback's arguments signature by giving access to an `applicator`'s `payloadList`. | |
applicatorRoot.after.stateful = handleApplicatorSetup_modifyAfter_statefully.bind(traitSetup); // - modifier already does touch a callback's arguments signature by giving access to an `applicator`'s `payloadList`. | |
applicatorRoot.afterReturning = handleApplicatorSetup_modifyAfterReturning.bind(traitSetup); // - all other modifiers are intercepting methods that always do | |
applicatorRoot.afterThrowing = handleApplicatorSetup_modifyAfterThrowing.bind(traitSetup); // change a callback's arguments signature anyhow ... and thus | |
applicatorRoot.afterFinally = handleApplicatorSetup_modifyAfterFinally.bind(traitSetup); // also do provide access to an `applicator`'s `payloadList` | |
applicatorRoot.around = handleApplicatorSetup_modifyAround.bind(traitSetup); // as last argument of such a modifier method/function. | |
requireAndComposeExternalTraitReferences = prepareSetupLanguage_useTraits.bind(traitSetup); | |
requireApplicatorAndCreateMethodModifiers = prepareSetupLanguage_applicator.bind(traitSetup); | |
descriptorTemplate( | |
requireAndComposeExternalTraitReferences, | |
requireApplicatorAndCreateMethodModifiers | |
); | |
trait = createTrait(traitSetup); // trait factory forward. | |
} | |
// console.log("triggerCreateTrait - traitSetup : ", traitSetup); | |
return trait; | |
} | |
// object_assign(Function, { | |
// | |
// isFunctionType : isFunctionType, | |
// isFunction : isFunction, | |
// isFunctionObject : isFunctionObject, | |
// isApplicable : isApplicableType, | |
// //isApplicableType : isApplicableType, | |
// //isApplicableFunction : isApplicableFunction, | |
// isClass : isClassConstructor, | |
// isTrait : isTraitType | |
// }); | |
return (global.Trait = { // create(, globally assign) and return module. | |
create : triggerCreateTrait, | |
// isTrait : isTraitType, | |
// isApplicable: isApplicableType | |
isFunctionType : isFunctionType, | |
isFunction : isFunction, | |
isFunctionObject : isFunctionObject, | |
isApplicable : isApplicableType, | |
//isApplicableType : isApplicableType, | |
//isApplicableFunction : isApplicableFunction, | |
isClass : isClassConstructor, | |
isTrait : isTraitType | |
}); | |
}(Function("return this")())); // inject 'global' object. | |
/* | |
[http://closure-compiler.appspot.com/home] | |
- Simple - 24794 byte | |
(function(m){function B(a){return["^\\[object\\s+",a,"\\]$"].join("")}function M(a){return(a=r(Aa).exec(N.call(a)))&&a[1]}function F(a){return null==a?a:Ba.call(a).valueOf()}function O(a){return typeof a==P}function u(a){return O(a)&&typeof a.call==P&&typeof a.apply==P}function aa(a){return r(Ca).test(C.call(a))}function ba(a){return r(Da).test(C.call(a))}function Q(a){return r(Ea).test(C.call(a))}function p(a){return r(Fa).test(C.call(a))}function R(a,b){var c=r(b);return c.test(M(a))||c.test(M(I(a)))}function ca(a){return r("^class\\s+").test(a)}function h(a){var b,c;if(c=u(a))c=!r(Ga).test(C.call(a));if(c=c&&(b=N.call(a)))c=b,c=!r(Ha).test(c);if(b=c&&!ca(b))b=!r(Ia).test(M(a));b&&(b=!(R(a,Ja)||R(a,Ka)||R(a,La)));return b}function da(a){return u(a)&&ca(N.call(a))}function v(a,b){var c=Ma[b];return!!c&&0<=c.indexOf(a)}function S(a,b,c){return function(){var d=arguments;b.apply(c,d);return a.apply(c,d)}}function T(a,b,c){return function(){var d=arguments,e=a.apply(c,d);b.apply(c,d);return e}}function Na(a,b,c,d){return function(){var e=arguments;b.call(c,e,d);return a.apply(c,e)}}function Oa(a,b,c,d){return function(){var e=arguments,g=a.apply(c,e);b.call(c,e,d);return g}}function Pa(a,b,c,d){return function(){var e=arguments,g=a.apply(c,e);b.call(c,g,e,d);return g}}function Qa(a,b,c,d){return function(){var e=arguments;try{var g=a.apply(c,e)}catch(k){b.call(c,k,e,d)}return g}}function Ra(a,b,c,d){return function(){var e=arguments;try{var g=a.apply(c,e)}catch(ea){var k=ea}b.call(c,k||g,e,d);return g}}function Sa(a,b,c,d){return function(){return b.call(c,a,b,arguments,d)}}function Ta(a,b){return function(){var c=this[a];h(c)||(c=t);this[a]=S(c,b,this)}}function Ua(a,b){return function(){var c=this[a];h(c)||(c=t);this[a]=T(c,b,this)}}function Va(a,b){return function(c){var d=this[a];h(d)||(d=t);this[a]=Na(d,b,this,c)}}function Wa(a,b){return function(c){var d=this[a];h(d)||(d=t);this[a]=Oa(d,b,this,c)}}function Xa(a,b){return function(c){var d=this[a];h(d)||(d=t);this[a]=Pa(d,b,this,c)}}function Ya(a,b){return function(c){var d=this[a];h(d)||(d=t);this[a]=Qa(d,b,this,c)}}function Za(a,b){return function(c){var d=this[a];h(d)||(d=t);this[a]=Ra(d,b,this,c)}}function $a(a,b){return function(c){var d=this[a];h(d)||(d=t);this[a]=Sa(d,b,this,c)}}function fa(a,b,c){a.useTraits.rules.push(new A({type:"without",traitList:b,methodNameList:c}))}function ha(a,b,c,d){a.useTraits.rules.push(new A({type:"as",trait:b,methodName:c,methodAlias:d}))}function ia(a){return ja(q(a)).reduce(function(a,c){p(c)&&a.push(F(c));return a},[])}function ka(){if(U(this)){var a=this.valueOf();var b=a.parentLink;if(w(b)){var c=b.getSetup();var d=c.chainData;var e=d.recentCalleeName;if(v(e,"without"))if(e=ia(arguments),1<=e.length)d.recentCalleeName="without",fa(c,a.traitList,e);else throw new f("Not even a single <String> type was passed to 'without' as to be excluded method name.");else{d=["\u2026 invalid chaining of '",e,"().without()'"].join("");if("applyBehavior"==e)throw new n([d," in case of excluding one or more certain behaviors."].join(""));throw new n(d);}}else throw new l("Please do not spoof the context of 'use'.");}else throw new l("Please do not spoof the context of 'apply'.");return b}function V(a,b){var c=a.getSetup();if(ab(b,a.valueOf().traitList))c.chainData.recentCalleeName="applyTraits",c=new W({traitList:b,parentLink:a}),a.putChild(c);else throw new f("Any trait that got passed to 'apply' needs to be registered before via 'use'.");return c}function ab(a,b){return a.every(function(a){return 0<=b.indexOf(a)})}function bb(){var a=this.getSetup();var b=this.valueOf().traitList;J(this,a,a.chainData.recentCalleeName);a=V(this,b);return ka.apply(a,arguments)}function cb(){var a=this.getSetup(),b=this.valueOf().traitList;J(this,a,a.chainData.recentCalleeName);return V(this,b)}function la(){var a=q(arguments);if(w(this)){var b=this.getSetup();var c=b.chainData;c=c.recentCalleeName;J(this,b,c);b=["\u2026 invalid chaining of '",c,"().apply()'"].join("");if(v(c,"apply"))if(x(a[0]))if(p(a[1]))if(v(c,"applyBehavior"))if(c=a[0],a=F(a[1]),b=this.getSetup(),0<=this.valueOf().traitList.indexOf(c)){var d={};c.call(d);if(h(d[a]))b.chainData.recentCalleeName="applyBehavior",a=new X({trait:c,methodName:a,parentLink:this}),this.putChild(a);else throw new l(["The requested '",a,"' method has not been implemented by the trait that got passed to 'apply'."].join(""));}else throw new f("Any trait that got passed to 'apply' needs to be registered before via 'use'.");else throw new n([b," in case of applying just a certain behavior."].join(""));else if(q(a).every(x))if(v(c,"applyTraits"))a=V(this,a);else throw new n([b," in case of applying from one or more traits."].join(""));else throw new f("'apply(\u2026)' excepts either, as its 2nd delimiting argument, just a 'String' type or exclusively one or more 'Trait' and 'Function' types.");else throw new f("'apply(<Trait|Function>, \u2026)' excepts as its 1st argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(b);}else throw new l("'use(\u2026).apply(\u2026)' only works within a validly chained context, please do not try spoofing the latter.");return a}function ma(){var a=this;if(U(a)||G(a))a=a.valueOf(),a=a.parentLink,a=la.apply(a,arguments);else throw new l("Please do not spoof the context of 'apply'.");return a}function J(a,b,c){var d,e;a&&!b.chainData.isTerminated&&(d=a.getChild())&&(e=d.valueOf())&&("applyTraits"==c&&U(d)?fa(b,e.traitList,[]):"applyBehavior"==c&&G(d)&&(a=e.methodName,ha(b,e.trait,a,a)));b.chainData.recentCalleeName="apply"}function X(a){this.valueOf=function(){return{trait:a.trait,methodName:a.methodName,parentLink:a.parentLink}};this.toString=function(){return["ApplyLink::singleBehavior :: ",Y.stringify(a)].join("")};return this}function G(a){var b;return null!=a&&(a instanceof X||h(a.as)&&h(a.after)&&h(a.before)&&h(a.valueOf)&&(b=a.valueOf())&&x(b.trait)&&p(b.methodName)&&w(b.parentLink))}function W(a){this.valueOf=function(){return{traitList:a.traitList,parentLink:a.parentLink}};this.toString=function(){return["ApplyLink::fromTraits :: ",Y.stringify(a)].join("")};return this}function U(a){var b;return null!=a&&(a instanceof W||h(a.without)&&h(a.valueOf)&&(b=a.valueOf())&&Q(b.traitList)&&w(b.parentLink))}function Z(a,b){var c=null;this.getSetup=function(){return b};this.deleteChild=function(){c=null};this.putChild=function(a){c=a};this.getChild=function(){return c};this.valueOf=function(){return{traitList:q(a.traitList)}};this.toString=function(){return["UseRoot :: ",Y.stringify(a)].join("")};this.apply=la.bind(this);this.apply.all=cb.bind(this);this.apply.all.without=bb.bind(this);return this}function w(a){var b;return null!=a&&(a instanceof Z||h(a.apply)&&h(a.valueOf)&&h(a.getSetup)&&(b=a.valueOf())&&Q(b.traitList)&&(b=a.getSetup())&&ba(b))}function db(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Ta(a,b));else throw new f("'before(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'before(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function eb(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Va(a,b));else throw new f("'before.stateful(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'before.stateful(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function fb(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Ua(a,b));else throw new f("'after(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'after(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function gb(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Wa(a,b));else throw new f("'after.stateful(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'after.stateful(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function hb(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Xa(a,b));else throw new f("'afterReturning(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'afterReturning(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function ib(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Ya(a,b));else throw new f("'afterThrowing(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'afterThrowing(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function jb(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push(Za(a,b));else throw new f("'afterFinally(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'afterFinally(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function kb(a,b){var c=this.applicator,d=c.root,e=c.modifiers;c.canRequire=!1;if(p(a))if(h(b))e.push($a(a,b));else throw new f("'around(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new f("'around(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function lb(){var a=this.applicator,b=a.root,c=a.didRequire;if(a.canRequire)if(a.canRequire=!1,a.didRequire=!0,c=ia(arguments),1<=c.length)a.requires=c;else throw new f("Not even a single <String> type was passed to 'requires' as method name that a trait, at its apply time, expects to be present at least.");else{if(c)throw new n("'requires' can be invoked exactly once, right after having executed a trait's 'applicator' method.");throw new n("'requires' can not bee invoked after a modifier method, but has to be the direct follower of a trait's 'applicator' method.");}return b}function mb(a){J(this.useTraits.root,this,this.chainData.recentCalleeName);this.chainData.isTerminated=!0;var b=this.applicator,c=this.useTraits.rules,d=0>=c.length;if(!d&&!na(c))throw new l("The trait composition language's rule set does not result in applicable behavior. This happens e.g. if all behavior has been deleted via 'without'.");if(null!=a)if(h(a=F(a)))b.body=a,a.call(b.proxy);else throw new f("The applicator should either stay empty or receive a sole applicable type like a 'Trait' or a 'Function' type.");else d&&0>=b.modifiers.length&&D.warn("The trait descriptor till now did neither receive an applicable function via the 'applicator' method nor any composition rule via 'use(\u2026).apply(\u2026)' nor any method modifier.");return b.root}function nb(){var a=ja(q(arguments)).filter(function(a){return x(a)});if(1<=a.length)a=new Z({traitList:a},this);else throw new f("Not even a single valid 'Trait' or 'Class' or 'Function' type has been provided to 'use(<Trait|Function>[, \u2026])'.");return this.useTraits.root=a}function y(a,b){return a.findIndex(function(a){return a.trait===b})}function oa(a){return{type:a.type,trait:a.trait,methodName:a.methodName}}function pa(a){return{type:a.type,trait:a.trait,fromTrait:a.fromTrait,methodName:a.methodName}}function A(a){this.valueOf=function(){return ob[a.type](a)}}function na(a){var b=!0;if(1<=a.length){var c={};b=qa(a);var d=ra(b);d.forEach(function(a){a.trait.call(a.proxy)});a.forEach(function(a){a.execute(c,d)});b=1<=E(c).length}return b}function pb(a){E(a).forEach(function(b){h(a[b])||delete a[b]})}function qb(a){return new a}function rb(a,b){return new a(b[0])}function sb(a,b){return new a(b[0],b[1])}function tb(a,b){return new a(b[0],b[1],b[2])}function ub(a,b){return new a(b[0],b[1],b[2],b[3])}function vb(a,b){return new a(b[0],b[1],b[2],b[3],b[4])}function wb(a,b){return new a(b[0],b[1],b[2],b[3],b[4],b[5])}function xb(a,b){return new a(b[0],b[1],b[2],b[3],b[4],b[5],b[6])}function yb(a,b){return new a(b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7])}function zb(a,b){return new a(b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8])}function sa(a,b){return new a(b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],b[8],b[9])}function Ab(a,b){D.warn("Injecting more than 10 arguments into an applicable class-constructor type is not supported ... ",a,b);return sa(a,b)}function ta(a,b){return{0:qb,1:rb,2:sb,3:tb,4:ub,5:vb,6:wb,7:xb,8:yb,9:zb,10:sa,11:Ab}[Bb(b.length,11)](a,b)}function Cb(a,b,c){function d(a){return"constructor"!==a&&h(this[a])}function e(a){this.target[a]=this.source[a]}var g=z.getOwnPropertyNames;c=c||[];a=ta(a,c);for(var k=I({}),f=I(a);a&&f&&f!==k;)pb(a),g(f).filter(d,f).forEach(e,{source:f,target:b}),Db(b,a),a=f.constructor,a=O(a)&&ta(a,c),f=I(f)}function Eb(a,b,c){if(c[0]!==ua){var d=b.reduce(function(b,c){h(a[c])||b.push(c);return b},[]);if(1<=d.length)throw new f("The type misses following required method(s) \u2026 '"+d.join("', '")+"'.");}return d}function Fb(a,b,c){a.forEach(function(a){a.call(b,c)})}function Gb(a){this.call=function(){var b=q(arguments);var c=b.shift();c=null!=c&&c||null;a.apply(c,b);return c};this.apply=function(b,c){null==c&&(c=[]);b=null!=b&&b||null;a.apply(b,c);return b};return this}function Hb(a){this.requires=function(){return q(a)};return this}function Ib(a){var b=[],c={};a.call(c,ua);b=E(c).sort(function(a,b){return a<b&&-1||a>b&&1||0});c=null;this.keys=function(){return q(b)};return this}function va(a,b){this.toString=function(){return"[object Trait]"};this.valueOf=function(){return a};Gb.call(this,a);Hb.call(this,b);Ib.call(this,a);return this}function wa(a){var b;if(b=!!a)(b=a instanceof va)||(b="object"==typeof a&&h(a.call)&&h(a.apply)&&h(a.valueOf)&&h(a.valueOf()));return b}function x(a){return wa(a)||h(a)}function qa(a){return a.reduce(function(a,c){var b=c.valueOf(),e=b.trait,g=b.fromTrait;e&&0>a.indexOf(e)&&a.push(e);g&&0>a.indexOf(g)&&a.push(g);(b.traitList||[]).forEach(function(b){0>a.indexOf(b)&&a.push(b)});return a},[])}function ra(a){return a.map(function(a){return{trait:a,proxy:{}}})}function Jb(a,b,c,d){var e=[],g={};if(!(0>=b.length||na(b)))throw new l("The trait composition language's rule set does not result in applicable behavior. This happens e.g. if all behavior has been deleted via 'without'.");h(c)&&(c.call(g),e=E(g));return[a,b,e,d].some(function(a){return 1<=a.length})}function Kb(a){var b=a.useTraits.rules,c=a.applicator;a=c.body;var d=c.requires;c=c.modifiers;var e=qa(b);if(Jb(e,b,a,c)){c=function(a,b,c,d,e){return function(){var g=this,f=q(arguments),k=ra(a);k.forEach(function(a){var b=a.trait;a=a.proxy;da(b)?Cb(b,a,f):b.apply(a,f)});b.forEach(function(a){a.execute(g,k)});Eb(g,c,f);h(d)&&d.apply(g,f);Fb(e,g,f);return g}}(e,b,d,a,c);var g=new va(c,d)}return g}var xa=m.Function,z=m.Object,H=m.Array,r=m.RegExp,Lb=m.Number,Mb=m.Math,Y=m.JSON,f=m.TypeError,l=m.ReferenceError,n=m.SyntaxError,K=z.prototype,ya=Z.prototype,za=W.prototype,L=X.prototype,N=xa.prototype.toString,Ba=K.valueOf,C=K.toString,Nb=H.prototype.slice,P=typeof xa,Ca=B("Function"),Da=B("Object"),Ea=B("Array"),Ob=B("Arguments"),Fa=B("String"),Ga=B("GeneratorFunction"),Ha="\\([^)]*\\)\\s+=>\\s+\\(",Aa="^function\\s+([^(]+)\\(",Ja="^(?:Node|CharacterData|Event|DOMError|DOMException|DOMImplementation|DOMStringList|DOMTokenList|EventTarget|HTMLCollection|MutationObserver|MutationRecord|NodeFilter|NodeIterator|NodeList|Range|TreeWalker|URL|Document)$",Ka="^(?:HTMLElement|HTMLMediaElement|Element)$",La="^(?:CanvasRenderingContext2D|CanvasGradient|CanvasPattern|TextMetrics|ImageData|DOMStringMap|MediaError|HTMLCollection|NodeList)$",Ia="^(?:Array|ArrayBuffer|AsyncFunction|Atomics|Boolean|DataView|Date|Error|EvalError|Float32Array|Float64Array|Function|Generator|GeneratorFunction|Int16Array|Int32Array|Int8Array|InternalError|Collator|DateTimeFormat|NumberFormat|Iterator|Map|Number|Object|Promise|Proxy|RangeError|ReferenceError|RegExp|Bool16x8|Bool32x4|Bool64x2|Bool8x16|Float32x4|Float64x2|Int16x8|Int32x4|Int8x16|Uint16x8|Uint32x4|Uint8x16|Set|SharedArrayBuffer|StopIteration|String|Symbol|SyntaxError|TypeError|TypedArray|URIError|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|WeakMap|WeakSet)$",ua={},Ma={without:["apply","applyTraits"],as:["apply","applyBehavior"],after:["apply","applyBehavior","after","before"],before:["apply","applyBehavior","after","before"],apply:"apply applyBehavior applyTraits without as after before use".split(" "),applyTraits:"apply applyBehavior applyTraits without as after before use".split(" "),applyBehavior:"apply applyBehavior applyTraits without as after before use".split(" ")},ob={beforeWrap:oa,afterWrap:oa,beforeApply:pa,afterApply:pa,without:function(a){return{type:a.type,traitList:q(a.traitList),methodNameList:q(a.methodNameList)}},as:function(a){return{type:a.type,trait:a.trait,methodName:a.methodName,methodAlias:a.methodAlias}}},Pb={beforeWrap:function(a,b,c){var d=y(c,a.trait);c=c[d];a=a.methodName;b[a]=S((c&&c.proxy||{})[a],b[a],b)},afterWrap:function(a,b,c){var d=y(c,a.trait);c=c[d];a=a.methodName;b[a]=T((c&&c.proxy||{})[a],b[a],b)},beforeApply:function(a,b,c){var d=y(c,a.trait),e=y(c,a.fromTrait);d=c[d];e=c[e];c=d&&d.proxy||{};e=e&&e.proxy||{};a=a.methodName;a in b&&delete b.methodName;b[a]=S(c[a],e[a],b)},afterApply:function(a,b,c){var d=y(c,a.trait),e=y(c,a.fromTrait);d=c[d];e=c[e];c=d&&d.proxy||{};e=e&&e.proxy||{};a=a.methodName;a in b&&delete b.methodName;b[a]=T(c[a],e[a],b)},without:function(a,b,c){var d=a.traitList,e=a.methodNameList.reduce(function(a,b){a[b]=null;return a},{});d.forEach(function(a){a=y(c,a);var d=(a=c[a])&&a.proxy||{};E(d).forEach(function(a){a in e||(a in b&&delete b.methodName,b[a]=function(a,b){return function(){return a.apply(b,arguments)}}(d[a],b))})});a=c=d=e=null},as:function(a,b,c){var d=y(c,a.trait);c=(c=c[d])&&c.proxy||{};d=a.methodAlias;a=a.methodName;d in b&&delete b.methodAlias;b[d]=function(a,b){return function(){return a.apply(b,arguments)}}(c[a],b);a=c=d=c=c=d=a=null}},Qb=function(a){try{a.call(null,"length"),a=function(a,c){return function(b,e){return b!=c&&a.call(b,e)}}(a,null)}catch(b){a=function(a,b){return function(c,d){var e=c!=b;if(e)try{e=a.call(c,d)}catch(ea){e=!0}return e}}(a,null)}return a}(K.propertyIsEnumerable),I=u(z.getPrototypeOf)&&z.getPrototypeOf||function(a){var b=a&&a.__proto__;return b||null===b?b:aa(a.constructor)?a.constructor.prototype:a instanceof z?K:null},Rb=Lb.isFinite,Sb=u(H.isArguments)&&H.isArguments||function(){function a(a){return r(Ob).test(C.call(a))}a(arguments)||(a=function(a){return ba(a)&&"number"==typeof a.length&&Rb(a.length)&&!Qb(a,"length")});return a}(),q=u(H.from)&&H.from||function(a){return Nb.call(a)},ja=function c(b){b=Sb(b)&&q(b)||b;Q(b)&&(b=b.reduce(function(b,e){return b.concat(c(e))},[]));return b},E=z.keys,Db=u(z.assign)&&z.assign||function(b,c){E(c).forEach(function(d){b[d]=c[d]});return b},Bb=Mb.min,t=function(){};var D=(D=m.console)&&u(D.warn)&&u(D.log)&&D||{error:t,warn:t,log:t};L.as=function(b){if(G(this)){var c=this.valueOf();var d=c.parentLink;if(w(d)){var e=d.getSetup();var g=e.chainData;var h=g.recentCalleeName;if(v(h,"as"))if(p(b=F(b)))if(h=c.trait,c=c.methodName,c!==b)g.recentCalleeName="as",ha(e,h,c,b);else throw new f("Using identical method names in case of aliasing is considered to be a rule violating contradiction.");else throw new f("'as(<String>)' excepts as its sole argument just a 'String' type.");else{b=["\u2026 invalid chaining of '",h,"().as()'"].join("");if("applyTraits"==h)throw new n([b," in case of aliasing just a certain behavior."].join(""));throw new n(b);}}else throw new l("Please do not spoof the context of 'use'.");}else throw new l("Please do not spoof the context of 'apply'.");return d};L.after=function(b){if(G(this)){var c=this.valueOf();var d=c.parentLink;if(w(d)){var e=d.getSetup();var g=e.chainData;var k=g.recentCalleeName;if(v(k,"after"))if(x(b))if(k=d.valueOf(),k=k.traitList,0<=k.indexOf(b))if(k=c.trait,k!==b){var m=c.methodName;c={};b.call(c);if(h(c[m]))g.recentCalleeName="after",e.useTraits.rules.push(new A({type:"afterApply",trait:b,fromTrait:k,methodName:m}));else throw new l(["Please consider applying '",m,"' directly. This expected behavior has not been implemented by the trait that got passed to 'after'."].join(""));}else throw new l("Passing identical trait references to both 'apply' and 'after' is a contradiction that violates the composition rules.");else throw new f("Any trait passed to 'after' has to be registered before via 'use'.");else throw new f("'after(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",k,"().after()'"].join(""));}else throw new l("Please do not spoof the context of 'use'.");}else throw new l("Please do not spoof the context of 'apply'.");return d};L.before=function(b){if(G(this)){var c=this.valueOf();var d=c.parentLink;if(w(d)){var e=d.getSetup();var g=e.chainData;var k=g.recentCalleeName;if(v(k,"before"))if(x(b))if(k=d.valueOf(),k=k.traitList,0<=k.indexOf(b))if(k=c.trait,k!==b){var m=c.methodName;c={};b.call(c);if(h(c[m]))g.recentCalleeName="before",e.useTraits.rules.push(new A({type:"beforeApply",trait:b,fromTrait:k,methodName:m}));else throw new l(["Please consider applying '",m,"' directly. This expected behavior has not been implemented by the trait that got passed to 'before'."].join(""));}else throw new l("Passing identical trait references to both 'apply' and 'before' is a contradiction that violates the composition rules.");else throw new f("Any trait passed to 'before' has to be registered before via 'use'.");else throw new f("'before(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",k,"().before()'"].join(""));}else throw new l("Please do not spoof the context of 'use'.");}else throw new l("Please do not spoof the context of 'apply'.");return d};L.apply=ma;za.without=ka;za.apply=ma;ya.after=function(b){if(w(this)){var c=this.getSetup();var d=c.chainData;var e=d.recentCalleeName;if(v(e,"after"))if(x(b))if(e=this.valueOf(),e=e.traitList,0<=e.indexOf(b)){e=this.getChild();var g=e.valueOf();e=g.trait;if(e!==b)if(g=g.methodName,e={},b.call(e),h(e[g]))d.recentCalleeName="after",c.useTraits.rules.push(new A({type:"afterWrap",trait:b,methodName:g}));else throw new l(["Please consider applying '",g,"' directly. This expected behavior has not been implemented by the trait that got passed to 'after'."].join(""));else throw new l("Passing identical trait references to both 'apply' and 'after' is a contradiction that violates the composition rules.");}else throw new f("Any trait passed to 'after' has to be registered before via 'use'.");else throw new f("'after(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",e,"().after()'"].join(""));}else throw new l("Please do not spoof the context of 'use'.");return this};ya.before=function(b){if(w(this)){var c=this.getSetup();var d=c.chainData;var e=d.recentCalleeName;if(v(e,"before"))if(x(b))if(e=this.valueOf(),e=e.traitList,0<=e.indexOf(b)){e=this.getChild();var g=e.valueOf();e=g.trait;if(e!==b)if(g=g.methodName,e={},b.call(e),h(e[g]))d.recentCalleeName="before",c.useTraits.rules.push(new A({type:"beforeWrap",trait:b,methodName:g}));else throw new l(["Please consider applying '",g,"' directly. This expected behavior has not been implemented by the trait that got passed to 'before'."].join(""));else throw new l("Passing identical trait references to both 'apply' and 'before' is a contradiction that violates the composition rules.");}else throw new f("Any trait passed to 'before' has to be registered before via 'use'.");else throw new f("'before(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",e,"().before()'"].join(""));}else throw new l("Please do not spoof the context of 'use'.");return this};A.prototype.execute=function(b,c){var d=this.valueOf();Pb[d.type](d,b,c)};return m.Trait={create:function(b){if(h(b=F(b))){var c={chainData:{isTerminated:!1,recentCalleeName:"use"},useTraits:{root:null,rules:[]},applicator:{body:null,proxy:{},root:{},modifiers:[],requires:[],canRequire:!0,didRequire:!1}};var d=c.applicator.root;d.requires=lb.bind(c);d.before=db.bind(c);d.after=fb.bind(c);d.before.stateful=eb.bind(c);d.after.stateful=gb.bind(c);d.afterReturning=hb.bind(c);d.afterThrowing=ib.bind(c);d.afterFinally=jb.bind(c);d.around=kb.bind(c);d=nb.bind(c);var e=mb.bind(c);b(d,e);c=Kb(c)}return c},isFunctionType:O,isFunction:u,isFunctionObject:aa,isApplicable:x,isClass:da,isTrait:wa}})(Function("return this")()); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment