Change how patching modules works (#1474)
This commit is contained in:
parent
690bfb79cb
commit
03efbfd447
|
@ -41,7 +41,8 @@ export default function () {
|
||||||
if (!Reflect.has(exports, key) || target[key]) continue;
|
if (!Reflect.has(exports, key) || target[key]) continue;
|
||||||
|
|
||||||
Object.defineProperty(target, key, {
|
Object.defineProperty(target, key, {
|
||||||
get: exports[key],
|
get: () => exports[key](),
|
||||||
|
set: v => {exports[key] = () => v;},
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true
|
configurable: true
|
||||||
});
|
});
|
||||||
|
|
|
@ -99,61 +99,17 @@ export default class Patcher {
|
||||||
originalFunction: module[functionName],
|
originalFunction: module[functionName],
|
||||||
proxyFunction: null,
|
proxyFunction: null,
|
||||||
revert: () => { // Calling revert will destroy any patches added to the same module after this
|
revert: () => { // Calling revert will destroy any patches added to the same module after this
|
||||||
if (patch.getter) {
|
|
||||||
Object.defineProperty(patch.module, functionName, {
|
|
||||||
...Object.getOwnPropertyDescriptor(patch.module, functionName),
|
|
||||||
get: () => patch.originalFunction,
|
|
||||||
set: undefined
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
patch.module[patch.functionName] = patch.originalFunction;
|
patch.module[patch.functionName] = patch.originalFunction;
|
||||||
}
|
|
||||||
|
|
||||||
patch.proxyFunction = null;
|
patch.proxyFunction = null;
|
||||||
patch.children = [];
|
patch.children = [];
|
||||||
},
|
},
|
||||||
counter: 0,
|
counter: 0,
|
||||||
children: []
|
children: []
|
||||||
};
|
};
|
||||||
|
patch.proxyFunction = module[functionName] = this.makeOverride(patch);
|
||||||
patch.proxyFunction = this.makeOverride(patch);
|
Object.assign(module[functionName], patch.originalFunction);
|
||||||
|
module[functionName].__originalFunction = patch.originalFunction;
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(module, functionName);
|
module[functionName].toString = () => patch.originalFunction.toString();
|
||||||
|
|
||||||
if (descriptor?.get) {
|
|
||||||
patch.getter = true;
|
|
||||||
Object.defineProperty(module, functionName, {
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
...descriptor,
|
|
||||||
get: () => patch.proxyFunction,
|
|
||||||
// eslint-disable-next-line no-setter-return
|
|
||||||
set: value => (patch.originalFunction = value)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
patch.getter = false;
|
|
||||||
module[functionName] = patch.proxyFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
const descriptors = Object.assign({}, Object.getOwnPropertyDescriptors(patch.originalFunction), {
|
|
||||||
__originalFunction: {
|
|
||||||
get: () => patch.originalFunction,
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
writeable: true
|
|
||||||
},
|
|
||||||
toString: {
|
|
||||||
value: () => patch.originalFunction.toString(),
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
writeable: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperties(patch.proxyFunction, descriptors);
|
|
||||||
|
|
||||||
this.patches.push(patch);
|
this.patches.push(patch);
|
||||||
return patch;
|
return patch;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +126,7 @@ export default class Patcher {
|
||||||
*
|
*
|
||||||
* @callback module:Patcher~patchCallback
|
* @callback module:Patcher~patchCallback
|
||||||
* @param {object} thisObject - `this` in the context of the original function.
|
* @param {object} thisObject - `this` in the context of the original function.
|
||||||
* @param {args} args - The original arguments of the original function.
|
* @param {arguments} args - The original arguments of the original function.
|
||||||
* @param {(function|*)} extraValue - For `instead` patches, this is the original function from the module. For `after` patches, this is the return value of the function.
|
* @param {(function|*)} extraValue - For `instead` patches, this is the original function from the module. For `after` patches, this is the return value of the function.
|
||||||
* @return {*} Makes sense only when using an `instead` or `after` patch. If something other than `undefined` is returned, the returned value replaces the value of `returnValue`. If used for `before` the return value is ignored.
|
* @return {*} Makes sense only when using an `instead` or `after` patch. If something other than `undefined` is returned, the returned value replaces the value of `returnValue`. If used for `before` the return value is ignored.
|
||||||
*/
|
*/
|
||||||
|
@ -242,12 +198,6 @@ export default class Patcher {
|
||||||
if (!module[functionName] && forcePatch) module[functionName] = function() {};
|
if (!module[functionName] && forcePatch) module[functionName] = function() {};
|
||||||
if (!(module[functionName] instanceof Function)) return null;
|
if (!(module[functionName] instanceof Function)) return null;
|
||||||
|
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(module, functionName);
|
|
||||||
if (descriptor && !descriptor?.configurable) {
|
|
||||||
Logger.err("Patcher", `Cannot patch ${functionName} of Module, property is readonly.`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof moduleToPatch === "string") options.displayName = moduleToPatch;
|
if (typeof moduleToPatch === "string") options.displayName = moduleToPatch;
|
||||||
const displayName = options.displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
|
const displayName = options.displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
|
||||||
|
|
||||||
|
@ -275,3 +225,4 @@ export default class Patcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue