diff --git a/renderer/src/modules/discordclasses.js b/renderer/src/modules/discordclasses.js index 92120ea7..5ab7ae38 100644 --- a/renderer/src/modules/discordclasses.js +++ b/renderer/src/modules/discordclasses.js @@ -20,7 +20,7 @@ const DiscordClassModules = Utilities.memoizeObject({ ); }, get EmptyImage() {return WebpackModules.getByProps("emptyImage", "emptyHeader");}, - get Modal() {return WebpackModules.getByProps("content", "root", "header");}, + get Modal() {return WebpackModules.getByProps("content", "root", "header", "close");}, get Scrollers() {return WebpackModules.getByProps("thin", "scrollerBase", "content");}, get Margins() {return WebpackModules.getByProps("marginXSmall", "marginBottom8");}, get Integrations() {return WebpackModules.getByProps("secondaryHeader", "detailsWrapper");}, diff --git a/renderer/src/modules/pluginmanager.js b/renderer/src/modules/pluginmanager.js index a01839d9..3ed7c102 100644 --- a/renderer/src/modules/pluginmanager.js +++ b/renderer/src/modules/pluginmanager.js @@ -9,10 +9,20 @@ import Events from "./emitter"; import Toasts from "../ui/toasts"; import Modals from "../ui/modals"; import SettingsRenderer from "../ui/settings"; +import Utilities from "./utilities"; const path = require("path"); const vm = require("vm"); + +const fileModification = name => ` +if (module.exports.default) { + module.exports = module.exports.default; +} +if (typeof(module.exports) !== "function") { + module.exports = eval("${name};") +}`; + export default new class PluginManager extends AddonManager { get name() {return "PluginManager";} get moduleExtension() {return ".js";} @@ -78,8 +88,16 @@ export default new class PluginManager extends AddonManager { if (!addon.exports || !addon.name) return new AddonError(addon.name || addon.filename, addon.filename, "Plugin had no exports or @name property", {message: "Plugin had no exports or no @name property. @name property is required for all addons.", stack: ""}, this.prefix); try { + const isValid = typeof(addon.exports) === "function"; + if (!isValid) return new AddonError(addon.name || addon.filename, addon.filename, "Plugin not a valid format.", {message: "Plugins should be either a function or a class", stack: ""}, this.prefix); + + const isClass = Utilities.isClass(addon.exports); const PluginClass = addon.exports; - const thePlugin = new PluginClass(); + const meta = Object.assign({}, addon); + delete meta.exports; + const thePlugin = isClass ? new PluginClass(meta) : addon.exports(meta); + if (!thePlugin.start || !thePlugin.stop) return new AddonError(addon.name || addon.filename, addon.filename, "Missing start or stop function.", {message: "Plugins must have both a start and stop function.", stack: ""}, this.prefix);; + addon.instance = thePlugin; addon.name = thePlugin.getName ? thePlugin.getName() : addon.name; addon.author = thePlugin.getAuthor ? thePlugin.getAuthor() : addon.author || "No author"; @@ -93,11 +111,13 @@ export default new class PluginManager extends AddonManager { return new AddonError(addon.name, addon.filename, "load() could not be fired.", {message: error.message, stack: error.stack}, this.prefix); } } - catch (error) {return new AddonError(addon.name, addon.filename, "Could not be constructed.", {message: error.message, stack: error.stack}, this.prefix);} + catch (error) { + return new AddonError(addon.name, addon.filename, "Could not be constructed.", {message: error.message, stack: error.stack}, this.prefix); + } } getFileModification(module, fileContent, meta) { - fileContent += `\nif (module.exports.default) {module.exports = module.exports.default;}\nif (!module.exports.prototype || !module.exports.prototype.start) {module.exports = ${meta.exports || meta.name};}`; + fileContent += fileModification(meta.exports || meta.name); window.global = window; window.module = module; diff --git a/renderer/src/modules/utilities.js b/renderer/src/modules/utilities.js index 04d4148a..b4e4cf15 100644 --- a/renderer/src/modules/utilities.js +++ b/renderer/src/modules/utilities.js @@ -113,6 +113,10 @@ export default class Utilities { return true; } + static isClass(obj) { + return typeof(obj) === "function" && /^\s*class\s+/.test(obj.toString()); + } + /** * Generates an automatically memoizing version of an object. * @author Zerebos diff --git a/renderer/src/ui/addonerrormodal.jsx b/renderer/src/ui/addonerrormodal.jsx index c99cf4c0..4e0fbe04 100644 --- a/renderer/src/ui/addonerrormodal.jsx +++ b/renderer/src/ui/addonerrormodal.jsx @@ -19,7 +19,7 @@ class AddonError extends React.Component { this.setState({expanded: !this.state.expanded}); } renderErrorBody(err) { - const stack = err.error && err.stack; + const stack = err?.error?.stack ?? err.stack; if (!this.state.expanded || !stack) return null; return