From 16c842808dcdddcdda043d9035e720b0306d75bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Steinh=C3=BCbl?= Date: Sat, 30 Dec 2023 16:54:59 +0100 Subject: [PATCH] refactor!: rewrite (#32) Thanks @Didas-git for big help https://github.com/xHyroM/bun-discord-bot/pull/31 --------- Co-authored-by: DidaS --- .github/workflows/validate.yml | 4 +- .gitignore | 5 +- README.md | 2 +- bun.lockb | Bin 37254 -> 16570 bytes data/tags/windows.md | 11 +- globals.d.ts | 7 + package.json | 13 +- pnpm-lock.yaml | 672 --------------------- scripts/validate_tags/bun.lockb | Bin 13622 -> 0 bytes scripts/validate_tags/index.ts | 121 ++++ scripts/validate_tags/package.json | 9 - scripts/validate_tags/src/index.ts | 117 ---- scripts/validate_tags/tsconfig.json | 3 - scripts/validate_tags/{src => }/types.d.ts | 0 src/commands/docs.ts | 94 --- src/commands/docs.tsx | 94 +++ src/commands/github.ts | 279 --------- src/commands/github.tsx | 275 +++++++++ src/commands/index.ts | 8 - src/commands/ping.ts | 30 - src/commands/ping.tsx | 16 + src/commands/tag.ts | 89 --- src/commands/tag.tsx | 54 ++ src/commands/version.ts | 18 - src/commands/version.tsx | 19 + src/constants.ts | 6 +- src/index.ts | 25 +- src/listeners/index.ts | 5 - src/listeners/interaction_create.ts | 59 -- src/listeners/member_add.ts | 9 + src/listeners/member_update.ts | 9 + src/listeners/message_create.ts | 105 ---- src/listeners/message_create.tsx | 96 +++ src/listeners/message_update.ts | 21 +- src/listeners/nickname_moderation.ts | 25 - src/listeners/ready.ts | 16 +- src/loaders/commands.ts | 26 - src/loaders/listeners.ts | 14 - src/loaders/tags.ts | 124 ++-- src/message-commands/ping.ts | 16 + src/message-commands/tag.ts | 32 + src/structs/Client.ts | 11 - src/structs/Command.ts | 41 -- src/structs/Listener.ts | 10 - src/structs/context/AutocompleteContext.ts | 34 -- src/structs/context/CommandContext.ts | 72 --- src/util.ts | 24 +- tsconfig.json | 19 +- 48 files changed, 922 insertions(+), 1817 deletions(-) create mode 100644 globals.d.ts delete mode 100644 pnpm-lock.yaml delete mode 100755 scripts/validate_tags/bun.lockb create mode 100644 scripts/validate_tags/index.ts delete mode 100644 scripts/validate_tags/package.json delete mode 100644 scripts/validate_tags/src/index.ts delete mode 100644 scripts/validate_tags/tsconfig.json rename scripts/validate_tags/{src => }/types.d.ts (100%) delete mode 100644 src/commands/docs.ts create mode 100644 src/commands/docs.tsx delete mode 100644 src/commands/github.ts create mode 100644 src/commands/github.tsx delete mode 100644 src/commands/index.ts delete mode 100644 src/commands/ping.ts create mode 100644 src/commands/ping.tsx delete mode 100644 src/commands/tag.ts create mode 100644 src/commands/tag.tsx delete mode 100644 src/commands/version.ts create mode 100644 src/commands/version.tsx delete mode 100644 src/listeners/index.ts delete mode 100644 src/listeners/interaction_create.ts create mode 100644 src/listeners/member_add.ts create mode 100644 src/listeners/member_update.ts delete mode 100644 src/listeners/message_create.ts create mode 100644 src/listeners/message_create.tsx delete mode 100644 src/listeners/nickname_moderation.ts delete mode 100644 src/loaders/commands.ts delete mode 100644 src/loaders/listeners.ts create mode 100644 src/message-commands/ping.ts create mode 100644 src/message-commands/tag.ts delete mode 100644 src/structs/Client.ts delete mode 100644 src/structs/Command.ts delete mode 100644 src/structs/Listener.ts delete mode 100644 src/structs/context/AutocompleteContext.ts delete mode 100644 src/structs/context/CommandContext.ts diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0b76e69..b90bc2b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -26,7 +26,9 @@ jobs: run: cp $HOME/files.json ./scripts/validate_tags/ - name: Validate tags - run: bun run validate:tags + run: | + bun i + bun run validate:tags env: github-token: ${{ secrets.GITHUB_TOKEN }} commit-sha: ${{ github.event.pull_request.head.sha }} diff --git a/.gitignore b/.gitignore index 54d3912..9f30e4f 100644 --- a/.gitignore +++ b/.gitignore @@ -80,10 +80,7 @@ web_modules/ # dotenv environment variable files .env -.env.development.local -.env.test.local -.env.production.local -.env.local +.env.* # parcel-bundler cache (https://parceljs.org/) .cache diff --git a/README.md b/README.md index cd60b85..1c878d3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Bun discord bot -Official serverless discord bot for [bun](https://bun.sh/) [discord server](https://bun.sh/discord) +Official discord bot for [bun](https://bun.sh/) [discord server](https://bun.sh/discord) ## Contributing tags To create a new tag, you need to fork this repository and add new file to `data/tags/name.md` file diff --git a/bun.lockb b/bun.lockb index 6aee8d47b1868e937e81e26d7df06774ffc33999..8733e23354592be30488a1b417680b346e369795 100755 GIT binary patch delta 5884 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 I|8?yD0Q=mW8~^|S diff --git a/data/tags/windows.md b/data/tags/windows.md index 6648563..af54ea2 100644 --- a/data/tags/windows.md +++ b/data/tags/windows.md @@ -5,5 +5,12 @@ keywords: - "windows support" --- -Bun does not currently have support for Windows, so you must use WSL (Windows Subsystem for Linux). -To install WSL, check [microsoft documentation]() +Bun provides a *limited*, experimental native builds for [Windows](). +To install, paste this into your terminal: +```ps +# WARNING: No stability is guaranteed on the experimental Windows builds +powershell -c "iwr bun.sh/install.ps1|iex" +``` + +However, it's still recommended to use [WSL]() for the best experience. +For more information, you can look into <#1149339379446325248> \ No newline at end of file diff --git a/globals.d.ts b/globals.d.ts new file mode 100644 index 0000000..857af7f --- /dev/null +++ b/globals.d.ts @@ -0,0 +1,7 @@ +declare module "bun" { + interface Env { + DISCORD_BOT_TOKEN: string; + BUN_ONLY_CHANNEL_ID: string; + MESSAGE_PREFIX: string; + } +} diff --git a/package.json b/package.json index 852d268..d12d0e7 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,22 @@ { "version": "0.0.0", + "private": true, "name": "bun-discord-bot", + "type": "module", "scripts": { - "start": "bun src/index.ts", - "validate:tags": "cd scripts/validate_tags && bun install && bun start" + "start": "NODE_ENV=production bun src/index.ts", + "validate:tags": "bun scripts/validate_tags/index.ts" }, "devDependencies": { - "bun-types": "^0.7.3" + "bun-types": "^1.0.14" }, "dependencies": { + "@lilybird/handlers": "^0.2.1", + "@lilybird/jsx": "^0.2.0", "@paperdave/logger": "^3.0.1", "algoliasearch": "^4.19.1", - "discord.js": "^14.13.0", - "glob": "^10.3.3", "gray-matter": "^4.0.3", + "lilybird": "^0.4.0", "zlib-sync": "^0.1.8" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 9e5b53e..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,672 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@paperdave/logger': - specifier: ^3.0.1 - version: 3.0.1 - algoliasearch: - specifier: ^4.19.1 - version: 4.19.1 - discord.js: - specifier: ^14.13.0 - version: 14.13.0 - glob: - specifier: ^10.3.3 - version: 10.3.3 - gray-matter: - specifier: ^4.0.3 - version: 4.0.3 - zlib-sync: - specifier: ^0.1.8 - version: 0.1.8 - -devDependencies: - bun-types: - specifier: ^0.7.3 - version: 0.7.3 - -packages: - - /@algolia/cache-browser-local-storage@4.19.1: - resolution: {integrity: sha512-FYAZWcGsFTTaSAwj9Std8UML3Bu8dyWDncM7Ls8g+58UOe4XYdlgzXWbrIgjaguP63pCCbMoExKr61B+ztK3tw==} - dependencies: - '@algolia/cache-common': 4.19.1 - dev: false - - /@algolia/cache-common@4.19.1: - resolution: {integrity: sha512-XGghi3l0qA38HiqdoUY+wvGyBsGvKZ6U3vTiMBT4hArhP3fOGLXpIINgMiiGjTe4FVlTa5a/7Zf2bwlIHfRqqg==} - dev: false - - /@algolia/cache-in-memory@4.19.1: - resolution: {integrity: sha512-+PDWL+XALGvIginigzu8oU6eWw+o76Z8zHbBovWYcrtWOEtinbl7a7UTt3x3lthv+wNuFr/YD1Gf+B+A9V8n5w==} - dependencies: - '@algolia/cache-common': 4.19.1 - dev: false - - /@algolia/client-account@4.19.1: - resolution: {integrity: sha512-Oy0ritA2k7AMxQ2JwNpfaEcgXEDgeyKu0V7E7xt/ZJRdXfEpZcwp9TOg4TJHC7Ia62gIeT2Y/ynzsxccPw92GA==} - dependencies: - '@algolia/client-common': 4.19.1 - '@algolia/client-search': 4.19.1 - '@algolia/transporter': 4.19.1 - dev: false - - /@algolia/client-analytics@4.19.1: - resolution: {integrity: sha512-5QCq2zmgdZLIQhHqwl55ZvKVpLM3DNWjFI4T+bHr3rGu23ew2bLO4YtyxaZeChmDb85jUdPDouDlCumGfk6wOg==} - dependencies: - '@algolia/client-common': 4.19.1 - '@algolia/client-search': 4.19.1 - '@algolia/requester-common': 4.19.1 - '@algolia/transporter': 4.19.1 - dev: false - - /@algolia/client-common@4.19.1: - resolution: {integrity: sha512-3kAIVqTcPrjfS389KQvKzliC559x+BDRxtWamVJt8IVp7LGnjq+aVAXg4Xogkur1MUrScTZ59/AaUd5EdpyXgA==} - dependencies: - '@algolia/requester-common': 4.19.1 - '@algolia/transporter': 4.19.1 - dev: false - - /@algolia/client-personalization@4.19.1: - resolution: {integrity: sha512-8CWz4/H5FA+krm9HMw2HUQenizC/DxUtsI5oYC0Jxxyce1vsr8cb1aEiSJArQT6IzMynrERif1RVWLac1m36xw==} - dependencies: - '@algolia/client-common': 4.19.1 - '@algolia/requester-common': 4.19.1 - '@algolia/transporter': 4.19.1 - dev: false - - /@algolia/client-search@4.19.1: - resolution: {integrity: sha512-mBecfMFS4N+yK/p0ZbK53vrZbL6OtWMk8YmnOv1i0LXx4pelY8TFhqKoTit3NPVPwoSNN0vdSN9dTu1xr1XOVw==} - dependencies: - '@algolia/client-common': 4.19.1 - '@algolia/requester-common': 4.19.1 - '@algolia/transporter': 4.19.1 - dev: false - - /@algolia/logger-common@4.19.1: - resolution: {integrity: sha512-i6pLPZW/+/YXKis8gpmSiNk1lOmYCmRI6+x6d2Qk1OdfvX051nRVdalRbEcVTpSQX6FQAoyeaui0cUfLYW5Elw==} - dev: false - - /@algolia/logger-console@4.19.1: - resolution: {integrity: sha512-jj72k9GKb9W0c7TyC3cuZtTr0CngLBLmc8trzZlXdfvQiigpUdvTi1KoWIb2ZMcRBG7Tl8hSb81zEY3zI2RlXg==} - dependencies: - '@algolia/logger-common': 4.19.1 - dev: false - - /@algolia/requester-browser-xhr@4.19.1: - resolution: {integrity: sha512-09K/+t7lptsweRTueHnSnmPqIxbHMowejAkn9XIcJMLdseS3zl8ObnS5GWea86mu3vy4+8H+ZBKkUN82Zsq/zg==} - dependencies: - '@algolia/requester-common': 4.19.1 - dev: false - - /@algolia/requester-common@4.19.1: - resolution: {integrity: sha512-BisRkcWVxrDzF1YPhAckmi2CFYK+jdMT60q10d7z3PX+w6fPPukxHRnZwooiTUrzFe50UBmLItGizWHP5bDzVQ==} - dev: false - - /@algolia/requester-node-http@4.19.1: - resolution: {integrity: sha512-6DK52DHviBHTG2BK/Vv2GIlEw7i+vxm7ypZW0Z7vybGCNDeWzADx+/TmxjkES2h15+FZOqVf/Ja677gePsVItA==} - dependencies: - '@algolia/requester-common': 4.19.1 - dev: false - - /@algolia/transporter@4.19.1: - resolution: {integrity: sha512-nkpvPWbpuzxo1flEYqNIbGz7xhfhGOKGAZS7tzC+TELgEmi7z99qRyTfNSUlW7LZmB3ACdnqAo+9A9KFBENviQ==} - dependencies: - '@algolia/cache-common': 4.19.1 - '@algolia/logger-common': 4.19.1 - '@algolia/requester-common': 4.19.1 - dev: false - - /@discordjs/builders@1.6.5: - resolution: {integrity: sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==} - engines: {node: '>=16.11.0'} - dependencies: - '@discordjs/formatters': 0.3.2 - '@discordjs/util': 1.0.1 - '@sapphire/shapeshift': 3.9.2 - discord-api-types: 0.37.50 - fast-deep-equal: 3.1.3 - ts-mixer: 6.0.3 - tslib: 2.6.2 - dev: false - - /@discordjs/collection@1.5.3: - resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==} - engines: {node: '>=16.11.0'} - dev: false - - /@discordjs/formatters@0.3.2: - resolution: {integrity: sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==} - engines: {node: '>=16.11.0'} - dependencies: - discord-api-types: 0.37.50 - dev: false - - /@discordjs/rest@2.0.1: - resolution: {integrity: sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==} - engines: {node: '>=16.11.0'} - dependencies: - '@discordjs/collection': 1.5.3 - '@discordjs/util': 1.0.1 - '@sapphire/async-queue': 1.5.0 - '@sapphire/snowflake': 3.5.1 - '@vladfrangu/async_event_emitter': 2.2.2 - discord-api-types: 0.37.50 - magic-bytes.js: 1.0.15 - tslib: 2.6.2 - undici: 5.22.1 - dev: false - - /@discordjs/util@1.0.1: - resolution: {integrity: sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==} - engines: {node: '>=16.11.0'} - dev: false - - /@discordjs/ws@1.0.1: - resolution: {integrity: sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==} - engines: {node: '>=16.11.0'} - dependencies: - '@discordjs/collection': 1.5.3 - '@discordjs/rest': 2.0.1 - '@discordjs/util': 1.0.1 - '@sapphire/async-queue': 1.5.0 - '@types/ws': 8.5.5 - '@vladfrangu/async_event_emitter': 2.2.2 - discord-api-types: 0.37.50 - tslib: 2.6.2 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: false - - /@isaacs/cliui@8.0.2: - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - dependencies: - string-width: 5.1.2 - string-width-cjs: /string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: /strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: false - - /@paperdave/logger@3.0.1: - resolution: {integrity: sha512-sLl/oM6U5KUU1bLzjDzshsJnrlGEPT7J0BFMqYr6HzX0RJbsKgRf4XRJgXsusT+rFDfOSHrJAootuImlt8q/9A==} - engines: {node: '>=16'} - dependencies: - '@paperdave/utils': 1.8.0 - ansi-escapes: 6.2.0 - chalk: 5.3.0 - strip-ansi: 7.1.0 - dev: false - - /@paperdave/utils@1.8.0: - resolution: {integrity: sha512-/1ckfqC0migr4GjtFhpqNUIgPibign4kRMmEzGsZ6hilvQ0cbL8Hu96ZzvM/matlOK4tOeEj9aH4f1Bip8AH1A==} - engines: {node: '>=16'} - dependencies: - utility-types: 3.10.0 - yaml: 2.3.1 - dev: false - - /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - requiresBuild: true - dev: false - optional: true - - /@sapphire/async-queue@1.5.0: - resolution: {integrity: sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - dev: false - - /@sapphire/shapeshift@3.9.2: - resolution: {integrity: sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - dependencies: - fast-deep-equal: 3.1.3 - lodash: 4.17.21 - dev: false - - /@sapphire/snowflake@3.5.1: - resolution: {integrity: sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - dev: false - - /@types/node@20.5.3: - resolution: {integrity: sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA==} - requiresBuild: true - dev: false - - /@types/ws@8.5.5: - resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} - requiresBuild: true - dependencies: - '@types/node': 20.5.3 - dev: false - - /@vladfrangu/async_event_emitter@2.2.2: - resolution: {integrity: sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - dev: false - - /algoliasearch@4.19.1: - resolution: {integrity: sha512-IJF5b93b2MgAzcE/tuzW0yOPnuUyRgGAtaPv5UUywXM8kzqfdwZTO4sPJBzoGz1eOy6H9uEchsJsBFTELZSu+g==} - dependencies: - '@algolia/cache-browser-local-storage': 4.19.1 - '@algolia/cache-common': 4.19.1 - '@algolia/cache-in-memory': 4.19.1 - '@algolia/client-account': 4.19.1 - '@algolia/client-analytics': 4.19.1 - '@algolia/client-common': 4.19.1 - '@algolia/client-personalization': 4.19.1 - '@algolia/client-search': 4.19.1 - '@algolia/logger-common': 4.19.1 - '@algolia/logger-console': 4.19.1 - '@algolia/requester-browser-xhr': 4.19.1 - '@algolia/requester-common': 4.19.1 - '@algolia/requester-node-http': 4.19.1 - '@algolia/transporter': 4.19.1 - dev: false - - /ansi-escapes@6.2.0: - resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} - engines: {node: '>=14.16'} - dependencies: - type-fest: 3.13.1 - dev: false - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: false - - /ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} - engines: {node: '>=12'} - dev: false - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: false - - /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - dev: false - - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: false - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: false - - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: false - - /bun-types@0.7.3: - resolution: {integrity: sha512-kssLD5mDLoawmLZFgQRRq0Wy+dca/os6TZ0MHWyFVoVAEwSrpAxmNCZ1K1GUelfhlDaL2FikRxeF9GkATdzXZg==} - dev: true - - /busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - dependencies: - streamsearch: 1.1.0 - dev: false - - /chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: false - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: false - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: false - - /discord-api-types@0.37.50: - resolution: {integrity: sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==} - dev: false - - /discord.js@14.13.0: - resolution: {integrity: sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==} - engines: {node: '>=16.11.0'} - dependencies: - '@discordjs/builders': 1.6.5 - '@discordjs/collection': 1.5.3 - '@discordjs/formatters': 0.3.2 - '@discordjs/rest': 2.0.1 - '@discordjs/util': 1.0.1 - '@discordjs/ws': 1.0.1 - '@sapphire/snowflake': 3.5.1 - '@types/ws': 8.5.5 - discord-api-types: 0.37.50 - fast-deep-equal: 3.1.3 - lodash.snakecase: 4.1.1 - tslib: 2.6.2 - undici: 5.22.1 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: false - - /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: false - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: false - - /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: false - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: false - - /extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - dependencies: - is-extendable: 0.1.1 - dev: false - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: false - - /foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} - engines: {node: '>=14'} - dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.1.0 - dev: false - - /glob@10.3.3: - resolution: {integrity: sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.0 - minimatch: 9.0.3 - minipass: 7.0.3 - path-scurry: 1.10.1 - dev: false - - /gray-matter@4.0.3: - resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} - engines: {node: '>=6.0'} - dependencies: - js-yaml: 3.14.1 - kind-of: 6.0.3 - section-matter: 1.0.0 - strip-bom-string: 1.0.0 - dev: false - - /is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - dev: false - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: false - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: false - - /jackspeak@2.3.0: - resolution: {integrity: sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==} - engines: {node: '>=14'} - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - dev: false - - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: false - - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - dev: false - - /lodash.snakecase@4.1.1: - resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - dev: false - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false - - /lru-cache@10.0.1: - resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} - engines: {node: 14 || >=16.14} - dev: false - - /magic-bytes.js@1.0.15: - resolution: {integrity: sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==} - dev: false - - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: false - - /minipass@7.0.3: - resolution: {integrity: sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==} - engines: {node: '>=16 || 14 >=14.17'} - dev: false - - /nan@2.17.0: - resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} - dev: false - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: false - - /path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - lru-cache: 10.0.1 - minipass: 7.0.3 - dev: false - - /section-matter@1.0.0: - resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} - engines: {node: '>=4'} - dependencies: - extend-shallow: 2.0.1 - kind-of: 6.0.3 - dev: false - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: false - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: false - - /signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - dev: false - - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: false - - /streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - dev: false - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: false - - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - dev: false - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: false - - /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - dependencies: - ansi-regex: 6.0.1 - dev: false - - /strip-bom-string@1.0.0: - resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} - engines: {node: '>=0.10.0'} - dev: false - - /ts-mixer@6.0.3: - resolution: {integrity: sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==} - dev: false - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: false - - /type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - dev: false - - /undici@5.22.1: - resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==} - engines: {node: '>=14.0'} - dependencies: - busboy: 1.6.0 - dev: false - - /utility-types@3.10.0: - resolution: {integrity: sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==} - engines: {node: '>= 4'} - dev: false - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: false - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: false - - /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - dev: false - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /yaml@2.3.1: - resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} - engines: {node: '>= 14'} - dev: false - - /zlib-sync@0.1.8: - resolution: {integrity: sha512-Xbu4odT5SbLsa1HFz8X/FvMgUbJYWxJYKB2+bqxJ6UOIIPaVGrqHEB3vyXDltSA6tTqBhSGYLgiVpzPQHYi3lA==} - requiresBuild: true - dependencies: - nan: 2.17.0 - dev: false diff --git a/scripts/validate_tags/bun.lockb b/scripts/validate_tags/bun.lockb deleted file mode 100755 index 69e6960577e783534f8789f3e43697bde446d8ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13622 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 UBL`prlb f.includes("tags"))) process.exit(0); + +const errors: string[] = []; + +const tags: Tag[] = []; +const tagPaths = Array.from( + new Glob( + join(import.meta.dir, "..", "..", "..", "data", "tags", "*.md") + ).scanSync() +); +for (const tagPath of tagPaths) { + const content = readFileSync(tagPath); + const frontMatter = matter(content); + + tags.push({ + name: dirname(tagPath), + question: frontMatter.data.question, + keywords: frontMatter.data.keywords, + answer: frontMatter.content, + category_ids: frontMatter.data.category_ids ?? null, + channel_ids: frontMatter.data.channel_ids ?? null, + }); +} + +try { + await requestGithub(`issues/${pullRequestNumber}/labels`, { + labels: ["tags"], + }); +} catch (e) { + errors.push(e.message); +} + +for (const tag of tags) { + const key = tag.name; + + if (!tag?.keywords || tag.keywords.length === 0) + errors.push(`**[${key}]:** Tag must have keywords`); + if (tag?.keywords?.[0] !== key) + errors.push( + `**[${key}]:** First keyword of tag is not the same as the tag name` + ); + if (!tag.answer) errors.push(`**[${key}]:** Tag must have content`); + + if (tag.answer) { + for (const url of tag.answer.match(urlRegex) || []) { + const firstChar = tag.answer.split(url)[0].slice(-1); + const lastChar = tag.answer.split(url)[1].slice(0, 1); + if (firstChar !== "<" || lastChar !== ">") + errors.push(`**[${key}]:** Link must be wrapped in <>`); + } + } + + if (tag.keywords) { + const keywords = [...new Set(tag.keywords)]; + if (keywords.length !== tag.keywords.length) + errors.push(`**[${key}]:** Keywords must be unique`); + } +} + +if (errors.length === 0) { + await requestGithub(`pulls/${pullRequestNumber}/reviews`, { + commit_id: commitSha, + event: "APPROVE", + }); + + await requestGithub(`pulls/${pullRequestNumber}/requested_reviewers`, { + reviewers: ["xHyroM"], + }); + + await requestGithub( + `issues/${pullRequestNumber}/labels/waiting`, + {}, + "DELETE" + ); + + await requestGithub(`issues/${pullRequestNumber}/labels`, { + labels: ["ready"], + }); +} else { + await requestGithub(`pulls/${pullRequestNumber}/reviews`, { + commit_id: commitSha, + body: "### Please fix the following problems:\n" + errors.join("\n"), + event: "REQUEST_CHANGES", + }); + + await requestGithub(`issues/${pullRequestNumber}/labels`, { + labels: ["waiting"], + }); +} + +async function requestGithub( + url: string, + body: any, + method?: "POST" | "DELETE" +) { + await fetch(`https://api.github.com/repos/xHyroM/bun-discord-bot/${url}`, { + method: method || "POST", + headers: { + Accept: "application/vnd.github+json", + Authorization: `token ${githubToken}`, + }, + body: JSON.stringify(body), + }); +} + +export {}; diff --git a/scripts/validate_tags/package.json b/scripts/validate_tags/package.json deleted file mode 100644 index e7cd61a..0000000 --- a/scripts/validate_tags/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "validate_tags", - "scripts": { - "start": "bun src/index.ts" - }, - "dependencies": { - "glob": "^10.3.3" - } -} diff --git a/scripts/validate_tags/src/index.ts b/scripts/validate_tags/src/index.ts deleted file mode 100644 index e72db3e..0000000 --- a/scripts/validate_tags/src/index.ts +++ /dev/null @@ -1,117 +0,0 @@ -import type { Tag } from "../../../src/structs/Tag.ts"; -import { globSync as glob } from "glob"; -import * as matter from "gray-matter"; -import { join, dirname } from "node:path"; -import { readFileSync } from "node:fs"; - -const githubToken = process.env['github-token']; -const commitSha = process.env['commit-sha']; -const pullRequestNumber = process.env['pr-number']; - -const urlRegex = - /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*)/gi; - -// Check if files/tags.toml was changed -const files = await Bun.file('./files.json').json() as string[]; -if (!files.some(f => f.includes("tags"))) process.exit(0); - -const errors = []; - -const tags: Tag[] = []; -const tagPaths = glob(join(__dirname, "..", "..", "..", "data", "tags", "*.md")); -for (const tagPath of tagPaths) { - const content = readFileSync(tagPath); - const frontMatter = matter(content); - - tags.push({ - name: dirname(tagPath), - question: frontMatter.data.question, - keywords: frontMatter.data.keywords, - answer: frontMatter.content, - category_ids: frontMatter.data.category_ids ?? null, - channel_ids: frontMatter.data.channel_ids ?? null, - }); -} - -try { - await requestGithub(`issues/${pullRequestNumber}/labels`, { - labels: ['tags'], - }); -} catch (e) { - errors.push(e.message); -} - -for (const tag of tags) { - const key = tag.name; - - if (!tag?.keywords || tag.keywords.length === 0) - errors.push(`**[${key}]:** Tag must have keywords`); - if (tag?.keywords?.[0] !== key) - errors.push( - `**[${key}]:** First keyword of tag is not the same as the tag name` - ); - if (!tag.answer) errors.push(`**[${key}]:** Tag must have content`); - - if (tag.answer) { - for (const url of tag.answer.match(urlRegex) || []) { - const firstChar = tag.answer.split(url)[0].slice(-1); - const lastChar = tag.answer.split(url)[1].slice(0, 1); - if (firstChar !== '<' || lastChar !== '>') - errors.push(`**[${key}]:** Link must be wrapped in <>`); - } - } - - if (tag.keywords) { - const keywords = [...new Set(tag.keywords)]; - if (keywords.length !== tag.keywords.length) - errors.push(`**[${key}]:** Keywords must be unique`); - } -} - -if (errors.length === 0) { - await requestGithub(`pulls/${pullRequestNumber}/reviews`, { - commit_id: commitSha, - event: 'APPROVE', - }); - - await requestGithub(`pulls/${pullRequestNumber}/requested_reviewers`, { - reviewers: ['xHyroM'], - }); - - await requestGithub( - `issues/${pullRequestNumber}/labels/waiting`, - {}, - 'DELETE' - ); - - await requestGithub(`issues/${pullRequestNumber}/labels`, { - labels: ['ready'], - }); -} else { - await requestGithub(`pulls/${pullRequestNumber}/reviews`, { - commit_id: commitSha, - body: '### Please fix the following problems:\n' + errors.join('\n'), - event: 'REQUEST_CHANGES', - }); - - await requestGithub(`issues/${pullRequestNumber}/labels`, { - labels: ['waiting'], - }); -} - -async function requestGithub( - url: string, - body: any, - method?: 'POST' | 'DELETE' -) { - await fetch(`https://api.github.com/repos/xHyroM/bun-discord-bot/${url}`, { - method: method || 'POST', - headers: { - Accept: 'application/vnd.github+json', - Authorization: `token ${githubToken}`, - }, - body: JSON.stringify(body), - }); -} - -export {}; diff --git a/scripts/validate_tags/tsconfig.json b/scripts/validate_tags/tsconfig.json deleted file mode 100644 index 4082f16..0000000 --- a/scripts/validate_tags/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../tsconfig.json" -} diff --git a/scripts/validate_tags/src/types.d.ts b/scripts/validate_tags/types.d.ts similarity index 100% rename from scripts/validate_tags/src/types.d.ts rename to scripts/validate_tags/types.d.ts diff --git a/src/commands/docs.ts b/src/commands/docs.ts deleted file mode 100644 index c9816b1..0000000 --- a/src/commands/docs.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { SlashCommandStringOption, SlashCommandUserOption } from "discord.js"; -import { defineCommand } from "../loaders/commands.ts"; -import { AutocompleteContext } from "../structs/context/AutocompleteContext.ts"; -import { InteractionCommandContext } from "../structs/context/CommandContext.ts"; -import algoliasearch from "algoliasearch"; - -const algoliaClient = algoliasearch("2527C13E0N", "4efc87205e1fce4a1f267cadcab42cb2"); -const algoliaIndex = algoliaClient.initIndex("bun"); - -defineCommand({ - name: "docs", - description: "Search at docs", - options: [ - { - ...new SlashCommandStringOption() - .setName("query") - .setRequired(true) - .setAutocomplete(true) - .setDescription("Select query") - .toJSON(), - run: async(context: AutocompleteContext) => { - const query = context.options.getString("query"); - const result = await algoliaIndex.search(query, { - hitsPerPage: 25, - }); - - return context.respond( - result.hits.map(hit => { - const name = getHitName(hit); - - return { - name: name.full.length > 100 ? name.full.slice(0, 100) : name.full, - value: name.name.length > 100 ? name.name.slice(0, 100) : name.name, - } - }) - ); - }, - }, - { - ...new SlashCommandUserOption() - .setName("target") - .setRequired(false) - .setDescription("User to mention") - .toJSON() - } - ], - run: async(context: InteractionCommandContext) => { - await context.interaction.deferReply(); - - const query = context.interaction.options.getString("query"); - const target = context.interaction.options.getUser("target"); - - const result = await algoliaIndex.search(query, { - hitsPerPage: 1, - }); - - const hit = result.hits[0]; - // @ts-expect-error exist - const url = hit.url; - const name = getHitName(hit); - // @ts-expect-error can exist - const snippetContent = hit._snippetResult?.content?.value?.replace(/<[^>]+>/g, ""); - // @ts-expect-error can exist - const notice = hit.content?.replace(/\r/g, ""); - - const content = [ - target ? `*Suggestion for <@${target.id}>:*\n` : "", - `[*${name.full}*](<${url}>)`, - snippetContent ? snippetContent : "", - notice ? notice.split("\n").map(s => `> ${s}`).join("\n") : "" - ].join("\n") - - await context.interaction.editReply({ - content, - allowedMentions: { - parse: [ "users" ], - } - }); - } -}) - -function getHitName(hit) { - const type = hit.hierarchy.lvl0 === "Documentation" ? "📖" : "🗺️"; - const hierarchy = Object.values(hit.hierarchy).filter(v => v); - hierarchy.shift(); - - const name = hierarchy.join(" > "); - - return { - full: `${type} ${name}`, - name: name, - emoji: type, - } -} diff --git a/src/commands/docs.tsx b/src/commands/docs.tsx new file mode 100644 index 0000000..cd251a5 --- /dev/null +++ b/src/commands/docs.tsx @@ -0,0 +1,94 @@ +import { ApplicationCommand, StringOption, UserOption } from "@lilybird/jsx"; +import { SlashCommand } from "@lilybird/handlers"; +import algoliasearch from "algoliasearch"; + +// @ts-expect-error It is callable, but algolia for some reason has a namespace with the same name +const algoliaClient = algoliasearch( + "2527C13E0N", + "4efc87205e1fce4a1f267cadcab42cb2" +); +const algoliaIndex = algoliaClient.initIndex("bun"); + +export default { + post: "GLOBAL", + data: ( + + + + + ), + autocomplete: async (interaction) => { + const query = interaction.data.getFocused().value; + const result = await algoliaIndex.search(query, { + hitsPerPage: 25, + }); + + return interaction.respond( + result.hits.map((hit: any) => { + const name = getHitName(hit); + + return { + name: name.full.length > 100 ? name.full.slice(0, 100) : name.full, + value: name.name.length > 100 ? name.name.slice(0, 100) : name.name, + }; + }) + ); + }, + run: async (interaction) => { + await interaction.deferReply(); + + const query = interaction.data.getString("query"); + const target = interaction.data.getUser("target"); + + const result = await algoliaIndex.search(query, { + hitsPerPage: 1, + }); + + const hit = result.hits[0]; + const url = hit.url; + const name = getHitName(hit); + const snippetContent = hit._snippetResult?.content?.value?.replace( + /<[^>]+>/g, + "" + ); + const notice = hit.content?.replace(/\r/g, ""); + + const content = [ + target ? `*Suggestion for <@${target}>:*\n` : "", + `[*${name.full}*](<${url}>)`, + snippetContent ? snippetContent : "", + notice + ? notice + .split("\n") + .map((s: any) => `> ${s}`) + .join("\n") + : "", + ].join("\n"); + + await interaction.editReply({ + content, + // allowedMentions: { + // parse: ["users"], + // } + }); + }, +} satisfies SlashCommand; + +function getHitName(hit: any) { + const type = hit.hierarchy.lvl0 === "Documentation" ? "📖" : "🗺️"; + const hierarchy = Object.values(hit.hierarchy).filter((v) => v); + hierarchy.shift(); + + const name = hierarchy.join(" > "); + + return { + full: `${type} ${name}`, + name: name, + emoji: type, + }; +} diff --git a/src/commands/github.ts b/src/commands/github.ts deleted file mode 100644 index 7f60ef3..0000000 --- a/src/commands/github.ts +++ /dev/null @@ -1,279 +0,0 @@ -import { SlashCommandBooleanOption, SlashCommandStringOption, time } from "discord.js"; -import { defineCommand } from "../loaders/commands.ts"; -import { AutocompleteContext } from "../structs/context/AutocompleteContext.ts"; -import { InteractionCommandContext } from "../structs/context/CommandContext.ts"; -import { safeSlice, silently } from "../util.ts"; - -type State = "open" | "closed_as_completed" | "closed_as_not_planned" | "closed" | "merged" | "draft" | "all"; -type StateEmoji = "🔴" | "🟠" | "🟢" | "⚫️" | "⚪️" | "🟣" | "📝"; -type Type = "issues" | "pull_requests" | "both"; - -interface Item { - html_url: string; - number: number; - title: string; - user: { - html_url: string; - login: string; - } - emoji: { - state: StateEmoji; - type: string; - }; - created_at: Date | null; - closed_at: Date | null; - pull_request?: { - merged_at: Date | null; - } -} - -defineCommand({ - name: "github", - description: "Query an issue, pull request or direct link to issue, pull request", - options: [ - { - ...new SlashCommandStringOption() - .setName("query") - .setDescription("Issue/Pull request number or name") - .setRequired(true) - .setAutocomplete(true) - .setMaxLength(100), - run: async(ctx: AutocompleteContext) => { - const query = ctx.options.getString("query"); - const state: State = ctx.options.getString("state") as State || "all"; - const type: Type = ctx.options.getString("type") as Type || "both"; - - const response = await search(query, state, type, 25); - - await silently(ctx.respond(response.map(r => ({ - name: safeSlice(`${r.emoji.type} ${r.emoji.state} #${r.number} | ${r.title}`, 100), - value: r.number.toString() - })))); - } - }, - { - ...new SlashCommandStringOption() - .setName("state") - .setDescription("Issue or Pull request state") - .setRequired(false) - .addChoices( - { - name: "🔴🟠 Open", - value: "open" - }, - { - name: "🟢 Closed as completed", - value: "closed_as_completed" - }, - { - name: "⚪️ Closed as not planned", - value: "closed_as_not_planned" - }, - { - name: "⚫️ Closed", - value: "closed" - }, - { - name: "🟣 Merged", - value: "merged" - }, - { - name: "📝 Draft", - value: "draft", - }, - { - name: "🌍 All", - value: "all", - } - ) - }, - { - ...new SlashCommandStringOption() - .setName("type") - .setDescription("Issue or Pull Requests") - .setRequired(false) - .addChoices( - { - name: "🐛 Issues", - value: "issues" - }, - { - name: "🔨 Pull Requests", - value: "pull_requests" - }, - { - name: "🌍 Both", - value: "both" - } - ) - }, - { - ...new SlashCommandBooleanOption() - .setName("hide") - .setDescription("Show this message only for you") - .setRequired(false) - } - ], - run: async(ctx: InteractionCommandContext) => { - const hide = ctx.interaction.options.getBoolean("hide") ?? false; - - await ctx.interaction.deferReply({ - ephemeral: hide - }); - - const query = ctx.interaction.options.getString("query"); - const state: State = ctx.interaction.options.getString("state") as State || "all"; - const type: Type = ctx.interaction.options.getString("type") as Type || "both"; - - const result = (await search(query, state, type))[0]; - if (!result) { - ctx.interaction.editReply({ - content: `❌ Couldn't find issue or pull request \`${query}\`` - }); - return; - } - - ctx.interaction.editReply({ - content: [ - `${result.emoji.type} ${result.emoji.state} [#${result.number} in oven-sh/bun](<${result.html_url}>) by [${result.user.login}](<${result.user.html_url}>) ${stateToText(result)} ${stateToTimestamp(result)}`, - result.title - ].join("\n") - }) - } -}); - -function stateToText(item: Item) { - switch (item.emoji.state) { - case "🔴": - case "🟠": - case "📝": { - return "opened"; - } - case "🟢": { - return "closed as completed"; - } - case "⚪️": { - return "closed as not planned"; - } - case "⚫️": { - return "closed"; - } - case "🟣": { - return "merged"; - } - } -} - -function stateToTimestamp(item: Item) { - let timestamp: Date; - - switch (item.emoji.state) { - case "🔴": - case "🟠": - case "📝": { - timestamp = item.created_at; - break; - } - case "🟢": - case "⚪️": - case "⚫️": { - timestamp = item.closed_at; - break; - } - case "🟣": { - timestamp = item.pull_request.merged_at; - break; - } - } - - return ``; -} - -async function search(query: string, state: State, type: Type, length = 1): Promise { - let actualQuery = "repo:oven-sh/bun "; - - switch (state) { - case "open": { - actualQuery += "state:open "; - break; - } - case "closed": { - actualQuery += "state:closed "; - break; - } - case "closed_as_completed": { - actualQuery += "state:closed reason:completed " - break; - } - case "closed_as_not_planned": { - actualQuery += "state:closed reason:\"not planned\" "; - break; - } - case "merged": { - actualQuery += "is:merged "; - break; - } - case "draft": { - actualQuery += "draft:true "; - break; - } - } - - switch (type) { - case "issues": { - actualQuery += "type:issue " - break; - } - case "pull_requests": { - actualQuery += "type:pr " - break; - } - } - - // append user query + remove all tags - actualQuery += query.replace(/\S+:\S+/g, "").trim(); - - const response = await fetch(`https://api.github.com/search/issues?q=${encodeURIComponent(actualQuery)}&per_page=${length}`, { - headers: { - "Authorization": `Bearer ${process.env.GITHUB_TOKEN}`, - "Accept": "application/vnd.github+json" - } - }); - - const body = await response.json(); - const items = body.items; - - return items.map(item => { - let state = ""; - if (item.state === "closed") { - if (item.pull_request) { - state = item.pull_request.merged_at ? "🟣" : "⚫️"; - } else { - state = item.state_reason === "completed" ? "🟢" : "⚪️"; - } - } else { - if (item.pull_request) { - state = item.draft ? "📝" : "🟠"; - } else { - state = "🔴"; - } - } - - const base = { - ...item, - emoji: { - state: state, - type: item.pull_request ? "🔨" : "🐛" - }, - created_at: new Date(item.created_at), - closed_at: item.closed_at ? new Date(item.cloased_at) : null - } - - if (item.pull_request) { - base.pull_request = {}; - base.pull_request.merged_at = item.pull_request.merged_at ? new Date(item.pull_request.merged_at) : null; - } - - return base; - }); -} diff --git a/src/commands/github.tsx b/src/commands/github.tsx new file mode 100644 index 0000000..eaf24e0 --- /dev/null +++ b/src/commands/github.tsx @@ -0,0 +1,275 @@ +import { + ApplicationCommand, + BooleanOption, + CommandOptions, + StringOption, +} from "@lilybird/jsx"; +import { SlashCommand } from "@lilybird/handlers"; +import { safeSlice, silently } from "../util.ts"; + +type State = + | "open" + | "closed_as_completed" + | "closed_as_not_planned" + | "closed" + | "merged" + | "draft" + | "all"; +type StateEmoji = "🔴" | "🟠" | "🟢" | "⚫️" | "⚪️" | "🟣" | "📝"; +type Type = "issues" | "pull_requests" | "both"; + +interface Item { + html_url: string; + number: number; + title: string; + user: { + html_url: string; + login: string; + }; + emoji: { + state: StateEmoji; + type: string; + }; + created_at: Date | null; + closed_at: Date | null; + pull_request?: { + merged_at: Date | null; + }; +} + +export default { + post: "GLOBAL", + data: ( + + + + + + + + + + + + + + + + + + + ), + run: async (interaction) => { + const hide = interaction.data.getBoolean("hide") ?? false; + + await interaction.deferReply(hide); + + const query = interaction.data.getString("query", true); + const state: State = + (interaction.data.getString("state") as State) || "all"; + const type: Type = (interaction.data.getString("type") as Type) || "both"; + + const result = (await search(query, state, type))[0]; + if (!result) { + interaction.editReply({ + content: `❌ Couldn't find issue or pull request \`${query}\``, + }); + return; + } + + interaction.editReply({ + content: [ + `${result.emoji.type} ${result.emoji.state} [#${ + result.number + } in oven-sh/bun](<${result.html_url}>) by [${result.user.login}](<${ + result.user.html_url + }>) ${stateToText(result)} ${stateToTimestamp(result)}`, + result.title, + ].join("\n"), + }); + }, + + autocomplete: async (interaction) => { + const query = interaction.data.getFocused().value; + const state: State = + (interaction.data.getString("state") as State) || "all"; + const type: Type = (interaction.data.getString("type") as Type) || "both"; + + const response = await search(query, state, type, 25); + + await silently( + interaction.respond( + response.map((r) => ({ + name: safeSlice( + `${r.emoji.type} ${r.emoji.state} #${r.number} | ${r.title}`, + 100 + ), + value: r.number.toString(), + })) + ) + ); + }, +} satisfies SlashCommand; + +function stateToText(item: Item) { + switch (item.emoji.state) { + case "🔴": + case "🟠": + case "📝": { + return "opened"; + } + case "🟢": { + return "closed as completed"; + } + case "⚪️": { + return "closed as not planned"; + } + case "⚫️": { + return "closed"; + } + case "🟣": { + return "merged"; + } + } +} + +function stateToTimestamp(item: Item) { + let timestamp: Date; + + switch (item.emoji.state) { + case "🔴": + case "🟠": + case "📝": { + timestamp = item.created_at as Date; + break; + } + case "🟢": + case "⚪️": + case "⚫️": { + timestamp = item.closed_at as Date; + break; + } + case "🟣": { + timestamp = item.pull_request?.merged_at as Date; + break; + } + } + + return ``; +} + +async function search( + query: string, + state: State, + type: Type, + length = 1 +): Promise { + let actualQuery = "repo:oven-sh/bun "; + + switch (state) { + case "open": { + actualQuery += "state:open "; + break; + } + case "closed": { + actualQuery += "state:closed "; + break; + } + case "closed_as_completed": { + actualQuery += "state:closed reason:completed "; + break; + } + case "closed_as_not_planned": { + actualQuery += 'state:closed reason:"not planned" '; + break; + } + case "merged": { + actualQuery += "is:merged "; + break; + } + case "draft": { + actualQuery += "draft:true "; + break; + } + } + + switch (type) { + case "issues": { + actualQuery += "type:issue "; + break; + } + case "pull_requests": { + actualQuery += "type:pr "; + break; + } + } + + // append user query + remove all tags + actualQuery += query.replace(/\S+:\S+/g, "").trim(); + + const response = await fetch( + `https://api.github.com/search/issues?q=${encodeURIComponent( + actualQuery + )}&per_page=${length}`, + { + headers: { + Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, + Accept: "application/vnd.github+json", + }, + } + ); + + const body = await response.json(); + const items = body.items; + + return items.map((item: any) => { + let state = ""; + if (item.state === "closed") { + if (item.pull_request) { + state = item.pull_request.merged_at ? "🟣" : "⚫️"; + } else { + state = item.state_reason === "completed" ? "🟢" : "⚪️"; + } + } else { + if (item.pull_request) { + state = item.draft ? "📝" : "🟠"; + } else { + state = "🔴"; + } + } + + const base = { + ...item, + emoji: { + state: state, + type: item.pull_request ? "🔨" : "🐛", + }, + created_at: new Date(item.created_at), + closed_at: item.closed_at ? new Date(item.cloased_at) : null, + }; + + if (item.pull_request) { + base.pull_request = {}; + base.pull_request.merged_at = item.pull_request.merged_at + ? new Date(item.pull_request.merged_at) + : null; + } + + return base; + }); +} diff --git a/src/commands/index.ts b/src/commands/index.ts deleted file mode 100644 index aa6cad5..0000000 --- a/src/commands/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import "./version.ts"; -import "./docs.ts"; -import "./tag.ts"; -import "./ping.ts"; -import "./github.ts"; - -import { registerCommands } from "../loaders/commands.ts"; -await registerCommands(); diff --git a/src/commands/ping.ts b/src/commands/ping.ts deleted file mode 100644 index 39e4683..0000000 --- a/src/commands/ping.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { defineCommand } from "../loaders/commands.ts"; -import { Bubu } from "../structs/Client.ts"; -import { InteractionCommandContext, MessageCommandContext } from "../structs/context/CommandContext.ts"; - -defineCommand({ - name: "ping", - description: "pong", - run: async(ctx: InteractionCommandContext) => { - const message = await ctx.interaction.deferReply({ - ephemeral: true, - }); - - const restPing = message.createdTimestamp - ctx.interaction.createdTimestamp; - - ctx.interaction.editReply({ - content: `🏓 WebSocket: \`${Bubu.ws.ping}ms\` | Rest: \`${restPing}ms\`` - }); - }, - runMessage: async(ctx: MessageCommandContext) => { - const message = await ctx.reply({ - content: "🏓...", - }); - - const restPing = message.createdTimestamp - ctx.message.createdTimestamp; - - message.edit({ - content: `🏓 WebSocket: \`${Bubu.ws.ping}ms\` | Rest: \`${restPing}ms\`` - }); - } -}) diff --git a/src/commands/ping.tsx b/src/commands/ping.tsx new file mode 100644 index 0000000..922c986 --- /dev/null +++ b/src/commands/ping.tsx @@ -0,0 +1,16 @@ +import { ApplicationCommand } from "@lilybird/jsx"; +import { SlashCommand } from "@lilybird/handlers"; + +export default { + post: "GLOBAL", + data: , + run: async (interaction) => { + await interaction.deferReply(); + + const { ws, rest } = await interaction.client.ping(); + + await interaction.editReply({ + content: `🏓 WebSocket: \`${ws}ms\` | Rest: \`${rest}ms\``, + }); + }, +} satisfies SlashCommand; diff --git a/src/commands/tag.ts b/src/commands/tag.ts deleted file mode 100644 index a9a3ae0..0000000 --- a/src/commands/tag.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { GuildTextBasedChannel, SlashCommandStringOption, SlashCommandUserOption, User } from "discord.js"; -import { defineCommand } from "../loaders/commands.ts"; -import { AutocompleteContext } from "../structs/context/AutocompleteContext.ts"; -import { getTags, searchTag } from "../loaders/tags.ts"; -import { InteractionCommandContext, MessageCommandContext } from "../structs/context/CommandContext.ts"; -import { Bubu } from "../structs/Client.ts"; - -defineCommand({ - name: "tag", - description: "Get tag", - options: [ - { - ...new SlashCommandStringOption() - .setName("query") - .setRequired(true) - .setAutocomplete(true) - .setDescription("Select query") - .toJSON(), - run: async(context: AutocompleteContext) => { - const query = context.options.getString("query"); - if (!query) { - return context.respond(getTags(context.channel, 25)); - } - - const tags = searchTag(context.channel, query, true); - if (tags.length > 0) - return context.respond(tags); - - return context.respond(getTags(context.channel, 25)); - }, - }, - { - ...new SlashCommandUserOption() - .setName("target") - .setRequired(false) - .setDescription("User to mention") - .toJSON() - } - ], - run: (ctx: InteractionCommandContext) => { - const query = ctx.interaction.options.getString("query"); - const target = ctx.interaction.options.getUser("target"); - - const tag = searchTag(ctx.channel, query, false); - if (!tag) { - return ctx.reply({ - content: `\`❌\` Could not find a tag \`${query}\``, - ephemeral: true, - }); - } - - ctx.reply({ - content: [ - target ? `*Suggestion for <@${target.id}>:*\n` : "", - `**${tag.question}**`, - tag.answer - ].join("\n"), - allowedMentions: { - parse: [ "users" ] - } - }); - }, - runMessage: (ctx: MessageCommandContext) => { - if (!ctx.message.inGuild()) return; - - const keyword = ctx.options?.[0] ?? "what-is-bun"; - - const target = ctx.options?.[1]?.match(/([0-9]+)/)?.[0]; - const resolvedTarget = target ? Bubu.users.cache.get(target) : null; - - const tag = searchTag(ctx.channel as GuildTextBasedChannel, keyword, false); - if (!keyword || !tag) { - return ctx.reply({ - content: `\`❌\` Could not find a tag \`${keyword}\``, - }); - } - - ctx.reply({ - content: [ - resolvedTarget ? `*Suggestion for <@${resolvedTarget.id}>:*\n` : "", - `**${tag.question}**`, - tag.answer - ].join("\n"), - allowedMentions: { - parse: [ "users" ] - } - }); - } -}) diff --git a/src/commands/tag.tsx b/src/commands/tag.tsx new file mode 100644 index 0000000..91f76bb --- /dev/null +++ b/src/commands/tag.tsx @@ -0,0 +1,54 @@ +import { ApplicationCommand, StringOption, UserOption } from "@lilybird/jsx"; +import { getTags, searchTag } from "../loaders/tags.ts"; +import { SlashCommand } from "@lilybird/handlers"; + +export default { + post: "GLOBAL", + data: ( + + + + + ), + run: async (interaction) => { + if (!interaction.inGuild()) return; + const query = interaction.data.getString("query", true); + const target = interaction.data.getUser("target"); + + const tag = searchTag(interaction.channel, query, false); + if (!tag) { + return interaction.reply({ + content: `\`❌\` Could not find a tag \`${query}\``, + ephemeral: true, + }); + } + + await interaction.reply({ + content: [ + target ? `*Suggestion for <@${target}>:*\n` : "", + `**${tag.question}**`, + tag.answer, + ].join("\n"), + // allowedMentions: { + // parse: ["users"] + // } + }); + }, + autocomplete: async (interaction) => { + if (!interaction.inGuild()) return; + const query = interaction.data.getFocused().value; + if (!query) { + return await interaction.respond(getTags(interaction.channel, 25)); + } + + const tags = searchTag(interaction.channel, query, true); + if (tags.length > 0) return await interaction.respond(tags); + + return await interaction.respond(getTags(interaction.channel, 25)); + }, +} satisfies SlashCommand; diff --git a/src/commands/version.ts b/src/commands/version.ts deleted file mode 100644 index f0f3723..0000000 --- a/src/commands/version.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineCommand } from "../loaders/commands.ts"; -import { COMMIT_HASH, PRODUCTION } from "../constants.ts"; -import { InteractionCommandContext } from "../structs/context/CommandContext.ts"; - -export default defineCommand({ - name: "version", - description: "Show version", - options: [], - run: (context: InteractionCommandContext) => { - context.interaction.reply({ - content: [ - `[git-bun-discord-bot-${COMMIT_HASH}]() ${!PRODUCTION ? "(dev)" : ""}`, - `[v${Bun.version} (${Bun.revision})]()` - ].join("\n"), - ephemeral: true, - }); - } -}); diff --git a/src/commands/version.tsx b/src/commands/version.tsx new file mode 100644 index 0000000..115c902 --- /dev/null +++ b/src/commands/version.tsx @@ -0,0 +1,19 @@ +import { COMMIT_HASH, PRODUCTION } from "../constants.ts"; +import { ApplicationCommand } from "@lilybird/jsx"; +import { SlashCommand } from "@lilybird/handlers"; + +export default { + post: "GLOBAL", + data: , + run: (interaction) => { + interaction.reply({ + content: [ + `[git-bun-discord-bot-${COMMIT_HASH}]() ${ + !PRODUCTION ? "(dev)" : "" + }`, + `[v${Bun.version} (${Bun.revision})]()`, + ].join("\n"), + ephemeral: true, + }); + }, +} satisfies SlashCommand; diff --git a/src/constants.ts b/src/constants.ts index 05e293c..fdcd80a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,11 +1,7 @@ import { spawnSync } from "bun"; export const COMMIT_HASH = spawnSync({ - cmd: [ "git", "log", "--pretty=format:%h", "-n", "1" ] + cmd: ["git", "log", "--pretty=format:%h", "-n", "1"], }).stdout.toString(); export const PRODUCTION = process.env.NODE_ENV === "production"; - -export const MESSAGE_PREFIX = PRODUCTION ? "b" : "<>"; - -export const BUN_ONLY_CHANNEL_ID = "1161157663867027476" diff --git a/src/index.ts b/src/index.ts index e6c0924..a6468d2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,28 @@ import "./loaders/tags.ts"; -import "./commands"; -import "./listeners"; -import { Bubu } from "./structs/Client.ts"; +import { createHandler } from "@lilybird/handlers"; +import { createClient, Intents } from "lilybird"; // Make sure bubu will not crash process.on("unhandledRejection", console.error); process.on("uncaughtException", console.error); -Bubu.login(process.env.DISCORD_BOT_TOKEN).catch(console.error); +const listeners = await createHandler({ + prefix: process.env.MESSAGE_PREFIX, + dirs: { + messageCommands: `${import.meta.dir}/message-commands`, + slashCommands: `${import.meta.dir}/commands`, + listeners: `${import.meta.dir}/listeners`, + }, +}); + +await createClient({ + token: process.env.DISCORD_BOT_TOKEN, + intents: [ + Intents.GUILDS, + Intents.GUILD_MESSAGES, + Intents.MESSAGE_CONTENT, + Intents.GUILD_MEMBERS, + ], + ...listeners, +}); diff --git a/src/listeners/index.ts b/src/listeners/index.ts deleted file mode 100644 index f96423d..0000000 --- a/src/listeners/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import "./ready.ts"; -import "./interaction_create.ts"; -import "./message_create.ts"; -import "./message_update.ts"; -import "./nickname_moderation.ts"; diff --git a/src/listeners/interaction_create.ts b/src/listeners/interaction_create.ts deleted file mode 100644 index 54ba7a1..0000000 --- a/src/listeners/interaction_create.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Events, Interaction, ChatInputCommandInteraction, AutocompleteInteraction, APIApplicationCommandSubcommandOption, APIApplicationCommandSubcommandGroupOption } from "discord.js"; -import { COMMANDS } from "../loaders/commands.ts"; -import { defineListener } from "../loaders/listeners.ts"; -import { InteractionCommandContext } from "../structs/context/CommandContext.ts"; -import { AutocompleteContext } from "../structs/context/AutocompleteContext.ts"; -import { Option, StringOption } from "../structs/Command.ts"; -import { error } from "@paperdave/logger"; - -defineListener({ - event: Events.InteractionCreate, - run: async(interaction: Interaction) => { - if (interaction.isChatInputCommand()) return await handleCommand(interaction); - if (interaction.isAutocomplete()) return await handleAutocomplete(interaction); - - return; - } -}) - -async function handleCommand(interaction: ChatInputCommandInteraction) { - const command = COMMANDS.get(interaction.commandName); - - if (!command || !command.run) { - interaction.reply({ - content: "Hmm.. Invalid command :P", - ephemeral: true, - }) - return; - } - - const context = new InteractionCommandContext(command, interaction); - await Promise.resolve(command.run(context)) - .catch(async err => { - error(err); - - context.reply({ - content: `Something went wrong... ${err.message} (${err.code})` - }); - }); -} - -async function handleAutocomplete(interaction: AutocompleteInteraction) { - const command = COMMANDS.get(interaction.commandName); - if (!command) return; - - let options = command.options; - - if (interaction.options.getSubcommandGroup(false)) - options = (options.find(o => o.name === interaction.options.getSubcommandGroup()) as APIApplicationCommandSubcommandGroupOption)?.options as Option[]; - - if (interaction.options.getSubcommand(false)) - options = (options.find(o => o.name === interaction.options.getSubcommand()) as APIApplicationCommandSubcommandOption)?.options as Option[]; - - const focused = interaction.options.getFocused(true); - const option = options.find(o => o.name === focused.name) as StringOption; - if (!option) return; - - const context = new AutocompleteContext(option, command, interaction); - await option.run(context); -} diff --git a/src/listeners/member_add.ts b/src/listeners/member_add.ts new file mode 100644 index 0000000..22a3cfe --- /dev/null +++ b/src/listeners/member_add.ts @@ -0,0 +1,9 @@ +import { moderateNick } from "../util.ts"; +import { Event } from "@lilybird/handlers"; + +export default { + event: "guildMemberAdd", + run: (member) => { + moderateNick(member); + }, +} satisfies Event<"guildMemberAdd">; diff --git a/src/listeners/member_update.ts b/src/listeners/member_update.ts new file mode 100644 index 0000000..e403953 --- /dev/null +++ b/src/listeners/member_update.ts @@ -0,0 +1,9 @@ +import { moderateNick } from "../util.ts"; +import { Event } from "@lilybird/handlers"; + +export default { + event: "guildMemberUpdate", + run: (member) => { + moderateNick(member); + }, +} satisfies Event<"guildMemberUpdate">; diff --git a/src/listeners/message_create.ts b/src/listeners/message_create.ts deleted file mode 100644 index 8b4ca09..0000000 --- a/src/listeners/message_create.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Events, Message } from "discord.js"; -import { defineListener } from "../loaders/listeners.ts"; -import { MESSAGE_PREFIX, BUN_ONLY_CHANNEL_ID } from "../constants.ts"; -import { COMMANDS } from "../loaders/commands.ts"; -import { MessageCommandContext } from "../structs/context/CommandContext.ts"; -import { extname, basename } from "node:path"; -import { safeSlice } from "../util.ts"; - -const GITHUB_LINE_URL_REGEX = /(?:https?:\/\/)?(?:www\.)?(?:github)\.com\/(?[a-zA-Z0-9-_]+\/[A-Za-z0-9_.-]+)\/blob\/(?.+?)#L(?\d+)[-~]?L?(?\d*)/i; - -defineListener({ - event: Events.MessageCreate, - run: async(message: Message) => { - if (handleBunOnlyChannel(message)) return; - if (message.system || message.author.bot) return; - - if (!message.content.toLowerCase().startsWith(MESSAGE_PREFIX)) return handleOthers(message); - - const [commandName, ...args] = message.content - .slice(MESSAGE_PREFIX.length) - .trim() - .split(/ +/g); - - if (commandName.length === 0) return; - - const command = COMMANDS.get(commandName); - if (!command || !command.runMessage) return; - - const context = new MessageCommandContext(command, message, args); - - await Promise.resolve(command.runMessage(context)) - .catch(async error => { - context.reply({ - content: `Something went wrong... ${error.message} (${error.code})` - }); - }); - } -}); - -function handleOthers(message: Message) { - handleGithubLink(message); -} - -function handleBunOnlyChannel(message: Message) { - if (message.channel.id !== BUN_ONLY_CHANNEL_ID) return false; - - if (message.content !== "bun") { - message.delete(); - return true; - } - - message.react("🐰"); - return true; -} - -async function handleGithubLink(message: Message) { - const match = GITHUB_LINE_URL_REGEX.exec(message.content); - const groups = match?.groups; - if (!groups) return; - - const repo = groups.repo; - const path = groups.path; - let extension = extname(path).slice(1); - const firstLineNumber = parseInt(groups.first_line_number) - 1; - const secondLineNumber = parseInt(groups.second_line_number) || firstLineNumber + 1; - - const contentUrl = `https://raw.githubusercontent.com/${repo}/${path}`; - const response = await fetch(contentUrl); - const content = await response.text(); - const lines = content.split("\n"); - - // limit, max 25 lines - possible flood - if (secondLineNumber - firstLineNumber > 25 && lines.length > secondLineNumber) { - message.react("❌"); - return; - } - - let text = ""; - - for (let i = 0; i < lines.length; i++) { - if (i < firstLineNumber || i >= secondLineNumber) continue; - - const line = lines[i]; - text += `${line}\n`; - } - - // delete the last \n - text = text.slice(0, -1); - - if (extension === "zig") extension = "rs"; - - message.reply({ - content: `***${basename(path)}*** — *(L${firstLineNumber + 1}${secondLineNumber ? `-L${secondLineNumber}` : ""})*\n\`\`\`${extension}\n${safeSlice(text, 2000 - 6 - extension.length)}\n\`\`\``, - components: [ - new ActionRowBuilder() - .setComponents( - new ButtonBuilder() - .setLabel(repo) - .setStyle(ButtonStyle.Link) - .setURL(`https://github.com/${repo}/blob/${path}#L${firstLineNumber + 1}${secondLineNumber ? `-L${secondLineNumber}` : ""}`) - ) - .toJSON() - ] - }) -} diff --git a/src/listeners/message_create.tsx b/src/listeners/message_create.tsx new file mode 100644 index 0000000..c4350eb --- /dev/null +++ b/src/listeners/message_create.tsx @@ -0,0 +1,96 @@ +import { Message, ButtonStyle } from "lilybird"; +import { ActionRow, Button } from "@lilybird/jsx"; +import { extname, basename } from "node:path"; +import { Event } from "@lilybird/handlers"; +import { safeSlice } from "../util.ts"; + +const GITHUB_LINE_URL_REGEX = + /(?:https?:\/\/)?(?:www\.)?(?:github)\.com\/(?[a-zA-Z0-9-_]+\/[A-Za-z0-9_.-]+)\/blob\/(?.+?)#L(?\d+)[-~]?L?(?\d*)/i; + +export default { + event: "messageCreate", + run: async (message) => { + if (handleBunOnlyChannel(message)) return; + if (!message.content?.toLowerCase().startsWith(process.env.MESSAGE_PREFIX)) + return handleOthers(message); + }, +} satisfies Event<"messageCreate">; + +function handleOthers(message: Message): void { + handleGithubLink(message); +} + +function handleBunOnlyChannel(message: Message): boolean { + if (message.channelId !== process.env.BUN_ONLY_CHANNEL_ID) return false; + + if (message.content !== "bun") { + message.delete(); + return true; + } + + message.react("🐰"); + return true; +} + +async function handleGithubLink(message: Message): Promise { + if (!message.content) return; + + const match = GITHUB_LINE_URL_REGEX.exec(message.content); + const groups = match?.groups; + if (!groups) return; + + const repo = groups.repo; + const path = groups.path; + let extension = extname(path).slice(1); + const firstLineNumber = parseInt(groups.first_line_number) - 1; + const secondLineNumber = + parseInt(groups.second_line_number) || firstLineNumber + 1; + + const contentUrl = `https://raw.githubusercontent.com/${repo}/${path}`; + const response = await fetch(contentUrl); + const content = await response.text(); + const lines = content.split("\n"); + + // limit, max 25 lines - possible flood + if ( + secondLineNumber - firstLineNumber > 25 && + lines.length > secondLineNumber + ) { + message.react("❌"); + return; + } + + let text = ""; + + for (let i = 0; i < lines.length; i++) { + if (i < firstLineNumber || i >= secondLineNumber) continue; + + const line = lines[i]; + text += `${line}\n`; + } + + // delete the last \n + text = text.slice(0, -1); + + if (extension === "zig") extension = "rs"; + + message.reply({ + content: `***${basename(path)}*** — *(L${firstLineNumber + 1}${ + secondLineNumber ? `-L${secondLineNumber}` : "" + })*\n\`\`\`${extension}\n${safeSlice( + text, + 2000 - 6 - extension.length + )}\n\`\`\``, + components: [ + +