npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

discord-decorated

v3.0.0

Published

- [Command decorators](#Command-Decorators) - [Dependency injection (using tsyringe)](#Dependency-Injection) - [Argument Transforming](#Argument-Transforming)

Downloads

5

Readme

Features

Installation

discord-decorated depends on discord.js tsyringe and a reflect polyfill - for the example we'll install reflect-metadata.

npm i discord-decorated discord.js tsyringe reflect-metadata
yarn add discord-decorated discord.js tsyringe reflect-metadata

Getting Started

discord-decorated seeks to make the setup for a discord bot simple, just create a DiscordClient instance - which just inherits from discord.js's Client - then assign command handlers and login!

// bot.ts
import "reflect-metadata"; // ensure to import a reflect-metadata as early as possible
import { DiscordClient } from "discord-decorated";
import { PingModule } from "./command-modules/PingModule";
import { GatewayIntentBits } from "discord.js";

const bot = new DiscordClient({
  commandPrefix: "!",
  commandModules: [PingModule],
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
    // ...
  ],
});

// DiscordClient extends Client, all discord.js methods are available
bot.on("ready", () => console.log("ready!"));

bot.login(process.env.token);
// command-modules/PingModule.ts
import { command } from "discord-decorated";
import { Message } from "discord.js";

export class PingModule {
  @command("ping")
  public async ping(msg: Message) {
    await msg.reply("pong!");
  }
}

You'll also have to modify your tsconfig.json to include the following settings

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Command Decorators

discord-decorated adds the ability to decorate class methods with command decorators allowing easier command creation / classification.

// PongModule.ts
export class PongModule {
  @command("ping")
  public async pong(message: Message) {
    return message.reply("pong!");
  }

  @command("zing")
  public async zong(message: Message) {
    return message.reply("zong!");
  }
}

A CommandModule can contain any number of commands, and the commands themselves can recieve up to two arguments: the Message, from discord.js, and the arguments, which currently are space delimited words from the original message (after the command string).

export class EchoModule {
  @command("echo")
  public async echo(message: Message, args: string[]) {
    // from discord: !echo hello world!
    // will recieve reply: hello world!

    return message.reply(args.join(" "));
  }
}

Dependency Injection

discord-decorated using tsyringe for dependency injection on it's CommandModule's and should work out of the box after following the install instructions.

// use tsyringe's decorators
@injectable()
export class DependentModule {
  // dbService injected through constructor using tsyringe
  constructor(private readonly dbService: DbService) {}

  @command("getSomeData")
  public async getSomeData(msg: Message) {
    // use dbService to grab some data and send it to the discord chat
    const data = await this.dbService.getData();

    return msg.reply(data.toString());
  }
}

Argument Transforming

discord-decorated comes with two built in argument transformers by default, the ParseNumberTransformer and the ParseIntTransformer which takes the string arguments from discord and parse them numbers / integers.

export class ParserModule {
  // pass the transformer in to the command annotation
  @command("parse-numbers", new ParseNumberTransformer())
  public async parse(message: Message, args: number[]) {
    // args will be an array of numbers
    console.log(args);
  }
}

You can easily create your own transformers by creating a class that implements the ITransformer interface from discord-decorated

import { ITransformer } from "discord-decorated";

// customer transformer which takes the arguments and converts them to caps
export class MyTransformer implements ITransformer<string> {
  // ITransformer requires a Promise returning an array of the desired transformed type
  async transform(args: string[]): Promise<string[]> {
    // simply transform each argument to uppercase
    return args.map((arg) => arg.toUpperCase());
  }
}
export class MyCommandModule {
  // pass the transformer in to the command annotation
  @command("transform", new MyTransformer())
  public async transform(message: Message, args: number[]) {
    // from discord: ["hello"]

    // args == ["HELLO"]
    console.log(args);
  }
}

To exit a transformer's parse method, in case parsing has failed, just throw an error and the command will not be run.

import { ITransformer } from "discord-decorated";

export class DisallowTheNumberOne implements ITransformer<number> {
  async transform(args: string[]): Promise<number[]> {
    return args.map((arg) => {
      const arg = parseFloat(arg);

      // if a user sends 1 in to the command, it will not be run!
      if (arg === 1) throw new Error();

      return arg;
    });
  }
}

Command Registration

After creating command modules you can register them to the DiscordClient by passing their constructors to the DiscordClientOptions:

const client = new DiscordClient({
  // ...
  commandModules: [PongModule, EchoModule, DependentModule],
  // ...
});

client.login(token);