Change how patching modules works (#1474)

This commit is contained in:
Zerebos 2022-11-06 14:33:47 -05:00 committed by GitHub
parent 690bfb79cb
commit 03efbfd447
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 225 additions and 273 deletions

View File

@ -41,7 +41,8 @@ export default function () {
if (!Reflect.has(exports, key) || target[key]) continue;
Object.defineProperty(target, key, {
get: exports[key],
get: () => exports[key](),
set: v => {exports[key] = () => v;},
enumerable: true,
configurable: true
});

View File

@ -3,11 +3,11 @@
* instead of the original function. Can also alter arguments and return values.
*/
import Logger from "common/logger";
import DiscordModules from "./discordmodules";
import WebpackModules from "./webpackmodules";
import Logger from "common/logger";
import DiscordModules from "./discordmodules";
import WebpackModules from "./webpackmodules";
export default class Patcher {
export default class Patcher {
static get patches() {return this._patches || (this._patches = []);}
@ -99,61 +99,17 @@ export default class Patcher {
originalFunction: module[functionName],
proxyFunction: null,
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.proxyFunction = null;
patch.children = [];
},
counter: 0,
children: []
};
patch.proxyFunction = this.makeOverride(patch);
const descriptor = Object.getOwnPropertyDescriptor(module, functionName);
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);
patch.proxyFunction = module[functionName] = this.makeOverride(patch);
Object.assign(module[functionName], patch.originalFunction);
module[functionName].__originalFunction = patch.originalFunction;
module[functionName].toString = () => patch.originalFunction.toString();
this.patches.push(patch);
return patch;
}
@ -170,7 +126,7 @@ export default class Patcher {
*
* @callback module:Patcher~patchCallback
* @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.
* @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] 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;
const displayName = options.displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
@ -274,4 +224,5 @@ export default class Patcher {
return child.unpatch;
}
}
}