this repo has no description

Merge pull request #164 from moonlight-mod/commands

Commands library

authored by notnite.com and committed by GitHub 87b1fac3 7429d768

Changed files
+260
packages
core-extensions
src
commands
types
src
coreExtensions
+76
packages/core-extensions/src/commands/index.ts
··· 1 + import { Patch, ExtensionWebpackModule } from "@moonlight-mod/types"; 2 + import { APPLICATION_ID } from "@moonlight-mod/types/coreExtensions/commands"; 3 + 4 + export const patches: Patch[] = [ 5 + { 6 + find: ".fI5MTU)", // COMMAND_SECTION_BUILT_IN_NAME 7 + replace: [ 8 + // inject commands 9 + { 10 + match: /return (\i)=\i/, 11 + replacement: (orig, commands) => 12 + `${commands}=[...${commands},...require("commands_commands").default._getCommands()];${orig}` 13 + }, 14 + 15 + // section 16 + { 17 + match: /(?<=\i={)(?=\[\i\.\i\.BUILT_IN]:{id:\i\.\i\.BUILT_IN,type:(\i.\i\.BUILT_IN))/, 18 + replacement: (_, type) => 19 + `"${APPLICATION_ID}":{id:"${APPLICATION_ID}",type:${type},get name(){return "moonlight"}},` 20 + } 21 + ] 22 + }, 23 + 24 + // index our section 25 + { 26 + find: '"ApplicationCommandIndexStore"', 27 + replace: { 28 + match: /(?<=let \i=(\i)\((\i\.\i)\[\i\.\i\.BUILT_IN\],(\i),!0,!0,(\i)\);)null!=(\i)&&(\i)\.push\(\i\)/, 29 + replacement: (_, createSection, sections, deny, props, section, commands) => 30 + `null!=${section}&&(${section}.data=${section}.data.filter(c=>c.applicationId=="-1")); 31 + null!=${section}&&${commands}.push(${section}); 32 + const moonlightCommands=${createSection}(${sections}["${APPLICATION_ID}"],${deny},!0,!0,${props}); 33 + null!=moonlightCommands&&(moonlightCommands.data=moonlightCommands.data.filter(c=>c.applicationId=="${APPLICATION_ID}")); 34 + null!=moonlightCommands&&${commands}.push(moonlightCommands)` 35 + } 36 + }, 37 + 38 + // grab legacy commands (needed for adding actions that act like sed/plus reacting) 39 + { 40 + find: "={tts:{action:", 41 + replace: { 42 + match: /Object\.setPrototypeOf\((\i),null\)/, 43 + replacement: (_, legacyCommands) => `require("commands_commands")._getLegacyCommands(${legacyCommands})` 44 + } 45 + }, 46 + 47 + // add icon 48 + { 49 + find: ",hasSpaceTerminator:", 50 + replace: { 51 + match: /(\i)\.type===/, 52 + replacement: (orig, section) => `${section}.id!=="${APPLICATION_ID}"&&${orig}` 53 + } 54 + }, 55 + { 56 + find: ".icon,bot:null===", 57 + replace: { 58 + match: /(\.useMemo\(\(\)=>{)(if\((\i)\.type)/, 59 + replacement: (_, before, after, section) => `${before} 60 + if (${section}.id==="${APPLICATION_ID}") return "https://moonlight-mod.github.io/favicon.png"; 61 + ${after}` 62 + } 63 + }, 64 + // fix icon sizing because they expect built in to be 24 and others to be 32 65 + { 66 + find: ".builtInSeparator}):null]", 67 + replace: { 68 + match: /(\i)\.type===\i\.\i\.BUILT_IN/, 69 + replacement: (orig, section) => `${section}.id!=="${APPLICATION_ID}"&&${orig}` 70 + } 71 + } 72 + ]; 73 + 74 + export const webpackModules: Record<string, ExtensionWebpackModule> = { 75 + commands: {} 76 + };
+11
packages/core-extensions/src/commands/manifest.json
··· 1 + { 2 + "$schema": "https://moonlight-mod.github.io/manifest.schema.json", 3 + "id": "commands", 4 + "apiLevel": 2, 5 + "meta": { 6 + "name": "Commands", 7 + "tagline": "A library to add commands", 8 + "authors": ["Cynosphere", "NotNite"], 9 + "tags": ["library"] 10 + } 11 + }
+55
packages/core-extensions/src/commands/webpackModules/commands.ts
··· 1 + import { 2 + APPLICATION_ID, 3 + Commands, 4 + LegacyCommand, 5 + RegisteredCommand 6 + } from "@moonlight-mod/types/coreExtensions/commands"; 7 + 8 + type LegacyCommands = Record<string, LegacyCommand>; 9 + let legacyCommands: LegacyCommands | undefined; 10 + let queuedLegacyCommands: Record<string, LegacyCommand> | null = {}; 11 + 12 + const registeredCommands: RegisteredCommand[] = []; 13 + 14 + export function _getLegacyCommands(commands: LegacyCommands) { 15 + legacyCommands = commands; 16 + if (queuedLegacyCommands != null) { 17 + for (const [key, value] of Object.entries(queuedLegacyCommands)) { 18 + legacyCommands[key] = value; 19 + } 20 + queuedLegacyCommands = null; 21 + } 22 + } 23 + 24 + export const commands: Commands = { 25 + registerCommand(command) { 26 + const registered: RegisteredCommand = { 27 + ...command, 28 + untranslatedName: command.id, 29 + displayName: command.id, 30 + applicationId: APPLICATION_ID, 31 + untranslatedDescription: command.description, 32 + displayDescription: command.description, 33 + options: command.options.map((o) => ({ 34 + ...o, 35 + displayName: o.name, 36 + displayDescription: o.description 37 + })) 38 + }; 39 + registeredCommands.push(registered); 40 + }, 41 + 42 + registerLegacyCommand(id, command) { 43 + if (!legacyCommands) { 44 + queuedLegacyCommands![id] = command; 45 + } else { 46 + legacyCommands[id] = command; 47 + } 48 + }, 49 + 50 + _getCommands() { 51 + return [...registeredCommands]; 52 + } 53 + }; 54 + 55 + export default commands;
+118
packages/types/src/coreExtensions/commands.ts
··· 1 + export const APPLICATION_ID = "-3"; 2 + 3 + export enum CommandType { 4 + CHAT = 1, 5 + MESSAGE = 3, 6 + PRIMARY_ENTRY_POINT = 4, 7 + USER = 2 8 + } 9 + 10 + export enum InputType { 11 + BOT = 3, 12 + BUILT_IN = 0, 13 + BUILT_IN_INTEGRATION = 2, 14 + BUILT_IN_TEXT = 1, 15 + PLACEHOLDER = 4 16 + } 17 + 18 + export enum OptionType { 19 + ATTACHMENT = 11, 20 + BOOLEAN = 5, 21 + CHANNEL = 7, 22 + INTEGER = 4, 23 + MENTIONABLE = 9, 24 + NUMBER = 10, 25 + ROLE = 8, 26 + STRING = 3, 27 + SUB_COMMAND = 1, 28 + SUB_COMMAND_GROUP = 2, 29 + USER = 6 30 + } 31 + 32 + export type RegisteredCommandOption = { 33 + name: string; 34 + displayName: string; 35 + type: OptionType; 36 + description: string; 37 + displayDescription: string; 38 + }; 39 + 40 + export type MoonlightCommandOption = { 41 + name: string; 42 + type: OptionType; 43 + description: string; 44 + }; 45 + 46 + // TODO: types 47 + export type CommandPredicateState = { 48 + channel: any; 49 + guild: any; 50 + }; 51 + 52 + export type RegisteredCommand = { 53 + id: string; 54 + untranslatedName: string; 55 + displayName: string; 56 + type: CommandType; 57 + inputType: InputType; 58 + applicationId: string; // set to -3! 59 + untranslatedDescription: string; 60 + displayDescription: string; 61 + options: RegisteredCommandOption[]; 62 + predicate?: (state: CommandPredicateState) => boolean; 63 + execute: (options: CommandOption[]) => void; 64 + }; 65 + 66 + export type MoonlightCommand = { 67 + id: string; 68 + description: string; 69 + type: CommandType; 70 + inputType: InputType; 71 + options: MoonlightCommandOption[]; 72 + predicate?: (state: CommandPredicateState) => boolean; 73 + execute: (options: CommandOption[]) => void; 74 + }; 75 + 76 + export type CommandOption = { 77 + name: string; 78 + } & ( // TODO: more of these 79 + | { 80 + type: Exclude<OptionType, OptionType.STRING>; 81 + value: any; 82 + } 83 + | { 84 + type: OptionType.STRING; 85 + value: string; 86 + } 87 + ); 88 + 89 + export type Commands = { 90 + /** 91 + * Register a command in the internal slash command system 92 + */ 93 + registerCommand: (command: MoonlightCommand) => void; 94 + 95 + /** 96 + * Register a legacy command that works via regex 97 + */ 98 + registerLegacyCommand: (id: string, command: LegacyCommand) => void; 99 + 100 + /** 101 + * @private 102 + */ 103 + _getCommands: () => RegisteredCommand[]; 104 + }; 105 + 106 + export type LegacyContext = { 107 + channel: any; 108 + isEdit: boolean; 109 + }; 110 + 111 + export type LegacyReturn = { 112 + content: string; 113 + }; 114 + 115 + export type LegacyCommand = { 116 + match?: RegExp; 117 + action: (content: string, context: LegacyContext) => LegacyReturn; 118 + };