mirror of
https://github.com/sern-handler/handler
synced 2026-06-25 01:02:17 +00:00
fix: faster autocomplete lookup (#387)
* fix:faster-autocmp * fixinitializing * fix * fixonwindows * unconsole
This commit is contained in:
@@ -6,12 +6,12 @@ import type {
|
||||
MessageContextMenuCommandInteraction,
|
||||
ModalSubmitInteraction,
|
||||
UserContextMenuCommandInteraction,
|
||||
AutocompleteInteraction
|
||||
AutocompleteInteraction,
|
||||
} from 'discord.js';
|
||||
import { ApplicationCommandOptionType, InteractionType } from 'discord.js';
|
||||
import { PluginType } from './structures/enums';
|
||||
import assert from 'assert';
|
||||
import type { Payload, UnpackedDependencies } from '../types/utility';
|
||||
import path from 'node:path'
|
||||
|
||||
export const createSDT = (module: Module, deps: UnpackedDependencies, params: string|undefined) => {
|
||||
return {
|
||||
@@ -57,51 +57,31 @@ export function partitionPlugins<T,V>
|
||||
return [controlPlugins, initPlugins] as [T[], V[]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses an iterative DFS to check if an autocomplete node exists on the option tree
|
||||
* @param iAutocomplete
|
||||
* @param options
|
||||
*/
|
||||
export function treeSearch(
|
||||
iAutocomplete: AutocompleteInteraction,
|
||||
options: SernOptionsData[] | undefined,
|
||||
): SernAutocompleteData & { parent?: string } | undefined {
|
||||
if (options === undefined) return undefined;
|
||||
//clone to prevent mutation of original command module
|
||||
const _options = options.map(a => ({ ...a }));
|
||||
const subcommands = new Set();
|
||||
while (_options.length > 0) {
|
||||
const cur = _options.pop()!;
|
||||
switch (cur.type) {
|
||||
export const createLookupTable = (options: SernOptionsData[]): Map<string, SernAutocompleteData> => {
|
||||
const table = new Map<string, SernAutocompleteData>();
|
||||
_createLookupTable(table, options, "<parent>");
|
||||
return table;
|
||||
}
|
||||
|
||||
const _createLookupTable = (table: Map<string, SernAutocompleteData>, options: SernOptionsData[], parent: string) => {
|
||||
for (const opt of options) {
|
||||
const name = path.posix.join(parent, opt.name)
|
||||
switch(opt.type) {
|
||||
case ApplicationCommandOptionType.Subcommand: {
|
||||
subcommands.add(cur.name);
|
||||
for (const option of cur.options ?? []) _options.push(option);
|
||||
} break;
|
||||
_createLookupTable(table, opt.options ?? [], name);
|
||||
} break;
|
||||
case ApplicationCommandOptionType.SubcommandGroup: {
|
||||
for (const command of cur.options ?? []) _options.push(command);
|
||||
} break;
|
||||
_createLookupTable(table, opt.options ?? [], name);
|
||||
} break;
|
||||
default: {
|
||||
if ('autocomplete' in cur && cur.autocomplete) {
|
||||
const choice = iAutocomplete.options.getFocused(true);
|
||||
assert( 'command' in cur, 'No `command` property found for option ' + cur.name);
|
||||
if (subcommands.size > 0) {
|
||||
const parent = iAutocomplete.options.getSubcommand();
|
||||
const parentAndOptionMatches =
|
||||
subcommands.has(parent) && cur.name === choice.name;
|
||||
if (parentAndOptionMatches) {
|
||||
return { ...cur, parent };
|
||||
}
|
||||
} else {
|
||||
if (cur.name === choice.name) {
|
||||
return { ...cur, parent: undefined };
|
||||
}
|
||||
}
|
||||
if(Reflect.get(opt, 'autocomplete') === true) {
|
||||
table.set(name, opt as SernAutocompleteData)
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface InteractionTypable {
|
||||
type: InteractionType;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { Module } from '../types/core-modules'
|
||||
import type { Module, SernAutocompleteData } from '../types/core-modules'
|
||||
import { callPlugins, executeModule } from './event-utils';
|
||||
import { SernError } from '../core/structures/enums'
|
||||
import { createSDT, isAutocomplete, isCommand, isContextCommand, isMessageComponent, isModal, resultPayload, treeSearch } from '../core/functions'
|
||||
import { createSDT, isAutocomplete, isCommand, isContextCommand, isMessageComponent, isModal, resultPayload } from '../core/functions'
|
||||
import type { UnpackedDependencies } from '../types/utility';
|
||||
import * as Id from '../core/id'
|
||||
import { Context } from '../core/structures/context';
|
||||
import path from 'node:path';
|
||||
|
||||
|
||||
|
||||
@@ -31,10 +32,15 @@ export function interactionHandler(deps: UnpackedDependencies, defaultPrefix?: s
|
||||
let payload;
|
||||
// handles autocomplete
|
||||
if(isAutocomplete(event)) {
|
||||
//@ts-ignore stfu
|
||||
const { command } = treeSearch(event, module.options);
|
||||
payload= { module: command as Module, //autocomplete is not a true "module" warning cast!
|
||||
args: [event, createSDT(command, deps, params)] };
|
||||
const lookupTable = module.locals['@sern/lookup-table'] as Map<string, SernAutocompleteData>
|
||||
const subCommandGroup = event.options.getSubcommandGroup() ?? "",
|
||||
subCommand = event.options.getSubcommand() ?? "",
|
||||
option = event.options.getFocused(true),
|
||||
fullPath = path.posix.join("<parent>", subCommandGroup, subCommand, option.name)
|
||||
|
||||
const resolvedModule = (lookupTable.get(fullPath)!.command) as Module
|
||||
payload= { module: resolvedModule , //autocomplete is not a true "module" warning cast!
|
||||
args: [event, createSDT(resolvedModule, deps, params)] };
|
||||
// either CommandTypes Slash | ContextMessage | ContextUesr
|
||||
} else if(isCommand(event)) {
|
||||
const sdt = createSDT(module, deps, params)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as Files from '../core/module-loading'
|
||||
import { once } from 'node:events';
|
||||
import { resultPayload } from '../core/functions';
|
||||
import { createLookupTable, resultPayload } from '../core/functions';
|
||||
import { CommandType } from '../core/structures/enums';
|
||||
import { Module } from '../types/core-modules';
|
||||
import { Module, SernOptionsData } from '../types/core-modules';
|
||||
import type { UnpackedDependencies, Wrapper } from '../types/utility';
|
||||
import { callInitPlugins } from './event-utils';
|
||||
import { SernAutocompleteData } from '..';
|
||||
|
||||
export default async function(dirs: string | string[], deps : UnpackedDependencies) {
|
||||
const { '@sern/client': client,
|
||||
@@ -28,6 +29,12 @@ export default async function(dirs: string | string[], deps : UnpackedDependenci
|
||||
throw Error(`Found ${module.name} at ${module.meta.absPath}, which has incorrect \`type\``);
|
||||
}
|
||||
const resultModule = await callInitPlugins(module, deps, true);
|
||||
|
||||
if(module.type === CommandType.Both || module.type === CommandType.Slash) {
|
||||
const options = (Reflect.get(module, 'options') ?? []) as SernOptionsData[];
|
||||
const lookupTable = createLookupTable(options)
|
||||
module.locals['@sern/lookup-table'] = lookupTable;
|
||||
}
|
||||
// FREEZE! no more writing!!
|
||||
commands.set(resultModule.meta.id, Object.freeze(resultModule));
|
||||
sEmitter.emit('module.register', resultPayload('success', resultModule));
|
||||
|
||||
Reference in New Issue
Block a user