mirror of
https://github.com/danbulant/discord.js-structures
synced 2026-05-19 04:08:36 +00:00
basic proxy setup
This commit is contained in:
parent
16664d7154
commit
bdb72158fd
12 changed files with 286 additions and 64 deletions
40
index.js
Normal file
40
index.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
const discord = require("discord.js");
|
||||
const proxyHandlers = require("./proxies/handlers");
|
||||
const Module = require("module");
|
||||
const StructuresDef = require("./proxies/structures.js");
|
||||
|
||||
const original = discord;
|
||||
const Structures = StructuresDef;
|
||||
|
||||
const proxy = new Proxy(discord, {
|
||||
get(target, property, receiver) {
|
||||
if(property in proxyHandlers) return proxyHandlers[property];
|
||||
if(property === "original") return original;
|
||||
if(property === "Structures") return Structures;
|
||||
if(property === "hook") return hook;
|
||||
return Reflect.get(target, property, receiver);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Hooks discord.js-structures into discord.js require, which should fix errors in 3rd party libraries trying to use Structures.
|
||||
* Overwrites global require function
|
||||
* @see [StackOverflow source](https://stackoverflow.com/a/24602188/8404532)
|
||||
*/
|
||||
function hook() {
|
||||
var origRequire = Module.prototype.require;
|
||||
var _require = function(context, path) {
|
||||
return origRequire.call(context, path);
|
||||
};
|
||||
|
||||
Module.prototype.require = function(path) {
|
||||
if(path === "discord.js") {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return _require(this, path);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = proxy;
|
||||
31
index.mjs
31
index.mjs
|
|
@ -1,31 +0,0 @@
|
|||
import discord from "discord.js";
|
||||
import { defaultProxy } from "./proxies/index.mjs";
|
||||
import Module from "module";
|
||||
|
||||
/** The proxied version, in case you like named params */
|
||||
export const proxy = new Proxy(discord, defaultProxy);
|
||||
|
||||
/** The original discord.js, unmodified. Useful when using discord.js-structures hooked */
|
||||
export const original = discord;
|
||||
|
||||
/**
|
||||
* Hooks discord.js-structures into discord.js require, which should fix errors in 3rd party libraries trying to use Structures.
|
||||
* Overwrites global require function
|
||||
* @see [StackOverflow source](https://stackoverflow.com/a/24602188/8404532)
|
||||
*/
|
||||
export function hook() {
|
||||
var origRequire = Module.prototype.require;
|
||||
var _require = function(context, path) {
|
||||
return origRequire.call(context, path);
|
||||
};
|
||||
|
||||
Module.prototype.require = function(path) {
|
||||
if(path === "discord.js") {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return _require(this, path);
|
||||
};
|
||||
}
|
||||
|
||||
export default proxy;
|
||||
|
|
@ -4,12 +4,15 @@
|
|||
"description": "Adds discord.js structures back into discord.js",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "node test/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"discord.js": ">=13.0.0-dev.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"discord.js": ">=13.0.0-dev.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
proxies/cache.js
Normal file
2
proxies/cache.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
module.exports = new WeakMap();
|
||||
9
proxies/client.js
Normal file
9
proxies/client.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
/**
|
||||
* @type {ProxyHandler<import("discord.js").Client>}
|
||||
*/
|
||||
module.exports = {
|
||||
get(target, property, receiver) {
|
||||
return Reflect.get(target, property, receiver);
|
||||
}
|
||||
}
|
||||
81
proxies/eventProxy.js
Normal file
81
proxies/eventProxy.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
module.exports = class EventProxy {
|
||||
proxies = new Map();
|
||||
once = new Map();
|
||||
on = new Map();
|
||||
targetEvents = new WeakMap();
|
||||
handlers = new Map();
|
||||
|
||||
setProxy(event, handler) {
|
||||
this.proxies.set(event, handler);
|
||||
}
|
||||
|
||||
handleEvent(event, args) {
|
||||
if(proxies.has(event)) {
|
||||
args = proxies.get(event)(...args);
|
||||
}
|
||||
for(const handler of (proxy.on.get(event) || [])) {
|
||||
handler(...args);
|
||||
}
|
||||
for(const handler of (proxy.once.get(event) || [])) {
|
||||
handler(...args);
|
||||
}
|
||||
proxy.once.delete(event);
|
||||
}
|
||||
|
||||
get proxy() {
|
||||
const proxy = this;
|
||||
/** @type {ProxyHandler} */
|
||||
const handler = {
|
||||
get(target, property) {
|
||||
const events = proxy.targetEvents.get(target) || [];
|
||||
switch(property) {
|
||||
case "on":
|
||||
return (event, handler) => {
|
||||
const handlers = proxy.on.get(event) || [];
|
||||
handlers.push(handler);
|
||||
proxy.on.set(event, handlers);
|
||||
if(!events.includes(event)) {
|
||||
const handler = (...args) => proxy.handleEvent(event, args);
|
||||
proxy.handlers.set(event, handler);
|
||||
target.on(event, handler);
|
||||
}
|
||||
}
|
||||
case "once":
|
||||
return (event, handler) => {
|
||||
const handlers = proxy.once.get(event) || [];
|
||||
handlers.push(handler);
|
||||
proxy.once.set(event, handlers);
|
||||
if(!events.includes(event)) {
|
||||
const handler = (...args) => proxy.handleEvent(event, args);
|
||||
proxy.handlers.set(event, handler);
|
||||
target.on(event, handler);
|
||||
}
|
||||
}
|
||||
case "off":
|
||||
return (event, handler) => {
|
||||
const handlers = proxy.on.get(event) || [];
|
||||
if(handlers.includes(handler)) handlers.splice(handlers.indexOf(handler), 1);
|
||||
if(handlers.length) {
|
||||
proxy.on.set(event, handlers);
|
||||
} else {
|
||||
proxy.on.delete(event);
|
||||
}
|
||||
const handlers2 = proxy.once.get(event) || [];
|
||||
if(handlers2.includes(handler)) handlers.splice(handlers.indexOf(handler), 1);
|
||||
if(handlers2.length) {
|
||||
proxy.once.set(event, handlers2);
|
||||
} else {
|
||||
proxy.once.delete(event);
|
||||
}
|
||||
if(!handlers.length && !handlers2.length) {
|
||||
target.off(event, proxy.handlers.get(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Reflect.get(...arguments);
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
13
proxies/handlers.js
Normal file
13
proxies/handlers.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const Structures = require("./structures.js");
|
||||
const discord = require("discord.js");
|
||||
const EventProxy = require("./eventProxy.js");
|
||||
|
||||
module.exports = {
|
||||
Client: class Client {
|
||||
constructor(...params) {
|
||||
var proxy = new EventProxy();
|
||||
return new Proxy(new Proxy(new discord.Client(...params), require("./client.js")), proxy.proxy);
|
||||
}
|
||||
},
|
||||
Structures: Structures
|
||||
};
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
const proxyHandlers = {};
|
||||
|
||||
/**
|
||||
* @type {ProxyHandler<import("discord.js")>}
|
||||
*/
|
||||
export const defaultProxy = {
|
||||
get(target, property, receiver) {
|
||||
if(property in proxyHandlers) return proxyHandlers[property];
|
||||
return Reflect.get(target, property, receiver);
|
||||
}
|
||||
}
|
||||
112
proxies/structures.js
Normal file
112
proxies/structures.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
const discord = require("discord.js");
|
||||
|
||||
/**
|
||||
* An extendable structure:
|
||||
* * **`GuildEmoji`**
|
||||
* * **`DMChannel`**
|
||||
* * **`TextChannel`**
|
||||
* * **`VoiceChannel`**
|
||||
* * **`CategoryChannel`**
|
||||
* * **`NewsChannel`**
|
||||
* * **`StoreChannel`**
|
||||
* * **`GuildMember`**
|
||||
* * **`Guild`**
|
||||
* * **`Message`**
|
||||
* * **`MessageReaction`**
|
||||
* * **`Presence`**
|
||||
* * **`ClientPresence`**
|
||||
* * **`VoiceState`**
|
||||
* * **`Role`**
|
||||
* * **`User`**
|
||||
* @typedef {string} ExtendableStructure
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allows for the extension of built-in Discord.js structures that are instantiated by {@link BaseManager Managers}.
|
||||
*/
|
||||
class Structures {
|
||||
constructor() {
|
||||
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a structure class.
|
||||
* @param {string} structure Name of the structure to retrieve
|
||||
* @returns {Function}
|
||||
*/
|
||||
static get(structure) {
|
||||
if (typeof structure === 'string') return structures[structure];
|
||||
throw new TypeError(`"structure" argument must be a string (received ${typeof structure})`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends a structure.
|
||||
* <warn> Make sure to extend all structures before instantiating your client.
|
||||
* Extending after doing so may not work as expected. </warn>
|
||||
* @param {ExtendableStructure} structure Name of the structure class to extend
|
||||
* @param {Function} extender Function that takes the base class to extend as its only parameter and returns the
|
||||
* extended class/prototype
|
||||
* @returns {Function} Extended class/prototype returned from the extender
|
||||
* @example
|
||||
* const { Structures } = require('discord.js');
|
||||
*
|
||||
* Structures.extend('Guild', Guild => {
|
||||
* class CoolGuild extends Guild {
|
||||
* constructor(client, data) {
|
||||
* super(client, data);
|
||||
* this.cool = true;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* return CoolGuild;
|
||||
* });
|
||||
*/
|
||||
static extend(structure, extender) {
|
||||
if (!structures[structure]) throw new RangeError(`"${structure}" is not a valid extensible structure.`);
|
||||
if (typeof extender !== 'function') {
|
||||
const received = `(received ${typeof extender})`;
|
||||
throw new TypeError(
|
||||
`"extender" argument must be a function that returns the extended structure class/prototype ${received}.`,
|
||||
);
|
||||
}
|
||||
|
||||
const extended = extender(structures[structure]);
|
||||
if (typeof extended !== 'function') {
|
||||
const received = `(received ${typeof extended})`;
|
||||
throw new TypeError(`The extender function must return the extended structure class/prototype ${received}.`);
|
||||
}
|
||||
|
||||
if (!(extended.prototype instanceof structures[structure])) {
|
||||
const prototype = Object.getPrototypeOf(extended);
|
||||
const received = `${extended.name || 'unnamed'}${prototype.name ? ` extends ${prototype.name}` : ''}`;
|
||||
throw new Error(
|
||||
'The class/prototype returned from the extender function must extend the existing structure class/prototype' +
|
||||
` (received function ${received}; expected extension of ${structures[structure].name}).`,
|
||||
);
|
||||
}
|
||||
|
||||
structures[structure] = extended;
|
||||
return extended;
|
||||
}
|
||||
}
|
||||
|
||||
const structures = {
|
||||
GuildEmoji: discord.GuildEmoji,
|
||||
DMChannel: discord.DMChannel,
|
||||
TextChannel: discord.TextChannel,
|
||||
VoiceChannel: discord.VoiceChannel,
|
||||
CategoryChannel: discord.CategoryChannel,
|
||||
NewsChannel: discord.NewsChannel,
|
||||
StoreChannel: discord.StoreChannel,
|
||||
GuildMember: discord.GuildMember,
|
||||
Guild: discord.Guild,
|
||||
Message: discord.Message,
|
||||
MessageReaction: discord.MessageReaction,
|
||||
Presence: discord.Presence,
|
||||
ClientPresence: discord.ClientPresence,
|
||||
VoiceState: discord.VoiceState,
|
||||
Role: discord.Role,
|
||||
User: discord.User,
|
||||
};
|
||||
|
||||
module.exports = Structures;
|
||||
25
test/index.js
Normal file
25
test/index.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
const discord = require("../index");
|
||||
const config = require("./config.json");
|
||||
|
||||
discord.Structures.extend('Message', Message => {
|
||||
class BetterMessage extends Message {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
this.cool = true;
|
||||
}
|
||||
}
|
||||
|
||||
return BetterMessage;
|
||||
});
|
||||
|
||||
const client = new discord.Client({
|
||||
intents: ["GUILDS", "GUILD_MESSAGES"]
|
||||
});
|
||||
client.login(config.token);
|
||||
|
||||
client.on("ready", () => {
|
||||
console.log("Ready as", client.user.tag);
|
||||
})
|
||||
client.on("message", (msg) => {
|
||||
console.log(msg);
|
||||
});
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import discord from "../index.mjs";
|
||||
import config from "./config.json";
|
||||
|
||||
discord.Structures.extend('Message', Message => {
|
||||
class BetterMessage extends Message {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
this.cool = true;
|
||||
}
|
||||
}
|
||||
|
||||
return BetterMessage;
|
||||
});
|
||||
|
||||
const client = new discord.Client();
|
||||
client.login(config.token);
|
||||
|
||||
client.on("message", (msg) => {
|
||||
console.log(msg);
|
||||
});
|
||||
Loading…
Reference in a new issue