58 lines
1.4 KiB
TypeScript
58 lines
1.4 KiB
TypeScript
/**
|
|
* creates an object, which has all the methods of a class instance, but as
|
|
* plain functions (required for composition)
|
|
*/
|
|
function dullCopy<X>(instance: X): X {
|
|
const methodBlacklist: Set<string> = new Set<string>([
|
|
"__defineGetter__",
|
|
"__defineSetter__",
|
|
"__lookupGetter__",
|
|
"__lookupSetter__",
|
|
"__proto__",
|
|
"constructor",
|
|
"isPrototypeOf",
|
|
"hasOwnProperty",
|
|
"propertyIsEnumerable",
|
|
"valueOf",
|
|
"toString",
|
|
"toLocaleString",
|
|
]);
|
|
const result = {};
|
|
// attributes
|
|
{
|
|
for (const [name, value] of Object.entries(instance)) {
|
|
result[name] = value;
|
|
}
|
|
}
|
|
// methods
|
|
{
|
|
const methodNames: Array<string> = Object.getOwnPropertyNames(instance["__proto__"]);
|
|
for (const methodName of methodNames) {
|
|
if (! methodBlacklist.has(methodName)) {
|
|
result[methodName] = function (...methodArgs) {
|
|
return instance[methodName].apply(instance, methodArgs);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return (result as X);
|
|
}
|
|
|
|
/**
|
|
* creates a combination of two class instances, forming a new object with the
|
|
* methods of both operands (as plain functions)
|
|
*/
|
|
function compose<X, Y>(x: X, y: Y): (X & Y) {
|
|
const result = {};
|
|
for (const object of [x, y]) {
|
|
for (const [name, implementation] of Object.entries(dullCopy(object))) {
|
|
if (name in result) {
|
|
process.stderr.write("[warn] overwriting method '" + name + "'\n");
|
|
}
|
|
result[name] = implementation;
|
|
}
|
|
}
|
|
return (result as (X & Y));
|
|
}
|
|
|