|
function wrappedCall( |
|
name: string, originalFunction: Function, that: any, args: any[]) { |
|
let result: any; |
|
(global as any).Tracing.traceCall(name, () => { |
|
result = originalFunction.apply(that, args); |
|
// wrap iterators |
|
if (!!result && typeof(result.next) === 'function' && |
|
result.__wrapped === undefined) { |
|
result.__wrapped = true; |
|
const orgNext = result.next; |
|
|
|
Reflect.set(result, 'next', function(this: any, ...args: any[]) { |
|
return wrappedCall(name, orgNext, this, args); |
|
}); |
|
} |
|
}, |
|
() => { |
|
// Uncomment this to trace arguments and return values |
|
// const r: {[k:string]:string} = {}; |
|
// for(let i = 0;i<args.length;i++) { |
|
// r[`arg${i}`] = String(args[i]); |
|
// } |
|
// r[`ret`] = String(result); |
|
// return r; |
|
return {}; |
|
}, |
|
); |
|
return result; |
|
} |
|
|
|
export function wrapFunction(obj: object, _key: PropertyKey, className?: string) { |
|
const descriptor = Reflect.getOwnPropertyDescriptor(obj, _key); |
|
const key = String(_key); |
|
if (!descriptor || descriptor.get || descriptor.set) { |
|
return; |
|
} |
|
|
|
if (key === 'constructor') { |
|
return; |
|
} |
|
|
|
const originalFunction = descriptor.value; |
|
if (!originalFunction || typeof originalFunction !== 'function') { |
|
return; |
|
} |
|
|
|
// set a key for the object in memory |
|
if (!className) { |
|
className = obj.constructor ? `${obj.constructor.name}` : ''; |
|
} |
|
const memKey = className + `:${key}`; |
|
|
|
// set a tag so we don't wrap a function twice |
|
const savedName = `__${key}__`; |
|
if (Reflect.has(obj, savedName)) { |
|
return; |
|
} |
|
|
|
Reflect.set(obj, savedName, originalFunction); |
|
Reflect.set(obj, _key, function(this: any, ...args: any[]) { |
|
return wrappedCall(memKey, originalFunction, this, args); |
|
}); |
|
} |
|
|
|
export function wrapEngine() { |
|
for(const m in Creep.prototype) { |
|
wrapFunction(Creep.prototype, m, 'Creep'); |
|
} |
|
for(const m in Room.prototype) { |
|
wrapFunction(Room.prototype, m, 'Room'); |
|
} |
|
} |
|
|
|
export function trace(target: any): void; |
|
export function trace( |
|
target: object, key: string|symbol, |
|
_descriptor: TypedPropertyDescriptor<any>): void; |
|
export function trace( |
|
target: object|Function, |
|
key?: string|symbol, |
|
_descriptor?: TypedPropertyDescriptor<Function>, |
|
): void { |
|
if (key) { |
|
// case of method decorator |
|
wrapFunction(target, key); |
|
return; |
|
} |
|
|
|
// case of class decorator |
|
const ctor = target as any; |
|
if (!ctor.prototype) { |
|
return; |
|
} |
|
|
|
const className = ctor.name; |
|
Reflect.ownKeys(ctor.prototype).forEach((k) => { |
|
wrapFunction(ctor.prototype, k, className); |
|
}); |
|
} |