Refactor parser to allow parsing of just arguments
This commit is contained in:
parent
aa7fe8643c
commit
97561a4b7f
@ -26,6 +26,12 @@ type ParserOptions = {
|
|||||||
resolver?: IResolver<unknown, unknown, unknown, unknown, unknown>
|
resolver?: IResolver<unknown, unknown, unknown, unknown, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ParseOptions = {
|
||||||
|
prefix?: string,
|
||||||
|
commandFilter?: (cmd: Command) => boolean,
|
||||||
|
guild?: unknown
|
||||||
|
}
|
||||||
|
|
||||||
class ParseError extends Error {}
|
class ParseError extends Error {}
|
||||||
|
|
||||||
const flagReg = /(?:^| )(?<flag>(?:--[a-z0-9]{3,})|(?:-[a-z]{1,2}))(?:$| )/iu;
|
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
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
async parseMessage (
|
async parseMessage (
|
||||||
message: string, prefix = this.prefix,
|
message: string,
|
||||||
guild?: unknown, commandFilter?: (command: Command) => boolean
|
{
|
||||||
|
prefix = this.prefix,
|
||||||
|
guild,
|
||||||
|
commandFilter
|
||||||
|
}: ParseOptions = {}
|
||||||
): Promise<ParseResult | null> {
|
): Promise<ParseResult | null> {
|
||||||
|
|
||||||
if (!message.startsWith(prefix) || !message.length)
|
if (!message.startsWith(prefix) || !message.length)
|
||||||
@ -134,11 +144,20 @@ class Parser extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const activeCommand = subcommand || command;
|
const activeCommand = subcommand || command;
|
||||||
const flags = activeCommand.options.filter((opt) => opt.flag);
|
|
||||||
|
|
||||||
params = Util.parseQuotes(params.join(' ')).map(([ str ]: (string | boolean)[]): string => str.toString());
|
params = Util.parseQuotes(params.join(' ')).map(([ str ]: (string | boolean)[]): string => str.toString());
|
||||||
this.debug(`Given params: "${params.join('", "')}"`);
|
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;
|
let currentFlag = null;
|
||||||
|
const flags = options.filter((opt) => opt.flag);
|
||||||
|
const args: ArgsResult = {};
|
||||||
|
|
||||||
// Parse flags
|
// Parse flags
|
||||||
for (let index = 0; index < params.length;) {
|
for (let index = 0; index < params.length;) {
|
||||||
@ -202,12 +221,13 @@ class Parser extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.debug(`Params after parsing "${params.join('", "')}"`);
|
this.debug(`Params after parsing "${params.join('", "')}"`);
|
||||||
const options = activeCommand.options.filter((opt) => !opt.flag && (opt.type !== OptionType.STRING || opt.choices.length));
|
// Non-string options
|
||||||
const stringOpts = activeCommand.options.filter((opt) => !opt.flag && !opt.choices.length && opt.type === OptionType.STRING);
|
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`);
|
this.debug(`Parsing non-flag options`);
|
||||||
// Parse out 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)) {
|
if (!params.some((param) => param !== null)) {
|
||||||
this.debug(`No potential values left in params`);
|
this.debug(`No potential values left in params`);
|
||||||
break;
|
break;
|
||||||
@ -279,26 +299,26 @@ class Parser extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This part is obsolete now, I think, the string option checks the choice value
|
// This part is obsolete now, I think, the string option checks the choice value
|
||||||
for (const arg of Object.values(args)) {
|
// for (const arg of Object.values(args)) {
|
||||||
if (!arg.choices.length)
|
// if (!arg.choices.length)
|
||||||
continue;
|
// continue;
|
||||||
if (!arg.choices.some((choice) => {
|
// if (!arg.choices.some((choice) => {
|
||||||
if (typeof arg.value === 'string' && typeof choice === 'string')
|
// if (typeof arg.value === 'string' && typeof choice === 'string')
|
||||||
return arg.value.toLowerCase() === choice.toLowerCase();
|
// return arg.value.toLowerCase() === choice.toLowerCase();
|
||||||
return arg.value === choice;
|
// 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('`, `') } };
|
// 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.`);
|
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])
|
if (!args[req.name])
|
||||||
throw new ParseError(`${req.name} is a required option`);
|
throw new ParseError(`${req.name} is a required option`);
|
||||||
|
|
||||||
if (strings.length)
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,3 +96,25 @@ test('Command Parser', async () => {
|
|||||||
await expect(parser.parseMessage('create code 1')).resolves.toHaveProperty('args.amount.value', 1);
|
await expect(parser.parseMessage('create code 1')).resolves.toHaveProperty('args.amount.value', 1);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Choice option', async () => {
|
||||||
|
|
||||||
|
const command = new Command({
|
||||||
|
name: 'create',
|
||||||
|
options: [{
|
||||||
|
name: 'registration-code',
|
||||||
|
aliases: ['code'],
|
||||||
|
type: OptionType.SUB_COMMAND,
|
||||||
|
options: [{
|
||||||
|
name: 'amount',
|
||||||
|
type: OptionType.STRING,
|
||||||
|
choices: ['one', 'two']
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
const parser = new Parser({ commands: [command], prefix: '' });
|
||||||
|
|
||||||
|
await expect(parser.parseMessage('create code 1')).rejects.toThrow();
|
||||||
|
await expect(parser.parseMessage('create code one')).resolves.toHaveProperty('args.amount.value', 'one');
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user