Understanding Gears

Basics

Before we get started, you should know how Gears works as it will make it easier to use the library. Don't worry if you can't understand this page right away. You can come back to it after reading the other guides if you are confused.

The adapter

The ClientAdapter is what makes Gears work with any messaging interface. It works by exposing "hooks" that are called by the client when a message or any other event occurs. These hooks then trigger the internals inside a Bot which sends the message through the tree.

Here's an example of the adapter from the Discord.js bindings:

class Adapter extends ClientAdapter {
  register(options, hooks) {
    const { token, listenToSelf, ...clientOptions } = options
    const client = new Discord.Client(clientOptions)

    client.on("message", message => {
      if (client.user.id !== message.author.id || listenToSelf) {
        hooks.message(message)
      }
    })

    client.on("ready", hooks.ready)
    client.on("resume", hooks.ready)
    client.on("disconnect", hooks.unready)
    client.on("error", hooks.error)

    return {
      client,
      methods: {
        start: async () => {
          await client.login(token)
        },
        getMessageContent: (message: Message) => message.content
      }
    }
  }
}

The command tree

When you define your bot using Command and CommandGroup, you are creating a tree which will be traversed upon a message.
Here's an example:

const a = new Command()
  .match(matchPrefixes("a"))
  .use(...)

const b = new Command()
  .match(matchPrefixes("b"))
  .use(...)

const c = new Command()
  .match(matchPrefixes("c"))
  .use(...)

const group = new CommandGroup()
  .match(matchPrefixes("!"))
  .setCommands(a, b)

const bot = new Bot({ commands: [group, c] })

note

Be aware that the order is important. If for example "group" also matched on the prefix "c", the "c" command would never fire because the group is tested before it.

This example would produce the following tree:

Traversing the tree

When a message is sent, the tree is traversed. During this process, a Chain is created. A chain is a list of CommandLike along with the Context at the point it was matched. With the above example in mind, if we sent a message like "!b", the tree would get traversed like this (from left to right):

Once the tree is traversed, the generated chain looks like this:

When the chain has been generated, the middleware inside each entry in the chain will be composed and executed, which brings us to...

Middleware

Middleware in Gears is heavily inspired by Koa.js, so if you understand that, this should be easy too.

When the chain is being executed, the middleware will be sequentially executed in the order of the chain, along with its context. With our example, this means that the middleware in "group" will be executed, then "b".

Understanding how Context works in a chain is very important. When a list of middleware in a chain is executed, it is executed with the resulting context that the matcher returned at that point.

Example

Imagine that in this example, the message sent was "An interesting message".

const a = new CommandBuilder()
  .match(matchPrefix("a"))
  // The callback in .use is our middleware
  .use((context) => {
    console.log(context.content)
    // The above log would be "n interesting message"
    // because the matcher removes the prefixed word from content.
  })
Installation
Creating your first bot