prefix-parser
v1.0.8
Published
The easiest way to parse and validate Discord prefix commands
Downloads
1
Maintainers
Readme
¡Discord Prefix Parser!
Easily parse and validate prefix commands in Discord
Features
👀 Parse messages into JS variables
- 👩💻
.parse('!rate @kangabru 10 Kang is pog --public')
- 🤖
>> ['72657579', 10, 'Kang is pog', true]
- 👩💻
👮♂️ Validate inputs
- 👩💻
.parse('!rate @kangabru 100 Kang is pog --public')
- 🤖
>> "Rating value '100' cannot be greater than '10'"
- 👩💻
🧠 Automatic command help
👩💻
.parse('!rate --help')
🤖
!rate
Rate your friends!Usage:
!rate
User {@user}
Rating {int} {0-10}
Reason {text}
Is Public {-p/--public}
Example:
!rate @user 6 lorem ipsum --public
🚀 Get started
Using node or discord.js? Install with:
npm i prefix-parser
Using Autocode? Install with:
const prefix = require('prefix-parser')
A green 'Installed Dependency' should popup to confirm the installation
📚 Usage
Create commands in 3 simple steps:
1. Create the command
const prefix = require('prefix-parser')
const command = prefix("!rate", "Rate your friends!")
.user('User')
.int('Rating', { min: 0, max: 10 })
.text('Reason')
.flag('Is Public', '--public')
2. Parse a message
const content = '!rate @kangabru 10 Kang is pog --public' // use 'message.content' in prod
const [args, infoOrError] = command.parse(content)
console.log(args) // ['72657579', 10, 'Kang is pog', true]
console.log(infoOrError) // null
3. Handle results
if (infoOrError)
{
// Send `infoOrError` as a message back to Discord.
// It's populated for --help and errors otherwise 'null'
sendMessage(infoOrError);
}
else if (args)
{
// Your command logic goes here
// It's populated when parsed successfully otherwise 'null'
handleRateCommand(args);
}
All together:
Combining steps 1-3 looks like this:
const prefix = require('prefix-parser')
const content = '!rate @kangabru 10 Kang is pog --public' // use 'message.content' in prod
const [args, infoOrError] = prefix("!rate")
.user('User')
.int('Rating', { min: 0, max: 10 })
.text('Reason')
.flag('Is Public', '--public')
.parse(content)
if (infoOrError)
{
// Send `infoOrError` as a message back to Discord.
sendMessage(infoOrError);
}
else if (args)
{
// Your command logic goes here
handleRateCommand(args); // ['72657579', 10, 'Kang is pog', true]
}
const prefix = require('prefix-parser')
client.on('messageCreate', message => {
const [args, infoOrError] = prefix("!rate", , "Rate your friends!")
.user('User')
.int('Rating', { min: 0, max: 10 })
.text('Reason')
.flag('Is Public', '--public')
.parse(message.content)
if (infoOrError) {
return message.channel.send(infoOrError)
}
else if (args) {
return handleRateCommand(args) // Replace with Rate command logic
}
// Handle other commands below...
})
Endpoint: message.create
const lib = require('lib')({token: process.env.STDLIB_SECRET_TOKEN});
const prefix = require('prefix-parser')
const { channel_id, content } = context.params.event;
const [args, infoOrError] = prefix("!rate", "Rate your friends!")
.user('User')
.int('Rating', { min: 0, max: 10 })
.text('Reason')
.flag('Is Public', '--public')
.parse(content)
if (infoOrError) {
return lib.discord.channels['@0.1.2'].messages.create({ channel_id, content: infoOrError })
}
else if (args) {
return handleRateCommand(args) // Replace with Rate command logic
}
// Handle other commands below...
Explained: args
These are the parsed arguments (args) for the command the user entered.
- It's always an array
[...]
of values when parsing was successful andnull
otherwise. - Args are returned in the same order they were defined in code.
- Args are validated so the user can only enter valid values.
- Arg values are returned as a suitable JS value. E.g.
int
andfloat
args return numbers.
const [args, infoOrError] = command.parse('!rate @kangabru 10 Kang is pog --public')
console.log(args) // ['72657579', 10, 'Kang is pog', true]
Explained: infoOrError
This is a descriptive message that should be shown to the end user.
- It's always a string
"..."
if an info or error occurred andnull
otherwise. - Info about the command is returned if
-h
or--help
was used on the command. - An error is returned if the user didn't use the command correctly. Args are automatically validated and users get descriptive messages about them. Errors are user friendly and render nicely in Discord.
const [args, infoOrError] = command.parse('!rate @kangabru 10') // Omit 'reason'
console.log(infoOrError) // 'Reason' not found
Explained: --help
All commands include a help flag -h
or --help
which explain what the command is and the arguments it accepts.
const [args, infoOrError] = command.parse('!rate --help')
console.log(infoOrError) // !rate <User {@user}> <Rating {int 0~10}> <Reason {text}> <Is Public {--public}>
📖 Examples
Here are some real world examples to showcase the various features.
Purge
Uses: int
// !purge 25
const [args, infoOrError] = prefix("!purge")
.int('Messages')
.parse(content)
const [messageCount] = args // [25]
Slap
Uses: user
// -slap @user
const [args, infoOrError] = prefix("-slap")
.user('User')
.parse(content)
const [user] = args // ['12345']
Math
Uses: rest
// *math 2+2
const [args, infoOrError] = prefix("*math")
.rest('Equation')
.parse(content)
const [equation] = args // ['2+2']
Giveaway
Uses: int
rest
// %giveaway 60 Win a jetski! 🚤
const [args, infoOrError] = prefix("%giveaway")
.int('Seconds', { min: 20, max: 300 }) // 20s - 5mins
.rest('Prize')
.parse(content)
const [seconds, prize] = args // [60, 'Win a jetski! 🚤']
Assign
Uses: user
role
// >assign @user @role
const [args, infoOrError] = prefix(">assign")
.user('User')
.role('Role')
.parse(content)
const [user, role] = args // ['12345', '12345']
Announce
Uses: channel
text
// !announce #announcements I love you all!
const [args, infoOrError] = prefix("!announce")
.channel('Post to')
.text('Message')
.parse(content)
const [channel, message] = args // ['12345', 'I love you all']
Invite
Uses: words
regex
// !invite Elon Musk [email protected]
const [args, infoOrError] = prefix("!invite")
.words('Name', 2)
.regex('Email', /\w+@\w+\.\w+/, '[email protected]')
.parse(content)
const [name, email] = args // ['Elon Musk', '[email protected]']
ASL
Uses: int
word
text
// ?asl 18 f Cali
const [args, infoOrError] = prefix("?asl")
.int('Age')
.word('Gender')
.text('Location')
.parse(content)
const [age, gender, location] = args // [18, 'f', 'Cali']
Remind
Uses: channel
int
text
flag
// remind me #general 2 Organise a team game --public
const [args, infoOrError] = prefix("remind me")
.channel('Where')
.int('Days', { min: 1, max: 7 })
.text('Reminder')
.flag('Is Public', '--public')
.parse(content)
const [where, days, reminder, isPublic] = args // ['12345', 2, 'Organise a team game', 'true']
Mute
Uses: user
text
channel
int
// !mute @user Talking too fast #mute-jail 15
const [args, infoOrError] = prefix("!mute")
.user('Where')
.text('Reason')
.channel('Jail')
.int('Hours')
.parse(content)
const [where, reason, channel, days] = args // ['12345', 'Talking too fast', '12345', 15]
Send $
Uses: user
, float
, regex
, rest
// $send @user 123.45 doge_01 Buying 100 dogecoins
const [args, infoOrError] = prefix("$send")
.user('Vendor')
.float('Amount')
.regex('Item ID', /\w{4}_\d{2}/, 'abcd_01')
.rest('Notes')
.parse(content)
const [vendor, amount, itemId, notes] = args // ['12345', 123.45, 'doge_01', 'Buying 100 dogecoins']
⚡ Arguments
Arguments are the building blocks that give your commands power. Here's every single one of them and how you can make your own.
Note that every argument must specify a name
(string) as the first argument to be used in help and error messages.
Words
Match 1 or more words that include characters a-z
, 0-9
, and _
.
word(name)
matches 1 word onlywords(name, words=1)
matches 1 or more words
Returns string
const cmd = prefix('!cmd')
const msg = '!cmd this is a sentence'
cmd.word('Word').parse(msg) // >> ['this']
cmd.words('Words', 2).parse(msg) // >> ['this is']
cmd.words('Words', 5).parse(msg) // >> Error: There are only 4 words
Text
Match text within or at the end of the command:
text(name)
will look for as much text as it can that include charactersa-z
,space
, and_
.rest(name)
will match all remaining text and must be the last argument.
Returns string
const cmd = prefix('!cmd')
const msg = '!cmd Pigs can fly. Monkeys cannot.'
cmd.text('Text').parse(msg) // >> ['Pigs can fly']
cmd.rest('Rest').parse(msg) // >> ['Pigs can fly. Monkeys cannot.']
Numbers
Match numbers like 123
and 12.34
:
int(name, options={})
will match numbers and convert them to integers.float(name, options={})
will match numbers and convert them to floats.
Options:
min
(number) - The minimum value a user can enter.max
(number) - The maximum value a user can enter.
Returns: number
const cmd = prefix('!cmd')
.int('Num 1')
.int('Num 2', { max: 100 }) // max of 100
.float('Num 3', { min: 0 }) // min of 0
cmd.parse('!cmd 8 12.34 56.78') // >> [8, 12, 56.78]
Time
Match time args like 30s
, 5m
, 2h
, 1d
, and returns the value in seconds.
time(name, options={})
will match times and convert them to seconds.
Options:
min
(string) - The minimum time a user can enter e.g.10s
max
(string) - The maximum time a user can enter e.g.2h
Returns number
Note: s=seconds, m=minutes, h=hours, d=days
const cmd = prefix('!cmd')
.time('Time 1')
.time('Time 2', { min: '5m' })
.time('Time 3', { max: '1d' })
cmd.parse('!cmd 30s 10m 2h') // >> [30, 600, 7200]
Emoji
Match emoji args like 🙂
and <:custom:789123>
.
emoji(name)
will match emojis.
Returns string
const cmd = prefix('!cmd')
.emoji('Emoji')
cmd.parse('!cmd 🔥') // >> ["🔥"]
Mentions
Match Discord mention types and extract their ID numbers.
user(name)
matches a mention like '@user' or a raw ID like '12345'.role(name)
matches a mention like '@role' or a raw ID like '12345'.channel(name)
matches a mention like '#channel' or a raw ID like '12345'.
Returns string
const cmd = prefix('!cmd')
.user('User')
.role('Role')
.channel('Channel')
// User types: !cmd @kangabru @admin #general
cmd.parse('!cmd <@12345> <@&67890> <#24680>') // >> ['12345', '67890', '24680']
Discord sends mention IDs like <@!12345> and the ID '12345' is extracted.
Flags
Match optional flags like --flag
which can be placed anywhere by the user.
flag(name, command, options={})
name
(string) The name of the argument uses in help messages.command
(string) A command like--abc
that must start with--
and have at least 3 characters.
Options:
short
(string) The short version of the command like-h
that must start with-
and have 1-3 characters.storeFalse
(boolean) Make the parser returnfalse
instead oftrue
when the flag is set by the user.
Returns boolean
const cmd = prefix('!cmd')
.flag('Allow', '--yes', { short: '-y' }) // Returns 'true' when set
.flag('Deny', '--no', { short: '-n', storeFalse: true }) // Returns 'false' when set
// When set
cmd.parse('!cmd --yes --no') // >> [true, false]
cmd.parse('!cmd -y -n') // >> [true, false]
// When unset
cmd.parse('!cmd') // >> [false, true]
Urls
Match urls.
url(name)
matches a url like www.discord.gg.
Returns string
const cmd = prefix('!cmd')
.url('Link')
cmd.parse('!cmd www.discord.gg') // >> ['www.discord.gg']
Regex
Default args not enough for you? Match custom text with regex.
regex(name, regexp, example, options={})
regexp
(RegExp) The regular expression like/\w+/
.example
(string) An example of what the regex will match. This is used in error messages and must match the regex provided or an error will be thrownm when.regex(...)
is called.
Options:
group
(number) The regex group index to return from the<text>.match(<regexp>)
call. Defaults to0
(the entire match).
Returns string
const simpleEmail = /\w+@\w+\.\w+/
const cmd = prefix('!cmd').regex('Email', simpleEmail, '[email protected]')
cmd.parse('!cmd [email protected]') // >> ['[email protected]']
cmd.parse('!cmd user.example@com') // >> Error: Email not found
Advanced: Still not enough? Create your own parser! See the various
src/
files to see how to inherit theBaseArg
and other args. You just need to implement theparse
andhelp
functions and it'll plug and play with everything nicely. Highly recommended to use Typescript to check input and return types.
❗ Prefix
The prefix
function is the starting point for defining commands. Under the hood it stores your arguments and can use them to provide cool features like the --help
function, infoOrError messages, and of course parsing values.
Use with Javascript like this:
const prefix = require('prefix-parser')
const cmd = prefix('!cmd')
Command Description
The prefix
function also accepts an optional description field which is used in the --help
command.
const cmd = prefix('!cmd', 'Best Command')
cmd.parse(`!cmd --help`) // >> `!cmd` Best Command ...
Args Fluent Interface
The easiest way to add arguments is via the fluent interface:
prefix('!cmd')
.int("Age")
.float("Height")
.text("Name")
.parse("!cmd 20 1.8 Jim Bob") // >> [20, 1.8, 'Jim Bob']
Args Array
Sick of the fluent interface or want dynamic args? Provide them via an array instead:
prefix('!cmd')
.args(...[
new IntegerArg("Age"),
new FloatArg("Height"),
new RestArg("Name"),
])
.parse("!cmd 20 1.8 Jim Bob") // >> [20, 1.8, 'Jim Bob']
💻 Development
Issues and PRs are welcome!
The quickest way to code is via a test. Follow the examples in the test/
dir and run npm run test
to run them. For even faster deving use the VSCode 'jest' extension to test automatically on code changes.
📄 About
Copyright 2021 Kangabru