Expose webpack to bdapi

This commit is contained in:
Zack Rauen 2022-08-01 17:53:43 -04:00
parent 29666219fd
commit 267b37ddc1
4 changed files with 77 additions and 25 deletions

View File

@ -9,7 +9,6 @@ const fs = require("fs");
const electron = require("electron"); const electron = require("electron");
const UserSettings = WebpackModules.getByProps("updateAccount"); const UserSettings = WebpackModules.getByProps("updateAccount");
const Dispatcher = WebpackModules.getByProps("dirtyDispatch"); const Dispatcher = WebpackModules.getByProps("dirtyDispatch");
const ActionTypes = WebpackModules.getByProps("ActionTypes", "ActivityFlags").ActionTypes;
export default new class CustomCSS extends Builtin { export default new class CustomCSS extends Builtin {
get name() {return "Custom CSS";} get name() {return "Custom CSS";}
@ -151,6 +150,6 @@ export default new class CustomCSS extends Builtin {
}); });
this.isDetached = true; this.isDetached = true;
UserSettings.close(); UserSettings.close();
Dispatcher.dispatch({type: ActionTypes.LAYER_POP}); Dispatcher.dispatch({type: "LAYER_POP"});
} }
}; };

View File

@ -3,7 +3,7 @@ import DiscordModules from "./discordmodules";
import Utilities from "./utilities"; import Utilities from "./utilities";
import Events from "./emitter"; import Events from "./emitter";
const {Dispatcher, DiscordConstants, UserSettingsStore} = DiscordModules; const {Dispatcher, UserSettingsStore} = DiscordModules;
export default new class LocaleManager { export default new class LocaleManager {
get discordLocale() {return UserSettingsStore.locale;} get discordLocale() {return UserSettingsStore.locale;}
@ -16,7 +16,7 @@ export default new class LocaleManager {
initialize() { initialize() {
this.setLocale(this.discordLocale); this.setLocale(this.discordLocale);
Dispatcher.subscribe(DiscordConstants.ActionTypes.USER_SETTINGS_UPDATE, ({settings}) => { Dispatcher.subscribe("USER_SETTINGS_UPDATE", ({settings}) => {
const newLocale = settings.locale; const newLocale = settings.locale;
if (newLocale && newLocale != this.locale) this.setLocale(newLocale); if (newLocale && newLocale != this.locale) this.setLocale(newLocale);
}); });

View File

@ -1,6 +1,6 @@
import {Config} from "data"; import {Config} from "data";
import Utilities from "./utilities"; import Utilities from "./utilities";
import WebpackModules from "./webpackmodules"; import WebpackModules, {Filters} from "./webpackmodules";
import DiscordModules from "./discordmodules"; import DiscordModules from "./discordmodules";
import DataStore from "./datastore"; import DataStore from "./datastore";
import DOMManager from "./dommanager"; import DOMManager from "./dommanager";
@ -134,7 +134,7 @@ BdApi.findModule = function(filter) {
// Finds module // Finds module
BdApi.findAllModules = function(filter) { BdApi.findAllModules = function(filter) {
return WebpackModules.getModule(filter, false); return WebpackModules.getModule(filter, {first: false});
}; };
// Finds module // Finds module
@ -282,9 +282,44 @@ BdApi.Patcher = {
} }
}; };
BdApi.Webpack = {
Filters: Filters,
/**
* Finds a module using a filter function.
* @param {(exports, module, moduleId) => boolean} filter A function to use to filter modules
* @param {object} [options] Whether to return only the first matching module
* @param {Boolean} [options.first=true] Whether to return only the first matching module
* @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export
* @return {Any}
*/
getModule(filter, options = {}) {
if (Reflect.has(options, "first") && typeof(options.first) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.first", options.first, "boolean expected.");
if (Reflect.has(options, "defaultExport") && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~getModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected.");
return WebpackModules.getModule(filter, options);
},
/**
* Finds a module that lazily loaded.
* @param {(exports) => boolean} filter A function to use to filter modules.
* @param {object} [options] Whether to return only the first matching module
* @param {AbortSignal} [options.signal] AbortSignal of an AbortController to cancel the promise
* @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export
* @returns {Promise<any>}
*/
waitForModule(filter, options = {}) {
if (Reflect.has(options, "defaultExport") && typeof(options.defaultExport) !== "boolean") return Logger.error("BdApi.Webpack~waitForModule", "Unsupported type used for options.defaultExport", options.defaultExport, "boolean expected.");
if (Reflect.has(options, "signal") && !(options.signal instanceof AbortSignal)) return Logger.error("BdApi.Webpack~waitForModule", "Unsupported type used for options.signal", options.signal, "AbortSignal expected.");
return WebpackModules.getLazy(filter, options);
},
};
Object.freeze(BdApi); Object.freeze(BdApi);
Object.freeze(BdApi.Plugins); Object.freeze(BdApi.Plugins);
Object.freeze(BdApi.Themes); Object.freeze(BdApi.Themes);
Object.freeze(BdApi.Patcher); Object.freeze(BdApi.Patcher);
Object.freeze(BdApi.Webpack);
Object.freeze(BdApi.Webpack.Filters);
export default BdApi; export default BdApi;

View File

@ -22,12 +22,12 @@ export class Filters {
* @param {module:WebpackModules.Filters~filter} filter - Additional filter * @param {module:WebpackModules.Filters~filter} filter - Additional filter
* @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties
*/ */
static byProperties(props, filter = m => m) { static byProps(props, filter = m => m) {
return module => { return module => {
const component = filter(module); const component = filter(module);
if (!component) return false; if (!component) return false;
for (let p = 0; p < props.length; p++) { for (let p = 0; p < props.length; p++) {
if (component[props[p]] === undefined) return false; if (!Reflect.has(component, props[p])) return false;
} }
return true; return true;
}; };
@ -45,7 +45,7 @@ export class Filters {
if (!component) return false; if (!component) return false;
if (!component.prototype) return false; if (!component.prototype) return false;
for (let f = 0; f < fields.length; f++) { for (let f = 0; f < fields.length; f++) {
if (component.prototype[fields[f]] === undefined) return false; if (!Reflect.has(component.prototype, fields[f])) return false;
} }
return true; return true;
}; };
@ -57,7 +57,7 @@ export class Filters {
* @param {module:WebpackModules.Filters~filter} filter - Additional filter * @param {module:WebpackModules.Filters~filter} filter - Additional filter
* @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties
*/ */
static byCode(search, filter = m => m) { static byRegex(search, filter = m => m) {
return module => { return module => {
const method = filter(module); const method = filter(module);
if (!method) return false; if (!method) return false;
@ -73,7 +73,7 @@ export class Filters {
* @param {...String} search - A RegExp to check on the module * @param {...String} search - A RegExp to check on the module
* @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of strings * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of strings
*/ */
static byString(...strings) { static byStrings(...strings) {
return module => { return module => {
let moduleString = ""; let moduleString = "";
try {moduleString = module.toString([]);} try {moduleString = module.toString([]);}
@ -137,13 +137,21 @@ export default class WebpackModules {
/** /**
* Finds a module using a filter function. * Finds a module using a filter function.
* @param {Function} filter A function to use to filter modules * @param {Function} filter A function to use to filter modules
* @param {Boolean} first Whether to return only the first matching module * @param {object} [options] Whether to return only the first matching module
* @param {Boolean} [options.first=true] Whether to return only the first matching module
* @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export
* @return {Any} * @return {Any}
*/ */
static getModule(filter, first = true) { static getModule(filter, options = {}) {
const wrappedFilter = (m) => { const {first = true, defaultExport = true} = options;
try {return filter(m);} const wrappedFilter = (exports, module, moduleId) => {
catch (err) {return false;} try {
return filter(exports, module, moduleId);
}
catch (err) {
Logger.warn("WebpackModules~getModule", "Module filter threw an exception.", filter, err);
return false;
}
}; };
const modules = this.getAllModules(); const modules = this.getAllModules();
const rm = []; const rm = [];
@ -154,8 +162,8 @@ export default class WebpackModules {
let foundModule = null; let foundModule = null;
if (!exports) continue; if (!exports) continue;
if (exports.__esModule && exports.default && wrappedFilter(exports.default)) foundModule = exports.default; if (exports.__esModule && exports.default && wrappedFilter(exports.default, module, index)) foundModule = defaultExport ? exports.default : exports;
if (wrappedFilter(exports)) foundModule = exports; if (wrappedFilter(exports, module, index)) foundModule = exports;
if (!foundModule) continue; if (!foundModule) continue;
if (first) return protect(foundModule); if (first) return protect(foundModule);
rm.push(protect(foundModule)); rm.push(protect(foundModule));
@ -186,7 +194,7 @@ export default class WebpackModules {
* @return {Any} * @return {Any}
*/ */
static getByRegex(regex, first = true) { static getByRegex(regex, first = true) {
return this.getModule(Filters.byCode(regex), first); return this.getModule(Filters.byRegex(regex), first);
} }
/** /**
@ -213,7 +221,7 @@ export default class WebpackModules {
* @return {Any} * @return {Any}
*/ */
static getByProps(...props) { static getByProps(...props) {
return this.getModule(Filters.byProperties(props), true); return this.getModule(Filters.byProps(props), true);
} }
/** /**
@ -222,7 +230,7 @@ export default class WebpackModules {
* @return {Any} * @return {Any}
*/ */
static getAllByProps(...props) { static getAllByProps(...props) {
return this.getModule(Filters.byProperties(props), false); return this.getModule(Filters.byProps(props), false);
} }
/** /**
@ -231,7 +239,7 @@ export default class WebpackModules {
* @return {Any} * @return {Any}
*/ */
static getByString(...strings) { static getByString(...strings) {
return this.getModule(Filters.byString(...strings), true); return this.getModule(Filters.byStrings(...strings), true);
} }
/** /**
@ -240,15 +248,21 @@ export default class WebpackModules {
* @return {Any} * @return {Any}
*/ */
static getAllByString(...strings) { static getAllByString(...strings) {
return this.getModule(Filters.byString(...strings), false); return this.getModule(Filters.byStrings(...strings), false);
} }
/** /**
* Finds a module that lazily loaded. * Finds a module that lazily loaded.
* @param {(m) => boolean} filter A function to use to filter modules. * @param {(m) => boolean} filter A function to use to filter modules.
* @param {object} [options] Whether to return only the first matching module
* @param {AbortSignal} [options.signal] AbortSignal of an AbortController to cancel the promise
* @param {Boolean} [options.defaultExport=true] Whether to return default export when matching the default export
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
static getLazy(filter) { static getLazy(filter, options = {}) {
/** @type {AbortSignal} */
const abortSignal = options.signal;
const defaultExport = options.defaultExport;
const fromCache = this.getModule(filter); const fromCache = this.getModule(filter);
if (fromCache) return Promise.resolve(fromCache); if (fromCache) return Promise.resolve(fromCache);
@ -266,10 +280,14 @@ export default class WebpackModules {
if (!defaultMatch) return; if (!defaultMatch) return;
cancel(); cancel();
resolve(m.default); resolve(defaultExport ? m.default : defaultExport);
}; };
this.addListener(listener); this.addListener(listener);
abortSignal?.addEventListener("abort", () => {
cancel();
resolve();
});
}); });
} }