From 855609bc8ce04808dc25146952f6afbbc2fd85ce Mon Sep 17 00:00:00 2001 From: Avraj Sahota Date: Fri, 2 Feb 2024 09:10:51 +0300 Subject: [PATCH] style(prettier): update config and reformat codebase --- .github/workflows/deploy-dev-build.yaml | 110 ++-- .github/workflows/lint.yaml | 42 +- .github/workflows/publish.yaml | 44 +- .prettierignore | 6 + .prettierrc.json | 8 +- CHANGELOG.md | 28 +- CONTRIBUTING.md | 8 +- apps/docs/next.config.js | 4 +- apps/docs/package.json | 44 +- apps/docs/pages/_app.mdx | 16 +- apps/docs/pages/_meta.json | 24 +- apps/docs/pages/docs/_meta.json | 6 +- apps/docs/pages/docs/classes/CommandKit.mdx | 22 +- apps/docs/pages/docs/classes/_meta.json | 4 +- .../docs/classes/components/ButtonKit.mdx | 36 +- .../pages/docs/classes/components/_meta.json | 2 +- apps/docs/pages/docs/enums/ReloadType.mdx | 4 +- apps/docs/pages/docs/enums/_meta.json | 2 +- .../pages/docs/typedef/AutocompleteProps.mdx | 6 +- ...tonBuilderInteractionCollectorDispatch.mdx | 4 +- ...nteractionCollectorDispatchContextData.mdx | 6 +- .../typedef/CommandKitButtonBuilderOnEnd.mdx | 2 +- .../docs/pages/docs/typedef/CommandObject.mdx | 8 +- .../pages/docs/typedef/CommandOptions.mdx | 8 +- .../docs/typedef/ContextMenuCommandProps.mdx | 6 +- .../pages/docs/typedef/SlashCommandProps.mdx | 6 +- .../pages/docs/typedef/ValidationProps.mdx | 8 +- apps/docs/pages/docs/typedef/_meta.json | 20 +- apps/docs/pages/guide/_meta.json | 22 +- apps/docs/pages/guide/buttonkit.mdx | 107 ++-- apps/docs/pages/guide/command-file-setup.mdx | 12 +- apps/docs/pages/guide/commandkit-config.mdx | 70 +-- apps/docs/pages/guide/commandkit-setup.mdx | 24 +- apps/docs/pages/guide/create-commandkit.mdx | 8 +- apps/docs/pages/guide/installation.mdx | 42 +- .../guide/migrating-from-djs-commander.mdx | 83 +-- apps/docs/pages/guide/using-cli.mdx | 11 +- .../pages/guide/validation-file-setup.mdx | 12 +- apps/docs/postcss.config.js | 8 +- apps/docs/tailwind.config.ts | 20 +- apps/docs/theme.config.tsx | 138 ++--- apps/docs/tsconfig.json | 40 +- package.json | 34 +- packages/commandkit/package.json | 134 ++--- packages/commandkit/spec/main.spec.ts | 6 +- packages/commandkit/src/CommandKit.ts | 322 +++++------ packages/commandkit/src/bootstrap/client.ts | 20 +- packages/commandkit/src/bootstrap/loadEnv.ts | 6 +- .../commandkit/src/components/ButtonKit.ts | 277 +++++----- packages/commandkit/src/config.ts | 133 ++--- .../src/environment/actions/development.ts | 90 +-- .../src/environment/bundler/bundle.ts | 56 +- .../src/environment/bundler/shims.ts | 99 ++-- packages/commandkit/src/environment/cli.ts | 54 +- .../src/environment/common/config.ts | 22 +- .../src/environment/common/logger.ts | 32 +- .../command-handler/CommandHandler.ts | 511 +++++++++--------- .../functions/loadCommandsWithRest.ts | 252 +++++---- .../functions/registerCommands.ts | 412 +++++++------- .../src/handlers/command-handler/typings.ts | 166 +++--- .../utils/areSlashCommandsDifferent.ts | 25 +- .../command-handler/validations/devOnly.ts | 66 ++- .../validations/permissions.ts | 146 ++--- .../handlers/event-handler/EventHandler.ts | 164 +++--- .../src/handlers/event-handler/typings.ts | 8 +- .../validation-handler/ValidationHandler.ts | 139 ++--- .../handlers/validation-handler/typings.ts | 4 +- packages/commandkit/src/hooks/common.ts | 26 +- packages/commandkit/src/hooks/response.ts | 34 +- packages/commandkit/src/hooks/useChannel.ts | 6 +- packages/commandkit/src/hooks/useClient.ts | 2 +- .../commandkit/src/hooks/useCommandData.ts | 6 +- .../commandkit/src/hooks/useCommandKit.ts | 6 +- packages/commandkit/src/hooks/useGuild.ts | 6 +- .../commandkit/src/hooks/useInteraction.ts | 10 +- packages/commandkit/src/hooks/useMember.ts | 6 +- packages/commandkit/src/hooks/useUser.ts | 6 +- packages/commandkit/src/types/index.ts | 282 +++++----- packages/commandkit/src/typings.ts | 156 +++--- packages/commandkit/src/utils/colors.ts | 46 +- packages/commandkit/src/utils/get-paths.ts | 61 ++- .../commandkit/src/utils/resolve-file-url.ts | 4 +- packages/commandkit/src/utils/signal.ts | 74 +-- packages/commandkit/tests/commandkit.mjs | 8 +- packages/commandkit/tests/src/client.ts | 14 +- .../tests/src/commands/misc/count.ts | 108 ++-- .../tests/src/commands/misc/giveaway.ts | 70 +-- .../tests/src/commands/misc/ping.ts | 110 ++-- .../tests/src/commands/misc/reload.ts | 30 +- .../tests/src/events/messageCreate/say-hi.ts | 6 +- .../tests/src/events/ready/console-log.ts | 2 +- .../tests/src/validations/devOnly.ts | 16 +- packages/commandkit/tsconfig.json | 16 +- packages/commandkit/tsup.config.ts | 24 +- packages/commandkit/vitest.config.ts | 10 +- packages/create-commandkit/package.json | 92 ++-- .../src/functions/copyTemplates.ts | 8 +- .../src/functions/installDeps.ts | 20 +- .../create-commandkit/src/functions/setup.ts | 48 +- packages/create-commandkit/src/index.ts | 74 +-- packages/create-commandkit/src/utils.ts | 46 +- .../templates/JavaScript/cjs/commandkit.cjs | 4 +- .../cjs/src/commands/General/ping.js | 30 +- .../JavaScript/cjs/src/events/ready/ready.js | 2 +- .../templates/JavaScript/cjs/src/index.js | 18 +- .../templates/JavaScript/esm/commandkit.mjs | 4 +- .../esm/src/commands/General/ping.js | 8 +- .../JavaScript/esm/src/events/ready/ready.js | 2 +- .../templates/JavaScript/esm/src/index.js | 18 +- packages/create-commandkit/tsconfig.json | 16 +- packages/create-commandkit/tsup.config.ts | 22 +- packages/tsconfig/base.json | 26 +- packages/tsconfig/package.json | 8 +- pnpm-workspace.yaml | 4 +- turbo.json | 20 +- 115 files changed, 3058 insertions(+), 2816 deletions(-) diff --git a/.github/workflows/deploy-dev-build.yaml b/.github/workflows/deploy-dev-build.yaml index d648e82..59acbcf 100644 --- a/.github/workflows/deploy-dev-build.yaml +++ b/.github/workflows/deploy-dev-build.yaml @@ -1,60 +1,60 @@ name: Publish Dev Build on: - push: - branches: - - master - paths: - - 'packages/commandkit/**' + push: + branches: + - master + paths: + - 'packages/commandkit/**' jobs: - release: - name: 🚀 Publish Dev Build - runs-on: ubuntu-latest - steps: - - uses: pnpm/action-setup@v2 - with: - version: 8 - - - name: 📚 Checkout - uses: actions/checkout@v3 - - - name: 🟢 Node - uses: actions/setup-node@v2 - with: - node-version: 18 - registry-url: https://registry.npmjs.org - - - name: 🍳 Prepare - run: pnpm install - - - name: 🔢 Update Version - run: | - cd packages/commandkit - node -e "const pkg = require('./package.json'); \ - const newVersion = pkg.version + '-dev.' + new Date().toISOString().replace(/[:\-T]/g, '').substr(0,14); \ - pkg.version = newVersion; \ - require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));" - env: - DEBIAN_FRONTEND: noninteractive - - - name: 🚚 Publish - run: pnpm run deploy:package-dev - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} - - - name: 🚫 Deprecate Previous Dev Version - run: | - PACKAGE_NAME=$(node -e "console.log(require('./packages/commandkit/package.json').name);") - ALL_VERSIONS=$(npm info $PACKAGE_NAME versions -json) - VERSION_TO_DEPRECATE=$(echo $ALL_VERSIONS | node -e " - const versions = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf-8')); - const devVersions = versions.filter(v => v.includes('-dev.')); - const versionToDeprecate = devVersions[devVersions.length - 2]; - console.log(versionToDeprecate); - ") - echo Deprecating version $VERSION_TO_DEPRECATE - npm deprecate $PACKAGE_NAME@$VERSION_TO_DEPRECATE "Deprecated dev version." - - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} + release: + name: 🚀 Publish Dev Build + runs-on: ubuntu-latest + steps: + - uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: 📚 Checkout + uses: actions/checkout@v3 + + - name: 🟢 Node + uses: actions/setup-node@v2 + with: + node-version: 18 + registry-url: https://registry.npmjs.org + + - name: 🍳 Prepare + run: pnpm install + + - name: 🔢 Update Version + run: | + cd packages/commandkit + node -e "const pkg = require('./package.json'); \ + const newVersion = pkg.version + '-dev.' + new Date().toISOString().replace(/[:\-T]/g, '').substr(0,14); \ + pkg.version = newVersion; \ + require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));" + env: + DEBIAN_FRONTEND: noninteractive + + - name: 🚚 Publish + run: pnpm run deploy:package-dev + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} + + - name: 🚫 Deprecate Previous Dev Version + run: | + PACKAGE_NAME=$(node -e "console.log(require('./packages/commandkit/package.json').name);") + ALL_VERSIONS=$(npm info $PACKAGE_NAME versions -json) + VERSION_TO_DEPRECATE=$(echo $ALL_VERSIONS | node -e " + const versions = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf-8')); + const devVersions = versions.filter(v => v.includes('-dev.')); + const versionToDeprecate = devVersions[devVersions.length - 2]; + console.log(versionToDeprecate); + ") + echo Deprecating version $VERSION_TO_DEPRECATE + npm deprecate $PACKAGE_NAME@$VERSION_TO_DEPRECATE "Deprecated dev version." + + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 5e47f6c..02a9f58 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,30 +1,30 @@ name: Lint on: - push: - branches: - - '**' + push: + branches: + - '**' jobs: - build: - name: 🔍 Lint - runs-on: ubuntu-latest - steps: - - uses: pnpm/action-setup@v2 - with: - version: 8 + build: + name: 🔍 Lint + runs-on: ubuntu-latest + steps: + - uses: pnpm/action-setup@v2 + with: + version: 8 - - name: 📚 Checkout - uses: actions/checkout@v3 + - name: 📚 Checkout + uses: actions/checkout@v3 - - name: 🟢 Node - uses: actions/setup-node@v2 - with: - node-version: 16 - registry-url: https://registry.npmjs.org + - name: 🟢 Node + uses: actions/setup-node@v2 + with: + node-version: 16 + registry-url: https://registry.npmjs.org - - name: 🍳 Prepare - run: pnpm install + - name: 🍳 Prepare + run: pnpm install - - name: ✨ Lint - run: pnpm lint + - name: ✨ Lint + run: pnpm lint diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 8adfe7c..0672603 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -1,31 +1,31 @@ name: Publish to NPM on: - release: - types: [created] + release: + types: [created] jobs: - release: - name: 🚀 Publish - runs-on: ubuntu-latest - steps: - - uses: pnpm/action-setup@v2 - with: - version: 8 + release: + name: 🚀 Publish + runs-on: ubuntu-latest + steps: + - uses: pnpm/action-setup@v2 + with: + version: 8 - - name: 📚 Checkout - uses: actions/checkout@v3 + - name: 📚 Checkout + uses: actions/checkout@v3 - - name: 🟢 Node - uses: actions/setup-node@v2 - with: - node-version: 16 - registry-url: https://registry.npmjs.org + - name: 🟢 Node + uses: actions/setup-node@v2 + with: + node-version: 16 + registry-url: https://registry.npmjs.org - - name: 🍳 Prepare - run: pnpm install + - name: 🍳 Prepare + run: pnpm install - - name: 🚚 Publish - run: pnpm run deploy:package - env: - NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} + - name: 🚚 Publish + run: pnpm run deploy:package + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}} diff --git a/.prettierignore b/.prettierignore index 68a7ad2..d91fa10 100644 --- a/.prettierignore +++ b/.prettierignore @@ -18,3 +18,9 @@ pnpm-debug.log* .env .env.production +.env.* + +.gitignore +.npmignore + +turbo-lint.log \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json index 029b0d4..ee7a020 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,6 +1,6 @@ { - "printWidth": 100, - "tabWidth": 4, - "singleQuote": true, - "arrowParens": "always" + "printWidth": 80, + "tabWidth": 2, + "singleQuote": true, + "arrowParens": "always" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b4694bb..8054f1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,45 +6,45 @@ All notable changes to this project will be documented in this file. ### Fixed -- CommonJS projects crash when using commandkit cli with watch mode. +- CommonJS projects crash when using commandkit cli with watch mode. ### Added -- add `onEnd` to ButtonKit +- add `onEnd` to ButtonKit ## [0.1.9] - 2023-12-12 ### Changes (breaking) -- Update `ValidationFunctionProps` type name to `ValidationProps`. -- Update `autocompleteRun` command function name to `autocomplete`. -- Update `AutocompleteCommandProps` type name to `AutocompleteProps`. +- Update `ValidationFunctionProps` type name to `ValidationProps`. +- Update `autocompleteRun` command function name to `autocomplete`. +- Update `AutocompleteCommandProps` type name to `AutocompleteProps`. ### Deprecated -- `guildOnly` in command options. CommandKit no longer handles the `guildOnly` condition. Use `dm_permission` in your command `data` object instead. +- `guildOnly` in command options. CommandKit no longer handles the `guildOnly` condition. Use `dm_permission` in your command `data` object instead. ### Fixed -- Broken docs links. +- Broken docs links. ### Added -- `ValidationProps` type definition. +- `ValidationProps` type definition. ## [0.1.10 - dev] - 2023-12-29 ### Fixed -- Typos during command load/reload in specific guild (REST). +- Typos during command load/reload in specific guild (REST). ### Changed -- Use `process.emitWarning()` for warnings instead of regular console logs. -- Throw an error if a global command registration/deletion fails instead of just logging (for legacy command registation). +- Use `process.emitWarning()` for warnings instead of regular console logs. +- Throw an error if a global command registration/deletion fails instead of just logging (for legacy command registation). ### Removed -- `guildOnly` from docs examples. Closes [#42](https://github.com/underctrl-io/commandkit/issues/42) -- `guildOnly` deprecation warning. -- Emojis from logs, warnings, and errors. +- `guildOnly` from docs examples. Closes [#42](https://github.com/underctrl-io/commandkit/issues/42) +- `guildOnly` deprecation warning. +- Emojis from logs, warnings, and errors. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40ac0a8..db480ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,8 +7,8 @@ Firstly, thank you for considering contributing to CommandKit! Whether you're lo ### Prerequisites 1. Ensure you have `Node.js` and `pnpm` installed. - - Node.js: [Download here](https://nodejs.org/) - - pnpm: Install via `npm install -g pnpm` if you haven't. + - Node.js: [Download here](https://nodejs.org/) + - pnpm: Install via `npm install -g pnpm` if you haven't. ### Fork & Clone @@ -40,8 +40,8 @@ git checkout -b your-feature-or-bugfix 3. Ensure that your changes don't break any existing functionality. You can test the functionality of your code depending on where you've made changes: - 1. If you've made changes to the CommandKit package, you can use the "tests" folder in the "packages/commandkit" directory to test your own bot. Just make sure to create a new `.env` file with the template from the `.env.example` file provided. You can run the application using `pnpm test`. - 2. If you've made changes to the docs, you can run `pnpm dev` inside "apps/docs" to spin up a local development server. + 1. If you've made changes to the CommandKit package, you can use the "tests" folder in the "packages/commandkit" directory to test your own bot. Just make sure to create a new `.env` file with the template from the `.env.example` file provided. You can run the application using `pnpm test`. + 2. If you've made changes to the docs, you can run `pnpm dev` inside "apps/docs" to spin up a local development server. 4. Run `pnpm lint` from the root directory to ensure all lint scripts and formatting is valid. diff --git a/apps/docs/next.config.js b/apps/docs/next.config.js index 6a33f84..f6ab2b8 100644 --- a/apps/docs/next.config.js +++ b/apps/docs/next.config.js @@ -1,6 +1,6 @@ const withNextra = require('nextra')({ - theme: 'nextra-theme-docs', - themeConfig: './theme.config.tsx', + theme: 'nextra-theme-docs', + themeConfig: './theme.config.tsx', }); module.exports = withNextra(); diff --git a/apps/docs/package.json b/apps/docs/package.json index 9e8db91..1d48ff1 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -1,24 +1,24 @@ { - "name": "commandkit-docs", - "version": "0.0.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start" - }, - "dependencies": { - "@types/node": "^20.11.6", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "autoprefixer": "^10.4.17", - "next": "^14.1.0", - "nextra": "^2.13.2", - "nextra-theme-docs": "^2.13.2", - "postcss": "^8.4.33", - "react": "18.2.0", - "react-dom": "18.2.0", - "tailwindcss": "^3.4.1", - "typescript": "^5.3.3" - } + "name": "commandkit-docs", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "@types/node": "^20.11.6", + "@types/react": "^18.2.48", + "@types/react-dom": "^18.2.18", + "autoprefixer": "^10.4.17", + "next": "^14.1.0", + "nextra": "^2.13.2", + "nextra-theme-docs": "^2.13.2", + "postcss": "^8.4.33", + "react": "18.2.0", + "react-dom": "18.2.0", + "tailwindcss": "^3.4.1", + "typescript": "^5.3.3" + } } diff --git a/apps/docs/pages/_app.mdx b/apps/docs/pages/_app.mdx index 10f86a8..64a3e7a 100644 --- a/apps/docs/pages/_app.mdx +++ b/apps/docs/pages/_app.mdx @@ -2,12 +2,12 @@ import '../styles/globals.css'; import Head from 'next/head'; export default function Nextra({ Component, pageProps }) { - return ( - <> - - - - - - ); + return ( + <> + + + + + + ); } diff --git a/apps/docs/pages/_meta.json b/apps/docs/pages/_meta.json index 78a8086..0e2b2c4 100644 --- a/apps/docs/pages/_meta.json +++ b/apps/docs/pages/_meta.json @@ -1,14 +1,14 @@ { - "index": { - "title": "Home", - "type": "page" - }, - "guide": { - "title": "Guide", - "type": "page" - }, - "docs": { - "title": "Documentation", - "type": "page" - } + "index": { + "title": "Home", + "type": "page" + }, + "guide": { + "title": "Guide", + "type": "page" + }, + "docs": { + "title": "Documentation", + "type": "page" + } } diff --git a/apps/docs/pages/docs/_meta.json b/apps/docs/pages/docs/_meta.json index 744435e..abe4125 100644 --- a/apps/docs/pages/docs/_meta.json +++ b/apps/docs/pages/docs/_meta.json @@ -1,5 +1,5 @@ { - "classes": "Classes", - "enums": "Enums", - "typedef": "Types" + "classes": "Classes", + "enums": "Enums", + "typedef": "Types" } diff --git a/apps/docs/pages/docs/classes/CommandKit.mdx b/apps/docs/pages/docs/classes/CommandKit.mdx index 19e607d..b7e094b 100644 --- a/apps/docs/pages/docs/classes/CommandKit.mdx +++ b/apps/docs/pages/docs/classes/CommandKit.mdx @@ -2,61 +2,61 @@ ### `commands` -- Type: [`CommandObject[]`](/typedef/CommandObject) +- Type: [`CommandObject[]`](/typedef/CommandObject) An array of all the command objects that CommandKit is handling. This includes all the properties and methods that are also set outside of CommandKit's configuration. It does however not include the `run` method since CommandKit handles that internally. ### `commandsPath` -- Type: `string` | `undefined` +- Type: `string` | `undefined` The path to the commands directory which was set when [instantiating CommandKit](/docs/commandkit-setup). ### `eventsPath` -- Type: `string` | `undefined` +- Type: `string` | `undefined` The path to the events directory which was set when [instantiating CommandKit](/docs/commandkit-setup). ### `validationsPath` -- Type: `string` | `undefined` +- Type: `string` | `undefined` The path to the validations directory which was set when [instantiating CommandKit](/docs/commandkit-setup). ### `devUserIds` -- Type: `string[]` +- Type: `string[]` The array of developer user IDs which was set when [instantiating CommandKit](/docs/commandkit-setup). ### `devGuildIds` -- Type: `string[]` +- Type: `string[]` The array of development server IDs which was set when [instantiating CommandKit](/docs/commandkit-setup). ### `devRoleIds` -- Type: `string[]` +- Type: `string[]` The array of developer role IDs which was set when [instantiating CommandKit](/docs/commandkit-setup). ### `reloadCommands` -- Props type: `'dev'` | `'global'` | [`ReloadType`](/enums/ReloadType) (optional) -- Return type: `Promise` +- Props type: `'dev'` | `'global'` | [`ReloadType`](/enums/ReloadType) (optional) +- Return type: `Promise` Reloads application commands. Using "dev" will only reload commands marked with `devOnly`, and using "global" will do the opposite. Not passing in a property will reload both dev and global commands. The reload behaviour depends on [`bulkRegister`](/docs/commandkit-setup#bulkregister-optional). ### `reloadEvents` -- Return type: `Promise` +- Return type: `Promise` Resets and reloads application events. ### `reloadValidations` -- Return type: `Promise` +- Return type: `Promise` Reloads application commands validations. diff --git a/apps/docs/pages/docs/classes/_meta.json b/apps/docs/pages/docs/classes/_meta.json index c4d2f81..75ef68f 100644 --- a/apps/docs/pages/docs/classes/_meta.json +++ b/apps/docs/pages/docs/classes/_meta.json @@ -1,4 +1,4 @@ { - "CommandKit": "CommandKit", - "components": "Components" + "CommandKit": "CommandKit", + "components": "Components" } diff --git a/apps/docs/pages/docs/classes/components/ButtonKit.mdx b/apps/docs/pages/docs/classes/components/ButtonKit.mdx index 3149e01..d0a7951 100644 --- a/apps/docs/pages/docs/classes/components/ButtonKit.mdx +++ b/apps/docs/pages/docs/classes/components/ButtonKit.mdx @@ -3,17 +3,17 @@ import { Callout } from 'nextra/components'; # ButtonKit - ButtonKit extends the - [ButtonBuilder](https://discord.js.org/docs/packages/discord.js/main/ButtonBuilder:Class) class, - provided by discord.js. + ButtonKit extends the + [ButtonBuilder](https://discord.js.org/docs/packages/discord.js/main/ButtonBuilder:Class) + class, provided by discord.js. ### `onClick` -- Return type: `ButtonKit` -- Arguments: - - handler: [`CommandKitButtonBuilderInteractionCollectorDispatch`](/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch) - - data?: [`CommandKitButtonBuilderInteractionCollectorDispatchContextData`](/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch) | `undefined` +- Return type: `ButtonKit` +- Arguments: + - handler: [`CommandKitButtonBuilderInteractionCollectorDispatch`](/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch) + - data?: [`CommandKitButtonBuilderInteractionCollectorDispatchContextData`](/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch) | `undefined` Sets up an inline interaction collector for this button. This collector by default allows as many interactions as possible if it is actively used. If unused, this expires after 24 hours or custom time if specified. @@ -21,22 +21,22 @@ Sets up an inline interaction collector for this button. This collector by defau ```ts const button = new ButtonKit() - .setLabel('Click me') - .setStyle(ButtonStyle.Primary) - .setCustomId('click_me'); + .setLabel('Click me') + .setStyle(ButtonStyle.Primary) + .setCustomId('click_me'); const row = new ActionRowBuilder().addComponents(button); const message = await channel.send({ - content: 'Click the button', - components: [row], + content: 'Click the button', + components: [row], }); button.onClick( - async (interaction) => { - await interaction.reply('You clicked me!'); - }, - { message }, + async (interaction) => { + await interaction.reply('You clicked me!'); + }, + { message }, ); // Remove onClick handler and destroy the interaction collector @@ -45,5 +45,5 @@ button.onClick(null); ### onEnd -- Return type: `ButtonKit` -- Props type: [`CommandKitButtonBuilderOnEnd`](/docs/typedef/CommandKitButtonBuilderOnEnd) +- Return type: `ButtonKit` +- Props type: [`CommandKitButtonBuilderOnEnd`](/docs/typedef/CommandKitButtonBuilderOnEnd) diff --git a/apps/docs/pages/docs/classes/components/_meta.json b/apps/docs/pages/docs/classes/components/_meta.json index 3f4fa5b..4a1f962 100644 --- a/apps/docs/pages/docs/classes/components/_meta.json +++ b/apps/docs/pages/docs/classes/components/_meta.json @@ -1,3 +1,3 @@ { - "ButtonKit": "ButtonKit" + "ButtonKit": "ButtonKit" } diff --git a/apps/docs/pages/docs/enums/ReloadType.mdx b/apps/docs/pages/docs/enums/ReloadType.mdx index 2e58178..d9fd80f 100644 --- a/apps/docs/pages/docs/enums/ReloadType.mdx +++ b/apps/docs/pages/docs/enums/ReloadType.mdx @@ -2,8 +2,8 @@ ### Developer -- Value: `dev` +- Value: `dev` ### Global -- Value: `global` +- Value: `global` diff --git a/apps/docs/pages/docs/enums/_meta.json b/apps/docs/pages/docs/enums/_meta.json index 5397412..5d1204d 100644 --- a/apps/docs/pages/docs/enums/_meta.json +++ b/apps/docs/pages/docs/enums/_meta.json @@ -1,3 +1,3 @@ { - "ReloadType": "ReloadType" + "ReloadType": "ReloadType" } diff --git a/apps/docs/pages/docs/typedef/AutocompleteProps.mdx b/apps/docs/pages/docs/typedef/AutocompleteProps.mdx index 0e964d9..b41648d 100644 --- a/apps/docs/pages/docs/typedef/AutocompleteProps.mdx +++ b/apps/docs/pages/docs/typedef/AutocompleteProps.mdx @@ -2,12 +2,12 @@ ### `client` -- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) +- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) ### `handler` -- Type: [`CommandKit`](/docs/typedef/CommandKit) +- Type: [`CommandKit`](/docs/typedef/CommandKit) ### `interaction` -- Type [`AutocompleteInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/AutocompleteInteraction) +- Type [`AutocompleteInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/AutocompleteInteraction) diff --git a/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch.mdx b/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch.mdx index 2bb39e5..8957fda 100644 --- a/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch.mdx +++ b/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatch.mdx @@ -1,7 +1,7 @@ # CommandKitButtonBuilderInteractionCollectorDispatch -- Type: `(interaction: ButtonInteraction) => Awaitable;` +- Type: `(interaction: ButtonInteraction) => Awaitable;` ## References -- [`ButtonInteraction`](https://discord.js.org/docs/packages/discord.js/main/ButtonInteraction:Class) +- [`ButtonInteraction`](https://discord.js.org/docs/packages/discord.js/main/ButtonInteraction:Class) diff --git a/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatchContextData.mdx b/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatchContextData.mdx index bc7a4f9..1cd46c4 100644 --- a/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatchContextData.mdx +++ b/apps/docs/pages/docs/typedef/CommandKitButtonBuilderInteractionCollectorDispatchContextData.mdx @@ -6,16 +6,16 @@ Extends `Omit, 'filter' | 'compon The message to listen for button interactions on. -- Type: [Message](https://discord.js.org/docs/packages/discord.js/main/Message:Class) +- Type: [Message](https://discord.js.org/docs/packages/discord.js/main/Message:Class) ### `time` The duration (in ms) that the collector should run for. -- Type: `number` | `undefined` +- Type: `number` | `undefined` ### `autoReset` If the collector should automatically reset the timer when a button is clicked. -- Type: `boolean` | `undefined` +- Type: `boolean` | `undefined` diff --git a/apps/docs/pages/docs/typedef/CommandKitButtonBuilderOnEnd.mdx b/apps/docs/pages/docs/typedef/CommandKitButtonBuilderOnEnd.mdx index d32eecf..84bee00 100644 --- a/apps/docs/pages/docs/typedef/CommandKitButtonBuilderOnEnd.mdx +++ b/apps/docs/pages/docs/typedef/CommandKitButtonBuilderOnEnd.mdx @@ -1,3 +1,3 @@ # CommandKitButtonBuilderOnEnd -- Type: `() => Awaitable` +- Type: `() => Awaitable` diff --git a/apps/docs/pages/docs/typedef/CommandObject.mdx b/apps/docs/pages/docs/typedef/CommandObject.mdx index b59118c..320ba5d 100644 --- a/apps/docs/pages/docs/typedef/CommandObject.mdx +++ b/apps/docs/pages/docs/typedef/CommandObject.mdx @@ -2,16 +2,16 @@ ### `data` -- Type: [`CommandData`](/docs/typedef/CommandData) +- Type: [`CommandData`](/docs/typedef/CommandData) ### `options` (optional) -- Type: [`CommandOptions`](/docs/typedef/CommandOptions) +- Type: [`CommandOptions`](/docs/typedef/CommandOptions) ### `filePath` -- Type: `string` +- Type: `string` ### `category` -- Type: `string` | `null` +- Type: `string` | `null` diff --git a/apps/docs/pages/docs/typedef/CommandOptions.mdx b/apps/docs/pages/docs/typedef/CommandOptions.mdx index ba2d76d..9d83bbc 100644 --- a/apps/docs/pages/docs/typedef/CommandOptions.mdx +++ b/apps/docs/pages/docs/typedef/CommandOptions.mdx @@ -2,24 +2,24 @@ ### `devOnly` (optional) -- Type: `boolean` +- Type: `boolean` This determines whether the command should only be registered in development guilds and be executed by the bot developers. ### `userPermissions` (optional) -- Type: [`PermissionsString[]`](https://discord.js.org/docs/packages/discord.js/main/PermissionsString:TypeAlias) +- Type: [`PermissionsString[]`](https://discord.js.org/docs/packages/discord.js/main/PermissionsString:TypeAlias) This determines whether the user has the required permissions to execute the command. This is checked against the user's permissions in the guild where the command was executed (if any). ### `botPermissions` (optional) -- Type: [`PermissionsString[]`](https://discord.js.org/docs/packages/discord.js/main/PermissionsString:TypeAlias) +- Type: [`PermissionsString[]`](https://discord.js.org/docs/packages/discord.js/main/PermissionsString:TypeAlias) This determines whether the bot has the required permissions to execute the command. This is checked against the bot's permissions in the guild where the command was executed (if any). ### `deleted` (optional) -- Type: `boolean` +- Type: `boolean` This determines whether the command should be deleted on the next reload. diff --git a/apps/docs/pages/docs/typedef/ContextMenuCommandProps.mdx b/apps/docs/pages/docs/typedef/ContextMenuCommandProps.mdx index 5f7d01c..06fbfaa 100644 --- a/apps/docs/pages/docs/typedef/ContextMenuCommandProps.mdx +++ b/apps/docs/pages/docs/typedef/ContextMenuCommandProps.mdx @@ -2,12 +2,12 @@ ### `client` -- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) +- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) ### `handler` -- Type: [`CommandKit`](/docs/typedef/CommandKit) +- Type: [`CommandKit`](/docs/typedef/CommandKit) ### `interaction` -- Type [`ContextMenuCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ContextMenuCommandInteraction) +- Type [`ContextMenuCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ContextMenuCommandInteraction) diff --git a/apps/docs/pages/docs/typedef/SlashCommandProps.mdx b/apps/docs/pages/docs/typedef/SlashCommandProps.mdx index d39e99d..80565c0 100644 --- a/apps/docs/pages/docs/typedef/SlashCommandProps.mdx +++ b/apps/docs/pages/docs/typedef/SlashCommandProps.mdx @@ -2,12 +2,12 @@ ### `client` -- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) +- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) ### `handler` -- Type: [`CommandKit`](/typedef/CommandKit) +- Type: [`CommandKit`](/typedef/CommandKit) ### `interaction` -- Type [`ChatInputCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ChatInputCommandInteraction) +- Type [`ChatInputCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ChatInputCommandInteraction) diff --git a/apps/docs/pages/docs/typedef/ValidationProps.mdx b/apps/docs/pages/docs/typedef/ValidationProps.mdx index 53d8820..8840393 100644 --- a/apps/docs/pages/docs/typedef/ValidationProps.mdx +++ b/apps/docs/pages/docs/typedef/ValidationProps.mdx @@ -2,16 +2,16 @@ ### `client` -- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) +- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) ### `commandObj` -- Type: [`CommandObject`](/docs/typedef/CommandObject) +- Type: [`CommandObject`](/docs/typedef/CommandObject) ### `handler` -- Type: [`CommandKit`](/docs/typedef/CommandKit) +- Type: [`CommandKit`](/docs/typedef/CommandKit) ### `interaction` -- Type: [`ChatInputCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ChatInputCommandInteraction) | [`ContextMenuCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ContextMenuCommandInteraction) | [`AutocompleteInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/AutocompleteInteraction) +- Type: [`ChatInputCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ChatInputCommandInteraction) | [`ContextMenuCommandInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/ContextMenuCommandInteraction) | [`AutocompleteInteraction`](https://old.discordjs.dev/#/docs/discord.js/main/class/AutocompleteInteraction) diff --git a/apps/docs/pages/docs/typedef/_meta.json b/apps/docs/pages/docs/typedef/_meta.json index 8e2f4cf..e5e4f6a 100644 --- a/apps/docs/pages/docs/typedef/_meta.json +++ b/apps/docs/pages/docs/typedef/_meta.json @@ -1,12 +1,12 @@ { - "AutocompleteProps": "AutocompleteProps", - "CommandData": "CommandData", - "CommandKitButtonBuilderInteractionCollectorDispatch": "CommandKitButtonBuilderInteractionCollectorDispatch", - "CommandKitButtonBuilderInteractionCollectorDispatchContextData": "CommandKitButtonBuilderInteractionCollectorDispatchContextData", - "CommandKitButtonBuilderOnEnd": "CommandKitButtonBuilderOnEnd", - "CommandObject": "CommandObject", - "CommandOptions": "CommandOptions", - "ContextMenuCommandProps": "ContextMenuCommandProps", - "SlashCommandProps": "SlashCommandProps", - "ValidationProps": "ValidationProps" + "AutocompleteProps": "AutocompleteProps", + "CommandData": "CommandData", + "CommandKitButtonBuilderInteractionCollectorDispatch": "CommandKitButtonBuilderInteractionCollectorDispatch", + "CommandKitButtonBuilderInteractionCollectorDispatchContextData": "CommandKitButtonBuilderInteractionCollectorDispatchContextData", + "CommandKitButtonBuilderOnEnd": "CommandKitButtonBuilderOnEnd", + "CommandObject": "CommandObject", + "CommandOptions": "CommandOptions", + "ContextMenuCommandProps": "ContextMenuCommandProps", + "SlashCommandProps": "SlashCommandProps", + "ValidationProps": "ValidationProps" } diff --git a/apps/docs/pages/guide/_meta.json b/apps/docs/pages/guide/_meta.json index af36bdb..84a4701 100644 --- a/apps/docs/pages/guide/_meta.json +++ b/apps/docs/pages/guide/_meta.json @@ -1,13 +1,13 @@ { - "installation": "Installation", - "create-commandkit": "create-commandkit", - "commandkit-setup": "CommandKit Setup", - "command-file-setup": "Commands Setup", - "event-file-setup": "Events Setup", - "validation-file-setup": "Validations Setup", - "buttonkit": "Using ButtonKit", - "using-cli": "Using CommandKit CLI", - "commandkit-config": "CommandKit Config", - "using-signals": "Using Signals", - "migrating-from-djs-commander": "Migrating from DJS-Commander" + "installation": "Installation", + "create-commandkit": "create-commandkit", + "commandkit-setup": "CommandKit Setup", + "command-file-setup": "Commands Setup", + "event-file-setup": "Events Setup", + "validation-file-setup": "Validations Setup", + "buttonkit": "Using ButtonKit", + "using-cli": "Using CommandKit CLI", + "commandkit-config": "CommandKit Config", + "using-signals": "Using Signals", + "migrating-from-djs-commander": "Migrating from DJS-Commander" } diff --git a/apps/docs/pages/guide/buttonkit.mdx b/apps/docs/pages/guide/buttonkit.mdx index 94655a7..e54217b 100644 --- a/apps/docs/pages/guide/buttonkit.mdx +++ b/apps/docs/pages/guide/buttonkit.mdx @@ -90,8 +90,9 @@ It is not recommended to use this to listen for button clicks forever since it c In the above example, you may notice how similar `ButtonKit` is to the native Discord.js `ButtonBuilder` class. That's because it's built on top of it. It introduces a new method called `onClick` which will allow you to quickly handle button interactions without having to create collectors. CommandKit does that for you! - ButtonKit doesn't work without a custom ID, so ensure you provide one whenever instantiating a - button. This is required to keep track of what button was clicked. + ButtonKit doesn't work without a custom ID, so ensure you provide one whenever + instantiating a button. This is required to keep track of what button was + clicked. ### Arguments Explained @@ -100,9 +101,9 @@ Here's an empty `onClick` method without any arguments: ```js copy const myButton = new ButtonKit() - .setCustomId('custom_button') - .setLabel('Click me!') - .setStyle(ButtonStyle.Primary); + .setCustomId('custom_button') + .setLabel('Click me!') + .setStyle(ButtonStyle.Primary); myButton.onClick(); ``` @@ -111,7 +112,7 @@ The first argument required by this function is your handler function which will ```js copy myButton.onClick((buttonInteraction) => { - buttonInteraction.reply('You clicked a button!'); + buttonInteraction.reply('You clicked a button!'); }); ``` @@ -122,10 +123,10 @@ const row = new ActionRowBuilder().addComponents(myButton); const message = await channel.send({ components: [row] }); myButton.onClick( - (buttonInteraction) => { - buttonInteraction.reply('You clicked a button!'); - }, - { message }, + (buttonInteraction) => { + buttonInteraction.reply('You clicked a button!'); + }, + { message }, ); ``` @@ -133,13 +134,16 @@ This also works with interaction replies. Just ensure you pass `fetchReply` alon ```js copy const row = new ActionRowBuilder().addComponents(myButton); -const message = await interaction.reply({ components: [row], fetchReply: true }); +const message = await interaction.reply({ + components: [row], + fetchReply: true, +}); myButton.onClick( - (buttonInteraction) => { - buttonInteraction.reply('You clicked a button!'); - }, - { message }, + (buttonInteraction) => { + buttonInteraction.reply('You clicked a button!'); + }, + { message }, ); ``` @@ -147,26 +151,26 @@ myButton.onClick( ### `message` -- Type: [`Message`](https://old.discordjs.dev/#/docs/discord.js/main/class/Message) +- Type: [`Message`](https://old.discordjs.dev/#/docs/discord.js/main/class/Message) The message object that ButtonKit uses to listen for button clicks (interactions). ### `time` (optional) -- Type: `number` -- Default: `86400000` +- Type: `number` +- Default: `86400000` The duration (in ms) the collector should run for and listen for button clicks. ### `autoReset` (optional) -- Type: `boolean` +- Type: `boolean` Whether or not the collector should automatically reset the timer when a button is clicked. ### Additional optional options -- Type: [`InteractionCollectorOptions`](https://old.discordjs.dev/#/docs/discord.js/main/typedef/InteractionCollectorOptions) +- Type: [`InteractionCollectorOptions`](https://old.discordjs.dev/#/docs/discord.js/main/typedef/InteractionCollectorOptions) ## Handle collector end @@ -174,51 +178,54 @@ When setting up an `onClick()` method using ButtonKit, you may also want to run ```js copy {16-21} const myButton = new ButtonKit() - .setCustomId('custom_button') - .setLabel('Click me!') - .setStyle(ButtonStyle.Primary); + .setCustomId('custom_button') + .setLabel('Click me!') + .setStyle(ButtonStyle.Primary); const row = new ActionRowBuilder().addComponents(myButton); -const message = await interaction.reply({ components: [row], fetchReply: true }); +const message = await interaction.reply({ + components: [row], + fetchReply: true, +}); myButton - .onClick( - (buttonInteraction) => { - buttonInteraction.reply('You clicked a button!'); - }, - { message }, - ) - .onEnd(() => { - console.log('Button collector ended.'); - - myButton.setDisabled(true); - message.edit({ components: [row] }); - }); + .onClick( + (buttonInteraction) => { + buttonInteraction.reply('You clicked a button!'); + }, + { message }, + ) + .onEnd(() => { + console.log('Button collector ended.'); + + myButton.setDisabled(true); + message.edit({ components: [row] }); + }); ``` ## Dispose button collector - This feature is currently only available in the [development - version](/guide/installation#development-version). + This feature is currently only available in the [development + version](/guide/installation#development-version). To dispose the button collector, you can make use of the `dispose` method. By disposing the collector like this, your `onEnd` handler (if any) will be called automatically. ```js copy {15} myButton - .onClick( - (buttonInteraction) => { - buttonInteraction.reply('You clicked a button!'); - }, - { message }, - ) - .onEnd(() => { - console.log('Button collector ended.'); - - myButton.setDisabled(true); - message.edit({ components: [row] }); - }); + .onClick( + (buttonInteraction) => { + buttonInteraction.reply('You clicked a button!'); + }, + { message }, + ) + .onEnd(() => { + console.log('Button collector ended.'); + + myButton.setDisabled(true); + message.edit({ components: [row] }); + }); myButton.dispose(); ``` diff --git a/apps/docs/pages/guide/command-file-setup.mdx b/apps/docs/pages/guide/command-file-setup.mdx index dc881ee..ce1fe79 100644 --- a/apps/docs/pages/guide/command-file-setup.mdx +++ b/apps/docs/pages/guide/command-file-setup.mdx @@ -278,27 +278,27 @@ Here's an example of how to use the `autocomplete` function: ### `data` -- Type: [`CommandData`](/docs/typedef/CommandData) | [`SlashCommandBuilder`](https://discord.js.org/docs/packages/builders/main/SlashCommandBuilder:Class) | [`ContextMenuCommandBuilder`](https://discord.js.org/docs/packages/builders/main/ContextMenuCommandBuilder:Class) +- Type: [`CommandData`](/docs/typedef/CommandData) | [`SlashCommandBuilder`](https://discord.js.org/docs/packages/builders/main/SlashCommandBuilder:Class) | [`ContextMenuCommandBuilder`](https://discord.js.org/docs/packages/builders/main/ContextMenuCommandBuilder:Class) This property contains the command's structural information, and is required to register and handle commands. ### `run` -- Type: `void` +- Type: `void` -- Props Type: [`SlashCommandProps`](/docs/typedef/SlashCommandProps) | [`ContextMenuCommandProps`](/docs/typedef/ContextMenuCommandProps) +- Props Type: [`SlashCommandProps`](/docs/typedef/SlashCommandProps) | [`ContextMenuCommandProps`](/docs/typedef/ContextMenuCommandProps) This function will be called when the command is executed. ### `autocomplete` -- Type: `void` -- Props Type: [`AutocompleteProps`](/docs/typedef/AutocompleteProps) +- Type: `void` +- Props Type: [`AutocompleteProps`](/docs/typedef/AutocompleteProps) This function will be called when an autocomplete interaction event is triggered for any option set as autocomplete in this command's `data` object. ### `options` (optional) -- Type: [`CommandOptions`](/docs/typedef/CommandOptions) +- Type: [`CommandOptions`](/docs/typedef/CommandOptions) This property contains the command's registration/handling behaviour. diff --git a/apps/docs/pages/guide/commandkit-config.mdx b/apps/docs/pages/guide/commandkit-config.mdx index 005c86f..6af0b7b 100644 --- a/apps/docs/pages/guide/commandkit-config.mdx +++ b/apps/docs/pages/guide/commandkit-config.mdx @@ -4,14 +4,14 @@ import { Callout } from 'nextra/components'; CommandKit CLI can be configured using `commandkit.config` file in the root of your project directory (for example, by `package.json`). You can use either of the following files: -- `commandkit.js` -- `commandkit.config.js` -- `commandkit.mjs` -- `commandkit.config.mjs` -- `commandkit.cjs` -- `commandkit.config.cjs` -- `commandkit.json` -- `commandkit.config.json` +- `commandkit.js` +- `commandkit.config.js` +- `commandkit.mjs` +- `commandkit.config.mjs` +- `commandkit.cjs` +- `commandkit.config.cjs` +- `commandkit.json` +- `commandkit.config.json` Throughout this guide, we'll be using `commandkit.config.mjs` as an example. @@ -21,96 +21,98 @@ The following is the sample configuration required to run your bot: import { defineConfig } from 'commandkit'; export default defineConfig({ - src: 'src', // The source directory of your project. - main: 'index.mjs', // The JavaScript entry point of your project. + src: 'src', // The source directory of your project. + main: 'index.mjs', // The JavaScript entry point of your project. }); ``` - For CommandKit CLI on version `0.1.7` it's recommended to use an ESM project instead of CommonJS - due to the behavior of `require()`. If you're using CommonJS you'll have to use dynamic - `import()`. However, this is not an issue for TypeScript CommonJS projects. + For CommandKit CLI on version `0.1.7` it's recommended to use an ESM project + instead of CommonJS due to the behavior of `require()`. If you're using + CommonJS you'll have to use dynamic `import()`. However, this is not an issue + for TypeScript CommonJS projects. ## Options ### `src` -- Type: `string` +- Type: `string` The source directory of the project where your source code lives. ### `main` -- Type: `string` +- Type: `string` The entry point to your project. Example: If your source is structured as `src/index.ts`, this option must be set to `index.mjs`. This is because CommandKit always compiles your source code to esm format. - The "src" part in this option isn't required because it's already defined in the `src` option. + The "src" part in this option isn't required because it's already defined in + the `src` option. ### `watch` (optional) -- Type: `boolean` -- Default: `true` +- Type: `boolean` +- Default: `true` Whether to watch for file changes or not. ### `outDir` (optional) -- Type: `string` -- Default: `"dist"` +- Type: `string` +- Default: `"dist"` The output directory to emit the production build to. ### `envExtra` (optional) -- Type: `boolean` -- Default: `true` +- Type: `boolean` +- Default: `true` Extra env utilities to load. This allows you to load environment variables in different formats, like `Date`, `JSON`, `Boolean`, etc. ### `nodeOptions` (optional) -- Type: `string[]` -- Default: `[]` +- Type: `string[]` +- Default: `[]` Options to pass to Node.js. ### `clearRestartLogs` (optional) -- Type: `boolean` -- Default: `true` +- Type: `boolean` +- Default: `true` Whether or not to clear default restart logs. ### `minify` (optional) -- Type: `boolean` -- Default: `false` +- Type: `boolean` +- Default: `false` Whether or not to minify the production build. ### `sourcemap` (optional) -- Type: `boolean` | `"inline"` -- Default: `false` +- Type: `boolean` | `"inline"` +- Default: `false` Whether or not to include sourcemaps in the production build. ### `antiCrash` (optional) -- Type: `boolean` -- Default: `true` +- Type: `boolean` +- Default: `true` Whether or not to inject anti-crash script in the production build. ### `requirePolyfill` (optional) -- Type: `boolean` -- Default: `true` +- Type: `boolean` +- Default: `true` Whether or not to polyfill `require` function. diff --git a/apps/docs/pages/guide/commandkit-setup.mdx b/apps/docs/pages/guide/commandkit-setup.mdx index f83b80c..453e25f 100644 --- a/apps/docs/pages/guide/commandkit-setup.mdx +++ b/apps/docs/pages/guide/commandkit-setup.mdx @@ -100,38 +100,38 @@ This is a simple overview of how to set up CommandKit with all the available opt - Some Discord.js properties are only accessible using the correct intents. + Some Discord.js properties are only accessible using the correct intents. ## CommandKit options ### `client` -- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) +- Type: [`Client`](https://old.discordjs.dev/#/docs/discord.js/main/class/Client) This is your Discord.js client object. This is required to register and handle application commands and events. ### `commandsPath` (optional) -- Type: `string` +- Type: `string` This is the path to your commands directory. It's used to fetch, register, and listen for application commands. ### `eventsPath` (optional) -- Type: `string` +- Type: `string` This is the path to your events directory. It's used to fetch and set event listeners based on the folder names inside of it. ### `validationsPath` (optional) -- Type: `string` +- Type: `string` This is the path to your validations directory. It's used to fetch and call validation functions before running application commands. ### `devGuildIds` (optional) -- Type: `string[]` +- Type: `string[]` This is a list of development server IDs. It's used to restrict commands marked with `devOnly` to specific servers. @@ -139,7 +139,7 @@ If there is at least 1 guild ID provided, CommandKit will register any commands ### `devUserIds` (optional) -- Type: `string[]` +- Type: `string[]` This is a list of developer user IDs. It's used to restrict commands marked with `devOnly` to specific users. @@ -147,7 +147,7 @@ Trying to execute a command when this is set to at-least 1 user ID will call a b ### `devRoleIds` (optional) -- Type: `string[]` +- Type: `string[]` This is a list of developer role IDs. It's used to restrict commands marked with `devOnly` to specific roles. @@ -155,14 +155,14 @@ Trying to execute a command when this is set to at-least 1 role ID will call a b ### `skipBuiltInValidations` (optional) -- Type: `boolean` -- Default: `false` +- Type: `boolean` +- Default: `false` This is used to disable CommandKit's built-in validation functions. Setting this to `true` will ignore the default behaviour of validating who is running commands marked with `devOnly`. ### `bulkRegister` (optional) -- Type: `boolean` -- Default: `false` +- Type: `boolean` +- Default: `false` This is used to change the behaviour of how CommandKit loads application commands. By default it's one-by-one while comparing changes. Setting this option to `true` will load application commands all at once on every restart, and when [`reloadCommands()`](/docs/typedef/CommandKit#reloadcommands) is called. diff --git a/apps/docs/pages/guide/create-commandkit.mdx b/apps/docs/pages/guide/create-commandkit.mdx index c53a550..cb1ca82 100644 --- a/apps/docs/pages/guide/create-commandkit.mdx +++ b/apps/docs/pages/guide/create-commandkit.mdx @@ -16,12 +16,12 @@ This will start the CLI in the current directory. When running create-commandkit, you should be asked the following questions: -- **Project Directory:** Defines where your project will be located. It defaults to the current working directory. +- **Project Directory:** Defines where your project will be located. It defaults to the current working directory. -- **Package Manager:** Lets you choose which package manager to use — npm, pnpm, or Yarn. +- **Package Manager:** Lets you choose which package manager to use — npm, pnpm, or Yarn. -- **Module Type:** Allows you to pick between CommonJS (using require and module.exports), and ESM (using import and export). +- **Module Type:** Allows you to pick between CommonJS (using require and module.exports), and ESM (using import and export). -- **Bot Token:** Asks you for your bot token, and writes it into the `.env` file where it will be stored. +- **Bot Token:** Asks you for your bot token, and writes it into the `.env` file where it will be stored. After these questions are answered, your project solution should appear in the selected folder. diff --git a/apps/docs/pages/guide/installation.mdx b/apps/docs/pages/guide/installation.mdx index 739205a..4e3ee31 100644 --- a/apps/docs/pages/guide/installation.mdx +++ b/apps/docs/pages/guide/installation.mdx @@ -3,22 +3,28 @@ import { Callout } from 'nextra/components'; # Installation
- -
- + +
+
To install CommandKit, run one of the following commands based on your preferred package manager: @@ -35,4 +41,6 @@ To install the development version of CommandKit, run one of the following comma npm install commandkit@dev ``` -The development version is likely to have bugs. + + The development version is likely to have bugs. + diff --git a/apps/docs/pages/guide/migrating-from-djs-commander.mdx b/apps/docs/pages/guide/migrating-from-djs-commander.mdx index 5b97649..4d8a461 100644 --- a/apps/docs/pages/guide/migrating-from-djs-commander.mdx +++ b/apps/docs/pages/guide/migrating-from-djs-commander.mdx @@ -5,8 +5,9 @@ import { Callout } from 'nextra/components'; If you're trying to use CommandKit as a drop-in replacement for DJS-Commander, you'll need to make a few changes to your code. - This guide is **not** introducing the features this library offers over DJS-Commander. It's just - going over the changes you'll need to make to your code to get it working with this library. + This guide is **not** introducing the features this library offers over + DJS-Commander. It's just going over the changes you'll need to make to your + code to get it working with this library. ## Setting up the command handler @@ -17,9 +18,9 @@ In DJS-Commander, you'd import and instantiate the `CommandHandler` class. The o const { CommandKit } = require('commandkit'); new CommandKit({ - client, - commandsPath, - eventsPath, + client, + commandsPath, + eventsPath, }); ``` @@ -29,10 +30,10 @@ In DJS-Commander only a single development server was supported, and it was setu ```js new CommandHandler({ - client, - commandsPath, - eventsPath, - testServer: '123456789012345678', // ❌ + client, + commandsPath, + eventsPath, + testServer: '123456789012345678', // ❌ }); ``` @@ -40,10 +41,10 @@ In CommandKit, you can setup multiple development servers under the property nam ```js new CommandKit({ - client, - commandsPath, - eventsPath, - devGuildIds: ['123456789012345678', '876543210987654321'], // ✅ + client, + commandsPath, + eventsPath, + devGuildIds: ['123456789012345678', '876543210987654321'], // ✅ }); ``` @@ -51,18 +52,18 @@ However, this does not automatically register all the commands in those specific ```js module.exports = { - data: { - name: 'ping', - description: 'Pong!', - }, - - run: ({ interaction }) => { - interaction.reply('Pong!'); - }, - - options: { - devOnly: true, // ✅ - }, + data: { + name: 'ping', + description: 'Pong!', + }, + + run: ({ interaction }) => { + interaction.reply('Pong!'); + }, + + options: { + devOnly: true, // ✅ + }, }; ``` @@ -70,11 +71,11 @@ This command will now be registered in your development server, however you won' ```js new CommandKit({ - client, - commandsPath, - eventsPath, - devGuildIds: ['123456789012345678', '876543210987654321'], - devUserIds: ['123456789012345678', '876543210987654321'], // ✅ + client, + commandsPath, + eventsPath, + devGuildIds: ['123456789012345678', '876543210987654321'], + devUserIds: ['123456789012345678', '876543210987654321'], // ✅ }); ``` @@ -84,20 +85,20 @@ Deleting commands with CommandKit is a bit different from DJS-Commander's. In DJ ```js module.exports = { - data: { - name: 'ping', - description: 'Pong!', - }, + data: { + name: 'ping', + description: 'Pong!', + }, - run: ({ interaction }) => { - interaction.reply('Pong!'); - }, + run: ({ interaction }) => { + interaction.reply('Pong!'); + }, - deleted: true, // ❌ + deleted: true, // ❌ - options: { - deleted: true, // ✅ - }, + options: { + deleted: true, // ✅ + }, }; ``` diff --git a/apps/docs/pages/guide/using-cli.mdx b/apps/docs/pages/guide/using-cli.mdx index 9c0e840..1e01de3 100644 --- a/apps/docs/pages/guide/using-cli.mdx +++ b/apps/docs/pages/guide/using-cli.mdx @@ -5,9 +5,10 @@ import { Callout } from 'nextra/components'; CommandKit CLI allows you to start, build, and manage your bot application. It also includes features such as anti-crash so you can be rest assured your bot won't crash and go offline during production. - For CommandKit CLI on version `0.1.7` it's recommended to use an ESM project instead of CommonJS - due to the behavior of `require()`. If you're using CommonJS you'll have to use dynamic - `import()`. However, this is not an issue for TypeScript CommonJS projects. + For CommandKit CLI on version `0.1.7` it's recommended to use an ESM project + instead of CommonJS due to the behavior of `require()`. If you're using + CommonJS you'll have to use dynamic `import()`. However, this is not an issue + for TypeScript CommonJS projects. To get a list of the available CLI commands, run the following command inside your project directory: @@ -32,8 +33,8 @@ Commands: ``` - CommandKit does not perform type checking on your code. You need to do that yourself using `tsc - --noEmit` command or any other tool of your choice. + CommandKit does not perform type checking on your code. You need to do that + yourself using `tsc --noEmit` command or any other tool of your choice. ## Available commands diff --git a/apps/docs/pages/guide/validation-file-setup.mdx b/apps/docs/pages/guide/validation-file-setup.mdx index cb358f7..f9add11 100644 --- a/apps/docs/pages/guide/validation-file-setup.mdx +++ b/apps/docs/pages/guide/validation-file-setup.mdx @@ -7,8 +7,9 @@ Validations are functions that are called before the `run` function from a comma Validation functions are called on every command trigger, so it's important to keep them as lightweight as possible. - Custom validation functions are called before the built-in validations provided by CommandKit. - This provides you with more control over the flow of commands. + Custom validation functions are called before the built-in validations + provided by CommandKit. This provides you with more control over the flow of + commands. @@ -79,7 +80,8 @@ The `handler` object is the current CommandKit instance. You may notice that the code above is returning `true`. This is important as it tells the command handler to not run any other validations and to not run the command. If you do not return `true` (or any truthy value), the command will run as normal. - Interactions (commands in this case) must be handled within 3 seconds, so make sure your - validations are not using up much of that time. If you're using a database or an external API, - it's recommended to implement caching to keep things quick. + Interactions (commands in this case) must be handled within 3 seconds, so make + sure your validations are not using up much of that time. If you're using a + database or an external API, it's recommended to implement caching to keep + things quick. diff --git a/apps/docs/postcss.config.js b/apps/docs/postcss.config.js index 67cdf1a..12a703d 100644 --- a/apps/docs/postcss.config.js +++ b/apps/docs/postcss.config.js @@ -1,6 +1,6 @@ module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, }; diff --git a/apps/docs/tailwind.config.ts b/apps/docs/tailwind.config.ts index a030166..58d2ff4 100644 --- a/apps/docs/tailwind.config.ts +++ b/apps/docs/tailwind.config.ts @@ -1,15 +1,15 @@ import type { Config } from 'tailwindcss'; const config: Config = { - content: [ - './pages/**/*.{js,ts,jsx,tsx,md,mdx}', - './components/**/*.{js,ts,jsx,tsx,md,mdx}', - './app/**/*.{js,ts,jsx,tsx,md,mdx}', - './theme.config.tsx', - ], - theme: { - extend: {}, - }, - plugins: [], + content: [ + './pages/**/*.{js,ts,jsx,tsx,md,mdx}', + './components/**/*.{js,ts,jsx,tsx,md,mdx}', + './app/**/*.{js,ts,jsx,tsx,md,mdx}', + './theme.config.tsx', + ], + theme: { + extend: {}, + }, + plugins: [], }; export default config; diff --git a/apps/docs/theme.config.tsx b/apps/docs/theme.config.tsx index 48394e9..97b7027 100644 --- a/apps/docs/theme.config.tsx +++ b/apps/docs/theme.config.tsx @@ -4,77 +4,83 @@ import { useRouter } from 'next/router'; import Image from 'next/image'; const config: DocsThemeConfig = { - logo: ( -
- CommandKit Favicon - CommandKit -
- ), - chat: { - link: 'https://ctrl.lol/discord', - }, - project: { - link: 'https://github.com/underctrl-io/commandkit', - }, - docsRepositoryBase: 'https://github.com/underctrl-io/commandkit/blob/master/apps/docs', - useNextSeoProps() { - const { asPath } = useRouter(); - if (asPath !== '/') { - return { - titleTemplate: '%s – CommandKit', - }; - } - }, - gitTimestamp({ timestamp }) { - const { locale, asPath } = useRouter(); + logo: ( +
+ CommandKit Favicon + CommandKit +
+ ), + chat: { + link: 'https://ctrl.lol/discord', + }, + project: { + link: 'https://github.com/underctrl-io/commandkit', + }, + docsRepositoryBase: + 'https://github.com/underctrl-io/commandkit/blob/master/apps/docs', + useNextSeoProps() { + const { asPath } = useRouter(); + if (asPath !== '/') { + return { + titleTemplate: '%s – CommandKit', + }; + } + }, + gitTimestamp({ timestamp }) { + const { locale, asPath } = useRouter(); - if (asPath !== '/') { - return ( - <> - Last updated on:{' '} - - - ); - } - }, - head: (meta: any) => { - const { frontMatter, title } = useConfig(); - const { asPath } = useRouter(); + if (asPath !== '/') { + return ( + <> + Last updated on:{' '} + + + ); + } + }, + head: (meta: any) => { + const { frontMatter, title } = useConfig(); + const { asPath } = useRouter(); - let ogTitle = `${title} – CommandKit`; + let ogTitle = `${title} – CommandKit`; - if (asPath === '/') { - ogTitle = title; - } + if (asPath === '/') { + ogTitle = title; + } - const ogDescription = frontMatter.description || ''; + const ogDescription = frontMatter.description || ''; - return ( - <> - - - - - - - ); - }, - footer: { - text: ( - - MIT {new Date().getFullYear()} ©{' '} - - Under Ctrl - - - ), - }, + return ( + <> + + + + + + + ); + }, + footer: { + text: ( + + MIT {new Date().getFullYear()} ©{' '} + + Under Ctrl + + + ), + }, }; export default config; diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index e535ba6..e223a00 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -1,22 +1,22 @@ { - "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "paths": { - "@/*": ["./*"] - } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/_app.msx"], - "exclude": ["node_modules"] + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/_app.msx"], + "exclude": ["node_modules"] } diff --git a/package.json b/package.json index d35d69a..df4e5f0 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,19 @@ { - "name": "commandkit", - "version": "0.0.0", - "private": true, - "license": "MIT", - "scripts": { - "dev": "turbo dev", - "lint": "turbo lint && prettier ./ --check --ignore-path=.prettierignore", - "build": "turbo lint && turbo build", - "build:package": "turbo lint --filter='commandkit' && turbo build --filter='commandkit'", - "deploy:package": "turbo lint --filter='commandkit' && turbo build --filter='commandkit' && turbo deploy --filter='commandkit'", - "deploy:package-dev": "turbo lint --filter='commandkit' && turbo build --filter='commandkit' && turbo deploy-dev --filter='commandkit'", - "format": "prettier --write \"./{packages,apps}/**/*.{js,ts,jsx,tsx,mjs,mts,cjs,cts,css,md,mdx}\"" - }, - "devDependencies": { - "prettier": "^3.0.3", - "turbo": "^1.10.13" - } + "name": "commandkit", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "dev": "turbo dev", + "lint": "turbo lint && prettier ./ --check --ignore-path=.prettierignore", + "build": "turbo lint && turbo build", + "build:package": "turbo lint --filter='commandkit' && turbo build --filter='commandkit'", + "deploy:package": "turbo lint --filter='commandkit' && turbo build --filter='commandkit' && turbo deploy --filter='commandkit'", + "deploy:package-dev": "turbo lint --filter='commandkit' && turbo build --filter='commandkit' && turbo deploy-dev --filter='commandkit'", + "format": "prettier --write \"./{packages,apps}/**/*.{js,ts,jsx,tsx,mjs,mts,cjs,cts,css,md,mdx,json,yaml}\"" + }, + "devDependencies": { + "prettier": "^3.0.3", + "turbo": "^1.10.13" + } } diff --git a/packages/commandkit/package.json b/packages/commandkit/package.json index 94eb876..57a90c6 100644 --- a/packages/commandkit/package.json +++ b/packages/commandkit/package.json @@ -1,70 +1,70 @@ { - "name": "commandkit", - "description": "Beginner friendly command & event handler for Discord.js", - "version": "0.1.10", - "license": "MIT", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "bin": "./bin/index.mjs", - "exports": { - ".": { - "require": "./dist/index.js", - "import": "./dist/index.mjs", - "types": "./dist/index.d.ts" - }, - "./cli": { - "require": "./dist/environment/cli.js", - "import": "./dist/environment/cli.mjs", - "types": "./dist/environment/cli.d.ts" - } + "name": "commandkit", + "description": "Beginner friendly command & event handler for Discord.js", + "version": "0.1.10", + "license": "MIT", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "bin": "./bin/index.mjs", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" }, - "files": [ - "dist", - "bin" - ], - "scripts": { - "lint": "tsc --noEmit", - "dev": "tsup --watch", - "build": "tsup", - "deploy": "npm publish", - "deploy-dev": "npm publish --access public --tag dev", - "test": "vitest", - "test:dev": "cd ./tests && node ../bin/index.mjs dev", - "test:build": "cd ./tests && node ../bin/index.mjs build", - "test:prod": "cd ./tests && node ../bin/index.mjs start" - }, - "repository": { - "type": "git", - "url": "https://github.com/underctrl-io/commandkit", - "directory": "packages/commandkit" - }, - "homepage": "https://commandkit.js.org", - "keywords": [ - "discord.js", - "command handler", - "event handler" - ], - "dependencies": { - "dotenv-cra": "^3.0.3", - "ora": "^8.0.1", - "rfdc": "^1.3.1", - "rimraf": "^5.0.5", - "source-map-support": "^0.5.21", - "tsup": "^8.0.1", - "yargs": "^17.7.2" - }, - "devDependencies": { - "@types/node": "^20.11.6", - "@types/yargs": "^17.0.32", - "discord.js": "^14.14.1", - "esbuild-plugin-version-injector": "^1.2.1", - "tsconfig": "workspace:*", - "tsx": "^4.7.0", - "typescript": "^5.3.3", - "vitest": "^1.2.1" - }, - "peerDependencies": { - "discord.js": "^14" + "./cli": { + "require": "./dist/environment/cli.js", + "import": "./dist/environment/cli.mjs", + "types": "./dist/environment/cli.d.ts" } -} \ No newline at end of file + }, + "files": [ + "dist", + "bin" + ], + "scripts": { + "lint": "tsc --noEmit", + "dev": "tsup --watch", + "build": "tsup", + "deploy": "npm publish", + "deploy-dev": "npm publish --access public --tag dev", + "test": "vitest", + "test:dev": "cd ./tests && node ../bin/index.mjs dev", + "test:build": "cd ./tests && node ../bin/index.mjs build", + "test:prod": "cd ./tests && node ../bin/index.mjs start" + }, + "repository": { + "type": "git", + "url": "https://github.com/underctrl-io/commandkit", + "directory": "packages/commandkit" + }, + "homepage": "https://commandkit.js.org", + "keywords": [ + "discord.js", + "command handler", + "event handler" + ], + "dependencies": { + "dotenv-cra": "^3.0.3", + "ora": "^8.0.1", + "rfdc": "^1.3.1", + "rimraf": "^5.0.5", + "source-map-support": "^0.5.21", + "tsup": "^8.0.1", + "yargs": "^17.7.2" + }, + "devDependencies": { + "@types/node": "^20.11.6", + "@types/yargs": "^17.0.32", + "discord.js": "^14.14.1", + "esbuild-plugin-version-injector": "^1.2.1", + "tsconfig": "workspace:*", + "tsx": "^4.7.0", + "typescript": "^5.3.3", + "vitest": "^1.2.1" + }, + "peerDependencies": { + "discord.js": "^14" + } +} diff --git a/packages/commandkit/spec/main.spec.ts b/packages/commandkit/spec/main.spec.ts index 9d84ad4..933b9e2 100644 --- a/packages/commandkit/spec/main.spec.ts +++ b/packages/commandkit/spec/main.spec.ts @@ -1,7 +1,7 @@ import { describe, test, expect } from 'vitest'; describe('commandkit', () => { - test('passes', () => { - expect(2 + 2).toBe(4); - }); + test('passes', () => { + expect(2 + 2).toBe(4); + }); }); diff --git a/packages/commandkit/src/CommandKit.ts b/packages/commandkit/src/CommandKit.ts index 5d10492..1b29981 100644 --- a/packages/commandkit/src/CommandKit.ts +++ b/packages/commandkit/src/CommandKit.ts @@ -1,4 +1,8 @@ -import type { CommandKitData, CommandKitOptions, ReloadOptions } from './typings'; +import type { + CommandKitData, + CommandKitOptions, + ReloadOptions, +} from './typings'; import type { CommandObject } from './types'; import { CommandHandler, EventHandler, ValidationHandler } from './handlers'; @@ -6,174 +10,176 @@ import { CommandHandler, EventHandler, ValidationHandler } from './handlers'; import colors from './utils/colors'; export class CommandKit { - #data: CommandKitData; - static _instance: CommandKit | null = null; - - /** - * Create a new command and event handler with CommandKit. - * - * @param options - The default CommandKit configuration. - * @see {@link https://commandkit.js.org/docs/commandkit-setup} - */ - constructor(options: CommandKitOptions) { - if (!options.client) { - throw new Error(colors.red('"client" is required when instantiating CommandKit.')); - } - - if (options.validationsPath && !options.commandsPath) { - throw new Error( - colors.red('"commandsPath" is required when "validationsPath" is set.'), - ); - } - - this.#data = options; - CommandKit._instance = this; - - this.#init(); + #data: CommandKitData; + static _instance: CommandKit | null = null; + + /** + * Create a new command and event handler with CommandKit. + * + * @param options - The default CommandKit configuration. + * @see {@link https://commandkit.js.org/docs/commandkit-setup} + */ + constructor(options: CommandKitOptions) { + if (!options.client) { + throw new Error( + colors.red('"client" is required when instantiating CommandKit.'), + ); } - /** - * Get the client attached to this CommandKit instance. - */ - get client() { - return this.#data.client; + if (options.validationsPath && !options.commandsPath) { + throw new Error( + colors.red('"commandsPath" is required when "validationsPath" is set.'), + ); } - /** - * Get command handler instance. - */ - get commandHandler() { - return this.#data.commandHandler; + this.#data = options; + CommandKit._instance = this; + + this.#init(); + } + + /** + * Get the client attached to this CommandKit instance. + */ + get client() { + return this.#data.client; + } + + /** + * Get command handler instance. + */ + get commandHandler() { + return this.#data.commandHandler; + } + + /** + * (Private) Initialize CommandKit. + */ + async #init() { + // + if (this.#data.eventsPath) { + const eventHandler = new EventHandler({ + client: this.#data.client, + eventsPath: this.#data.eventsPath, + commandKitInstance: this, + }); + + await eventHandler.init(); + + this.#data.eventHandler = eventHandler; } - /** - * (Private) Initialize CommandKit. - */ - async #init() { - // - if (this.#data.eventsPath) { - const eventHandler = new EventHandler({ - client: this.#data.client, - eventsPath: this.#data.eventsPath, - commandKitInstance: this, - }); - - await eventHandler.init(); - - this.#data.eventHandler = eventHandler; - } - - // - if (this.#data.validationsPath) { - const validationHandler = new ValidationHandler({ - validationsPath: this.#data.validationsPath, - }); - - await validationHandler.init(); - - this.#data.validationHandler = validationHandler; - } - - // - if (this.#data.commandsPath) { - const commandHandler = new CommandHandler({ - client: this.#data.client, - commandsPath: this.#data.commandsPath, - devGuildIds: this.#data.devGuildIds || [], - devUserIds: this.#data.devUserIds || [], - devRoleIds: this.#data.devRoleIds || [], - validationHandler: this.#data.validationHandler, - skipBuiltInValidations: this.#data.skipBuiltInValidations || false, - commandkitInstance: this, - bulkRegister: this.#data.bulkRegister || false, - enableHooks: this.#data.experimental?.hooks ?? false, - }); - - await commandHandler.init(); - - this.#data.commandHandler = commandHandler; - } - } - - /** - * Updates application commands with the latest from "commandsPath". - */ - async reloadCommands(type?: ReloadOptions) { - if (!this.#data.commandHandler) return; - await this.#data.commandHandler.reloadCommands(type); - } - - /** - * Updates application events with the latest from "eventsPath". - */ - async reloadEvents() { - if (!this.#data.eventHandler) return; - await this.#data.eventHandler.reloadEvents(this.#data.commandHandler); - } - - /** - * Updates application command validations with the latest from "validationsPath". - */ - async reloadValidations() { - if (!this.#data.validationHandler) return; - await this.#data.validationHandler.reloadValidations(); - } - - /** - * @returns An array of objects of all the commands that CommandKit is handling. - */ - get commands(): CommandObject[] { - if (!this.#data.commandHandler) { - return []; - } + // + if (this.#data.validationsPath) { + const validationHandler = new ValidationHandler({ + validationsPath: this.#data.validationsPath, + }); - const commands = this.#data.commandHandler.commands.map((cmd) => { - const { run, autocomplete, ...command } = cmd; - return command; - }); + await validationHandler.init(); - return commands; + this.#data.validationHandler = validationHandler; } - /** - * @returns The path to the commands folder which was set when instantiating CommandKit. - */ - get commandsPath(): string | undefined { - return this.#data.commandsPath; + // + if (this.#data.commandsPath) { + const commandHandler = new CommandHandler({ + client: this.#data.client, + commandsPath: this.#data.commandsPath, + devGuildIds: this.#data.devGuildIds || [], + devUserIds: this.#data.devUserIds || [], + devRoleIds: this.#data.devRoleIds || [], + validationHandler: this.#data.validationHandler, + skipBuiltInValidations: this.#data.skipBuiltInValidations || false, + commandkitInstance: this, + bulkRegister: this.#data.bulkRegister || false, + enableHooks: this.#data.experimental?.hooks ?? false, + }); + + await commandHandler.init(); + + this.#data.commandHandler = commandHandler; } - - /** - * @returns The path to the events folder which was set when instantiating CommandKit. - */ - get eventsPath(): string | undefined { - return this.#data.eventsPath; - } - - /** - * @returns The path to the validations folder which was set when instantiating CommandKit. - */ - get validationsPath(): string | undefined { - return this.#data.validationsPath; - } - - /** - * @returns An array of all the developer user IDs which was set when instantiating CommandKit. - */ - get devUserIds(): string[] { - return this.#data.devUserIds || []; - } - - /** - * @returns An array of all the developer guild IDs which was set when instantiating CommandKit. - */ - get devGuildIds(): string[] { - return this.#data.devGuildIds || []; + } + + /** + * Updates application commands with the latest from "commandsPath". + */ + async reloadCommands(type?: ReloadOptions) { + if (!this.#data.commandHandler) return; + await this.#data.commandHandler.reloadCommands(type); + } + + /** + * Updates application events with the latest from "eventsPath". + */ + async reloadEvents() { + if (!this.#data.eventHandler) return; + await this.#data.eventHandler.reloadEvents(this.#data.commandHandler); + } + + /** + * Updates application command validations with the latest from "validationsPath". + */ + async reloadValidations() { + if (!this.#data.validationHandler) return; + await this.#data.validationHandler.reloadValidations(); + } + + /** + * @returns An array of objects of all the commands that CommandKit is handling. + */ + get commands(): CommandObject[] { + if (!this.#data.commandHandler) { + return []; } - /** - * @returns An array of all the developer role IDs which was set when instantiating CommandKit. - */ - get devRoleIds(): string[] { - return this.#data.devRoleIds || []; - } + const commands = this.#data.commandHandler.commands.map((cmd) => { + const { run, autocomplete, ...command } = cmd; + return command; + }); + + return commands; + } + + /** + * @returns The path to the commands folder which was set when instantiating CommandKit. + */ + get commandsPath(): string | undefined { + return this.#data.commandsPath; + } + + /** + * @returns The path to the events folder which was set when instantiating CommandKit. + */ + get eventsPath(): string | undefined { + return this.#data.eventsPath; + } + + /** + * @returns The path to the validations folder which was set when instantiating CommandKit. + */ + get validationsPath(): string | undefined { + return this.#data.validationsPath; + } + + /** + * @returns An array of all the developer user IDs which was set when instantiating CommandKit. + */ + get devUserIds(): string[] { + return this.#data.devUserIds || []; + } + + /** + * @returns An array of all the developer guild IDs which was set when instantiating CommandKit. + */ + get devGuildIds(): string[] { + return this.#data.devGuildIds || []; + } + + /** + * @returns An array of all the developer role IDs which was set when instantiating CommandKit. + */ + get devRoleIds(): string[] { + return this.#data.devRoleIds || []; + } } diff --git a/packages/commandkit/src/bootstrap/client.ts b/packages/commandkit/src/bootstrap/client.ts index 444e9ac..8412c47 100644 --- a/packages/commandkit/src/bootstrap/client.ts +++ b/packages/commandkit/src/bootstrap/client.ts @@ -7,26 +7,26 @@ let discord_client: Client; * @internal */ export function getClient() { - return discord_client; + return discord_client; } /** * Fetches the client instance. If the client instance is not initialized, an error will be thrown. */ export function client() { - if (!discord_client) { - throw new Error( - 'Client was not initialized. Make sure to run "commandkit dev" to bootstrap the client.', - ); - } + if (!discord_client) { + throw new Error( + 'Client was not initialized. Make sure to run "commandkit dev" to bootstrap the client.', + ); + } - return discord_client as Client; + return discord_client as Client; } export function createClient() { - const config = getConfig(); + const config = getConfig(); - discord_client = new Client(config.clientOptions); + discord_client = new Client(config.clientOptions); - return discord_client; + return discord_client; } diff --git a/packages/commandkit/src/bootstrap/loadEnv.ts b/packages/commandkit/src/bootstrap/loadEnv.ts index 6c3c452..08efb9e 100644 --- a/packages/commandkit/src/bootstrap/loadEnv.ts +++ b/packages/commandkit/src/bootstrap/loadEnv.ts @@ -1,9 +1,9 @@ import { config } from 'dotenv-cra'; export function loadEnv(type: 'development' | 'production') { - process.env.NODE_ENV = type; + process.env.NODE_ENV = type; - const result = config(); + const result = config(); - return result.error?.message; + return result.error?.message; } diff --git a/packages/commandkit/src/components/ButtonKit.ts b/packages/commandkit/src/components/ButtonKit.ts index c23bf0e..2bd21b9 100644 --- a/packages/commandkit/src/components/ButtonKit.ts +++ b/packages/commandkit/src/components/ButtonKit.ts @@ -1,13 +1,13 @@ import { - type Message, - type Awaitable, - type ButtonInteraction, - type InteractionCollector, - type InteractionCollectorOptions, - type APIButtonComponentWithCustomId, - ButtonStyle, - ButtonBuilder, - ComponentType, + type Message, + type Awaitable, + type ButtonInteraction, + type InteractionCollector, + type InteractionCollectorOptions, + type APIButtonComponentWithCustomId, + ButtonStyle, + ButtonBuilder, + ComponentType, } from 'discord.js'; /** @@ -15,151 +15,164 @@ import { * If the first argument is null, it means that the interaction collector has been destroyed. */ export type CommandKitButtonBuilderInteractionCollectorDispatch = ( - interaction: ButtonInteraction, + interaction: ButtonInteraction, ) => Awaitable; export type CommandKitButtonBuilderOnEnd = () => Awaitable; export type CommandKitButtonBuilderInteractionCollectorDispatchContextData = { - /** - * The message to listen for button interactions on. - */ - message: Message; - /** - * The duration (in ms) that the collector should run for. - */ - time?: number; - /** - * If the collector should automatically reset the timer when a button is clicked. - */ - autoReset?: boolean; -} & Omit, 'filter' | 'componentType'>; + /** + * The message to listen for button interactions on. + */ + message: Message; + /** + * The duration (in ms) that the collector should run for. + */ + time?: number; + /** + * If the collector should automatically reset the timer when a button is clicked. + */ + autoReset?: boolean; +} & Omit< + InteractionCollectorOptions, + 'filter' | 'componentType' +>; export class ButtonKit extends ButtonBuilder { - #onClickHandler: CommandKitButtonBuilderInteractionCollectorDispatch | null = null; - #onEndHandler: CommandKitButtonBuilderOnEnd | null = null; - #contextData: CommandKitButtonBuilderInteractionCollectorDispatchContextData | null = null; - #collector: InteractionCollector | null = null; - - /** - * Sets up an inline interaction collector for this button. This collector by default allows as many interactions as possible if it is actively used. - * If unused, this expires after 24 hours or custom time if specified. - * @param handler The handler to run when the button is clicked - * @param data The context data to use for the interaction collector - * @returns This button - * @example - * ```ts - * const button = new ButtonKit() - * .setLabel('Click me') - * .setStyle(ButtonStyle.Primary) - * .setCustomId('click_me'); - * - * const row = new ActionRowBuilder().addComponents(button); - * - * const message = await channel.send({ content: 'Click the button', components: [row] }); - * - * button.onClick(async (interaction) => { - * await interaction.reply('You clicked me!'); - * }, { message }); - * - * // Remove onClick handler and destroy the interaction collector - * button.onClick(null); - * ``` - */ - public onClick( - handler: CommandKitButtonBuilderInteractionCollectorDispatch, - data?: CommandKitButtonBuilderInteractionCollectorDispatchContextData, - ): this { - if (this.data.style === ButtonStyle.Link) { - throw new TypeError('Cannot setup "onClick" handler on link buttons.'); - } - - if (!handler) { - throw new TypeError('Cannot setup "onClick" without a handler function parameter.'); - } - - this.#destroyCollector(); - - this.#onClickHandler = handler; - if (data) this.#contextData = data; - - this.#setupInteractionCollector(); - - return this; + #onClickHandler: CommandKitButtonBuilderInteractionCollectorDispatch | null = + null; + #onEndHandler: CommandKitButtonBuilderOnEnd | null = null; + #contextData: CommandKitButtonBuilderInteractionCollectorDispatchContextData | null = + null; + #collector: InteractionCollector | null = null; + + /** + * Sets up an inline interaction collector for this button. This collector by default allows as many interactions as possible if it is actively used. + * If unused, this expires after 24 hours or custom time if specified. + * @param handler The handler to run when the button is clicked + * @param data The context data to use for the interaction collector + * @returns This button + * @example + * ```ts + * const button = new ButtonKit() + * .setLabel('Click me') + * .setStyle(ButtonStyle.Primary) + * .setCustomId('click_me'); + * + * const row = new ActionRowBuilder().addComponents(button); + * + * const message = await channel.send({ content: 'Click the button', components: [row] }); + * + * button.onClick(async (interaction) => { + * await interaction.reply('You clicked me!'); + * }, { message }); + * + * // Remove onClick handler and destroy the interaction collector + * button.onClick(null); + * ``` + */ + public onClick( + handler: CommandKitButtonBuilderInteractionCollectorDispatch, + data?: CommandKitButtonBuilderInteractionCollectorDispatchContextData, + ): this { + if (this.data.style === ButtonStyle.Link) { + throw new TypeError('Cannot setup "onClick" handler on link buttons.'); } - public onEnd(handler: CommandKitButtonBuilderOnEnd): this { - if (!handler) { - throw new TypeError('Cannot setup "onEnd" without a handler function parameter.'); - } - - this.#onEndHandler = handler; - - return this; + if (!handler) { + throw new TypeError( + 'Cannot setup "onClick" without a handler function parameter.', + ); } - #setupInteractionCollector() { - if (!this.#contextData || !this.#onClickHandler) return; - - const message = this.#contextData.message; + this.#destroyCollector(); - if (!message) { - throw new TypeError( - 'Cannot setup "onClick" handler without a message in the context data.', - ); - } + this.#onClickHandler = handler; + if (data) this.#contextData = data; - if ('customId' in this.data && !this.data.customId) { - throw new TypeError('Cannot setup "onClick" handler on a button without a custom id.'); - } + this.#setupInteractionCollector(); - const data = { - time: 86_400_000, - autoReset: true, - ...this.#contextData, - }; + return this; + } - const collector = (this.#collector = message.createMessageComponentCollector({ - filter: (interaction) => - interaction.customId === (this.data).custom_id && - interaction.message.id === message.id, - componentType: ComponentType.Button, - ...data, - })); - - this.#collector.on('collect', (interaction) => { - const handler = this.#onClickHandler; + public onEnd(handler: CommandKitButtonBuilderOnEnd): this { + if (!handler) { + throw new TypeError( + 'Cannot setup "onEnd" without a handler function parameter.', + ); + } - if (!handler) return this.#destroyCollector(); + this.#onEndHandler = handler; - if (!this.#collector) { - return collector.stop('destroyed'); - } + return this; + } - if (data.autoReset) { - this.#collector.resetTimer(); - } + #setupInteractionCollector() { + if (!this.#contextData || !this.#onClickHandler) return; - return handler(interaction); - }); + const message = this.#contextData.message; - this.#collector.on('end', () => { - this.#destroyCollector(); - this.#onEndHandler?.(); - }); + if (!message) { + throw new TypeError( + 'Cannot setup "onClick" handler without a message in the context data.', + ); } - public dispose() { - this.#destroyCollector(); - this.#onEndHandler?.(); - return this; + if ('customId' in this.data && !this.data.customId) { + throw new TypeError( + 'Cannot setup "onClick" handler on a button without a custom id.', + ); } - #destroyCollector() { - this.#collector?.stop('end'); - this.#collector?.removeAllListeners(); - this.#collector = null; - this.#contextData = null; - this.#onClickHandler = null; - } + const data = { + time: 86_400_000, + autoReset: true, + ...this.#contextData, + }; + + const collector = (this.#collector = + message.createMessageComponentCollector({ + filter: (interaction) => + interaction.customId === + (this.data).custom_id && + interaction.message.id === message.id, + componentType: ComponentType.Button, + ...data, + })); + + this.#collector.on('collect', (interaction) => { + const handler = this.#onClickHandler; + + if (!handler) return this.#destroyCollector(); + + if (!this.#collector) { + return collector.stop('destroyed'); + } + + if (data.autoReset) { + this.#collector.resetTimer(); + } + + return handler(interaction); + }); + + this.#collector.on('end', () => { + this.#destroyCollector(); + this.#onEndHandler?.(); + }); + } + + public dispose() { + this.#destroyCollector(); + this.#onEndHandler?.(); + return this; + } + + #destroyCollector() { + this.#collector?.stop('end'); + this.#collector?.removeAllListeners(); + this.#collector = null; + this.#contextData = null; + this.#onClickHandler = null; + } } diff --git a/packages/commandkit/src/config.ts b/packages/commandkit/src/config.ts index 127ce9d..aa7d004 100644 --- a/packages/commandkit/src/config.ts +++ b/packages/commandkit/src/config.ts @@ -1,86 +1,89 @@ import type { ClientOptions } from 'discord.js'; export interface CommandKitConfig { - /** - * The Discord client options. - */ - clientOptions: ClientOptions; - /** - * The Discord bot token. Defaults to `process.env.DISCORD_TOKEN`. - */ - token?: string; - /** - * Whether or not to use the watch mode. Defaults to `true`. - */ - watch: boolean; - /** - * The output directory of the project. Defaults to `dist`. - */ - outDir: string; - /** - * Whether or not to include extra env utilities. Defaults to `true`. - */ - envExtra: boolean; - /** - * Node.js cli options. - */ - nodeOptions: string[]; - /** - * Whether or not to clear default restart logs. Defaults to `true`. - */ - clearRestartLogs: boolean; - /** - * Whether or not to minify the output. Defaults to `false`. - */ - minify: boolean; - /** - * Whether or not to include sourcemaps in production build. Defaults to `false`. - */ - sourcemap: boolean | 'inline'; - /** - * Whether or not to include anti-crash handler in production. Defaults to `true`. - */ - antiCrash: boolean; - /** - * Whether or not to polyfill `require` function. Defaults to `true`. - */ - requirePolyfill: boolean; + /** + * The Discord client options. + */ + clientOptions: ClientOptions; + /** + * The Discord bot token. Defaults to `process.env.DISCORD_TOKEN`. + */ + token?: string; + /** + * Whether or not to use the watch mode. Defaults to `true`. + */ + watch: boolean; + /** + * The output directory of the project. Defaults to `dist`. + */ + outDir: string; + /** + * Whether or not to include extra env utilities. Defaults to `true`. + */ + envExtra: boolean; + /** + * Node.js cli options. + */ + nodeOptions: string[]; + /** + * Whether or not to clear default restart logs. Defaults to `true`. + */ + clearRestartLogs: boolean; + /** + * Whether or not to minify the output. Defaults to `false`. + */ + minify: boolean; + /** + * Whether or not to include sourcemaps in production build. Defaults to `false`. + */ + sourcemap: boolean | 'inline'; + /** + * Whether or not to include anti-crash handler in production. Defaults to `true`. + */ + antiCrash: boolean; + /** + * Whether or not to polyfill `require` function. Defaults to `true`. + */ + requirePolyfill: boolean; } let globalConfig: Partial = { - envExtra: true, - outDir: 'dist', - watch: true, - clearRestartLogs: true, - minify: false, - sourcemap: false, - nodeOptions: [], - antiCrash: true, - requirePolyfill: true, - token: process.env.DISCORD_TOKEN, + envExtra: true, + outDir: 'dist', + watch: true, + clearRestartLogs: true, + minify: false, + sourcemap: false, + nodeOptions: [], + antiCrash: true, + requirePolyfill: true, + token: process.env.DISCORD_TOKEN, }; export function getConfig(): CommandKitConfig { - return globalConfig as CommandKitConfig; + return globalConfig as CommandKitConfig; } const requiredProps = ['clientOptions'] as const; type R = (typeof requiredProps)[number]; -type PartialConfig = Partial> & Pick; +type PartialConfig = Partial> & + Pick; export function defineConfig(config: PartialConfig) { - for (const prop of requiredProps) { - if (!config[prop]) { - throw new Error(`[CommandKit Config] Missing required config property: ${prop}`); - } + for (const prop of requiredProps) { + if (!config[prop]) { + throw new Error( + `[CommandKit Config] Missing required config property: ${prop}`, + ); } + } - globalConfig = { - ...globalConfig, - ...config, - }; + globalConfig = { + ...globalConfig, + ...config, + }; - return globalConfig; + return globalConfig; } diff --git a/packages/commandkit/src/environment/actions/development.ts b/packages/commandkit/src/environment/actions/development.ts index 024dbff..67f2a9e 100644 --- a/packages/commandkit/src/environment/actions/development.ts +++ b/packages/commandkit/src/environment/actions/development.ts @@ -9,60 +9,62 @@ import { bundle } from '../bundler/bundle'; const commandkitVersion = '[VI]{{inject}}[/VI]'; function printBanner() { - const banner = colors.magenta(`${String.fromCharCode(9670)} CommandKit ${commandkitVersion}`); - Logger.Log(banner); - Logger.Info('Initializing the development environment...'); + const banner = colors.magenta( + `${String.fromCharCode(9670)} CommandKit ${commandkitVersion}`, + ); + Logger.Log(banner); + Logger.Info('Initializing the development environment...'); } export async function initializeDevelopmentEnvironment( - args: yargs.ArgumentsCamelCase<{ - config?: string | undefined; - nodeOptions?: string | undefined; - }>, + args: yargs.ArgumentsCamelCase<{ + config?: string | undefined; + nodeOptions?: string | undefined; + }>, ) { - printBanner(); + printBanner(); - if (getClient()) { - Logger.Fatal('The development environment is already initialized.'); - return; - } + if (getClient()) { + Logger.Fatal('The development environment is already initialized.'); + return; + } - const envErr = loadEnv('development'); + const envErr = loadEnv('development'); - if (envErr) { - Logger.Warning('Failed to load .env', envErr); - } else { - Logger.Debug('Loaded .env'); - } + if (envErr) { + Logger.Warning('Failed to load .env', envErr); + } else { + Logger.Debug('Loaded .env'); + } - const configPath = await findConfigPath(args.config ?? process.cwd()); - if (!configPath) { - const msg = `Could not locate the commandkit config file${ - args.config ? ' at ' + args.config : ' in the current working directory' - }.`; - Logger.Fatal(msg); - return; - } + const configPath = await findConfigPath(args.config ?? process.cwd()); + if (!configPath) { + const msg = `Could not locate the commandkit config file${ + args.config ? ' at ' + args.config : ' in the current working directory' + }.`; + Logger.Fatal(msg); + return; + } - try { - var config = await importConfig(configPath); - Logger.Debug('Loaded config from', colors.yellow(configPath)); - } catch (e) { - Logger.Warning('Failed to load config'); - Logger.Fatal(colors.red((e as Error).stack ?? `${e}`)); - return; - } + try { + var config = await importConfig(configPath); + Logger.Debug('Loaded config from', colors.yellow(configPath)); + } catch (e) { + Logger.Warning('Failed to load config'); + Logger.Fatal(colors.red((e as Error).stack ?? `${e}`)); + return; + } - const client = createClient(); + const client = createClient(); - // build the project - const entrypoint = await bundle('development'); + // build the project + const entrypoint = await bundle('development'); - try { - // load the client entrypoint - await import(`file://${entrypoint}`); - await client.login(config.token); - } catch (e) { - Logger.Fatal('Failed to load the client entrypoint', e); - } + try { + // load the client entrypoint + await import(`file://${entrypoint}`); + await client.login(config.token); + } catch (e) { + Logger.Fatal('Failed to load the client entrypoint', e); + } } diff --git a/packages/commandkit/src/environment/bundler/bundle.ts b/packages/commandkit/src/environment/bundler/bundle.ts index 2116e02..4d25131 100644 --- a/packages/commandkit/src/environment/bundler/bundle.ts +++ b/packages/commandkit/src/environment/bundler/bundle.ts @@ -3,37 +3,37 @@ import { getConfig } from '../../config'; import { join } from 'path'; export function bundle(mode: 'development' | 'production') { - switch (mode) { - case 'development': - return buildDevelopment(); - default: - throw new Error('Not implemented'); - } + switch (mode) { + case 'development': + return buildDevelopment(); + default: + throw new Error('Not implemented'); + } } function buildDevelopment() { - const { watch } = getConfig(); + const { watch } = getConfig(); - const outDir = join(process.cwd(), '.commandkit'); + const outDir = join(process.cwd(), '.commandkit'); - return build({ - clean: true, - format: ['esm'], - bundle: false, - dts: false, - skipNodeModulesBundle: true, - minify: false, - shims: true, - sourcemap: 'inline', - keepNames: true, - outDir: '.commandkit', - silent: true, - entry: ['src'], - watch, - async onSuccess() { - // return await injectShims('.commandkit', main, false, requirePolyfill); - }, - }).then(() => { - return join(outDir, 'client.mjs'); - }); + return build({ + clean: true, + format: ['esm'], + bundle: false, + dts: false, + skipNodeModulesBundle: true, + minify: false, + shims: true, + sourcemap: 'inline', + keepNames: true, + outDir: '.commandkit', + silent: true, + entry: ['src'], + watch, + async onSuccess() { + // return await injectShims('.commandkit', main, false, requirePolyfill); + }, + }).then(() => { + return join(outDir, 'client.mjs'); + }); } diff --git a/packages/commandkit/src/environment/bundler/shims.ts b/packages/commandkit/src/environment/bundler/shims.ts index 363165d..8240973 100644 --- a/packages/commandkit/src/environment/bundler/shims.ts +++ b/packages/commandkit/src/environment/bundler/shims.ts @@ -2,55 +2,62 @@ import { readFile, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; export async function injectShims( - outDir: string, - main: string, - antiCrash: boolean, - polyfillRequire: boolean, + outDir: string, + main: string, + antiCrash: boolean, + polyfillRequire: boolean, ) { - const path = join(process.cwd(), outDir, main); + const path = join(process.cwd(), outDir, main); - const head = ['\n\n;await (async()=>{', " 'use strict';"].join('\n'); - const tail = '\n})();'; - const requireScript = polyfillRequire - ? [ - '// --- CommandKit require() polyfill ---', - ' if (typeof require === "undefined") {', - ' const { createRequire } = await import("node:module");', - ' const __require = createRequire(import.meta.url);', - ' Object.defineProperty(globalThis, "require", {', - ' value: (id) => {', - ' return __require(id);', - ' },', - ' configurable: true,', - ' enumerable: false,', - ' writable: true,', - ' });', - ' }', - '// --- CommandKit require() polyfill ---', - ].join('\n') - : ''; + const head = ['\n\n;await (async()=>{', " 'use strict';"].join('\n'); + const tail = '\n})();'; + const requireScript = polyfillRequire + ? [ + '// --- CommandKit require() polyfill ---', + ' if (typeof require === "undefined") {', + ' const { createRequire } = await import("node:module");', + ' const __require = createRequire(import.meta.url);', + ' Object.defineProperty(globalThis, "require", {', + ' value: (id) => {', + ' return __require(id);', + ' },', + ' configurable: true,', + ' enumerable: false,', + ' writable: true,', + ' });', + ' }', + '// --- CommandKit require() polyfill ---', + ].join('\n') + : ''; - const antiCrashScript = antiCrash - ? [ - '// --- CommandKit Anti-Crash Monitor ---', - " // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process", - ' // instead of using it as a means to resume operation.', - ' // But it exists here due to compatibility reasons with discord bot ecosystem.', - " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", - ' if (!process.eventNames().includes(e1)) // skip if it is already handled', - ' process.on(e1, (e) => {', - ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', - ' })', - ' if (!process.eventNames().includes(e2)) // skip if it is already handled', - ' process.on(e2, (r) => {', - ' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));', - ' });', - '// --- CommandKit Anti-Crash Monitor ---', - ].join('\n') - : ''; + const antiCrashScript = antiCrash + ? [ + '// --- CommandKit Anti-Crash Monitor ---', + " // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process", + ' // instead of using it as a means to resume operation.', + ' // But it exists here due to compatibility reasons with discord bot ecosystem.', + " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", + ' if (!process.eventNames().includes(e1)) // skip if it is already handled', + ' process.on(e1, (e) => {', + ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', + ' })', + ' if (!process.eventNames().includes(e2)) // skip if it is already handled', + ' process.on(e2, (r) => {', + ' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));', + ' });', + '// --- CommandKit Anti-Crash Monitor ---', + ].join('\n') + : ''; - const contents = await readFile(path, 'utf-8'); - const finalScript = [head, requireScript, antiCrashScript, tail, '\n\n', contents].join('\n'); + const contents = await readFile(path, 'utf-8'); + const finalScript = [ + head, + requireScript, + antiCrashScript, + tail, + '\n\n', + contents, + ].join('\n'); - return writeFile(path, finalScript); + return writeFile(path, finalScript); } diff --git a/packages/commandkit/src/environment/cli.ts b/packages/commandkit/src/environment/cli.ts index 03d66fd..de0764c 100644 --- a/packages/commandkit/src/environment/cli.ts +++ b/packages/commandkit/src/environment/cli.ts @@ -3,30 +3,30 @@ import { hideBin } from 'yargs/helpers'; import { initializeDevelopmentEnvironment } from './actions/development'; yargs(hideBin(process.argv)) - .scriptName('commandkit') - .command( - 'dev', - 'Start the bot in development mode', - () => {}, - async (args) => { - await initializeDevelopmentEnvironment(args); - }, - ) - .command('start', 'Start the production build') - .command('build', 'Generate production build of the project') - .options({ - config: { - alias: 'c', - type: 'string', - description: 'Path to the commandkit config file', - }, - nodeOptions: { - alias: 'n', - type: 'string', - description: 'Node options to pass to the process', - }, - }) - .version('[VI]{{inject}}[/VI]') - .help() - .demandCommand() - .parse(); + .scriptName('commandkit') + .command( + 'dev', + 'Start the bot in development mode', + () => {}, + async (args) => { + await initializeDevelopmentEnvironment(args); + }, + ) + .command('start', 'Start the production build') + .command('build', 'Generate production build of the project') + .options({ + config: { + alias: 'c', + type: 'string', + description: 'Path to the commandkit config file', + }, + nodeOptions: { + alias: 'n', + type: 'string', + description: 'Node options to pass to the process', + }, + }) + .version('[VI]{{inject}}[/VI]') + .help() + .demandCommand() + .parse(); diff --git a/packages/commandkit/src/environment/common/config.ts b/packages/commandkit/src/environment/common/config.ts index 97ba968..f444471 100644 --- a/packages/commandkit/src/environment/common/config.ts +++ b/packages/commandkit/src/environment/common/config.ts @@ -3,22 +3,22 @@ import { join } from 'node:path'; import type { CommandKitConfig } from '../../config'; const ConfigLookupPaths = [ - // javascript - 'js', - 'cjs', - 'mjs', + // javascript + 'js', + 'cjs', + 'mjs', ]; export async function findConfigPath(relative: string) { - for (const extension of ConfigLookupPaths) { - const path = join(relative, `commandkit.${extension}`); - if (existsSync(path)) return path; - } + for (const extension of ConfigLookupPaths) { + const path = join(relative, `commandkit.${extension}`); + if (existsSync(path)) return path; + } - return null; + return null; } export async function importConfig(path: string): Promise { - const config = await import(`file://${path}`); - return config?.default ?? config; + const config = await import(`file://${path}`); + return config?.default ?? config; } diff --git a/packages/commandkit/src/environment/common/logger.ts b/packages/commandkit/src/environment/common/logger.ts index aad3ec0..3f85a9d 100644 --- a/packages/commandkit/src/environment/common/logger.ts +++ b/packages/commandkit/src/environment/common/logger.ts @@ -1,20 +1,20 @@ import colors from '../../utils/colors'; export const Logger = { - Fatal: (...message: unknown[]) => { - console.log(colors.red('[FATAL ERROR]'), ...message); - process.exit(1); - }, - Warning: (...message: unknown[]) => { - console.log(colors.yellow('[WARNING]'), ...message); - }, - Info: (...message: unknown[]) => { - console.log(colors.green('[INFO]'), ...message); - }, - Debug: (...message: unknown[]) => { - console.log(colors.blue('[DEBUG]'), ...message); - }, - Log: (...message: unknown[]) => { - console.log(...message); - }, + Fatal: (...message: unknown[]) => { + console.log(colors.red('[FATAL ERROR]'), ...message); + process.exit(1); + }, + Warning: (...message: unknown[]) => { + console.log(colors.yellow('[WARNING]'), ...message); + }, + Info: (...message: unknown[]) => { + console.log(colors.green('[INFO]'), ...message); + }, + Debug: (...message: unknown[]) => { + console.log(colors.blue('[DEBUG]'), ...message); + }, + Log: (...message: unknown[]) => { + console.log(...message); + }, }; diff --git a/packages/commandkit/src/handlers/command-handler/CommandHandler.ts b/packages/commandkit/src/handlers/command-handler/CommandHandler.ts index 439fb61..d50e58c 100644 --- a/packages/commandkit/src/handlers/command-handler/CommandHandler.ts +++ b/packages/commandkit/src/handlers/command-handler/CommandHandler.ts @@ -1,4 +1,8 @@ -import type { CommandHandlerData, CommandHandlerOptions, CommandKitInteraction } from './typings'; +import type { + CommandHandlerData, + CommandHandlerOptions, + CommandKitInteraction, +} from './typings'; import type { CommandFileObject, ReloadOptions } from '../../typings'; import { toFileURL } from '../../utils/resolve-file-url'; @@ -13,293 +17,300 @@ import { AsyncLocalStorage } from 'async_hooks'; import type { CommandData } from '../../types'; export interface hCommandContext { - interaction: CommandKitInteraction; - command: CommandData; + interaction: CommandKitInteraction; + command: CommandData; } /** * A handler for client application commands. */ export class CommandHandler { - #data: CommandHandlerData; - context: AsyncLocalStorage | null = null; - - constructor({ ...options }: CommandHandlerOptions) { - this.#data = { - ...options, - builtInValidations: [], - commands: [], - }; + #data: CommandHandlerData; + context: AsyncLocalStorage | null = null; + + constructor({ ...options }: CommandHandlerOptions) { + this.#data = { + ...options, + builtInValidations: [], + commands: [], + }; + } + + async init() { + if (this.#data.enableHooks && !this.context) { + this.context = new AsyncLocalStorage(); } + await this.#buildCommands(); - async init() { - if (this.#data.enableHooks && !this.context) { - this.context = new AsyncLocalStorage(); - } - await this.#buildCommands(); + this.#buildBuiltInValidations(); - this.#buildBuiltInValidations(); + const devOnlyCommands = this.#data.commands.filter( + (cmd) => cmd.options?.devOnly, + ); - const devOnlyCommands = this.#data.commands.filter((cmd) => cmd.options?.devOnly); + if (devOnlyCommands.length && !this.#data.devGuildIds.length) { + process.emitWarning( + colors.yellow( + 'You have commands marked as "devOnly", but "devGuildIds" have not been set.', + ), + ); + } - if (devOnlyCommands.length && !this.#data.devGuildIds.length) { - process.emitWarning( - colors.yellow( - 'You have commands marked as "devOnly", but "devGuildIds" have not been set.', - ), - ); - } + if ( + devOnlyCommands.length && + !this.#data.devUserIds.length && + !this.#data.devRoleIds.length + ) { + process.emitWarning( + colors.yellow( + 'You have commands marked as "devOnly", but "devUserIds" or "devRoleIds" have not been set.', + ), + ); + } - if ( - devOnlyCommands.length && - !this.#data.devUserIds.length && - !this.#data.devRoleIds.length - ) { - process.emitWarning( - colors.yellow( - 'You have commands marked as "devOnly", but "devUserIds" or "devRoleIds" have not been set.', - ), - ); - } + if (this.#data.bulkRegister) { + await loadCommandsWithRest({ + client: this.#data.client, + devGuildIds: this.#data.devGuildIds, + commands: this.#data.commands, + }); + } else { + await registerCommands({ + client: this.#data.client, + devGuildIds: this.#data.devGuildIds, + commands: this.#data.commands, + }); + } - if (this.#data.bulkRegister) { - await loadCommandsWithRest({ - client: this.#data.client, - devGuildIds: this.#data.devGuildIds, - commands: this.#data.commands, - }); - } else { - await registerCommands({ - client: this.#data.client, - devGuildIds: this.#data.devGuildIds, - commands: this.#data.commands, - }); - } + this.handleCommands(); + } + + async #buildCommands() { + const allowedExtensions = /\.(js|mjs|cjs|ts)$/i; + const paths = await getFilePaths(this.#data.commandsPath, true); + + const commandFilePaths = paths.filter((path) => + allowedExtensions.test(path), + ); + + for (const commandFilePath of commandFilePaths) { + const modulePath = toFileURL(commandFilePath); + + const importedObj = await import(`${modulePath}?t=${Date.now()}`); + let commandObj: CommandFileObject = clone(importedObj); // Make commandObj extensible + + // If it's CommonJS, invalidate the import cache + if (typeof module !== 'undefined' && typeof require !== 'undefined') { + delete require.cache[require.resolve(commandFilePath)]; + } + + const compactFilePath = + commandFilePath.split(process.cwd())[1] || commandFilePath; + + if (commandObj.default) + commandObj = commandObj.default as CommandFileObject; + + // Ensure builder properties + if (importedObj.default) { + commandObj.data = importedObj.default.data; + } else { + commandObj.data = importedObj.data; + } + + if (!commandObj.data) { + process.emitWarning( + colors.yellow( + `Ignoring: Command file ${compactFilePath} does not export "data".`, + ), + ); + continue; + } + + if (!commandObj.data.name) { + process.emitWarning( + colors.yellow( + `Ignoring: Command file ${compactFilePath} does not export "data.name".`, + ), + ); + continue; + } + + if (!commandObj.run) { + process.emitWarning( + colors.yellow( + `Ignoring: Command file ${commandObj.data.name} does not export "run".`, + ), + ); + continue; + } + + if (typeof commandObj.run !== 'function') { + process.emitWarning( + colors.yellow( + `Ignoring: Command file ${commandObj.data.name} does not export "run" as a function.`, + ), + ); + continue; + } + + commandObj.filePath = commandFilePath; + + let commandCategory = + commandFilePath + .split(this.#data.commandsPath)[1] + ?.replace(/\\\\|\\/g, '/') + .split('/')[1] || null; + + if (commandCategory && allowedExtensions.test(commandCategory)) { + commandObj.category = null; + } else { + commandObj.category = commandCategory; + } + + this.#data.commands.push(commandObj); + } + } - this.handleCommands(); + #buildBuiltInValidations() { + for (const builtInValidationFunction of builtInValidationsFunctions) { + this.#data.builtInValidations.push(builtInValidationFunction); } + } - async #buildCommands() { - const allowedExtensions = /\.(js|mjs|cjs|ts)$/i; - const paths = await getFilePaths(this.#data.commandsPath, true); + handleCommands() { + const areHooksEnabled = this.#data.enableHooks; - const commandFilePaths = paths.filter((path) => allowedExtensions.test(path)); + this.#data.client.on('interactionCreate', async (interaction) => { + if ( + !interaction.isChatInputCommand() && + !interaction.isContextMenuCommand() && + !interaction.isAutocomplete() + ) + return; - for (const commandFilePath of commandFilePaths) { - const modulePath = toFileURL(commandFilePath); + const isAutocomplete = interaction.isAutocomplete(); - const importedObj = await import(`${modulePath}?t=${Date.now()}`); - let commandObj: CommandFileObject = clone(importedObj); // Make commandObj extensible + const targetCommand = this.#data.commands.find( + (cmd) => cmd.data.name === interaction.commandName, + ); - // If it's CommonJS, invalidate the import cache - if (typeof module !== 'undefined' && typeof require !== 'undefined') { - delete require.cache[require.resolve(commandFilePath)]; - } + if (!targetCommand) return; - const compactFilePath = commandFilePath.split(process.cwd())[1] || commandFilePath; + const { data, options, run, autocomplete, ...rest } = targetCommand; - if (commandObj.default) commandObj = commandObj.default as CommandFileObject; + // Skip if autocomplete handler is not defined + if (isAutocomplete && !autocomplete) return; - // Ensure builder properties - if (importedObj.default) { - commandObj.data = importedObj.default.data; - } else { - commandObj.data = importedObj.data; - } + const executor = async () => { + const commandObj = { + data: targetCommand.data, + options: targetCommand.options, + ...rest, + }; - if (!commandObj.data) { - process.emitWarning( - colors.yellow( - `Ignoring: Command file ${compactFilePath} does not export "data".`, - ), - ); - continue; - } + if (this.#data.validationHandler) { + let canRun = true; - if (!commandObj.data.name) { - process.emitWarning( - colors.yellow( - `Ignoring: Command file ${compactFilePath} does not export "data.name".`, - ), - ); - continue; - } + for (const validationFunction of this.#data.validationHandler + .validations) { + const stopValidationLoop = await validationFunction({ + interaction, + commandObj, + client: this.#data.client, + handler: this.#data.commandkitInstance, + }); - if (!commandObj.run) { - process.emitWarning( - colors.yellow( - `Ignoring: Command file ${commandObj.data.name} does not export "run".`, - ), - ); - continue; + if (stopValidationLoop) { + canRun = false; + break; } + } - if (typeof commandObj.run !== 'function') { - process.emitWarning( - colors.yellow( - `Ignoring: Command file ${commandObj.data.name} does not export "run" as a function.`, - ), - ); - continue; - } + if (!canRun) return; + } - commandObj.filePath = commandFilePath; + let canRun = true; - let commandCategory = - commandFilePath - .split(this.#data.commandsPath)[1] - ?.replace(/\\\\|\\/g, '/') - .split('/')[1] || null; + // If custom validations pass and !skipBuiltInValidations, run built-in CommandKit validation functions + if (!this.#data.skipBuiltInValidations) { + for (const validation of this.#data.builtInValidations) { + const stopValidationLoop = validation({ + targetCommand, + interaction, + handlerData: this.#data, + }); - if (commandCategory && allowedExtensions.test(commandCategory)) { - commandObj.category = null; - } else { - commandObj.category = commandCategory; + if (stopValidationLoop) { + canRun = false; + break; } - - this.#data.commands.push(commandObj); - } - } - - #buildBuiltInValidations() { - for (const builtInValidationFunction of builtInValidationsFunctions) { - this.#data.builtInValidations.push(builtInValidationFunction); + } } - } - handleCommands() { - const areHooksEnabled = this.#data.enableHooks; - - this.#data.client.on('interactionCreate', async (interaction) => { - if ( - !interaction.isChatInputCommand() && - !interaction.isContextMenuCommand() && - !interaction.isAutocomplete() - ) - return; - - const isAutocomplete = interaction.isAutocomplete(); - - const targetCommand = this.#data.commands.find( - (cmd) => cmd.data.name === interaction.commandName, - ); - - if (!targetCommand) return; - - const { data, options, run, autocomplete, ...rest } = targetCommand; - - // Skip if autocomplete handler is not defined - if (isAutocomplete && !autocomplete) return; - - const executor = async () => { - const commandObj = { - data: targetCommand.data, - options: targetCommand.options, - ...rest, - }; - - if (this.#data.validationHandler) { - let canRun = true; - - for (const validationFunction of this.#data.validationHandler.validations) { - const stopValidationLoop = await validationFunction({ - interaction, - commandObj, - client: this.#data.client, - handler: this.#data.commandkitInstance, - }); - - if (stopValidationLoop) { - canRun = false; - break; - } - } - - if (!canRun) return; - } - - let canRun = true; - - // If custom validations pass and !skipBuiltInValidations, run built-in CommandKit validation functions - if (!this.#data.skipBuiltInValidations) { - for (const validation of this.#data.builtInValidations) { - const stopValidationLoop = validation({ - targetCommand, - interaction, - handlerData: this.#data, - }); - - if (stopValidationLoop) { - canRun = false; - break; - } - } - } - - if (!canRun) return; - - const command = targetCommand[isAutocomplete ? 'autocomplete' : 'run']!; - - // if hooks are not enabled, pass the context to the command via its arguments - if (!areHooksEnabled) { - const context = { - interaction, - client: this.#data.client, - handler: this.#data.commandkitInstance, - }; - return await command(context); - } - - // @ts-expect-error - context data is not passed when hooks are enabled - return command(); - }; - - if (this.context) - return this.context.run( - { - command: targetCommand.data, - interaction, - }, - executor, - ); - return executor(); - }); - } + if (!canRun) return; - get commands() { - return this.#data.commands; - } + const command = targetCommand[isAutocomplete ? 'autocomplete' : 'run']!; - async reloadCommands(type?: ReloadOptions) { - if (!this.#data.commandsPath) { - throw new Error( - colors.red( - 'Cannot reload commands as "commandsPath" was not provided when instantiating CommandKit.', - ), - ); + // if hooks are not enabled, pass the context to the command via its arguments + if (!areHooksEnabled) { + const context = { + interaction, + client: this.#data.client, + handler: this.#data.commandkitInstance, + }; + return await command(context); } - this.#data.commands = []; - - // Re-build commands tree - await this.#buildCommands(); + // @ts-expect-error - context data is not passed when hooks are enabled + return command(); + }; + + if (this.context) + return this.context.run( + { + command: targetCommand.data, + interaction, + }, + executor, + ); + return executor(); + }); + } + + get commands() { + return this.#data.commands; + } + + async reloadCommands(type?: ReloadOptions) { + if (!this.#data.commandsPath) { + throw new Error( + colors.red( + 'Cannot reload commands as "commandsPath" was not provided when instantiating CommandKit.', + ), + ); + } - if (this.#data.bulkRegister) { - await loadCommandsWithRest({ - client: this.#data.client, - devGuildIds: this.#data.devGuildIds, - commands: this.#data.commands, - reloading: true, - type, - }); - } else { - await registerCommands({ - client: this.#data.client, - devGuildIds: this.#data.devGuildIds, - commands: this.#data.commands, - reloading: true, - type, - }); - } + this.#data.commands = []; + + // Re-build commands tree + await this.#buildCommands(); + + if (this.#data.bulkRegister) { + await loadCommandsWithRest({ + client: this.#data.client, + devGuildIds: this.#data.devGuildIds, + commands: this.#data.commands, + reloading: true, + type, + }); + } else { + await registerCommands({ + client: this.#data.client, + devGuildIds: this.#data.devGuildIds, + commands: this.#data.commands, + reloading: true, + type, + }); } + } } diff --git a/packages/commandkit/src/handlers/command-handler/functions/loadCommandsWithRest.ts b/packages/commandkit/src/handlers/command-handler/functions/loadCommandsWithRest.ts index 66138ec..648cd9d 100644 --- a/packages/commandkit/src/handlers/command-handler/functions/loadCommandsWithRest.ts +++ b/packages/commandkit/src/handlers/command-handler/functions/loadCommandsWithRest.ts @@ -4,54 +4,64 @@ import type { CommandFileObject, ReloadOptions } from '../../../typings'; import colors from '../../../utils/colors'; type LoadCommandsWithRestProps = { - /** - * The main client. - */ - client: Client; - - /** - * An array of command objects. - */ - commands: CommandFileObject[]; - - /** - * An array of developer guild IDs. - */ - devGuildIds: string[]; - - /** - * A boolean indicating whether these commands are reloading. - */ - reloading?: boolean; - - /** - * A type for reloading the commands (if this is reloading). - */ - type?: ReloadOptions; + /** + * The main client. + */ + client: Client; + + /** + * An array of command objects. + */ + commands: CommandFileObject[]; + + /** + * An array of developer guild IDs. + */ + devGuildIds: string[]; + + /** + * A boolean indicating whether these commands are reloading. + */ + reloading?: boolean; + + /** + * A type for reloading the commands (if this is reloading). + */ + type?: ReloadOptions; }; /** * Use REST to load commands. * @param props - Options for loading commands. */ -export default async function loadCommandsWithRest(props: LoadCommandsWithRestProps) { - if (props.reloading) { - if (props.client.isReady()) { - await handleLoading( - props.client, - props.commands, - props.devGuildIds, - props.reloading, - props.type, - ); - } else { - throw new Error(colors.red(`Cannot reload commands when client is not ready.`)); - } +export default async function loadCommandsWithRest( + props: LoadCommandsWithRestProps, +) { + if (props.reloading) { + if (props.client.isReady()) { + await handleLoading( + props.client, + props.commands, + props.devGuildIds, + props.reloading, + props.type, + ); } else { - props.client.once('ready', async (c) => { - await handleLoading(c, props.commands, props.devGuildIds, props.reloading, props.type); - }); + throw new Error( + colors.red(`Cannot reload commands when client is not ready.`), + ); } + } else { + props.client.once('ready', async (c) => { + await handleLoading( + c, + props.commands, + props.devGuildIds, + props.reloading, + props.type, + ); + }); + } } /** @@ -63,24 +73,24 @@ export default async function loadCommandsWithRest(props: LoadCommandsWithRestPr * @param type - A type for reloading the commands (if this is reloading). */ async function handleLoading( - client: Client, - commands: CommandFileObject[], - devGuildIds: string[], - reloading?: boolean, - type?: ReloadOptions, + client: Client, + commands: CommandFileObject[], + devGuildIds: string[], + reloading?: boolean, + type?: ReloadOptions, ) { - commands = commands.filter((cmd) => !cmd.options?.deleted); - const devOnlyCommands = commands.filter((cmd) => cmd.options?.devOnly); - const globalCommands = commands.filter((cmd) => !cmd.options?.devOnly); - - if (type === 'dev') { - await loadDevCommands(client, devOnlyCommands, devGuildIds, reloading); - } else if (type === 'global') { - await loadGlobalCommands(client, globalCommands, reloading); - } else { - await loadDevCommands(client, devOnlyCommands, devGuildIds, reloading); - await loadGlobalCommands(client, globalCommands, reloading); - } + commands = commands.filter((cmd) => !cmd.options?.deleted); + const devOnlyCommands = commands.filter((cmd) => cmd.options?.devOnly); + const globalCommands = commands.filter((cmd) => !cmd.options?.devOnly); + + if (type === 'dev') { + await loadDevCommands(client, devOnlyCommands, devGuildIds, reloading); + } else if (type === 'global') { + await loadGlobalCommands(client, globalCommands, reloading); + } else { + await loadDevCommands(client, devOnlyCommands, devGuildIds, reloading); + await loadGlobalCommands(client, globalCommands, reloading); + } } /** @@ -90,26 +100,32 @@ async function handleLoading( * @param reloading - A boolean indicating whether the commands are reloading. */ async function loadGlobalCommands( - client: Client, - commands: CommandFileObject[], - reloading?: boolean, + client: Client, + commands: CommandFileObject[], + reloading?: boolean, ) { - const requestBody = commands.map((cmd) => cmd.data); - - await client.application.commands - .set(requestBody as ApplicationCommandDataResolvable[]) - .catch((error) => { - throw new Error( - colors.red( - `Error ${reloading ? 'reloading' : 'loading'} global application commands.\n`, - ), - error, - ); - }); - - console.log( - colors.green(`${reloading ? 'Reloaded' : 'Loaded'} ${requestBody.length} global commands.`), - ); + const requestBody = commands.map((cmd) => cmd.data); + + await client.application.commands + .set(requestBody as ApplicationCommandDataResolvable[]) + .catch((error) => { + throw new Error( + colors.red( + `Error ${ + reloading ? 'reloading' : 'loading' + } global application commands.\n`, + ), + error, + ); + }); + + console.log( + colors.green( + `${reloading ? 'Reloaded' : 'Loaded'} ${ + requestBody.length + } global commands.`, + ), + ); } /** @@ -120,48 +136,48 @@ async function loadGlobalCommands( * @param reloading - A boolean indicating whether the commands are reloading. */ async function loadDevCommands( - client: Client, - commands: CommandFileObject[], - guildIds: string[], - reloading?: boolean, + client: Client, + commands: CommandFileObject[], + guildIds: string[], + reloading?: boolean, ) { - const requestBody = commands.map((cmd) => cmd.data); - - for (const guildId of guildIds) { - const targetGuild = - client.guilds.cache.get(guildId) || (await client.guilds.fetch(guildId)); - - if (!targetGuild) { - process.emitWarning( - `Cannot ${ - reloading ? 'reload' : 'load' - } commands in guild "${guildId}" - guild doesn't exist or client isn't part of the guild.`, - ); - - continue; - } - - await targetGuild.commands - .set(requestBody as ApplicationCommandDataResolvable[]) - .catch((error) => { - throw new Error( - colors.red( - `Error ${ - reloading ? 'reloading' : 'loading' - } developer application commands in guild "${ - targetGuild?.name || guildId - }".\n`, - ), - error, - ); - }); - - console.log( - colors.green( - `${reloading ? 'Reloaded' : 'Loaded'} ${ - requestBody.length - } developer commands in guild "${targetGuild.name}".`, - ), - ); + const requestBody = commands.map((cmd) => cmd.data); + + for (const guildId of guildIds) { + const targetGuild = + client.guilds.cache.get(guildId) || (await client.guilds.fetch(guildId)); + + if (!targetGuild) { + process.emitWarning( + `Cannot ${ + reloading ? 'reload' : 'load' + } commands in guild "${guildId}" - guild doesn't exist or client isn't part of the guild.`, + ); + + continue; } + + await targetGuild.commands + .set(requestBody as ApplicationCommandDataResolvable[]) + .catch((error) => { + throw new Error( + colors.red( + `Error ${ + reloading ? 'reloading' : 'loading' + } developer application commands in guild "${ + targetGuild?.name || guildId + }".\n`, + ), + error, + ); + }); + + console.log( + colors.green( + `${reloading ? 'Reloaded' : 'Loaded'} ${ + requestBody.length + } developer commands in guild "${targetGuild.name}".`, + ), + ); + } } diff --git a/packages/commandkit/src/handlers/command-handler/functions/registerCommands.ts b/packages/commandkit/src/handlers/command-handler/functions/registerCommands.ts index ad8084e..72e07bc 100644 --- a/packages/commandkit/src/handlers/command-handler/functions/registerCommands.ts +++ b/packages/commandkit/src/handlers/command-handler/functions/registerCommands.ts @@ -1,9 +1,9 @@ import type { - Guild, - Client, - ApplicationCommandData, - GuildApplicationCommandManager, - ApplicationCommandDataResolvable, + Guild, + Client, + ApplicationCommandData, + GuildApplicationCommandManager, + ApplicationCommandDataResolvable, } from 'discord.js'; import type { CommandFileObject, ReloadOptions } from '../../../typings'; @@ -12,11 +12,11 @@ import areSlashCommandsDifferent from '../utils/areSlashCommandsDifferent'; import colors from '../../../utils/colors'; type RegisterCommandProps = { - client: Client; - commands: CommandFileObject[]; - devGuildIds: string[]; - reloading?: boolean; - type?: ReloadOptions; + client: Client; + commands: CommandFileObject[]; + devGuildIds: string[]; + reloading?: boolean; + type?: ReloadOptions; }; /** @@ -24,213 +24,249 @@ type RegisterCommandProps = { * @param props */ export default async function registerCommands(props: RegisterCommandProps) { - if (props.reloading) { - if (props.client.isReady()) { - await handleRegistration(props.client, props.commands, props.devGuildIds, props.type); - } else { - throw new Error(colors.red(`Cannot reload commands when client is not ready.`)); - } + if (props.reloading) { + if (props.client.isReady()) { + await handleRegistration( + props.client, + props.commands, + props.devGuildIds, + props.type, + ); } else { - props.client.once('ready', async (c) => { - await handleRegistration(c, props.commands, props.devGuildIds, props.type); - }); + throw new Error( + colors.red(`Cannot reload commands when client is not ready.`), + ); } + } else { + props.client.once('ready', async (c) => { + await handleRegistration( + c, + props.commands, + props.devGuildIds, + props.type, + ); + }); + } } async function handleRegistration( - client: Client, - commands: CommandFileObject[], - devGuildIds: string[], - type?: ReloadOptions, + client: Client, + commands: CommandFileObject[], + devGuildIds: string[], + type?: ReloadOptions, ) { - const devOnlyCommands = commands.filter((cmd) => cmd.options?.devOnly); - const globalCommands = commands.filter((cmd) => !cmd.options?.devOnly); - - if (type === 'dev') { - await registerDevCommands(client, devOnlyCommands, devGuildIds); - } else if (type === 'global') { - await registerGlobalCommands(client, globalCommands); - } else { - await registerDevCommands(client, devOnlyCommands, devGuildIds); - await registerGlobalCommands(client, globalCommands); - } + const devOnlyCommands = commands.filter((cmd) => cmd.options?.devOnly); + const globalCommands = commands.filter((cmd) => !cmd.options?.devOnly); + + if (type === 'dev') { + await registerDevCommands(client, devOnlyCommands, devGuildIds); + } else if (type === 'global') { + await registerGlobalCommands(client, globalCommands); + } else { + await registerDevCommands(client, devOnlyCommands, devGuildIds); + await registerGlobalCommands(client, globalCommands); + } } -async function registerGlobalCommands(client: Client, commands: CommandFileObject[]) { - const appCommandsManager = client.application.commands; - await appCommandsManager.fetch(); - - for (const command of commands) { - const targetCommand = appCommandsManager.cache.find( - (cmd) => cmd.name === command.data.name, +async function registerGlobalCommands( + client: Client, + commands: CommandFileObject[], +) { + const appCommandsManager = client.application.commands; + await appCommandsManager.fetch(); + + for (const command of commands) { + const targetCommand = appCommandsManager.cache.find( + (cmd) => cmd.name === command.data.name, + ); + + // + if (command.options?.deleted) { + if (!targetCommand) { + process.emitWarning( + colors.yellow( + `Ignoring: Command "${command.data.name}" is globally marked as deleted.`, + ), ); + } else { + await targetCommand.delete().catch((error) => { + throw new Error( + colors.red( + `Failed to delete command "${command.data.name}" globally.\n`, + ), + error, + ); + }); - // - if (command.options?.deleted) { - if (!targetCommand) { - process.emitWarning( - colors.yellow( - `Ignoring: Command "${command.data.name}" is globally marked as deleted.`, - ), - ); - } else { - await targetCommand.delete().catch((error) => { - throw new Error( - colors.red(`Failed to delete command "${command.data.name}" globally.\n`), - error, - ); - }); - - console.log(colors.green(`Deleted command "${command.data.name}" globally.`)); - } - - continue; - } - - // - if (targetCommand) { - const commandsAreDifferent = areSlashCommandsDifferent(targetCommand, command.data); + console.log( + colors.green(`Deleted command "${command.data.name}" globally.`), + ); + } - if (commandsAreDifferent) { - await targetCommand - .edit(command.data as Partial) - .catch((error) => { - throw new Error( - colors.red(`Failed to edit command "${command.data.name}" globally.\n`), - error, - ); - }); + continue; + } - console.log(colors.green(`Edited command "${command.data.name}" globally.`)); + // + if (targetCommand) { + const commandsAreDifferent = areSlashCommandsDifferent( + targetCommand, + command.data, + ); + + if (commandsAreDifferent) { + await targetCommand + .edit(command.data as Partial) + .catch((error) => { + throw new Error( + colors.red( + `Failed to edit command "${command.data.name}" globally.\n`, + ), + error, + ); + }); - continue; - } - } + console.log( + colors.green(`Edited command "${command.data.name}" globally.`), + ); - // - if (targetCommand) continue; + continue; + } + } - await appCommandsManager - .create(command.data as ApplicationCommandDataResolvable) - .catch((error) => { - throw new Error( - colors.red(`Failed to register command "${command.data.name}" globally.\n`), - error, - ); - }); + // + if (targetCommand) continue; + + await appCommandsManager + .create(command.data as ApplicationCommandDataResolvable) + .catch((error) => { + throw new Error( + colors.red( + `Failed to register command "${command.data.name}" globally.\n`, + ), + error, + ); + }); - console.log(colors.green(`Registered command "${command.data.name}" globally.`)); - } + console.log( + colors.green(`Registered command "${command.data.name}" globally.`), + ); + } } async function registerDevCommands( - client: Client, - commands: CommandFileObject[], - guildIds: string[], + client: Client, + commands: CommandFileObject[], + guildIds: string[], ) { - const devGuilds: Guild[] = []; + const devGuilds: Guild[] = []; + + for (const guildId of guildIds) { + const guild = + client.guilds.cache.get(guildId) || (await client.guilds.fetch(guildId)); + + if (!guild) { + process.emitWarning( + colors.yellow( + `Ignoring: Guild ${guildId} doesn't exist or client isn't part of the guild.`, + ), + ); + continue; + } - for (const guildId of guildIds) { - const guild = client.guilds.cache.get(guildId) || (await client.guilds.fetch(guildId)); + devGuilds.push(guild); + } - if (!guild) { - process.emitWarning( - colors.yellow( - `Ignoring: Guild ${guildId} doesn't exist or client isn't part of the guild.`, - ), + const guildCommandsManagers: GuildApplicationCommandManager[] = []; + + for (const guild of devGuilds) { + const guildCommandsManager = guild.commands; + await guildCommandsManager.fetch(); + + guildCommandsManagers.push(guildCommandsManager); + } + + for (const command of commands) { + for (const guildCommands of guildCommandsManagers) { + const targetCommand = guildCommands.cache.find( + (cmd) => cmd.name === command.data.name, + ); + + // + if (command.options?.deleted) { + if (!targetCommand) { + process.emitWarning( + colors.yellow( + `Ignoring: Command "${command.data.name}" is marked as deleted in ${guildCommands.guild.name}.`, + ), + ); + } else { + await targetCommand.delete().catch((error) => { + throw new Error( + colors.red( + `Failed to delete command "${command.data.name}" in ${guildCommands.guild.name}.`, + ), + error, ); - continue; + }); + + console.log( + colors.green( + `Deleted command "${command.data.name}" in ${guildCommands.guild.name}.`, + ), + ); } - devGuilds.push(guild); - } + continue; + } - const guildCommandsManagers: GuildApplicationCommandManager[] = []; + // + if (targetCommand) { + const commandsAreDifferent = areSlashCommandsDifferent( + targetCommand, + command.data, + ); - for (const guild of devGuilds) { - const guildCommandsManager = guild.commands; - await guildCommandsManager.fetch(); + if (commandsAreDifferent) { + await targetCommand + .edit(command.data as Partial) + .catch((error) => { + throw new Error( + colors.red( + `Failed to edit command "${command.data.name}" in ${guildCommands.guild.name}.\n`, + ), + error, + ); + }); - guildCommandsManagers.push(guildCommandsManager); - } + console.log( + colors.green( + `Edited command "${command.data.name}" in ${guildCommands.guild.name}.`, + ), + ); - for (const command of commands) { - for (const guildCommands of guildCommandsManagers) { - const targetCommand = guildCommands.cache.find((cmd) => cmd.name === command.data.name); - - // - if (command.options?.deleted) { - if (!targetCommand) { - process.emitWarning( - colors.yellow( - `Ignoring: Command "${command.data.name}" is marked as deleted in ${guildCommands.guild.name}.`, - ), - ); - } else { - await targetCommand.delete().catch((error) => { - throw new Error( - colors.red( - `Failed to delete command "${command.data.name}" in ${guildCommands.guild.name}.`, - ), - error, - ); - }); - - console.log( - colors.green( - `Deleted command "${command.data.name}" in ${guildCommands.guild.name}.`, - ), - ); - } - - continue; - } - - // - if (targetCommand) { - const commandsAreDifferent = areSlashCommandsDifferent(targetCommand, command.data); - - if (commandsAreDifferent) { - await targetCommand - .edit(command.data as Partial) - .catch((error) => { - throw new Error( - colors.red( - `Failed to edit command "${command.data.name}" in ${guildCommands.guild.name}.\n`, - ), - error, - ); - }); - - console.log( - colors.green( - `Edited command "${command.data.name}" in ${guildCommands.guild.name}.`, - ), - ); - - continue; - } - } - - // - if (targetCommand) continue; - - await guildCommands - .create(command.data as ApplicationCommandDataResolvable) - .catch((error) => { - throw new Error( - colors.red( - `Failed to register command "${command.data.name}" in ${guildCommands.guild.name}.\n`, - ), - error, - ); - }); - - console.log( - colors.green( - `Registered command "${command.data.name}" in ${guildCommands.guild.name}.`, - ), - ); + continue; } + } + + // + if (targetCommand) continue; + + await guildCommands + .create(command.data as ApplicationCommandDataResolvable) + .catch((error) => { + throw new Error( + colors.red( + `Failed to register command "${command.data.name}" in ${guildCommands.guild.name}.\n`, + ), + error, + ); + }); + + console.log( + colors.green( + `Registered command "${command.data.name}" in ${guildCommands.guild.name}.`, + ), + ); } + } } diff --git a/packages/commandkit/src/handlers/command-handler/typings.ts b/packages/commandkit/src/handlers/command-handler/typings.ts index e88ca75..78f530c 100644 --- a/packages/commandkit/src/handlers/command-handler/typings.ts +++ b/packages/commandkit/src/handlers/command-handler/typings.ts @@ -1,8 +1,8 @@ import type { - AutocompleteInteraction, - ChatInputCommandInteraction, - Client, - ContextMenuCommandInteraction, + AutocompleteInteraction, + ChatInputCommandInteraction, + Client, + ContextMenuCommandInteraction, } from 'discord.js'; import type { CommandKit } from '../../CommandKit'; import type { CommandFileObject } from '../../typings'; @@ -13,103 +13,103 @@ import type { ValidationHandler } from '../validation-handler/ValidationHandler' * Similar to CommandKit options in structure. */ export interface CommandHandlerOptions { - /** - * The client created by the user. - */ - client: Client; - - /** - * Path to the user's commands. - */ - commandsPath: string; - - /** - * An array of developer guild IDs. - */ - devGuildIds: string[]; - - /** - * An array of developer user IDs. - */ - devUserIds: string[]; - - /** - * An array of developer role IDs. - */ - devRoleIds: string[]; - - /** - * A validation handler instance to run validations before commands. - */ - validationHandler?: ValidationHandler; - - /** - * A boolean indicating whether to skip CommandKit's built-in validations (permission checking, etc.) - */ - skipBuiltInValidations: boolean; - - /** - * The CommandKit handler that instantiated this. - */ - commandkitInstance: CommandKit; - - /** - * A boolean indicating whether to register all commands in bulk. - */ - bulkRegister: boolean; - /** - * Whether to enable hooks context. - */ - enableHooks: boolean; + /** + * The client created by the user. + */ + client: Client; + + /** + * Path to the user's commands. + */ + commandsPath: string; + + /** + * An array of developer guild IDs. + */ + devGuildIds: string[]; + + /** + * An array of developer user IDs. + */ + devUserIds: string[]; + + /** + * An array of developer role IDs. + */ + devRoleIds: string[]; + + /** + * A validation handler instance to run validations before commands. + */ + validationHandler?: ValidationHandler; + + /** + * A boolean indicating whether to skip CommandKit's built-in validations (permission checking, etc.) + */ + skipBuiltInValidations: boolean; + + /** + * The CommandKit handler that instantiated this. + */ + commandkitInstance: CommandKit; + + /** + * A boolean indicating whether to register all commands in bulk. + */ + bulkRegister: boolean; + /** + * Whether to enable hooks context. + */ + enableHooks: boolean; } /** * Private command handler data. */ export interface CommandHandlerData extends CommandHandlerOptions { - /** - * An array of command file objects. - */ - commands: CommandFileObject[]; - - /** - * An array of built-in validations. - */ - builtInValidations: BuiltInValidation[]; - - /** - * A validation handler instance to run validations before commands. - */ - validationHandler?: ValidationHandler; + /** + * An array of command file objects. + */ + commands: CommandFileObject[]; + + /** + * An array of built-in validations. + */ + builtInValidations: BuiltInValidation[]; + + /** + * A validation handler instance to run validations before commands. + */ + validationHandler?: ValidationHandler; } /** * Parameters for CommandKit's built-in validations. */ export interface BuiltInValidationParams { - /** - * The target command to validate. - */ - targetCommand: CommandFileObject; - - /** - * The interaction of the target command. - */ - interaction: CommandKitInteraction; - - /** - * The command handler's data. - */ - handlerData: CommandHandlerData; + /** + * The target command to validate. + */ + targetCommand: CommandFileObject; + + /** + * The interaction of the target command. + */ + interaction: CommandKitInteraction; + + /** + * The command handler's data. + */ + handlerData: CommandHandlerData; } /** * Represents a command interaction. */ export type CommandKitInteraction = - | ChatInputCommandInteraction - | ContextMenuCommandInteraction - | AutocompleteInteraction; + | ChatInputCommandInteraction + | ContextMenuCommandInteraction + | AutocompleteInteraction; /** * A built in validation. Returns a boolean or void. diff --git a/packages/commandkit/src/handlers/command-handler/utils/areSlashCommandsDifferent.ts b/packages/commandkit/src/handlers/command-handler/utils/areSlashCommandsDifferent.ts index 59e1e46..b3e600c 100644 --- a/packages/commandkit/src/handlers/command-handler/utils/areSlashCommandsDifferent.ts +++ b/packages/commandkit/src/handlers/command-handler/utils/areSlashCommandsDifferent.ts @@ -4,17 +4,20 @@ * @param localCommand - The local command. * @returns A boolean indicating whether these commands are different */ -export default function areSlashCommandsDifferent(appCommand: any, localCommand: any) { - if (!appCommand.options) appCommand.options = []; - if (!localCommand.options) localCommand.options = []; +export default function areSlashCommandsDifferent( + appCommand: any, + localCommand: any, +) { + if (!appCommand.options) appCommand.options = []; + if (!localCommand.options) localCommand.options = []; - if (!appCommand.description) appCommand.description = ''; - if (!localCommand.description) localCommand.description = ''; + if (!appCommand.description) appCommand.description = ''; + if (!localCommand.description) localCommand.description = ''; - if ( - localCommand.description !== appCommand.description || - localCommand.options.length !== appCommand.options.length - ) { - return true; - } + if ( + localCommand.description !== appCommand.description || + localCommand.options.length !== appCommand.options.length + ) { + return true; + } } diff --git a/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts b/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts index 682baa7..96f62c9 100644 --- a/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts +++ b/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts @@ -1,38 +1,48 @@ import type { BuiltInValidationParams } from '../typings'; -export default function ({ interaction, targetCommand, handlerData }: BuiltInValidationParams) { - if (interaction.isAutocomplete()) return; - - if (targetCommand.options?.devOnly) { - if (interaction.inGuild() && !handlerData.devGuildIds.includes(interaction.guildId)) { - interaction.reply({ - content: '❌ This command can only be used inside development servers.', - ephemeral: true, - }); - - return true; - } +export default function ({ + interaction, + targetCommand, + handlerData, +}: BuiltInValidationParams) { + if (interaction.isAutocomplete()) return; + + if (targetCommand.options?.devOnly) { + if ( + interaction.inGuild() && + !handlerData.devGuildIds.includes(interaction.guildId) + ) { + interaction.reply({ + content: '❌ This command can only be used inside development servers.', + ephemeral: true, + }); + + return true; + } - const guildMember = interaction.guild?.members.cache.get(interaction.user.id); - const memberRoles = guildMember?.roles.cache; + const guildMember = interaction.guild?.members.cache.get( + interaction.user.id, + ); + const memberRoles = guildMember?.roles.cache; - let hasDevRole = false; + let hasDevRole = false; - memberRoles?.forEach((role) => { - if (handlerData.devRoleIds.includes(role.id)) { - hasDevRole = true; - } - }); + memberRoles?.forEach((role) => { + if (handlerData.devRoleIds.includes(role.id)) { + hasDevRole = true; + } + }); - const isDevUser = handlerData.devUserIds.includes(interaction.user.id) || hasDevRole; + const isDevUser = + handlerData.devUserIds.includes(interaction.user.id) || hasDevRole; - if (!isDevUser) { - interaction.reply({ - content: '❌ This command can only be used by developers.', - ephemeral: true, - }); + if (!isDevUser) { + interaction.reply({ + content: '❌ This command can only be used by developers.', + ephemeral: true, + }); - return true; - } + return true; } + } } diff --git a/packages/commandkit/src/handlers/command-handler/validations/permissions.ts b/packages/commandkit/src/handlers/command-handler/validations/permissions.ts index 3d89a64..45eae8d 100644 --- a/packages/commandkit/src/handlers/command-handler/validations/permissions.ts +++ b/packages/commandkit/src/handlers/command-handler/validations/permissions.ts @@ -1,88 +1,98 @@ import type { BuiltInValidationParams } from '../typings'; import { EmbedBuilder } from 'discord.js'; -export default function ({ interaction, targetCommand }: BuiltInValidationParams) { - if (interaction.isAutocomplete()) return; - const userPermissions = interaction.memberPermissions; - let userPermissionsRequired = targetCommand.options?.userPermissions; - let missingUserPermissions: string[] = []; - - if (typeof userPermissionsRequired === 'string') { - userPermissionsRequired = [userPermissionsRequired]; +export default function ({ + interaction, + targetCommand, +}: BuiltInValidationParams) { + if (interaction.isAutocomplete()) return; + const userPermissions = interaction.memberPermissions; + let userPermissionsRequired = targetCommand.options?.userPermissions; + let missingUserPermissions: string[] = []; + + if (typeof userPermissionsRequired === 'string') { + userPermissionsRequired = [userPermissionsRequired]; + } + + const botPermissions = interaction.guild?.members.me?.permissions; + let botPermissionsRequired = targetCommand.options?.botPermissions; + let missingBotPermissions: string[] = []; + + if (typeof botPermissionsRequired === 'string') { + botPermissionsRequired = [botPermissionsRequired]; + } + + if (!userPermissionsRequired?.length && !botPermissionsRequired?.length) { + return; + } + + if (userPermissions && userPermissionsRequired) { + for (const permission of userPermissionsRequired) { + const hasPermission = userPermissions.has(permission); + + if (!hasPermission) { + missingUserPermissions.push(permission); + } } + } - const botPermissions = interaction.guild?.members.me?.permissions; - let botPermissionsRequired = targetCommand.options?.botPermissions; - let missingBotPermissions: string[] = []; + if (botPermissions && botPermissionsRequired) { + for (const permission of botPermissionsRequired) { + const hasPermission = botPermissions.has(permission); - if (typeof botPermissionsRequired === 'string') { - botPermissionsRequired = [botPermissionsRequired]; + if (!hasPermission) { + missingBotPermissions.push(permission); + } } + } - if (!userPermissionsRequired?.length && !botPermissionsRequired?.length) { - return; - } - - if (userPermissions && userPermissionsRequired) { - for (const permission of userPermissionsRequired) { - const hasPermission = userPermissions.has(permission); - - if (!hasPermission) { - missingUserPermissions.push(permission); - } - } - } + if (!missingUserPermissions.length && !missingBotPermissions.length) { + return; + } - if (botPermissions && botPermissionsRequired) { - for (const permission of botPermissionsRequired) { - const hasPermission = botPermissions.has(permission); + // Fix casing. e.g. KickMembers -> Kick Members + const pattern = /([a-z])([A-Z])|([A-Z]+)([A-Z][a-z])/g; - if (!hasPermission) { - missingBotPermissions.push(permission); - } - } - } + missingUserPermissions = missingUserPermissions.map((str) => + str.replace(pattern, '$1$3 $2$4'), + ); + missingBotPermissions = missingBotPermissions.map((str) => + str.replace(pattern, '$1$3 $2$4'), + ); - if (!missingUserPermissions.length && !missingBotPermissions.length) { - return; - } + let embedDescription = ''; - // Fix casing. e.g. KickMembers -> Kick Members - const pattern = /([a-z])([A-Z])|([A-Z]+)([A-Z][a-z])/g; + const formatter = new Intl.ListFormat('en', { + style: 'long', + type: 'conjunction', + }); - missingUserPermissions = missingUserPermissions.map((str) => str.replace(pattern, '$1$3 $2$4')); - missingBotPermissions = missingBotPermissions.map((str) => str.replace(pattern, '$1$3 $2$4')); + const getPermissionWord = (permissions: string[]) => + permissions.length === 1 ? 'permission' : 'permissions'; - let embedDescription = ''; + if (missingUserPermissions.length) { + const formattedPermissions = missingUserPermissions.map((p) => `\`${p}\``); + const permissionsString = formatter.format(formattedPermissions); - const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }); + embedDescription += `- You must have the ${permissionsString} ${getPermissionWord( + missingUserPermissions, + )} to be able to run this command.\n`; + } - const getPermissionWord = (permissions: string[]) => - permissions.length === 1 ? 'permission' : 'permissions'; + if (missingBotPermissions.length) { + const formattedPermissions = missingBotPermissions.map((p) => `\`${p}\``); + const permissionsString = formatter.format(formattedPermissions); - if (missingUserPermissions.length) { - const formattedPermissions = missingUserPermissions.map((p) => `\`${p}\``); - const permissionsString = formatter.format(formattedPermissions); - - embedDescription += `- You must have the ${permissionsString} ${getPermissionWord( - missingUserPermissions, - )} to be able to run this command.\n`; - } - - if (missingBotPermissions.length) { - const formattedPermissions = missingBotPermissions.map((p) => `\`${p}\``); - const permissionsString = formatter.format(formattedPermissions); - - embedDescription += `- I must have the ${permissionsString} ${getPermissionWord( - missingBotPermissions, - )} to be able to execute this command.\n`; - } + embedDescription += `- I must have the ${permissionsString} ${getPermissionWord( + missingBotPermissions, + )} to be able to execute this command.\n`; + } - const embed = new EmbedBuilder() - .setTitle(`:x: Missing permissions!`) - .setDescription(embedDescription) - .setColor('Red'); + const embed = new EmbedBuilder() + .setTitle(`:x: Missing permissions!`) + .setDescription(embedDescription) + .setColor('Red'); - interaction.reply({ embeds: [embed], ephemeral: true }); - return true; + interaction.reply({ embeds: [embed], ephemeral: true }); + return true; } diff --git a/packages/commandkit/src/handlers/event-handler/EventHandler.ts b/packages/commandkit/src/handlers/event-handler/EventHandler.ts index fc507d8..aa28403 100644 --- a/packages/commandkit/src/handlers/event-handler/EventHandler.ts +++ b/packages/commandkit/src/handlers/event-handler/EventHandler.ts @@ -9,111 +9,115 @@ import colors from '../../utils/colors'; * A handler for client events. */ export class EventHandler { - #data: EventHandlerData; + #data: EventHandlerData; - constructor({ ...options }: EventHandlerOptions) { - this.#data = { - ...options, - events: [], - }; - } - - async init() { - await this.#buildEvents(); - this.#registerEvents(); - } + constructor({ ...options }: EventHandlerOptions) { + this.#data = { + ...options, + events: [], + }; + } - async #buildEvents() { - const eventFolderPaths = await getFolderPaths(this.#data.eventsPath); + async init() { + await this.#buildEvents(); + this.#registerEvents(); + } - for (const eventFolderPath of eventFolderPaths) { - const eventName = eventFolderPath - .replace(/\\\\|\\/g, '/') - .split('/') - .pop() as string; + async #buildEvents() { + const eventFolderPaths = await getFolderPaths(this.#data.eventsPath); - const allowedExtensions = /\.(js|mjs|cjs|ts)$/i; - const eventPaths = await getFilePaths(eventFolderPath, true); + for (const eventFolderPath of eventFolderPaths) { + const eventName = eventFolderPath + .replace(/\\\\|\\/g, '/') + .split('/') + .pop() as string; - const eventFilePaths = eventPaths.filter((path) => allowedExtensions.test(path)); + const allowedExtensions = /\.(js|mjs|cjs|ts)$/i; + const eventPaths = await getFilePaths(eventFolderPath, true); - const eventObj = { - name: eventName, - functions: [] as Function[], - }; + const eventFilePaths = eventPaths.filter((path) => + allowedExtensions.test(path), + ); - this.#data.events.push(eventObj); + const eventObj = { + name: eventName, + functions: [] as Function[], + }; - for (const eventFilePath of eventFilePaths) { - const modulePath = toFileURL(eventFilePath); + this.#data.events.push(eventObj); - let importedFunction = (await import(`${modulePath}?t=${Date.now()}`)).default; - let eventFunction = clone(importedFunction); + for (const eventFilePath of eventFilePaths) { + const modulePath = toFileURL(eventFilePath); - // If it's CommonJS, invalidate the import cache - if (typeof module !== 'undefined' && typeof require !== 'undefined') { - delete require.cache[require.resolve(eventFilePath)]; - } + let importedFunction = (await import(`${modulePath}?t=${Date.now()}`)) + .default; + let eventFunction = clone(importedFunction); - if (eventFunction?.default) { - eventFunction = eventFunction.default; - } + // If it's CommonJS, invalidate the import cache + if (typeof module !== 'undefined' && typeof require !== 'undefined') { + delete require.cache[require.resolve(eventFilePath)]; + } - const compactFilePath = eventFilePath.split(process.cwd())[1] || eventFilePath; + if (eventFunction?.default) { + eventFunction = eventFunction.default; + } - if (typeof eventFunction !== 'function') { - process.emitWarning( - colors.yellow( - `Ignoring: Event file ${compactFilePath} does not export a function.`, - ), - ); - continue; - } + const compactFilePath = + eventFilePath.split(process.cwd())[1] || eventFilePath; - eventObj.functions.push(eventFunction); - } + if (typeof eventFunction !== 'function') { + process.emitWarning( + colors.yellow( + `Ignoring: Event file ${compactFilePath} does not export a function.`, + ), + ); + continue; } + + eventObj.functions.push(eventFunction); + } } + } - #registerEvents() { - const client = this.#data.client; - const handler = this.#data.commandKitInstance; + #registerEvents() { + const client = this.#data.client; + const handler = this.#data.commandKitInstance; - for (const eventObj of this.#data.events) { - client.on(eventObj.name, async (...params) => { - for (const eventFunction of eventObj.functions) { - const stopEventLoop = await eventFunction(...params, client, handler); + for (const eventObj of this.#data.events) { + client.on(eventObj.name, async (...params) => { + for (const eventFunction of eventObj.functions) { + const stopEventLoop = await eventFunction(...params, client, handler); - if (stopEventLoop) { - break; - } - } - }); + if (stopEventLoop) { + break; + } } + }); } - - get events() { - return this.#data.events; + } + + get events() { + return this.#data.events; + } + + async reloadEvents(commandHandler?: CommandHandler) { + if (!this.#data.eventsPath) { + throw new Error( + colors.red( + 'Cannot reload events as "eventsPath" was not provided when instantiating CommandKit.', + ), + ); } - async reloadEvents(commandHandler?: CommandHandler) { - if (!this.#data.eventsPath) { - throw new Error( - colors.red( - 'Cannot reload events as "eventsPath" was not provided when instantiating CommandKit.', - ), - ); - } + this.#data.events = []; - this.#data.events = []; + await this.#buildEvents(); - await this.#buildEvents(); + this.#data.client.removeAllListeners(); - this.#data.client.removeAllListeners(); + this.#registerEvents(); - this.#registerEvents(); - - // Re-register "interactionCreate" event for application commands. - commandHandler?.handleCommands(); - } + // Re-register "interactionCreate" event for application commands. + commandHandler?.handleCommands(); + } } diff --git a/packages/commandkit/src/handlers/event-handler/typings.ts b/packages/commandkit/src/handlers/event-handler/typings.ts index c978233..ff663af 100644 --- a/packages/commandkit/src/handlers/event-handler/typings.ts +++ b/packages/commandkit/src/handlers/event-handler/typings.ts @@ -5,14 +5,14 @@ import type { CommandKit } from '../../CommandKit'; * Event handler options. */ export interface EventHandlerOptions { - client: Client; - eventsPath: string; - commandKitInstance: CommandKit; + client: Client; + eventsPath: string; + commandKitInstance: CommandKit; } /** * Private event handler data. */ export interface EventHandlerData extends EventHandlerOptions { - events: { name: string; functions: Function[] }[]; + events: { name: string; functions: Function[] }[]; } diff --git a/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts b/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts index d387461..3879534 100644 --- a/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts +++ b/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts @@ -1,4 +1,7 @@ -import type { ValidationHandlerData, ValidationHandlerOptions } from './typings'; +import type { + ValidationHandlerData, + ValidationHandlerOptions, +} from './typings'; import { toFileURL } from '../../utils/resolve-file-url'; import { getFilePaths } from '../../utils/get-paths'; import { clone } from '../../utils/clone'; @@ -8,75 +11,81 @@ import colors from '../../utils/colors'; * A handler for command validations. */ export class ValidationHandler { - #data: ValidationHandlerData; - - constructor({ ...options }: ValidationHandlerOptions) { - this.#data = { - ...options, - validations: [], - }; - } - - async init() { - this.#data.validations = await this.#buildValidations(); + #data: ValidationHandlerData; + + constructor({ ...options }: ValidationHandlerOptions) { + this.#data = { + ...options, + validations: [], + }; + } + + async init() { + this.#data.validations = await this.#buildValidations(); + } + + async #buildValidations() { + const allowedExtensions = /\.(js|mjs|cjs|ts)$/i; + + const validationPaths = await getFilePaths( + this.#data.validationsPath, + true, + ); + const validationFilePaths = validationPaths.filter((path) => + allowedExtensions.test(path), + ); + + const validationFunctions: Function[] = []; + + for (const validationFilePath of validationFilePaths) { + const modulePath = toFileURL(validationFilePath); + + let importedFunction = (await import(`${modulePath}?t=${Date.now()}`)) + .default; + let validationFunction = clone(importedFunction); + + // If it's CommonJS, invalidate the import cache + if (typeof module !== 'undefined' && typeof require !== 'undefined') { + delete require.cache[require.resolve(validationFilePath)]; + } + + if (validationFunction?.default) { + validationFunction = validationFunction.default; + } + + const compactFilePath = + validationFilePath.split(process.cwd())[1] || validationFilePath; + + if (typeof validationFunction !== 'function') { + process.emitWarning( + colors.yellow( + `Ignoring: Validation file ${compactFilePath} does not export a function.`, + ), + ); + continue; + } + + validationFunctions.push(validationFunction); } - async #buildValidations() { - const allowedExtensions = /\.(js|mjs|cjs|ts)$/i; - - const validationPaths = await getFilePaths(this.#data.validationsPath, true); - const validationFilePaths = validationPaths.filter((path) => allowedExtensions.test(path)); - - const validationFunctions: Function[] = []; - - for (const validationFilePath of validationFilePaths) { - const modulePath = toFileURL(validationFilePath); - - let importedFunction = (await import(`${modulePath}?t=${Date.now()}`)).default; - let validationFunction = clone(importedFunction); - - // If it's CommonJS, invalidate the import cache - if (typeof module !== 'undefined' && typeof require !== 'undefined') { - delete require.cache[require.resolve(validationFilePath)]; - } + return validationFunctions; + } - if (validationFunction?.default) { - validationFunction = validationFunction.default; - } + get validations() { + return this.#data.validations; + } - const compactFilePath = - validationFilePath.split(process.cwd())[1] || validationFilePath; - - if (typeof validationFunction !== 'function') { - process.emitWarning( - colors.yellow( - `Ignoring: Validation file ${compactFilePath} does not export a function.`, - ), - ); - continue; - } - - validationFunctions.push(validationFunction); - } - - return validationFunctions; + async reloadValidations() { + if (!this.#data.validationsPath) { + throw new Error( + colors.red( + 'Cannot reload validations as "validationsPath" was not provided when instantiating CommandKit.', + ), + ); } - get validations() { - return this.#data.validations; - } + const newValidations = await this.#buildValidations(); - async reloadValidations() { - if (!this.#data.validationsPath) { - throw new Error( - colors.red( - 'Cannot reload validations as "validationsPath" was not provided when instantiating CommandKit.', - ), - ); - } - - const newValidations = await this.#buildValidations(); - - this.#data.validations = newValidations; - } + this.#data.validations = newValidations; + } } diff --git a/packages/commandkit/src/handlers/validation-handler/typings.ts b/packages/commandkit/src/handlers/validation-handler/typings.ts index 285e628..2136035 100644 --- a/packages/commandkit/src/handlers/validation-handler/typings.ts +++ b/packages/commandkit/src/handlers/validation-handler/typings.ts @@ -2,12 +2,12 @@ * Validation handler options (validationsPath). */ export interface ValidationHandlerOptions { - validationsPath: string; + validationsPath: string; } /** * Private validation handler data. */ export interface ValidationHandlerData extends ValidationHandlerOptions { - validations: Function[]; + validations: Function[]; } diff --git a/packages/commandkit/src/hooks/common.ts b/packages/commandkit/src/hooks/common.ts index f6f5452..99ecb6e 100644 --- a/packages/commandkit/src/hooks/common.ts +++ b/packages/commandkit/src/hooks/common.ts @@ -1,28 +1,30 @@ import { CommandKit } from '..'; export function getCommandKit() { - return CommandKit._instance; + return CommandKit._instance; } export function getCommandHandler() { - const handler = getCommandKit()?.commandHandler; + const handler = getCommandKit()?.commandHandler; - if (!handler) { - throw new Error('CommandKit is not initialized.'); - } + if (!handler) { + throw new Error('CommandKit is not initialized.'); + } - return handler; + return handler; } export function getContext() { - const info = getCommandHandler().context; - if (!info) { - throw new Error('Context is not available, did you forget to enable hooks?'); - } + const info = getCommandHandler().context; + if (!info) { + throw new Error( + 'Context is not available, did you forget to enable hooks?', + ); + } - return info; + return info; } export function prepareHookInvocationError(name: string) { - return new Error(`Cannot invoke hook "${name}" outside of a command.`); + return new Error(`Cannot invoke hook "${name}" outside of a command.`); } diff --git a/packages/commandkit/src/hooks/response.ts b/packages/commandkit/src/hooks/response.ts index 1d4e019..953af37 100644 --- a/packages/commandkit/src/hooks/response.ts +++ b/packages/commandkit/src/hooks/response.ts @@ -1,30 +1,34 @@ // this is partially based on sapphire's safelyReplyToInteraction helper import type { - ChatInputCommandInteraction, - MessageComponentInteraction, - PartialTextBasedChannelFields, + ChatInputCommandInteraction, + MessageComponentInteraction, + PartialTextBasedChannelFields, } from 'discord.js'; import { useInteraction } from './useInteraction'; import { CommandKitInteraction } from '../handlers/command-handler/typings'; type ChatInputReplyData = Parameters[0]; type UpdateData = Parameters[0]; -type MessageData = Parameters[0] | ChatInputReplyData; +type MessageData = + | Parameters[0] + | ChatInputReplyData; export async function response(data: MessageData) { - const interaction = useInteraction() as CommandKitInteraction | MessageComponentInteraction; + const interaction = useInteraction() as + | CommandKitInteraction + | MessageComponentInteraction; - if (interaction.isAutocomplete()) return; + if (interaction.isAutocomplete()) return; - if (interaction.replied || interaction.deferred) { - await interaction.editReply(data); - } else if (interaction.isMessageComponent()) { - // TODO: this is not yet allowed in command handler - await interaction.update(data as UpdateData); - } else { - await interaction.reply(data as ChatInputReplyData); - } + if (interaction.replied || interaction.deferred) { + await interaction.editReply(data); + } else if (interaction.isMessageComponent()) { + // TODO: this is not yet allowed in command handler + await interaction.update(data as UpdateData); + } else { + await interaction.reply(data as ChatInputReplyData); + } - // TODO: handle message based commands + // TODO: handle message based commands } diff --git a/packages/commandkit/src/hooks/useChannel.ts b/packages/commandkit/src/hooks/useChannel.ts index d20cfb0..30ffda2 100644 --- a/packages/commandkit/src/hooks/useChannel.ts +++ b/packages/commandkit/src/hooks/useChannel.ts @@ -2,9 +2,9 @@ import type { TextBasedChannel } from 'discord.js'; import { getContext, prepareHookInvocationError } from './common'; export function useChannel(): TextBasedChannel | null { - const data = getContext().getStore(); + const data = getContext().getStore(); - if (!data) throw prepareHookInvocationError('useChannel'); + if (!data) throw prepareHookInvocationError('useChannel'); - return data.interaction.channel; + return data.interaction.channel; } diff --git a/packages/commandkit/src/hooks/useClient.ts b/packages/commandkit/src/hooks/useClient.ts index 4d9e876..ae63dc4 100644 --- a/packages/commandkit/src/hooks/useClient.ts +++ b/packages/commandkit/src/hooks/useClient.ts @@ -1,5 +1,5 @@ import { useCommandKit } from './useCommandKit'; export function useClient() { - return useCommandKit().client; + return useCommandKit().client; } diff --git a/packages/commandkit/src/hooks/useCommandData.ts b/packages/commandkit/src/hooks/useCommandData.ts index 6b01b0e..957ba4a 100644 --- a/packages/commandkit/src/hooks/useCommandData.ts +++ b/packages/commandkit/src/hooks/useCommandData.ts @@ -1,9 +1,9 @@ import { getContext, prepareHookInvocationError } from './common'; export function useCommandData() { - const data = getContext().getStore(); + const data = getContext().getStore(); - if (!data) throw prepareHookInvocationError('useCommandData'); + if (!data) throw prepareHookInvocationError('useCommandData'); - return data.command; + return data.command; } diff --git a/packages/commandkit/src/hooks/useCommandKit.ts b/packages/commandkit/src/hooks/useCommandKit.ts index 4d1e7ad..3baf865 100644 --- a/packages/commandkit/src/hooks/useCommandKit.ts +++ b/packages/commandkit/src/hooks/useCommandKit.ts @@ -1,8 +1,8 @@ import { getCommandKit } from './common'; export function useCommandKit() { - const kit = getCommandKit(); - if (!kit) throw new Error('CommandKit is not initialized.'); + const kit = getCommandKit(); + if (!kit) throw new Error('CommandKit is not initialized.'); - return kit; + return kit; } diff --git a/packages/commandkit/src/hooks/useGuild.ts b/packages/commandkit/src/hooks/useGuild.ts index f55c723..f30b6a5 100644 --- a/packages/commandkit/src/hooks/useGuild.ts +++ b/packages/commandkit/src/hooks/useGuild.ts @@ -2,9 +2,9 @@ import type { Guild } from 'discord.js'; import { getContext, prepareHookInvocationError } from './common'; export function useGuild(): Guild | null { - const data = getContext().getStore(); + const data = getContext().getStore(); - if (!data) throw prepareHookInvocationError('useGuild'); + if (!data) throw prepareHookInvocationError('useGuild'); - return data.interaction.guild; + return data.interaction.guild; } diff --git a/packages/commandkit/src/hooks/useInteraction.ts b/packages/commandkit/src/hooks/useInteraction.ts index 49ac081..40cbfc5 100644 --- a/packages/commandkit/src/hooks/useInteraction.ts +++ b/packages/commandkit/src/hooks/useInteraction.ts @@ -1,10 +1,12 @@ import { getContext, prepareHookInvocationError } from './common'; import { CommandKitInteraction } from '../handlers/command-handler/typings'; -export function useInteraction(): T { - const data = getContext().getStore(); +export function useInteraction< + T extends CommandKitInteraction = CommandKitInteraction, +>(): T { + const data = getContext().getStore(); - if (!data) throw prepareHookInvocationError('useInteraction'); + if (!data) throw prepareHookInvocationError('useInteraction'); - return data.interaction as T; + return data.interaction as T; } diff --git a/packages/commandkit/src/hooks/useMember.ts b/packages/commandkit/src/hooks/useMember.ts index 27ce798..8daa759 100644 --- a/packages/commandkit/src/hooks/useMember.ts +++ b/packages/commandkit/src/hooks/useMember.ts @@ -2,9 +2,9 @@ import type { APIInteractionGuildMember, GuildMember } from 'discord.js'; import { getContext, prepareHookInvocationError } from './common'; export function useMember(): GuildMember | APIInteractionGuildMember | null { - const data = getContext().getStore(); + const data = getContext().getStore(); - if (!data) throw prepareHookInvocationError('useMember'); + if (!data) throw prepareHookInvocationError('useMember'); - return data.interaction.member; + return data.interaction.member; } diff --git a/packages/commandkit/src/hooks/useUser.ts b/packages/commandkit/src/hooks/useUser.ts index 83a8e22..c36d879 100644 --- a/packages/commandkit/src/hooks/useUser.ts +++ b/packages/commandkit/src/hooks/useUser.ts @@ -2,9 +2,9 @@ import type { User } from 'discord.js'; import { getContext, prepareHookInvocationError } from './common'; export function useUser(): User { - const data = getContext().getStore(); + const data = getContext().getStore(); - if (!data) throw prepareHookInvocationError('useUser'); + if (!data) throw prepareHookInvocationError('useUser'); - return data.interaction.user; + return data.interaction.user; } diff --git a/packages/commandkit/src/types/index.ts b/packages/commandkit/src/types/index.ts index 7e2fb55..173732d 100644 --- a/packages/commandkit/src/types/index.ts +++ b/packages/commandkit/src/types/index.ts @@ -1,12 +1,12 @@ import type { - RESTPostAPIApplicationCommandsJSONBody, - MessageContextMenuCommandInteraction, - UserContextMenuCommandInteraction, - ContextMenuCommandInteraction, - ChatInputCommandInteraction, - AutocompleteInteraction, - PermissionsString, - Client, + RESTPostAPIApplicationCommandsJSONBody, + MessageContextMenuCommandInteraction, + UserContextMenuCommandInteraction, + ContextMenuCommandInteraction, + ChatInputCommandInteraction, + AutocompleteInteraction, + PermissionsString, + Client, } from 'discord.js'; import type { CommandKit } from '../CommandKit'; @@ -14,187 +14,187 @@ import type { CommandKit } from '../CommandKit'; * Props for command run functions. */ export interface CommandProps { - /** - * The current command interaction object. - */ - interaction: - | ChatInputCommandInteraction - | ContextMenuCommandInteraction - | UserContextMenuCommandInteraction - | MessageContextMenuCommandInteraction - | AutocompleteInteraction; - - /** - * The Discord.js client object that CommandKit is handling. - */ - client: Client; - - /** - * The current CommandKit handler instance. - */ - handler: CommandKit; + /** + * The current command interaction object. + */ + interaction: + | ChatInputCommandInteraction + | ContextMenuCommandInteraction + | UserContextMenuCommandInteraction + | MessageContextMenuCommandInteraction + | AutocompleteInteraction; + + /** + * The Discord.js client object that CommandKit is handling. + */ + client: Client; + + /** + * The current CommandKit handler instance. + */ + handler: CommandKit; } /** * Props for autocomplete command run functions. */ export interface AutocompleteProps extends CommandProps { - /** - * The current autocomplete command interaction object. - */ - interaction: AutocompleteInteraction; + /** + * The current autocomplete command interaction object. + */ + interaction: AutocompleteInteraction; } /** * Props for slash (chat input) command run functions. */ export interface SlashCommandProps extends CommandProps { - /** - * The current slash (chat input) command interaction object. - */ - interaction: ChatInputCommandInteraction; + /** + * The current slash (chat input) command interaction object. + */ + interaction: ChatInputCommandInteraction; } /** * Props for context menu command run functions. */ export interface ContextMenuCommandProps extends CommandProps { - /** - * The current context menu command interaction object. - */ - interaction: ContextMenuCommandInteraction; + /** + * The current context menu command interaction object. + */ + interaction: ContextMenuCommandInteraction; } /** * Props for user context menu command run functions. */ export interface UserContextMenuCommandProps extends CommandProps { - interaction: UserContextMenuCommandInteraction; + interaction: UserContextMenuCommandInteraction; } /** * Props for message context menu command run functions. */ export interface MessageContextMenuCommandProps extends CommandProps { - interaction: MessageContextMenuCommandInteraction; + interaction: MessageContextMenuCommandInteraction; } /** * Props for command validation functions. */ export interface ValidationProps { - /** - * The current command interaction object. - */ - interaction: - | ChatInputCommandInteraction - | ContextMenuCommandInteraction - | AutocompleteInteraction; - - /** - * The Discord.js client object that CommandKit is handling. - */ - client: Client; - - /** - * The current (local) target command object. - */ - commandObj: CommandObject; - - /** - * The current CommandKit handler instance. - */ - handler: CommandKit; + /** + * The current command interaction object. + */ + interaction: + | ChatInputCommandInteraction + | ContextMenuCommandInteraction + | AutocompleteInteraction; + + /** + * The Discord.js client object that CommandKit is handling. + */ + client: Client; + + /** + * The current (local) target command object. + */ + commandObj: CommandObject; + + /** + * The current CommandKit handler instance. + */ + handler: CommandKit; } /** * Additional command configuration options. */ export interface CommandOptions { - /** - * A boolean indicating whether the command is guild-only. - * Used for built-in validation. - * - * @deprecated Use `dm_permission` in the command's `data` object instead. - */ - guildOnly?: boolean; - - /** - * A boolean indicating whether the command is developer-only. - * Used for registration and built-in validation. - */ - devOnly?: boolean; - - /** - * A boolean indicating whether the command is deleted/ignored on restart/reload. - */ - deleted?: boolean; - - /** - * A string or array of permissions that a user needs for the current command to be executed. - * Used for built-in validation. - * - * @example - * userPermissions: 'BanMembers' - * or - * userPermissions: ['BanMembers', 'KickMembers'] - */ - userPermissions?: PermissionsString | PermissionsString[]; - - /** - * A string or array of permissions that the bot needs to execute the current command. - * Used for built-in validation. - * - * @example - * botPermissions: 'BanMembers' - * or - * botPermissions: ['BanMembers', 'KickMembers'] - */ - botPermissions?: PermissionsString | PermissionsString[]; - - [key: string]: any; + /** + * A boolean indicating whether the command is guild-only. + * Used for built-in validation. + * + * @deprecated Use `dm_permission` in the command's `data` object instead. + */ + guildOnly?: boolean; + + /** + * A boolean indicating whether the command is developer-only. + * Used for registration and built-in validation. + */ + devOnly?: boolean; + + /** + * A boolean indicating whether the command is deleted/ignored on restart/reload. + */ + deleted?: boolean; + + /** + * A string or array of permissions that a user needs for the current command to be executed. + * Used for built-in validation. + * + * @example + * userPermissions: 'BanMembers' + * or + * userPermissions: ['BanMembers', 'KickMembers'] + */ + userPermissions?: PermissionsString | PermissionsString[]; + + /** + * A string or array of permissions that the bot needs to execute the current command. + * Used for built-in validation. + * + * @example + * botPermissions: 'BanMembers' + * or + * botPermissions: ['BanMembers', 'KickMembers'] + */ + botPermissions?: PermissionsString | PermissionsString[]; + + [key: string]: any; } export type CommandData = RESTPostAPIApplicationCommandsJSONBody; export type CommandObject = { - /** - * An object which defines the structure of the application command. - */ - data: CommandData; - - /** - * Additional command configuration options. - */ - options?: CommandOptions; - - /** - * The path to the command file. - */ - filePath: string; - - /** - * The command's category. Determined based on the command folder. - * - * @example - * ```txt - * "/src/commands/ping.js" -> null - * "/src/commands/Misc/ping.js" -> "Misc" - * ``` - */ - category: string | null; - - [key: string]: any; + /** + * An object which defines the structure of the application command. + */ + data: CommandData; + + /** + * Additional command configuration options. + */ + options?: CommandOptions; + + /** + * The path to the command file. + */ + filePath: string; + + /** + * The command's category. Determined based on the command folder. + * + * @example + * ```txt + * "/src/commands/ping.js" -> null + * "/src/commands/Misc/ping.js" -> "Misc" + * ``` + */ + category: string | null; + + [key: string]: any; }; export enum ReloadType { - /** - * Reload developer/guild commands. - */ - Developer = 'dev', - - /** - * Reload global commands. - */ - Global = 'global', + /** + * Reload developer/guild commands. + */ + Developer = 'dev', + + /** + * Reload global commands. + */ + Global = 'global', } diff --git a/packages/commandkit/src/typings.ts b/packages/commandkit/src/typings.ts index 2defa75..fa6148c 100644 --- a/packages/commandkit/src/typings.ts +++ b/packages/commandkit/src/typings.ts @@ -2,110 +2,122 @@ // For exported types use ./types/index.ts import type { CacheType, Client, Interaction } from 'discord.js'; -import type { CommandData, CommandKit, CommandOptions, ReloadType } from './index'; -import type { CommandHandler, EventHandler, ValidationHandler } from './handlers'; +import type { + CommandData, + CommandKit, + CommandOptions, + ReloadType, +} from './index'; +import type { + CommandHandler, + EventHandler, + ValidationHandler, +} from './handlers'; /** * Options for instantiating a CommandKit handler. */ export interface CommandKitOptions { - /** - * The Discord.js client object to use with CommandKit. - */ - client: Client; + /** + * The Discord.js client object to use with CommandKit. + */ + client: Client; - /** - * The path to your commands directory. - */ - commandsPath?: string; + /** + * The path to your commands directory. + */ + commandsPath?: string; - /** - * The path to your events directory. - */ - eventsPath?: string; + /** + * The path to your events directory. + */ + eventsPath?: string; - /** - * The path to the validations directory. - */ - validationsPath?: string; + /** + * The path to the validations directory. + */ + validationsPath?: string; - /** - * List of development guild IDs to restrict devOnly commands to. - */ - devGuildIds?: string[]; + /** + * List of development guild IDs to restrict devOnly commands to. + */ + devGuildIds?: string[]; - /** - * List of developer user IDs to restrict devOnly commands to. - */ - devUserIds?: string[]; + /** + * List of developer user IDs to restrict devOnly commands to. + */ + devUserIds?: string[]; - /** - * List of developer role IDs to restrict devOnly commands to. - */ - devRoleIds?: string[]; + /** + * List of developer role IDs to restrict devOnly commands to. + */ + devRoleIds?: string[]; - /** - * Skip CommandKit's built-in validations (for devOnly commands). - */ - skipBuiltInValidations?: boolean; + /** + * Skip CommandKit's built-in validations (for devOnly commands). + */ + skipBuiltInValidations?: boolean; + /** + * Bulk register application commands instead of one-by-one. + */ + bulkRegister?: boolean; + /** + * Options for experimental features. + */ + experimental?: { /** - * Bulk register application commands instead of one-by-one. - */ - bulkRegister?: boolean; - /** - * Options for experimental features. + * Enable hooks. This allows you to utilize hooks such as `useInteraction()` to access the interaction object anywhere inside the command. */ - experimental?: { - /** - * Enable hooks. This allows you to utilize hooks such as `useInteraction()` to access the interaction object anywhere inside the command. - */ - hooks?: boolean; - }; + hooks?: boolean; + }; } /** * Private data for the CommandKit class. */ export interface CommandKitData extends CommandKitOptions { - commandHandler?: CommandHandler; - eventHandler?: EventHandler; - validationHandler?: ValidationHandler; + commandHandler?: CommandHandler; + eventHandler?: EventHandler; + validationHandler?: ValidationHandler; } /** * Represents a command context. */ -export interface CommandContext { - /** - * The interaction that triggered this command. - */ - interaction: Interaction; - /** - * The client that instantiated this command. - */ - client: Client; - /** - * The command data. - */ - handler: CommandKit; +export interface CommandContext< + T extends Interaction, + Cached extends CacheType, +> { + /** + * The interaction that triggered this command. + */ + interaction: Interaction; + /** + * The client that instantiated this command. + */ + client: Client; + /** + * The command data. + */ + handler: CommandKit; } /** * Represents a command file. */ export interface CommandFileObject { - data: CommandData; - options?: CommandOptions; - run: ( - ctx: CommandContext, - ) => Awaited; - autocomplete?: ( - ctx: CommandContext, - ) => Awaited; - filePath: string; - category: string | null; - [key: string]: any; + data: CommandData; + options?: CommandOptions; + run: ( + ctx: CommandContext, + ) => Awaited; + autocomplete?: ( + ctx: CommandContext, + ) => Awaited; + filePath: string; + category: string | null; + [key: string]: any; } /** diff --git a/packages/commandkit/src/utils/colors.ts b/packages/commandkit/src/utils/colors.ts index da6b3a5..726ab0a 100644 --- a/packages/commandkit/src/utils/colors.ts +++ b/packages/commandkit/src/utils/colors.ts @@ -1,29 +1,29 @@ const resetColor = '\x1b[0m'; export default { - reset: (text: string) => `${text}${resetColor}`, - bright: (text: string) => `\x1b[1m${text}${resetColor}`, - dim: (text: string) => `\x1b[2m${text}${resetColor}`, - underscore: (text: string) => `\x1b[4m${text}${resetColor}`, - blink: (text: string) => `\x1b[5m${text}${resetColor}`, - reverse: (text: string) => `\x1b[7m${text}${resetColor}`, - hidden: (text: string) => `\x1b[8m${text}${resetColor}`, + reset: (text: string) => `${text}${resetColor}`, + bright: (text: string) => `\x1b[1m${text}${resetColor}`, + dim: (text: string) => `\x1b[2m${text}${resetColor}`, + underscore: (text: string) => `\x1b[4m${text}${resetColor}`, + blink: (text: string) => `\x1b[5m${text}${resetColor}`, + reverse: (text: string) => `\x1b[7m${text}${resetColor}`, + hidden: (text: string) => `\x1b[8m${text}${resetColor}`, - black: (text: string) => `\x1b[30m${text}${resetColor}`, - red: (text: string) => `\x1b[31m${text}${resetColor}`, - green: (text: string) => `\x1b[32m${text}${resetColor}`, - yellow: (text: string) => `\x1b[33m${text}${resetColor}`, - blue: (text: string) => `\x1b[34m${text}${resetColor}`, - magenta: (text: string) => `\x1b[35m${text}${resetColor}`, - cyan: (text: string) => `\x1b[36m${text}${resetColor}`, - white: (text: string) => `\x1b[37m${text}${resetColor}`, + black: (text: string) => `\x1b[30m${text}${resetColor}`, + red: (text: string) => `\x1b[31m${text}${resetColor}`, + green: (text: string) => `\x1b[32m${text}${resetColor}`, + yellow: (text: string) => `\x1b[33m${text}${resetColor}`, + blue: (text: string) => `\x1b[34m${text}${resetColor}`, + magenta: (text: string) => `\x1b[35m${text}${resetColor}`, + cyan: (text: string) => `\x1b[36m${text}${resetColor}`, + white: (text: string) => `\x1b[37m${text}${resetColor}`, - bgBlack: (text: string) => `\x1b[40m${text}${resetColor}`, - bgRed: (text: string) => `\x1b[41m${text}${resetColor}`, - bgGreen: (text: string) => `\x1b[42m${text}${resetColor}`, - bgYellow: (text: string) => `\x1b[43m${text}${resetColor}`, - bgBlue: (text: string) => `\x1b[44m${text}${resetColor}`, - bgMagenta: (text: string) => `\x1b[45m${text}${resetColor}`, - bgCyan: (text: string) => `\x1b[46m${text}${resetColor}`, - bgWhite: (text: string) => `\x1b[47m${text}${resetColor}`, + bgBlack: (text: string) => `\x1b[40m${text}${resetColor}`, + bgRed: (text: string) => `\x1b[41m${text}${resetColor}`, + bgGreen: (text: string) => `\x1b[42m${text}${resetColor}`, + bgYellow: (text: string) => `\x1b[43m${text}${resetColor}`, + bgBlue: (text: string) => `\x1b[44m${text}${resetColor}`, + bgMagenta: (text: string) => `\x1b[45m${text}${resetColor}`, + bgCyan: (text: string) => `\x1b[46m${text}${resetColor}`, + bgWhite: (text: string) => `\x1b[47m${text}${resetColor}`, }; diff --git a/packages/commandkit/src/utils/get-paths.ts b/packages/commandkit/src/utils/get-paths.ts index af4c0ef..36125e0 100644 --- a/packages/commandkit/src/utils/get-paths.ts +++ b/packages/commandkit/src/utils/get-paths.ts @@ -1,46 +1,55 @@ import path from 'path'; import fs from 'fs/promises'; -export async function getFilePaths(directory: string, nesting?: boolean): Promise { - let filePaths: string[] = []; +export async function getFilePaths( + directory: string, + nesting?: boolean, +): Promise { + let filePaths: string[] = []; - if (!directory) return filePaths; + if (!directory) return filePaths; - const files = await fs.readdir(directory, { withFileTypes: true }); + const files = await fs.readdir(directory, { withFileTypes: true }); - for (const file of files) { - const filePath = path.join(directory, file.name); + for (const file of files) { + const filePath = path.join(directory, file.name); - if (file.isFile()) { - filePaths.push(filePath); - } + if (file.isFile()) { + filePaths.push(filePath); + } - if (nesting && file.isDirectory()) { - filePaths = [...filePaths, ...(await getFilePaths(filePath, true))]; - } + if (nesting && file.isDirectory()) { + filePaths = [...filePaths, ...(await getFilePaths(filePath, true))]; } + } - return filePaths; + return filePaths; } -export async function getFolderPaths(directory: string, nesting?: boolean): Promise { - let folderPaths: string[] = []; +export async function getFolderPaths( + directory: string, + nesting?: boolean, +): Promise { + let folderPaths: string[] = []; - if (!directory) return folderPaths; + if (!directory) return folderPaths; - const folders = await fs.readdir(directory, { withFileTypes: true }); + const folders = await fs.readdir(directory, { withFileTypes: true }); - for (const folder of folders) { - const folderPath = path.join(directory, folder.name); + for (const folder of folders) { + const folderPath = path.join(directory, folder.name); - if (folder.isDirectory()) { - folderPaths.push(folderPath); + if (folder.isDirectory()) { + folderPaths.push(folderPath); - if (nesting) { - folderPaths = [...folderPaths, ...(await getFolderPaths(folderPath, true))]; - } - } + if (nesting) { + folderPaths = [ + ...folderPaths, + ...(await getFolderPaths(folderPath, true)), + ]; + } } + } - return folderPaths; + return folderPaths; } diff --git a/packages/commandkit/src/utils/resolve-file-url.ts b/packages/commandkit/src/utils/resolve-file-url.ts index f4a3e1e..52fdbb3 100644 --- a/packages/commandkit/src/utils/resolve-file-url.ts +++ b/packages/commandkit/src/utils/resolve-file-url.ts @@ -6,6 +6,6 @@ import path from 'path'; * @returns - The converted file URL. */ export function toFileURL(filePath: string) { - const resolvedPath = path.resolve(filePath); - return 'file://' + resolvedPath.replace(/\\\\|\\/g, '/'); + const resolvedPath = path.resolve(filePath); + return 'file://' + resolvedPath.replace(/\\\\|\\/g, '/'); } diff --git a/packages/commandkit/src/utils/signal.ts b/packages/commandkit/src/utils/signal.ts index 29b1575..84447f4 100644 --- a/packages/commandkit/src/utils/signal.ts +++ b/packages/commandkit/src/utils/signal.ts @@ -2,9 +2,9 @@ export type CommandKitEffectCallback = () => void; export type CommandKitSignalInitializer = T | (() => T); export type CommandKitSignalUpdater = T | ((prev: T) => T); export type CommandKitSignal = readonly [ - () => T, - (value: CommandKitSignalUpdater) => void, - () => void, + () => T, + (value: CommandKitSignalUpdater) => void, + () => void, ]; const context: CommandKitEffectCallback[] = []; @@ -14,36 +14,38 @@ const context: CommandKitEffectCallback[] = []; * @param value - The initial value to use. * @returns An array of functions: a getter, a setter, and a disposer. */ -export function createSignal(value?: CommandKitSignalInitializer) { - const subscribers = new Set<() => void>(); +export function createSignal( + value?: CommandKitSignalInitializer, +) { + const subscribers = new Set<() => void>(); - let disposed = false; - let val: T | undefined = value instanceof Function ? value() : value; + let disposed = false; + let val: T | undefined = value instanceof Function ? value() : value; - const getter = () => { - if (!disposed) { - const running = getCurrentObserver(); - if (running) subscribers.add(running); - } + const getter = () => { + if (!disposed) { + const running = getCurrentObserver(); + if (running) subscribers.add(running); + } - return val; - }; + return val; + }; - const setter = (newValue: CommandKitSignalUpdater) => { - if (disposed) return; - val = newValue instanceof Function ? newValue(val!) : newValue; + const setter = (newValue: CommandKitSignalUpdater) => { + if (disposed) return; + val = newValue instanceof Function ? newValue(val!) : newValue; - for (const subscriber of subscribers) { - subscriber(); - } - }; + for (const subscriber of subscribers) { + subscriber(); + } + }; - const dispose = () => { - subscribers.clear(); - disposed = true; - }; + const dispose = () => { + subscribers.clear(); + disposed = true; + }; - return [getter, setter, dispose] as CommandKitSignal; + return [getter, setter, dispose] as CommandKitSignal; } /** @@ -51,22 +53,22 @@ export function createSignal(value?: CommandKitSignalInitializer * @param callback - The callback function to execute. */ export function createEffect(callback: CommandKitEffectCallback) { - const execute = () => { - context.push(execute); + const execute = () => { + context.push(execute); - try { - callback(); - } finally { - context.pop(); - } - }; + try { + callback(); + } finally { + context.pop(); + } + }; - execute(); + execute(); } /** * Get the current observer. */ function getCurrentObserver() { - return context[context.length - 1]; + return context[context.length - 1]; } diff --git a/packages/commandkit/tests/commandkit.mjs b/packages/commandkit/tests/commandkit.mjs index 47744d3..0bf3b5e 100644 --- a/packages/commandkit/tests/commandkit.mjs +++ b/packages/commandkit/tests/commandkit.mjs @@ -3,8 +3,8 @@ import { defineConfig } from '../dist/index.mjs'; export default defineConfig({ - clientOptions: { - intents: ['Guilds', 'GuildMembers', 'GuildMessages', 'MessageContent'] - }, - token: process.env.DISCORD_TOKEN + clientOptions: { + intents: ['Guilds', 'GuildMembers', 'GuildMessages', 'MessageContent'], + }, + token: process.env.DISCORD_TOKEN, }); diff --git a/packages/commandkit/tests/src/client.ts b/packages/commandkit/tests/src/client.ts index 2c60bf7..39bbc2c 100644 --- a/packages/commandkit/tests/src/client.ts +++ b/packages/commandkit/tests/src/client.ts @@ -1,11 +1,11 @@ import { client, CommandKit } from '../../dist/index.mjs'; new CommandKit({ - client: client(), - commandsPath: `${__dirname}/commands`, - eventsPath: `${__dirname}/events`, - validationsPath: `${__dirname}/validations`, - // devGuildIds: process.env.DEV_GUILD_ID?.split(',') ?? [], - // devUserIds: process.env.DEV_USER_ID?.split(',') ?? [], - bulkRegister: true, + client: client(), + commandsPath: `${__dirname}/commands`, + eventsPath: `${__dirname}/events`, + validationsPath: `${__dirname}/validations`, + // devGuildIds: process.env.DEV_GUILD_ID?.split(',') ?? [], + // devUserIds: process.env.DEV_USER_ID?.split(',') ?? [], + bulkRegister: true, }); diff --git a/packages/commandkit/tests/src/commands/misc/count.ts b/packages/commandkit/tests/src/commands/misc/count.ts index f60400c..008b567 100644 --- a/packages/commandkit/tests/src/commands/misc/count.ts +++ b/packages/commandkit/tests/src/commands/misc/count.ts @@ -1,106 +1,116 @@ -import type { SlashCommandProps, CommandOptions, CommandData } from '../../../../dist'; -import { ButtonKit, createEffect, createSignal } from '../../../../dist/index.mjs'; +import type { + SlashCommandProps, + CommandOptions, + CommandData, +} from '../../../../dist'; +import { + ButtonKit, + createEffect, + createSignal, +} from '../../../../dist/index.mjs'; import { ButtonStyle, ActionRowBuilder, ButtonInteraction } from 'discord.js'; export const data: CommandData = { - name: 'count', - description: 'Counter boi!', + name: 'count', + description: 'Counter boi!', }; function getButtons() { - // prettier-ignore - const dec = new ButtonKit() + // prettier-ignore + const dec = new ButtonKit() .setEmoji('➖') .setStyle(ButtonStyle.Primary) .setCustomId('decrement'); - // prettier-ignore - const reset = new ButtonKit() + // prettier-ignore + const reset = new ButtonKit() .setEmoji('0️⃣') .setStyle(ButtonStyle.Primary) .setCustomId('reset'); - // prettier-ignore - const inc = new ButtonKit() + // prettier-ignore + const inc = new ButtonKit() .setEmoji('➕') .setStyle(ButtonStyle.Primary) .setCustomId('increment'); - // prettier-ignore - const trash = new ButtonKit() + // prettier-ignore + const trash = new ButtonKit() .setEmoji('🗑️') .setStyle(ButtonStyle.Danger) .setCustomId('trash'); - // prettier-ignore - const row = new ActionRowBuilder() + // prettier-ignore + const row = new ActionRowBuilder() .addComponents(dec, reset, inc, trash); - return { dec, reset, inc, trash, row }; + return { dec, reset, inc, trash, row }; } export async function run({ interaction }: SlashCommandProps) { - const [count, setCount, disposeCountSubscribers] = createSignal(0); - const { dec, reset, inc, trash, row } = getButtons(); + const [count, setCount, disposeCountSubscribers] = createSignal(0); + const { dec, reset, inc, trash, row } = getButtons(); - let inter: ButtonInteraction; + let inter: ButtonInteraction; - const message = await interaction.reply({ - content: `Count is ${count()}`, - components: [row], - fetchReply: true, - }); + const message = await interaction.reply({ + content: `Count is ${count()}`, + components: [row], + fetchReply: true, + }); - createEffect(() => { - const value = count(); + createEffect(() => { + const value = count(); - inter?.update(`Count is ${value}`); - }); + inter?.update(`Count is ${value}`); + }); - const disposeButtons = async (interaction: ButtonInteraction | null = null) => { - const disposed = row.setComponents( - row.components.map((button) => button.onClick(null).setDisabled(true)), - ); + const disposeButtons = async ( + interaction: ButtonInteraction | null = null, + ) => { + const disposed = row.setComponents( + row.components.map((button) => button.onClick(null).setDisabled(true)), + ); - // Dispose the count's subscribers - disposeCountSubscribers(); + // Dispose the count's subscribers + disposeCountSubscribers(); - const data = { - content: 'Finished counting!', - components: [disposed], - }; - - if (interaction) await interaction.update(data); - else await message.edit(data); + const data = { + content: 'Finished counting!', + components: [disposed], }; - // prettier-ignore - dec.onClick((interaction) => { + if (interaction) await interaction.update(data); + else await message.edit(data); + }; + + // prettier-ignore + dec.onClick((interaction) => { if (!interaction) return disposeButtons(); inter = interaction; setCount((prev) => prev - 1); }, { message }); - // prettier-ignore - reset.onClick((interaction) => { + // prettier-ignore + reset.onClick((interaction) => { if (!interaction) return disposeButtons(); inter = interaction; setCount(0); }, { message }); - // prettier-ignore - inc.onClick((interaction) => { + // prettier-ignore + inc.onClick((interaction) => { if (!interaction) return disposeButtons(); inter = interaction; setCount((prev) => prev + 1); }, { message }); - // prettier-ignore - trash.onClick(async (interaction) => { + // prettier-ignore + trash.onClick(async (interaction) => { disposeButtons(interaction); }, { message }); } export const options: CommandOptions = { - devOnly: true, + devOnly: true, }; diff --git a/packages/commandkit/tests/src/commands/misc/giveaway.ts b/packages/commandkit/tests/src/commands/misc/giveaway.ts index d927641..fbed679 100644 --- a/packages/commandkit/tests/src/commands/misc/giveaway.ts +++ b/packages/commandkit/tests/src/commands/misc/giveaway.ts @@ -1,42 +1,44 @@ import { ChannelType, SlashCommandBuilder } from 'discord.js'; export const data = new SlashCommandBuilder() - .setName('giveaway') - .setDescription('Giveaway related commands') - .addSubcommand((cmd) => - cmd - .setName('create') - .setDescription('Create a giveaway with a modal') - .addChannelOption((option) => - option - .setName('channel') - .setDescription('The channel you would like to send the giveaway to') - .addChannelTypes(ChannelType.GuildText), - ) - .addRoleOption((option) => - option - .setName('ping-role') - .setDescription('The role you would like to ping for this giveaway'), - ), - ) - .addSubcommand((cmd) => - cmd - .setName('end') - .setDescription('End a giveaway early') - .addStringOption((option) => - option - .setName('giveaway-id') - .setDescription('The Message ID for the giveaway') - .setRequired(true), - ), - ) - .addSubcommand((cmd) => - cmd.setName('list').setDescription('List all active giveaways for this server'), - ); + .setName('giveaway') + .setDescription('Giveaway related commands') + .addSubcommand((cmd) => + cmd + .setName('create') + .setDescription('Create a giveaway with a modal') + .addChannelOption((option) => + option + .setName('channel') + .setDescription('The channel you would like to send the giveaway to') + .addChannelTypes(ChannelType.GuildText), + ) + .addRoleOption((option) => + option + .setName('ping-role') + .setDescription('The role you would like to ping for this giveaway'), + ), + ) + .addSubcommand((cmd) => + cmd + .setName('end') + .setDescription('End a giveaway early') + .addStringOption((option) => + option + .setName('giveaway-id') + .setDescription('The Message ID for the giveaway') + .setRequired(true), + ), + ) + .addSubcommand((cmd) => + cmd + .setName('list') + .setDescription('List all active giveaways for this server'), + ); export function run() {} export const options = { - devOnly: true, - // deleted: true, + devOnly: true, + // deleted: true, }; diff --git a/packages/commandkit/tests/src/commands/misc/ping.ts b/packages/commandkit/tests/src/commands/misc/ping.ts index fe8eaf3..f8bbb8e 100644 --- a/packages/commandkit/tests/src/commands/misc/ping.ts +++ b/packages/commandkit/tests/src/commands/misc/ping.ts @@ -1,77 +1,83 @@ -import { ActionRowBuilder, ApplicationCommandOptionType, ButtonStyle } from 'discord.js'; import { - SlashCommandProps, - CommandOptions, - CommandData, - ButtonKit, - AutocompleteProps, + ActionRowBuilder, + ApplicationCommandOptionType, + ButtonStyle, +} from 'discord.js'; +import { + SlashCommandProps, + CommandOptions, + CommandData, + ButtonKit, + AutocompleteProps, } from '../../../../dist/index.mjs'; export const data: CommandData = { - name: 'ping', - description: 'Pong!', - options: [ - { - name: 'test', - description: 'Test option for autocomplete', - autocomplete: true, - type: ApplicationCommandOptionType.String, - required: false, - }, - ], + name: 'ping', + description: 'Pong!', + options: [ + { + name: 'test', + description: 'Test option for autocomplete', + autocomplete: true, + type: ApplicationCommandOptionType.String, + required: false, + }, + ], }; const tests = Array.from({ length: 10 }, (_, i) => ({ - name: `Test ${i + 1}`, - value: `${i}_test`, + name: `Test ${i + 1}`, + value: `${i}_test`, })); export async function autocomplete({ interaction }: AutocompleteProps) { - const arg = interaction.options.getString('test', false); - console.log(arg); - if (!arg) return interaction.respond(tests); + const arg = interaction.options.getString('test', false); + console.log(arg); + if (!arg) return interaction.respond(tests); - const filtered = tests.filter((test) => test.name.toLowerCase().includes(arg.toLowerCase())); + const filtered = tests.filter((test) => + test.name.toLowerCase().includes(arg.toLowerCase()), + ); - interaction.respond(filtered); + interaction.respond(filtered); } export async function run({ interaction, client }: SlashCommandProps) { - if (!interaction.channel) return; - - const button = new ButtonKit() - .setCustomId('ping_btn') - .setStyle(ButtonStyle.Primary) - .setLabel('Ping Button!'); + if (!interaction.channel) return; - const row = new ActionRowBuilder().addComponents(button); + const button = new ButtonKit() + .setCustomId('ping_btn') + .setStyle(ButtonStyle.Primary) + .setLabel('Ping Button!'); - const message = await interaction.reply({ - content: 'Click one of the buttons', - components: [row], - fetchReply: true, - }); + const row = new ActionRowBuilder().addComponents(button); - button - .onClick( - (inter) => { - console.log('onClick called'); + const message = await interaction.reply({ + content: 'Click one of the buttons', + components: [row], + fetchReply: true, + }); - inter.reply({ - content: 'You clicked the ping button!', - ephemeral: true, - }); - }, - { message, time: 10_000, autoReset: true }, - ) - .onEnd(() => { - console.log('onEnd called'); + button + .onClick( + (inter) => { + console.log('onClick called'); - button.setDisabled(true); - message.edit({ components: [row] }); + inter.reply({ + content: 'You clicked the ping button!', + ephemeral: true, }); + }, + { message, time: 10_000, autoReset: true }, + ) + .onEnd(() => { + console.log('onEnd called'); + + button.setDisabled(true); + message.edit({ components: [row] }); + }); } export const options: CommandOptions = { - devOnly: true, + devOnly: true, }; diff --git a/packages/commandkit/tests/src/commands/misc/reload.ts b/packages/commandkit/tests/src/commands/misc/reload.ts index 20b1072..f72b1e5 100644 --- a/packages/commandkit/tests/src/commands/misc/reload.ts +++ b/packages/commandkit/tests/src/commands/misc/reload.ts @@ -1,25 +1,29 @@ -import { SlashCommandProps, CommandOptions, CommandData } from '../../../../dist/index.mjs'; +import { + SlashCommandProps, + CommandOptions, + CommandData, +} from '../../../../dist/index.mjs'; export const data: CommandData = { - name: 'reload', - description: 'Reload commands, events, and validations.', + name: 'reload', + description: 'Reload commands, events, and validations.', }; export async function run({ interaction, handler }: SlashCommandProps) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - // await handler.reloadCommands(); - // console.log('Reloaded commands'); + // await handler.reloadCommands(); + // console.log('Reloaded commands'); - // await handler.reloadEvents(); - // console.log('Reloaded events'); + // await handler.reloadEvents(); + // console.log('Reloaded events'); - await handler.reloadValidations(); - console.log('Reloaded validations.'); - interaction.followUp('Done!'); + await handler.reloadValidations(); + console.log('Reloaded validations.'); + interaction.followUp('Done!'); } export const options: CommandOptions = { - userPermissions: [], - devOnly: true, + userPermissions: [], + devOnly: true, }; diff --git a/packages/commandkit/tests/src/events/messageCreate/say-hi.ts b/packages/commandkit/tests/src/events/messageCreate/say-hi.ts index 6d951e5..8bccfaf 100644 --- a/packages/commandkit/tests/src/events/messageCreate/say-hi.ts +++ b/packages/commandkit/tests/src/events/messageCreate/say-hi.ts @@ -1,7 +1,7 @@ import type { Message } from 'discord.js'; export default function (message: Message) { - if (!message.author.bot && message.content === 'hello') { - message.reply('hi!'); - } + if (!message.author.bot && message.content === 'hello') { + message.reply('hi!'); + } } diff --git a/packages/commandkit/tests/src/events/ready/console-log.ts b/packages/commandkit/tests/src/events/ready/console-log.ts index 26349e7..93e3038 100644 --- a/packages/commandkit/tests/src/events/ready/console-log.ts +++ b/packages/commandkit/tests/src/events/ready/console-log.ts @@ -2,5 +2,5 @@ import type { Client } from 'discord.js'; import type { CommandKit } from '../../../../dist'; export default function (c: Client, client, handler: CommandKit) { - console.log(`${c.user.username} is online.`); + console.log(`${c.user.username} is online.`); } diff --git a/packages/commandkit/tests/src/validations/devOnly.ts b/packages/commandkit/tests/src/validations/devOnly.ts index c94a140..eb187b4 100644 --- a/packages/commandkit/tests/src/validations/devOnly.ts +++ b/packages/commandkit/tests/src/validations/devOnly.ts @@ -1,9 +1,13 @@ import type { ValidationProps } from '../../../dist'; -export default function ({ interaction, commandObj, handler }: ValidationProps) { - if (interaction.isAutocomplete()) return; - // if (commandObj.data.name === 'ping') { - // interaction.reply('blocked...'); - // return true; - // } +export default function ({ + interaction, + commandObj, + handler, +}: ValidationProps) { + if (interaction.isAutocomplete()) return; + // if (commandObj.data.name === 'ping') { + // interaction.reply('blocked...'); + // return true; + // } } diff --git a/packages/commandkit/tsconfig.json b/packages/commandkit/tsconfig.json index 9545a2b..33017fa 100644 --- a/packages/commandkit/tsconfig.json +++ b/packages/commandkit/tsconfig.json @@ -1,10 +1,10 @@ { - "extends": "tsconfig/base.json", - "compilerOptions": { - "outDir": "dist", - "skipLibCheck": true, - "skipDefaultLibCheck": true - }, - "include": ["src/**/*.ts", "helpers/**/*.ts", "spec"], - "exclude": ["node_modules"] + "extends": "tsconfig/base.json", + "compilerOptions": { + "outDir": "dist", + "skipLibCheck": true, + "skipDefaultLibCheck": true + }, + "include": ["src/**/*.ts", "helpers/**/*.ts", "spec"], + "exclude": ["node_modules"] } diff --git a/packages/commandkit/tsup.config.ts b/packages/commandkit/tsup.config.ts index 56f41f5..d0d4135 100644 --- a/packages/commandkit/tsup.config.ts +++ b/packages/commandkit/tsup.config.ts @@ -2,16 +2,16 @@ import { defineConfig } from 'tsup'; import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector'; export default defineConfig({ - format: ['cjs', 'esm'], - entry: ['./src'], - sourcemap: true, - minifyIdentifiers: false, - minifySyntax: true, - minifyWhitespace: true, - keepNames: true, - dts: true, - shims: true, - skipNodeModulesBundle: true, - clean: true, - esbuildPlugins: [esbuildPluginVersionInjector()], + format: ['cjs', 'esm'], + entry: ['./src'], + sourcemap: true, + minifyIdentifiers: false, + minifySyntax: true, + minifyWhitespace: true, + keepNames: true, + dts: true, + shims: true, + skipNodeModulesBundle: true, + clean: true, + esbuildPlugins: [esbuildPluginVersionInjector()], }); diff --git a/packages/commandkit/vitest.config.ts b/packages/commandkit/vitest.config.ts index 6503d25..c90b568 100644 --- a/packages/commandkit/vitest.config.ts +++ b/packages/commandkit/vitest.config.ts @@ -1,9 +1,9 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ - test: { - include: ['./spec/**/*.{test,spec}.?(c|m)[jt]s?(x)'], - watch: false, - dangerouslyIgnoreUnhandledErrors: true, - }, + test: { + include: ['./spec/**/*.{test,spec}.?(c|m)[jt]s?(x)'], + watch: false, + dangerouslyIgnoreUnhandledErrors: true, + }, }); diff --git a/packages/create-commandkit/package.json b/packages/create-commandkit/package.json index e0adb3a..e0288e6 100644 --- a/packages/create-commandkit/package.json +++ b/packages/create-commandkit/package.json @@ -1,48 +1,48 @@ { - "name": "create-commandkit", - "description": "Effortlessly create a CommandKit project", - "version": "2.0.0", - "main": "./dist/index.js", - "module": "./dist/index.js", - "bin": "./dist/index.js", - "type": "module", - "license": "MIT", - "keywords": [ - "commandkit", - "create-commandkit", - "discord.js", - "discord", - "node", - "client", - "cli", - "commands" - ], - "files": [ - "dist", - "templates" - ], - "repository": { - "type": "git", - "url": "https://github.com/underctrl-io/commandkit", - "directory": "packages/create-commandkit" - }, - "homepage": "https://commandkit.js.org", - "scripts": { - "build": "tsup", - "lint": "tsc" - }, - "dependencies": { - "@clack/prompts": "^0.7.0", - "colors": "^1.4.0", - "fs-extra": "^11.1.1", - "gradient-string": "^2.0.2" - }, - "devDependencies": { - "@types/node": "^20.11.6", - "@types/gradient-string": "^1.1.5", - "@types/fs-extra": "^11.0.4", - "typescript": "^5.3.3", - "tsconfig": "workspace:*", - "tsup": "^8.0.1" - } + "name": "create-commandkit", + "description": "Effortlessly create a CommandKit project", + "version": "2.0.0", + "main": "./dist/index.js", + "module": "./dist/index.js", + "bin": "./dist/index.js", + "type": "module", + "license": "MIT", + "keywords": [ + "commandkit", + "create-commandkit", + "discord.js", + "discord", + "node", + "client", + "cli", + "commands" + ], + "files": [ + "dist", + "templates" + ], + "repository": { + "type": "git", + "url": "https://github.com/underctrl-io/commandkit", + "directory": "packages/create-commandkit" + }, + "homepage": "https://commandkit.js.org", + "scripts": { + "build": "tsup", + "lint": "tsc" + }, + "dependencies": { + "@clack/prompts": "^0.7.0", + "colors": "^1.4.0", + "fs-extra": "^11.1.1", + "gradient-string": "^2.0.2" + }, + "devDependencies": { + "@types/node": "^20.11.6", + "@types/gradient-string": "^1.1.5", + "@types/fs-extra": "^11.0.4", + "typescript": "^5.3.3", + "tsconfig": "workspace:*", + "tsup": "^8.0.1" + } } diff --git a/packages/create-commandkit/src/functions/copyTemplates.ts b/packages/create-commandkit/src/functions/copyTemplates.ts index 43e276e..c691f3f 100644 --- a/packages/create-commandkit/src/functions/copyTemplates.ts +++ b/packages/create-commandkit/src/functions/copyTemplates.ts @@ -3,11 +3,11 @@ import { templates } from '../utils'; import fs from 'fs-extra'; interface CopyTemplatesProps { - type: ModuleType; - lang: Language; - dir: string; + type: ModuleType; + lang: Language; + dir: string; } export async function copyTemplates({ type, dir, lang }: CopyTemplatesProps) { - await fs.copy(templates[lang][type], dir); + await fs.copy(templates[lang][type], dir); } diff --git a/packages/create-commandkit/src/functions/installDeps.ts b/packages/create-commandkit/src/functions/installDeps.ts index 05210ce..0d57c8d 100644 --- a/packages/create-commandkit/src/functions/installDeps.ts +++ b/packages/create-commandkit/src/functions/installDeps.ts @@ -3,12 +3,20 @@ import { type IOType, execSync } from 'node:child_process'; import { dependencies } from '../utils'; interface InstallDepsProps { - manager: PackageManager; - dir: string; - lang: Language; - stdio: IOType; + manager: PackageManager; + dir: string; + lang: Language; + stdio: IOType; } -export function installDeps({ manager, dir, lang, stdio = 'pipe' }: InstallDepsProps) { - execSync(`${manager} add ${dependencies[lang].join(' ')}`, { cwd: dir, stdio }); +export function installDeps({ + manager, + dir, + lang, + stdio = 'pipe', +}: InstallDepsProps) { + execSync(`${manager} add ${dependencies[lang].join(' ')}`, { + cwd: dir, + stdio, + }); } diff --git a/packages/create-commandkit/src/functions/setup.ts b/packages/create-commandkit/src/functions/setup.ts index ae4edd4..64b3f2b 100644 --- a/packages/create-commandkit/src/functions/setup.ts +++ b/packages/create-commandkit/src/functions/setup.ts @@ -6,31 +6,37 @@ import fs from 'fs-extra'; import path from 'node:path'; interface SetupProps { - manager: PackageManager; - type: ModuleType; - token: string; - dir: string; - stdio?: IOType; + manager: PackageManager; + type: ModuleType; + token: string; + dir: string; + stdio?: IOType; } -export async function setup({ manager, type, token, dir, stdio = 'pipe' }: SetupProps) { - await fs.emptyDir(dir); - execSync(commands.init[manager], { cwd: dir, stdio }); +export async function setup({ + manager, + type, + token, + dir, + stdio = 'pipe', +}: SetupProps) { + await fs.emptyDir(dir); + execSync(commands.init[manager], { cwd: dir, stdio }); - const packageJsonPath = path.join(dir, 'package.json'); - const packageJson = await fs.readJSON(packageJsonPath); + const packageJsonPath = path.join(dir, 'package.json'); + const packageJson = await fs.readJSON(packageJsonPath); - delete packageJson.main; - packageJson.name = packageJson.name.toLowerCase(); - packageJson.type = type == 'esm' ? 'module' : 'commonjs'; - packageJson.version = '0.0.0'; + delete packageJson.main; + packageJson.name = packageJson.name.toLowerCase(); + packageJson.type = type == 'esm' ? 'module' : 'commonjs'; + packageJson.version = '0.0.0'; - packageJson.scripts = { - dev: 'commandkit dev', - build: 'commandkit build', - start: 'commandkit start', - }; + packageJson.scripts = { + dev: 'commandkit dev', + build: 'commandkit build', + start: 'commandkit start', + }; - await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 }); - await fs.writeFile(`${dir}/.env`, `TOKEN="${token}"`); + await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 }); + await fs.writeFile(`${dir}/.env`, `TOKEN="${token}"`); } diff --git a/packages/create-commandkit/src/index.ts b/packages/create-commandkit/src/index.ts index 5f700fe..326dc9c 100755 --- a/packages/create-commandkit/src/index.ts +++ b/packages/create-commandkit/src/index.ts @@ -16,52 +16,60 @@ import fs from 'fs-extra'; await intro(`Welcome to ${commandkit}!`); const dir = path.resolve( - process.cwd(), - (await text({ - message: 'Enter a project directory:', - placeholder: 'Leave blank for current directory', - defaultValue: '.', - validate: (value) => { - value = path.resolve(process.cwd(), value); - let isEmpty; + process.cwd(), + (await text({ + message: 'Enter a project directory:', + placeholder: 'Leave blank for current directory', + defaultValue: '.', + validate: (value) => { + value = path.resolve(process.cwd(), value); + let isEmpty; - try { - const contents = fs.readdirSync(value); - isEmpty = contents.length === 0; - } catch { - isEmpty = true; - } + try { + const contents = fs.readdirSync(value); + isEmpty = contents.length === 0; + } catch { + isEmpty = true; + } - return isEmpty ? undefined : 'Directory is not empty!'; - }, - })) as string, + return isEmpty ? undefined : 'Directory is not empty!'; + }, + })) as string, ); const manager = (await select({ - message: 'Select a package manager:', - options: [ - { label: 'npm', value: 'npm' }, - { label: 'pnpm', value: 'pnpm' }, - { label: 'yarn', value: 'yarn' }, - ], + message: 'Select a package manager:', + options: [ + { label: 'npm', value: 'npm' }, + { label: 'pnpm', value: 'pnpm' }, + { label: 'yarn', value: 'yarn' }, + ], })) as PackageManager; const type = (await select({ - message: 'Select a module type:', - options: [ - { label: 'CommonJS', value: 'cjs', hint: `${hints.require} & ${hints.module}` }, - { label: 'ES Modules', value: 'esm', hint: `${hints.import} & ${hints.export}` }, - ], + message: 'Select a module type:', + options: [ + { + label: 'CommonJS', + value: 'cjs', + hint: `${hints.require} & ${hints.module}`, + }, + { + label: 'ES Modules', + value: 'esm', + hint: `${hints.import} & ${hints.export}`, + }, + ], })) as ModuleType; const token = (await password({ - message: 'Enter your bot token:', - mask: colors.gray('*'), + message: 'Enter your bot token:', + mask: colors.gray('*'), })) as string; const installNow = await confirm({ - message: 'Install dependencies now?', - initialValue: true, + message: 'Install dependencies now?', + initialValue: true, }); outro(colors.cyan('Setup complete.')); @@ -70,7 +78,7 @@ await setup({ manager, dir, token, type }); await copyTemplates({ type, dir, lang: 'js' }); if (installNow) { - await installDeps({ manager, dir, lang: 'js', stdio: 'inherit' }); + await installDeps({ manager, dir, lang: 'js', stdio: 'inherit' }); } console.log(outroMsg); diff --git a/packages/create-commandkit/src/utils.ts b/packages/create-commandkit/src/utils.ts index 0ae2588..d30904b 100644 --- a/packages/create-commandkit/src/utils.ts +++ b/packages/create-commandkit/src/utils.ts @@ -6,41 +6,41 @@ import url from 'node:url'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); export const templates = { - js: { - esm: `${__dirname}/../templates/JavaScript/esm`, - cjs: `${__dirname}/../templates/JavaScript/cjs`, - }, + js: { + esm: `${__dirname}/../templates/JavaScript/esm`, + cjs: `${__dirname}/../templates/JavaScript/cjs`, + }, }; export const textColors = { - commandkit: ['#fdba74', '#e4a5a2', '#c288de', '#b27bf9'], - import: ['#c586c0', '#c586c0'], - export: ['#569cd6', '#569cd6'], - require: ['#dcdcaa', '#dcdcaa'], - module: ['#4ec9b0', '#4ec9b0'], - js: ['#f7e01c', '#f7e01c'], - ts: ['#2480c5', '#2480c5'], + commandkit: ['#fdba74', '#e4a5a2', '#c288de', '#b27bf9'], + import: ['#c586c0', '#c586c0'], + export: ['#569cd6', '#569cd6'], + require: ['#dcdcaa', '#dcdcaa'], + module: ['#4ec9b0', '#4ec9b0'], + js: ['#f7e01c', '#f7e01c'], + ts: ['#2480c5', '#2480c5'], }; export const dependencies = { - js: ['commandkit', 'discord.js', 'dotenv'], + js: ['commandkit', 'discord.js', 'dotenv'], }; export const commands = { - init: { - npm: 'npm init -y', - yarn: 'yarn init -y; yarn config set nodeLinker node-modules', - pnpm: 'pnpm init', - }, + init: { + npm: 'npm init -y', + yarn: 'yarn init -y; yarn config set nodeLinker node-modules', + pnpm: 'pnpm init', + }, }; export const hints = { - import: gradient(textColors.import)('import'), - export: gradient(textColors.export)('export'), - require: gradient(textColors.require)('require'), - module: gradient(textColors.module)('exports'), - javascript: gradient(textColors.js)('JavaScript'), - typescript: gradient(textColors.ts)('TypeScript'), + import: gradient(textColors.import)('import'), + export: gradient(textColors.export)('export'), + require: gradient(textColors.require)('require'), + module: gradient(textColors.module)('exports'), + javascript: gradient(textColors.js)('JavaScript'), + typescript: gradient(textColors.ts)('TypeScript'), }; export const commandkit = gradient(textColors.commandkit)('CommandKit'); diff --git a/packages/create-commandkit/templates/JavaScript/cjs/commandkit.cjs b/packages/create-commandkit/templates/JavaScript/cjs/commandkit.cjs index e5055be..5417a61 100644 --- a/packages/create-commandkit/templates/JavaScript/cjs/commandkit.cjs +++ b/packages/create-commandkit/templates/JavaScript/cjs/commandkit.cjs @@ -1,6 +1,6 @@ const { defineConfig } = require('commandkit'); module.exports = defineConfig({ - src: 'src', - main: 'index.mjs', + src: 'src', + main: 'index.mjs', }); diff --git a/packages/create-commandkit/templates/JavaScript/cjs/src/commands/General/ping.js b/packages/create-commandkit/templates/JavaScript/cjs/src/commands/General/ping.js index 973b856..65fd889 100644 --- a/packages/create-commandkit/templates/JavaScript/cjs/src/commands/General/ping.js +++ b/packages/create-commandkit/templates/JavaScript/cjs/src/commands/General/ping.js @@ -1,19 +1,19 @@ module.exports = { - /** @type {import('commandkit').CommandData} */ - data: { - name: 'ping', - description: 'Replies with Pong', - }, + /** @type {import('commandkit').CommandData} */ + data: { + name: 'ping', + description: 'Replies with Pong', + }, - /** - * @param {import('commandkit').SlashCommandProps} param0 - */ - run: ({ interaction }) => { - interaction.reply('Pong!'); - }, + /** + * @param {import('commandkit').SlashCommandProps} param0 + */ + run: ({ interaction }) => { + interaction.reply('Pong!'); + }, - /** @type {import('commandkit').CommandOptions} */ - options: { - // https://commandkit.js.org/typedef/CommandOptions - }, + /** @type {import('commandkit').CommandOptions} */ + options: { + // https://commandkit.js.org/typedef/CommandOptions + }, }; diff --git a/packages/create-commandkit/templates/JavaScript/cjs/src/events/ready/ready.js b/packages/create-commandkit/templates/JavaScript/cjs/src/events/ready/ready.js index a05ae4f..d6679fc 100644 --- a/packages/create-commandkit/templates/JavaScript/cjs/src/events/ready/ready.js +++ b/packages/create-commandkit/templates/JavaScript/cjs/src/events/ready/ready.js @@ -1,4 +1,4 @@ /** * @param {import('discord.js').Client} client */ module.exports = (client) => { - console.log(`${client.user.tag} is online!`); + console.log(`${client.user.tag} is online!`); }; diff --git a/packages/create-commandkit/templates/JavaScript/cjs/src/index.js b/packages/create-commandkit/templates/JavaScript/cjs/src/index.js index 1e6b1f7..86dcb6b 100644 --- a/packages/create-commandkit/templates/JavaScript/cjs/src/index.js +++ b/packages/create-commandkit/templates/JavaScript/cjs/src/index.js @@ -5,18 +5,18 @@ const { CommandKit } = require('commandkit'); const { join } = require('path'); const client = new Client({ - intents: [ - IntentsBitField.Flags.Guilds, - IntentsBitField.Flags.GuildMembers, - IntentsBitField.Flags.GuildMessages, - IntentsBitField.Flags.MessageContent, - ], + intents: [ + IntentsBitField.Flags.Guilds, + IntentsBitField.Flags.GuildMembers, + IntentsBitField.Flags.GuildMessages, + IntentsBitField.Flags.MessageContent, + ], }); new CommandKit({ - client, - eventsPath: join(__dirname, 'events'), - commandsPath: join(__dirname, 'commands'), + client, + eventsPath: join(__dirname, 'events'), + commandsPath: join(__dirname, 'commands'), }); client.login(process.env.TOKEN); diff --git a/packages/create-commandkit/templates/JavaScript/esm/commandkit.mjs b/packages/create-commandkit/templates/JavaScript/esm/commandkit.mjs index 937ee5f..9093eae 100644 --- a/packages/create-commandkit/templates/JavaScript/esm/commandkit.mjs +++ b/packages/create-commandkit/templates/JavaScript/esm/commandkit.mjs @@ -1,6 +1,6 @@ import { defineConfig } from 'commandkit'; export default defineConfig({ - src: 'src', - main: 'index.js', + src: 'src', + main: 'index.js', }); diff --git a/packages/create-commandkit/templates/JavaScript/esm/src/commands/General/ping.js b/packages/create-commandkit/templates/JavaScript/esm/src/commands/General/ping.js index 5dded16..a1359f5 100644 --- a/packages/create-commandkit/templates/JavaScript/esm/src/commands/General/ping.js +++ b/packages/create-commandkit/templates/JavaScript/esm/src/commands/General/ping.js @@ -1,17 +1,17 @@ /** @type {import('commandkit').CommandData} */ export const data = { - name: 'ping', - description: 'Replies with Pong', + name: 'ping', + description: 'Replies with Pong', }; /** * @param {import('commandkit').SlashCommandProps} param0 */ export const run = ({ interaction }) => { - interaction.reply('Pong!'); + interaction.reply('Pong!'); }; /** @type {import('commandkit').CommandOptions} */ export const options = { - // https://commandkit.js.org/typedef/CommandOptions + // https://commandkit.js.org/typedef/CommandOptions }; diff --git a/packages/create-commandkit/templates/JavaScript/esm/src/events/ready/ready.js b/packages/create-commandkit/templates/JavaScript/esm/src/events/ready/ready.js index 7c17460..95b62c5 100644 --- a/packages/create-commandkit/templates/JavaScript/esm/src/events/ready/ready.js +++ b/packages/create-commandkit/templates/JavaScript/esm/src/events/ready/ready.js @@ -1,4 +1,4 @@ /** * @param {import('discord.js').Client} client */ export default (client) => { - console.log(`${client.user.tag} is online!`); + console.log(`${client.user.tag} is online!`); }; diff --git a/packages/create-commandkit/templates/JavaScript/esm/src/index.js b/packages/create-commandkit/templates/JavaScript/esm/src/index.js index ce07d7e..b59138f 100644 --- a/packages/create-commandkit/templates/JavaScript/esm/src/index.js +++ b/packages/create-commandkit/templates/JavaScript/esm/src/index.js @@ -9,18 +9,18 @@ import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const client = new Client({ - intents: [ - IntentsBitField.Flags.Guilds, - IntentsBitField.Flags.GuildMembers, - IntentsBitField.Flags.GuildMessages, - IntentsBitField.Flags.MessageContent, - ], + intents: [ + IntentsBitField.Flags.Guilds, + IntentsBitField.Flags.GuildMembers, + IntentsBitField.Flags.GuildMessages, + IntentsBitField.Flags.MessageContent, + ], }); new CommandKit({ - client, - eventsPath: join(__dirname, 'events'), - commandsPath: join(__dirname, 'commands'), + client, + eventsPath: join(__dirname, 'events'), + commandsPath: join(__dirname, 'commands'), }); client.login(process.env.TOKEN); diff --git a/packages/create-commandkit/tsconfig.json b/packages/create-commandkit/tsconfig.json index 4f1c8f4..27f1088 100644 --- a/packages/create-commandkit/tsconfig.json +++ b/packages/create-commandkit/tsconfig.json @@ -1,10 +1,10 @@ { - "extends": "tsconfig/base.json", - "compilerOptions": { - "outDir": "dist", - "module": "ESNext", - "target": "ESNext" - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules", "templates"] + "extends": "tsconfig/base.json", + "compilerOptions": { + "outDir": "dist", + "module": "ESNext", + "target": "ESNext" + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "templates"] } diff --git a/packages/create-commandkit/tsup.config.ts b/packages/create-commandkit/tsup.config.ts index e1c2e57..fc69cf2 100644 --- a/packages/create-commandkit/tsup.config.ts +++ b/packages/create-commandkit/tsup.config.ts @@ -1,15 +1,15 @@ import { defineConfig } from 'tsup'; export default defineConfig({ - entry: ['./src/index.ts'], - format: 'esm', - outDir: 'dist', - skipNodeModulesBundle: true, - minifyIdentifiers: false, - minifySyntax: true, - minifyWhitespace: true, - keepNames: true, - clean: true, - shims: true, - dts: false, + entry: ['./src/index.ts'], + format: 'esm', + outDir: 'dist', + skipNodeModulesBundle: true, + minifyIdentifiers: false, + minifySyntax: true, + minifyWhitespace: true, + keepNames: true, + clean: true, + shims: true, + dts: false, }); diff --git a/packages/tsconfig/base.json b/packages/tsconfig/base.json index 5d952d6..0dd6eb1 100644 --- a/packages/tsconfig/base.json +++ b/packages/tsconfig/base.json @@ -1,15 +1,15 @@ { - "$schema": "https://json.schemastore.org/tsconfig", - "compilerOptions": { - "strict": true, - "noImplicitAny": true, - "esModuleInterop": true, - "strictNullChecks": true, - "target": "ES2022", - "moduleResolution": "Node", - "module": "CommonJS", - "declaration": true, - "isolatedModules": true, - "noEmit": true - } + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true, + "strictNullChecks": true, + "target": "ES2022", + "moduleResolution": "Node", + "module": "CommonJS", + "declaration": true, + "isolatedModules": true, + "noEmit": true + } } diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json index 02ad3eb..70219b6 100644 --- a/packages/tsconfig/package.json +++ b/packages/tsconfig/package.json @@ -1,6 +1,6 @@ { - "name": "tsconfig", - "version": "0.0.0", - "private": true, - "license": "MIT" + "name": "tsconfig", + "version": "0.0.0", + "private": true, + "license": "MIT" } diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1e13144..e9b0dad 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,3 @@ packages: - - 'apps/*' - - 'packages/*' + - 'apps/*' + - 'packages/*' diff --git a/turbo.json b/turbo.json index bb8b704..c1db680 100644 --- a/turbo.json +++ b/turbo.json @@ -1,13 +1,13 @@ { - "$schema": "https://turbo.build/schema.json", - "pipeline": { - "lint": {}, - "build": {}, - "deploy": {}, - "deploy-dev": {}, - "dev": { - "cache": false, - "persistent": true - } + "$schema": "https://turbo.build/schema.json", + "pipeline": { + "lint": {}, + "build": {}, + "deploy": {}, + "deploy-dev": {}, + "dev": { + "cache": false, + "persistent": true } + } }