|
|
|
@ -26,6 +26,12 @@ type ParserOptions = {
|
|
|
|
|
resolver?: IResolver<unknown, unknown, unknown, unknown, unknown>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ParseOptions = {
|
|
|
|
|
prefix?: string,
|
|
|
|
|
commandFilter?: (cmd: Command) => boolean,
|
|
|
|
|
guild?: unknown
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ParseError extends Error {}
|
|
|
|
|
|
|
|
|
|
const flagReg = /(?:^| )(?<flag>(?:--[a-z0-9]{3,})|(?:-[a-z]{1,2}))(?:$| )/iu;
|
|
|
|
@ -75,8 +81,12 @@ class Parser extends EventEmitter {
|
|
|
|
|
*/
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
|
|
|
async parseMessage (
|
|
|
|
|
message: string, prefix = this.prefix,
|
|
|
|
|
guild?: unknown, commandFilter?: (command: Command) => boolean
|
|
|
|
|
message: string,
|
|
|
|
|
{
|
|
|
|
|
prefix = this.prefix,
|
|
|
|
|
guild,
|
|
|
|
|
commandFilter
|
|
|
|
|
}: ParseOptions = {}
|
|
|
|
|
): Promise<ParseResult | null> {
|
|
|
|
|
|
|
|
|
|
if (!message.startsWith(prefix) || !message.length)
|
|
|
|
@ -134,11 +144,20 @@ class Parser extends EventEmitter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const activeCommand = subcommand || command;
|
|
|
|
|
const flags = activeCommand.options.filter((opt) => opt.flag);
|
|
|
|
|
|
|
|
|
|
params = Util.parseQuotes(params.join(' ')).map(([ str ]: (string | boolean)[]): string => str.toString());
|
|
|
|
|
this.debug(`Given params: "${params.join('", "')}"`);
|
|
|
|
|
|
|
|
|
|
parseResult.args = await this.parseOptions(params, activeCommand.options, guild);
|
|
|
|
|
|
|
|
|
|
return parseResult;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async parseOptions (params: string[], options: CommandOption[], guild?: unknown) {
|
|
|
|
|
let currentFlag = null;
|
|
|
|
|
const flags = options.filter((opt) => opt.flag);
|
|
|
|
|
const args: ArgsResult = {};
|
|
|
|
|
|
|
|
|
|
// Parse flags
|
|
|
|
|
for (let index = 0; index < params.length;) {
|
|
|
|
@ -202,12 +221,13 @@ class Parser extends EventEmitter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.debug(`Params after parsing "${params.join('", "')}"`);
|
|
|
|
|
const options = activeCommand.options.filter((opt) => !opt.flag && (opt.type !== OptionType.STRING || opt.choices.length));
|
|
|
|
|
const stringOpts = activeCommand.options.filter((opt) => !opt.flag && !opt.choices.length && opt.type === OptionType.STRING);
|
|
|
|
|
// Non-string options
|
|
|
|
|
const nStrOptions = options.filter((opt) => !opt.flag && (opt.type !== OptionType.STRING || opt.choices.length));
|
|
|
|
|
const stringOpts = options.filter((opt) => !opt.flag && !opt.choices.length && opt.type === OptionType.STRING);
|
|
|
|
|
|
|
|
|
|
this.debug(`Parsing non-flag options`);
|
|
|
|
|
// Parse out non-flag options
|
|
|
|
|
for (const option of options) { // String options are parsed separately at the end
|
|
|
|
|
for (const option of nStrOptions) { // String options are parsed separately at the end
|
|
|
|
|
if (!params.some((param) => param !== null)) {
|
|
|
|
|
this.debug(`No potential values left in params`);
|
|
|
|
|
break;
|
|
|
|
@ -279,26 +299,26 @@ class Parser extends EventEmitter {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This part is obsolete now, I think, the string option checks the choice value
|
|
|
|
|
for (const arg of Object.values(args)) {
|
|
|
|
|
if (!arg.choices.length)
|
|
|
|
|
continue;
|
|
|
|
|
if (!arg.choices.some((choice) => {
|
|
|
|
|
if (typeof arg.value === 'string' && typeof choice === 'string')
|
|
|
|
|
return arg.value.toLowerCase() === choice.toLowerCase();
|
|
|
|
|
return arg.value === choice;
|
|
|
|
|
}))
|
|
|
|
|
throw new ParseError(`Invalid choice: ${arg.name} value must be one of ${arg.choices.join(', ')}`); // return { error: true, index: 'O_COMMANDHANDLER_INVALID_CHOICE', params: { option: arg.name, value: arg.value, choices: arg.choices.map((c) => c).join('`, `') } };
|
|
|
|
|
}
|
|
|
|
|
// for (const arg of Object.values(args)) {
|
|
|
|
|
// if (!arg.choices.length)
|
|
|
|
|
// continue;
|
|
|
|
|
// if (!arg.choices.some((choice) => {
|
|
|
|
|
// if (typeof arg.value === 'string' && typeof choice === 'string')
|
|
|
|
|
// return arg.value.toLowerCase() === choice.toLowerCase();
|
|
|
|
|
// return arg.value === choice;
|
|
|
|
|
// }))
|
|
|
|
|
// throw new ParseError(`Invalid choice: ${arg.name} value must be one of ${arg.choices.join(', ')}`); // return { error: true, index: 'O_COMMANDHANDLER_INVALID_CHOICE', params: { option: arg.name, value: arg.value, choices: arg.choices.map((c) => c).join('`, `') } };
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
this.debug(`Making sure required options were given.`);
|
|
|
|
|
for (const req of activeCommand.options.filter((opt) => opt.required))
|
|
|
|
|
for (const req of options.filter((opt) => opt.required))
|
|
|
|
|
if (!args[req.name])
|
|
|
|
|
throw new ParseError(`${req.name} is a required option`);
|
|
|
|
|
|
|
|
|
|
if (strings.length)
|
|
|
|
|
throw new ParseError(`Unrecognised option(s): "${strings.join('", "')}"`);// return { error: true, index: 'O_COMMANDHANDLER_UNRECOGNISED_OPTIONS', params: { opts: strings.join('`, `') } };
|
|
|
|
|
throw new ParseError(`Unrecognised option(s): "${strings.join('", "')}"`);
|
|
|
|
|
|
|
|
|
|
return parseResult;
|
|
|
|
|
return args;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|