Compare commits

...

6 Commits

Author SHA1 Message Date
bdd73dd6a9
default parsers for some built-in types 2023-02-12 14:51:45 +02:00
19fef0ed6c
bugfix + tests 2022-07-29 23:22:29 +03:00
5c4accc58d
bugfix 2022-07-29 23:09:05 +03:00
e2aac258a7
string type 2022-07-29 22:19:24 +03:00
c6deb3764c
debug 2022-07-29 21:51:13 +03:00
3e43b568c1
misc 2022-07-29 21:24:37 +03:00
5 changed files with 83 additions and 12 deletions

View File

@ -106,7 +106,7 @@
"no-extend-native": "warn", "no-extend-native": "warn",
"no-extra-bind": "warn", "no-extra-bind": "warn",
"no-extra-label": "warn", "no-extra-label": "warn",
"no-extra-parens": "warn", // "no-extra-parens": "warn",
"no-floating-decimal": "warn", "no-floating-decimal": "warn",
"no-implicit-coercion": "warn", "no-implicit-coercion": "warn",
"no-implicit-globals": "warn", "no-implicit-globals": "warn",

View File

@ -1,6 +1,6 @@
{ {
"name": "commandparser", "name": "commandparser",
"version": "1.0.19", "version": "1.0.24",
"description": "Parser meant to parse commands and their options for discord bots", "description": "Parser meant to parse commands and their options for discord bots",
"main": "build/index.js", "main": "build/index.js",
"author": "Navy.gif", "author": "Navy.gif",

View File

@ -1,8 +1,8 @@
// eslint-disable-next-line max-classes-per-file // eslint-disable-next-line max-classes-per-file
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import Command from './classes/Command';
import CommandOption from './classes/CommandOption'; import CommandOption from './classes/CommandOption';
import ICommand from "./interfaces/Command";
import { OptionType } from "./interfaces/CommandOption"; import { OptionType } from "./interfaces/CommandOption";
import IResolver from './interfaces/Resolver'; import IResolver from './interfaces/Resolver';
import ExtendedMap from "./util/Map"; import ExtendedMap from "./util/Map";
@ -14,13 +14,13 @@ type ArgsResult = {
type ParseResult = { type ParseResult = {
args: ArgsResult, args: ArgsResult,
command: ICommand, command: Command,
subcommand: string | null, subcommand: string | null,
subcommandGroup: string | null subcommandGroup: string | null
} }
type ParserOptions = { type ParserOptions = {
commands: Iterable<ICommand>, commands: Iterable<Command>,
prefix?: string, prefix?: string,
debug?: boolean, debug?: boolean,
resolver: IResolver<unknown, unknown, unknown, unknown, unknown> resolver: IResolver<unknown, unknown, unknown, unknown, unknown>
@ -32,7 +32,7 @@ const flagReg = /(?:^| )(?<flag>(?:--[a-z0-9]{3,})|(?:-[a-z]{1,2}))(?:$| )/iu;
class Parser extends EventEmitter { class Parser extends EventEmitter {
private commands: ExtendedMap<string, ICommand>; private commands: ExtendedMap<string, Command>;
private _debug = false; private _debug = false;
@ -45,7 +45,7 @@ class Parser extends EventEmitter {
super(); super();
this._debug = debug; this._debug = debug;
this.commands = new ExtendedMap<string, ICommand>(); this.commands = new ExtendedMap<string, Command>();
for (const command of commands) this.commands.set(command.name, command); for (const command of commands) this.commands.set(command.name, command);
this.resolver = resolver; this.resolver = resolver;
@ -53,7 +53,7 @@ class Parser extends EventEmitter {
} }
private matchCommand(name: string): ICommand | null { private matchCommand(name: string): Command | null {
let command = null; let command = null;
if (this.commands.has(name)) command = this.commands.get(name); if (this.commands.has(name)) command = this.commands.get(name);
else command = this.commands.find((c) => c.aliases.includes(name)); else command = this.commands.find((c) => c.aliases.includes(name));
@ -73,7 +73,7 @@ class Parser extends EventEmitter {
*/ */
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
async parseMessage(message: string, prefix = this.prefix, async parseMessage(message: string, prefix = this.prefix,
guild?: unknown, commandFilter?: (command: ICommand) => boolean): Promise<ParseResult | null> { guild?: unknown, commandFilter?: (command: Command) => boolean): Promise<ParseResult | null> {
if (!message.startsWith(prefix) || !message.length) return null; if (!message.startsWith(prefix) || !message.length) return null;
let params: string[] = message.replace(prefix, '').split(' ').filter((str) => str.length); let params: string[] = message.replace(prefix, '').split(' ').filter((str) => str.length);
@ -82,9 +82,16 @@ class Parser extends EventEmitter {
const command = this.matchCommand(commandName); const command = this.matchCommand(commandName);
if (!command) return null; if (!command) return null;
if (commandFilter && typeof commandFilter === 'function' && await commandFilter(command)) return null;
this.debug(`Matched command ${command.name}`); this.debug(`Matched command ${command.name}`);
if (commandFilter && typeof commandFilter === 'function') {
const result = await commandFilter(command);
if (result) {
this.debug(`Ignoring command ${command.name}`);
return null;
}
}
const { subcommands, subcommandGroups } = command; const { subcommands, subcommandGroups } = command;
const args: ArgsResult = {}; const args: ArgsResult = {};
const parseResult: ParseResult = { args, command, subcommand: null, subcommandGroup: null }; const parseResult: ParseResult = { args, command, subcommand: null, subcommandGroup: null };

View File

@ -44,7 +44,7 @@ class CommandOption implements ICommandOption {
private resolver?: IResolver<unknown, unknown, unknown, unknown, unknown>|undefined = undefined; private resolver?: IResolver<unknown, unknown, unknown, unknown, unknown>|undefined = undefined;
constructor(def: CommandOptionDefinition|ICommandOption) { constructor(def: CommandOptionDefinition|CommandOption|ICommandOption) {
this.name = def.name; this.name = def.name;
this.aliases = def.aliases || []; this.aliases = def.aliases || [];
@ -101,6 +101,46 @@ class CommandOption implements ICommandOption {
return { value: member, removed: this.rawValue }; return { value: member, removed: this.rawValue };
} }
protected STRING() {
if (!this.rawValue) return { error: true };
if (this.aliased) return { value: this.rawValue.join(' '), removed: [] };
if (this.choices.length) {
const found = this.choices.find((c) => {
const choice = c as string;
return choice.toLowerCase() === this.rawValue?.join(' ').toLowerCase();
});
if (found) return { value: found, removed: this.rawValue };
return { error: true };
}
return { value: this.rawValue.join(' '), removed: this.rawValue };
}
protected INTEGER() {
if (!this.rawValue) return { error: true };
const integer = parseInt(this.rawValue[0]);
if(isNaN(integer)) return { error: true };
if (this.minimum !== undefined && integer < this.minimum) return { error: true };
if (this.maximum !== undefined && integer > this.maximum) return { error: true };
return { value: integer, removed: [this.rawValue[0]] };
}
protected FLOAT() {
if (!this.rawValue) return { error: true };
const float = parseFloat(this.rawValue[0]);
if(isNaN(float)) return { error: true };
if (this.minimum !== undefined && float < this.minimum) return { error: true };
if (this.maximum !== undefined && float > this.maximum) return { error: true };
return { value: (float), removed: [this.rawValue[0]] };
}
protected BOOLEAN() {
if (!this.rawValue) return { error: true };
const boolean = this.resolver?.resolveBoolean(this.rawValue[0]) || null;
if (boolean === null && this.valueOptional) return { value: this.defaultValue, removed: [] };
else if(boolean === null) return { error: true };
return { value: boolean, removed: [this.rawValue[0]] };
}
} }
export { CommandOption }; export { CommandOption };

View File

@ -0,0 +1,24 @@
const { Parser, Command, CommandOption, OptionType } = require('../build/index');
const opt = new CommandOption({
name: 'text',
type: OptionType.STRING
});
class TestCommand extends Command {
constructor() {
super({
name: 'test',
options: [opt]
})
}
};
const parser = new Parser({
commands: [new TestCommand()],
resolver: null
});
(async () => {
const parsed = await parser.parseMessage('test message.author')
console.log(parsed)
})();