Skip to content

Instantly share code, notes, and snippets.

@petsel
Last active August 25, 2023 08:23
Show Gist options
  • Save petsel/3a598704149e00541db0ff9790146c4a to your computer and use it in GitHub Desktop.
Save petsel/3a598704149e00541db0ff9790146c4a to your computer and use it in GitHub Desktop.
Just Another "Trait Composition Language" Library for ECMAScript
//
//
// 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