BetterDiscordApp-rauenzi/renderer/src/modules/reactcomponents.js

92 lines
3.3 KiB
JavaScript

import DiscordModules from "./discordmodules";
import Patcher from "./patcher";
const React = DiscordModules.React;
const components = {};
const unknownComponents = new Set();
const listeners = new Set();
export default new class ReactComponents {
get named() {return components;}
get unknown() {return unknownComponents;}
get listeners() {return listeners;}
constructor() {
Patcher.after("ReactComponents", React, "createElement", (_, __, returnValue) => {
this.walkRenderTree(returnValue);
});
Patcher.instead("ReactComponents", React.Component.prototype, "componentWillMount", (thisObject) => {
this.addComponent(thisObject.constructor);
});
Patcher.instead("ReactComponents", React.Component.prototype, "UNSAFE_componentWillMount", (thisObject) => {
this.addComponent(thisObject.constructor);
});
Patcher.instead("ReactComponents", React.PureComponent.prototype, "componentWillMount", (thisObject) => {
this.addComponent(thisObject.constructor);
});
Patcher.instead("ReactComponents", React.PureComponent.prototype, "UNSAFE_componentWillMount", (thisObject) => {
this.addComponent(thisObject.constructor);
});
}
initialize() {
this.walkReactTree(document.querySelector("#app-mount")._reactRootContainer._internalRoot.current);
}
get(name, filter) {
return new Promise(resolve => {
if (components[name]) return resolve(components[name]);
listeners.add({name, filter, resolve});
if (!filter) return;
for (const component of unknownComponents) {
if (!filter(component)) continue;
component.displayName = name;
unknownComponents.delete(component);
this.addNamedComponent(component);
}
});
}
addNamedComponent(component) {
const name = component.displayName;
if (!components[name]) {
components[name] = component;
for (const listener of listeners) {
if (listener.name !== name) continue;
listener.resolve(component);
listeners.delete(listener);
}
}
}
addUnknownComponent(component) {
if (unknownComponents.has(component)) return;
for (const listener of listeners) {
if (!listener.filter || !listener.filter(component)) continue;
component.displayName = listener.name;
this.addNamedComponent(component);
}
if (!component.displayName) unknownComponents.add(component);
}
addComponent(component) {
if (component.displayName) return this.addNamedComponent(component);
return this.addUnknownComponent(component);
}
walkRenderTree(tree) {
if (!tree) return;
if (typeof(tree.type) == "function") this.addComponent(tree.type);
if (Array.isArray(tree)) for (const value of tree) this.walkRenderTree(value);
if (tree.props && tree.props.children) this.walkRenderTree(tree.props.children);
}
walkReactTree(tree) {
if (!tree) return;
if (typeof(tree.type) == "function") this.addComponent(tree.type);
if (tree.child) this.walkReactTree(tree.child);
if (tree.sibling) this.walkReactTree(tree.sibling);
}
};