mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-23 12:00:09 +00:00
Compare commits
224 Commits
@discordjs
...
v13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e06035515 | ||
|
|
f475336b3e | ||
|
|
07caef4cd2 | ||
|
|
efc1536121 | ||
|
|
3d5d95775b | ||
|
|
5dd49339ea | ||
|
|
c08230edc0 | ||
|
|
67dd30a28a | ||
|
|
2ac8be09a1 | ||
|
|
a222e537c1 | ||
|
|
d0fd79c14a | ||
|
|
65bbed8a0f | ||
|
|
142db0ed8c | ||
|
|
f217335a9d | ||
|
|
610bdaa0f1 | ||
|
|
56b481b3e0 | ||
|
|
5f6a82d349 | ||
|
|
759c0b0d46 | ||
|
|
90ca02880a | ||
|
|
cb11c56a0b | ||
|
|
630b9d51ef | ||
|
|
f9e9843a92 | ||
|
|
85338ef073 | ||
|
|
4c072048be | ||
|
|
24ac27df4d | ||
|
|
5057f04304 | ||
|
|
c5a42ed5ec | ||
|
|
ad57e88744 | ||
|
|
53d347734f | ||
|
|
21dfac90ac | ||
|
|
d867936fce | ||
|
|
3386bab2c0 | ||
|
|
420f379933 | ||
|
|
4f26ba7c2a | ||
|
|
71161518ca | ||
|
|
28a5c7b125 | ||
|
|
7cf9224c46 | ||
|
|
add14acc20 | ||
|
|
5acecf031a | ||
|
|
a8d5325def | ||
|
|
09ca243c2f | ||
|
|
8f12054c06 | ||
|
|
f79a9b5450 | ||
|
|
48f7193ef1 | ||
|
|
1da4596820 | ||
|
|
3197ad7d1f | ||
|
|
6e11b846bb | ||
|
|
491f268b90 | ||
|
|
a51ddb2b06 | ||
|
|
51c3bf1f54 | ||
|
|
b9b037b886 | ||
|
|
af6a0e5d51 | ||
|
|
e15b70f79a | ||
|
|
df68520319 | ||
|
|
4bc25c40f5 | ||
|
|
120270e8dc | ||
|
|
9f7d1f3be5 | ||
|
|
224f21c9c0 | ||
|
|
7f1735d50a | ||
|
|
fd494a385e | ||
|
|
b586df884b | ||
|
|
0188e36283 | ||
|
|
84d34dc258 | ||
|
|
7737bbe2fe | ||
|
|
61fa6f45b4 | ||
|
|
0afa405f5a | ||
|
|
eed293f893 | ||
|
|
86329ad66f | ||
|
|
69d71e967e | ||
|
|
a7dc40f1a8 | ||
|
|
32cdaff7eb | ||
|
|
123d0f1aca | ||
|
|
d69529e3fe | ||
|
|
c2968b58f9 | ||
|
|
428798374f | ||
|
|
cf3c7a7c54 | ||
|
|
a941cb6ec5 | ||
|
|
6854df4218 | ||
|
|
35f6dadebf | ||
|
|
1779e1ba7e | ||
|
|
11d010f177 | ||
|
|
b01c81dd72 | ||
|
|
f0d42644df | ||
|
|
64575195b5 | ||
|
|
5115de9862 | ||
|
|
546ac43911 | ||
|
|
56e67185fc | ||
|
|
649058055a | ||
|
|
4ec3355961 | ||
|
|
ca662b4de8 | ||
|
|
98846cf863 | ||
|
|
0e0851aa18 | ||
|
|
eecc50bfda | ||
|
|
caf6f66073 | ||
|
|
c312da795e | ||
|
|
312923d370 | ||
|
|
8a6588a132 | ||
|
|
ea117bfb7e | ||
|
|
8d6a55d2c7 | ||
|
|
5ef30a0173 | ||
|
|
8f94a9ca2f | ||
|
|
fcd52d7fc6 | ||
|
|
f4e81330bf | ||
|
|
e6ee7d8374 | ||
|
|
56177998c5 | ||
|
|
ca68fc3f6b | ||
|
|
a507ed9590 | ||
|
|
f0c0166814 | ||
|
|
10b12ccea6 | ||
|
|
526ea74e66 | ||
|
|
b6f48ec84a | ||
|
|
11d69491e0 | ||
|
|
30e89a401d | ||
|
|
03c59e3a83 | ||
|
|
9ce7e5edcf | ||
|
|
2a46d9f58e | ||
|
|
78e494b06e | ||
|
|
ae43bca8b0 | ||
|
|
7321507559 | ||
|
|
d0a4199760 | ||
|
|
96125079a2 | ||
|
|
7b41fb6b5a | ||
|
|
4f7c1e35c3 | ||
|
|
622c77ba7a | ||
|
|
be35db2410 | ||
|
|
e95caa7e45 | ||
|
|
5c1e558570 | ||
|
|
4cf05559a2 | ||
|
|
d9432aba71 | ||
|
|
f2a6f9fc1d | ||
|
|
da3d4873a7 | ||
|
|
64928abb9e | ||
|
|
7b7cc1c6cb | ||
|
|
00a705707e | ||
|
|
4d86cf4ce0 | ||
|
|
beb3d8ec26 | ||
|
|
8fe166dcfd | ||
|
|
9cc336c43b | ||
|
|
a93f4b1ba2 | ||
|
|
f457cdd2de | ||
|
|
f704b261c0 | ||
|
|
631abee693 | ||
|
|
feb8e30d2e | ||
|
|
4063b90cef | ||
|
|
0e0f784447 | ||
|
|
e8d72c7245 | ||
|
|
4ae08ad9ef | ||
|
|
222fc9c679 | ||
|
|
079973f1cf | ||
|
|
125696fc79 | ||
|
|
c198e893c9 | ||
|
|
7e1904c2ad | ||
|
|
c61fc8082a | ||
|
|
65444f510d | ||
|
|
70450f6873 | ||
|
|
3638b4021a | ||
|
|
0ab2227984 | ||
|
|
afb18b99b7 | ||
|
|
613fd43fcf | ||
|
|
3095f350e0 | ||
|
|
0d0190a6fd | ||
|
|
8f6df90035 | ||
|
|
876816ab2a | ||
|
|
a8f2b2cfb4 | ||
|
|
ddfe15b872 | ||
|
|
114bcc07a9 | ||
|
|
76df9fdc45 | ||
|
|
a51420f7f8 | ||
|
|
e3cbd45e7d | ||
|
|
ea28638a0c | ||
|
|
43a7870b23 | ||
|
|
6dcf0bda05 | ||
|
|
816936eafb | ||
|
|
1d09ad4652 | ||
|
|
5165b18b85 | ||
|
|
7afcd9594a | ||
|
|
b9802f4b6f | ||
|
|
1040ce0e71 | ||
|
|
3eb45e30b3 | ||
|
|
ab324ea6ae | ||
|
|
022e138b9a | ||
|
|
9e4a900e6d | ||
|
|
6c5613255a | ||
|
|
ff49b82db7 | ||
|
|
ae7f991e8d | ||
|
|
cedc333940 | ||
|
|
6daee1b235 | ||
|
|
68498a87be | ||
|
|
ab6c2bad84 | ||
|
|
c9e4562fd5 | ||
|
|
e1cdcfa9a6 | ||
|
|
5e8162a137 | ||
|
|
9f09702854 | ||
|
|
8e7d15e49d | ||
|
|
b9c5676006 | ||
|
|
dfea9c27ce | ||
|
|
78140748ce | ||
|
|
a7535a2232 | ||
|
|
7a52785f7d | ||
|
|
13dd82d7fa | ||
|
|
93cdb2f2fa | ||
|
|
611d3a7b2f | ||
|
|
29d42ed319 | ||
|
|
1d97dcff08 | ||
|
|
679b87c4f8 | ||
|
|
b231bece0e | ||
|
|
49397c0ca4 | ||
|
|
215dfe02d5 | ||
|
|
69ba067a65 | ||
|
|
5f621c1995 | ||
|
|
ee1698d928 | ||
|
|
2fcf8af421 | ||
|
|
f0960698d2 | ||
|
|
30baff7ecb | ||
|
|
2b3db734df | ||
|
|
0b54089c43 | ||
|
|
77b8e01911 | ||
|
|
bc5ddc36fa | ||
|
|
5bcca8b97f | ||
|
|
988a51b764 | ||
|
|
1f4e633ce3 | ||
|
|
233084a601 | ||
|
|
ac8c122c2a | ||
|
|
2dabd82e26 |
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"name": "discord.js",
|
||||
"monoRepo": true,
|
||||
"packagePath": "packages/discord.js",
|
||||
"packagePath": ".",
|
||||
"tagTemplate": "{{new-version}}"
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"extends": ["@commitlint/config-angular"],
|
||||
"rules": {
|
||||
"type-enum": [
|
||||
2,
|
||||
"always",
|
||||
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types", "typings"]
|
||||
],
|
||||
"scope-case": [0]
|
||||
}
|
||||
"extends": ["@commitlint/config-angular"],
|
||||
"rules": {
|
||||
"type-enum": [
|
||||
2,
|
||||
"always",
|
||||
["chore", "build", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test", "types", "typings"]
|
||||
],
|
||||
"scope-case": [0]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# Packages
|
||||
node_modules/
|
||||
|
||||
# Log files
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Dist
|
||||
dist/
|
||||
|
||||
# Miscellaneous
|
||||
.tmp/
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
.idea/
|
||||
.DS_Store
|
||||
.turbo
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
# yarn
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/cache
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
207
.eslintrc.json
207
.eslintrc.json
@@ -1,11 +1,200 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "marine/prettier/node",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.eslint.json"
|
||||
},
|
||||
"ignorePatterns": ["**/dist/*"],
|
||||
"env": {
|
||||
"jest": true
|
||||
}
|
||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||
"plugins": ["import"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2021
|
||||
},
|
||||
"env": {
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
"groups": ["builtin", "external", "internal", "index", "sibling", "parent"],
|
||||
"alphabetize": {
|
||||
"order": "asc"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prettier/prettier": [
|
||||
2,
|
||||
{
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "lf",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
],
|
||||
"strict": ["error", "global"],
|
||||
"no-await-in-loop": "warn",
|
||||
"no-compare-neg-zero": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"valid-jsdoc": [
|
||||
"error",
|
||||
{
|
||||
"requireReturn": false,
|
||||
"requireReturnDescription": false,
|
||||
"prefer": {
|
||||
"return": "returns",
|
||||
"arg": "param"
|
||||
},
|
||||
"preferType": {
|
||||
"String": "string",
|
||||
"Number": "number",
|
||||
"Boolean": "boolean",
|
||||
"Symbol": "symbol",
|
||||
"object": "Object",
|
||||
"function": "Function",
|
||||
"array": "Array",
|
||||
"date": "Date",
|
||||
"error": "Error",
|
||||
"null": "void"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"accessor-pairs": "warn",
|
||||
"array-callback-return": "error",
|
||||
"consistent-return": "error",
|
||||
"curly": ["error", "multi-line", "consistent"],
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": "error",
|
||||
"eqeqeq": "error",
|
||||
"no-empty-function": "error",
|
||||
"no-floating-decimal": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-invalid-this": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-multi-spaces": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-new": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-return-assign": "error",
|
||||
"no-return-await": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-useless-return": "error",
|
||||
"no-void": "error",
|
||||
"no-warning-comments": "warn",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"require-await": "warn",
|
||||
"wrap-iife": "error",
|
||||
"yoda": "error",
|
||||
|
||||
"no-label-var": "error",
|
||||
"no-shadow": "error",
|
||||
"no-undef-init": "error",
|
||||
|
||||
"callback-return": "error",
|
||||
"getter-return": "off",
|
||||
"handle-callback-err": "error",
|
||||
"no-mixed-requires": "error",
|
||||
"no-new-require": "error",
|
||||
"no-path-concat": "error",
|
||||
|
||||
"array-bracket-spacing": "error",
|
||||
"block-spacing": "error",
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
|
||||
"capitalized-comments": ["error", "always", { "ignoreConsecutiveComments": true }],
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
"comma-spacing": "error",
|
||||
"comma-style": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"consistent-this": ["error", "$this"],
|
||||
"eol-last": "error",
|
||||
"func-names": "error",
|
||||
"func-name-matching": "error",
|
||||
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],
|
||||
"key-spacing": "error",
|
||||
"keyword-spacing": "error",
|
||||
"max-depth": "error",
|
||||
"max-len": ["error", 120, 2],
|
||||
"max-nested-callbacks": ["error", { "max": 4 }],
|
||||
"max-statements-per-line": ["error", { "max": 2 }],
|
||||
"new-cap": "off",
|
||||
"newline-per-chained-call": ["error", { "ignoreChainWithDepth": 3 }],
|
||||
"no-array-constructor": "error",
|
||||
"no-inline-comments": "error",
|
||||
"no-lonely-if": "error",
|
||||
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
|
||||
"no-new-object": "error",
|
||||
"no-spaced-func": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
"nonblock-statement-body-position": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"operator-assignment": "error",
|
||||
"padded-blocks": ["error", "never"],
|
||||
"quote-props": ["error", "as-needed"],
|
||||
"quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
|
||||
"semi-spacing": "error",
|
||||
"semi": "error",
|
||||
"space-before-blocks": "error",
|
||||
"space-before-function-paren": [
|
||||
"error",
|
||||
{
|
||||
"anonymous": "never",
|
||||
"named": "never",
|
||||
"asyncArrow": "always"
|
||||
}
|
||||
],
|
||||
"space-in-parens": "error",
|
||||
"space-infix-ops": "error",
|
||||
"space-unary-ops": "error",
|
||||
"spaced-comment": "error",
|
||||
"template-tag-spacing": "error",
|
||||
"unicode-bom": "error",
|
||||
|
||||
"arrow-body-style": "error",
|
||||
"arrow-parens": ["error", "as-needed"],
|
||||
"arrow-spacing": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"prefer-arrow-callback": "error",
|
||||
"prefer-numeric-literals": "error",
|
||||
"prefer-rest-params": "error",
|
||||
"prefer-spread": "error",
|
||||
"prefer-template": "error",
|
||||
"rest-spread-spacing": "error",
|
||||
"template-curly-spacing": "error",
|
||||
"yield-star-spacing": "error",
|
||||
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
"name": "Buffer",
|
||||
"message": "Import Buffer from `node:buffer` instead"
|
||||
},
|
||||
{
|
||||
"name": "process",
|
||||
"message": "Import process from `node:process` instead"
|
||||
},
|
||||
{
|
||||
"name": "setTimeout",
|
||||
"message": "Import setTimeout from `node:timers` instead"
|
||||
},
|
||||
{
|
||||
"name": "setInterval",
|
||||
"message": "Import setInterval from `node:timers` instead"
|
||||
},
|
||||
{
|
||||
"name": "setImmediate",
|
||||
"message": "Import setImmediate from `node:timers` instead"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
11
.github/.kodiak.toml
vendored
Normal file
11
.github/.kodiak.toml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version = 1
|
||||
|
||||
[merge]
|
||||
require_automerge_label = false
|
||||
blocking_labels = ['blocked']
|
||||
method = 'squash'
|
||||
|
||||
[merge.message]
|
||||
title = 'pull_request_title'
|
||||
strip_html_comments = true
|
||||
include_coauthors = true
|
||||
2
.github/COMMIT_CONVENTION.md
vendored
2
.github/COMMIT_CONVENTION.md
vendored
@@ -68,7 +68,7 @@ Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`
|
||||
|
||||
### Scope
|
||||
|
||||
The scope could be anything specifying the place of the commit change. For example `GuildMember`, `Guild`, `Message`, `TextChannel` etc...
|
||||
The scope could be anything specifying the place of the commit change. For example `GuildMember`, `Guild`, `Message`, `MessageEmbed` etc...
|
||||
|
||||
### Subject
|
||||
|
||||
|
||||
9
.github/CONTRIBUTING.md
vendored
9
.github/CONTRIBUTING.md
vendored
@@ -11,8 +11,7 @@ is a great boon to your development process.
|
||||
To get ready to work on the codebase, please do the following:
|
||||
|
||||
1. Fork & clone the repository, and make sure you're on the **main** branch
|
||||
2. Run `yarn --immutable` ([install](https://yarnpkg.com/getting-started/install))
|
||||
3. Run `yarn build` to build local packages
|
||||
4. Code your heart out!
|
||||
5. Run `yarn test` to run ESLint and ensure any JSDoc changes are valid
|
||||
6. [Submit a pull request](https://github.com/discordjs/discord.js/compare) (Make sure you follow the [conventional commit format](https://github.com/discordjs/discord.js/blob/main/.github/COMMIT_CONVENTION.md))
|
||||
2. Run `npm ci`
|
||||
3. Code your heart out!
|
||||
4. Run `npm test` to run ESLint and ensure any JSDoc changes are valid
|
||||
5. [Submit a pull request](https://github.com/discordjs/discord.js/compare) (Make sure you follow the [conventional commit format](https://github.com/discordjs/discord.js/blob/main/.github/COMMIT_CONVENTION.md))
|
||||
|
||||
102
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
102
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,25 +1,12 @@
|
||||
name: Bug report
|
||||
description: Report incorrect or unexpected behavior of a package
|
||||
description: Report incorrect or unexpected behavior of discord.js
|
||||
labels: [bug, need repro]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use Discord for questions: https://discord.gg/djs
|
||||
- type: dropdown
|
||||
id: package
|
||||
attributes:
|
||||
label: Which package is this bug report for?
|
||||
options:
|
||||
- discord.js
|
||||
- builders
|
||||
- collection
|
||||
- rest
|
||||
- proxy
|
||||
- proxy-container
|
||||
- voice
|
||||
validations:
|
||||
required: true
|
||||
If you are reporting a voice issue, please post your issue at https://github.com/discordjs/voice/issues
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
@@ -43,16 +30,28 @@ body:
|
||||
description: Include a reproducible, minimal code sample. This will be automatically formatted into code, so no need for backticks.
|
||||
render: typescript
|
||||
placeholder: |
|
||||
Your code sample should be...
|
||||
... Minimal - Use as little code as possible that still produces the same problem (and is understandable)
|
||||
... Complete - Provide all parts someone else needs to reproduce your problem
|
||||
... Reproducible - Test the code you're about to provide to make sure it reproduces the problem
|
||||
const { Client, Intents } = require('discord.js');
|
||||
const client = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
||||
|
||||
client.on('ready', () => {
|
||||
console.log(`Logged in as ${client.user.tag}!`);
|
||||
});
|
||||
|
||||
client.on('interactionCreate', async interaction => {
|
||||
if (!interaction.isCommand()) return;
|
||||
|
||||
if (interaction.commandName === 'ping') {
|
||||
await interaction.reply('Pong!');
|
||||
}
|
||||
});
|
||||
|
||||
client.login('token');
|
||||
- type: input
|
||||
id: djs-version
|
||||
attributes:
|
||||
label: Package version
|
||||
description: Which version of are you using? Run `npm list <package>` in your project directory and paste the output.
|
||||
placeholder: We no longer support version 12 or earlier of discord.js
|
||||
label: discord.js version
|
||||
description: Which version of discord.js are you using? Run `npm list discord.js` in your project directory and paste the output.
|
||||
placeholder: 13.x.x (we no longer support version 12 or earlier)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
@@ -62,7 +61,7 @@ body:
|
||||
description: |
|
||||
Which version of Node.js are you using? Run `node --version` in your project directory and paste the output.
|
||||
If you are using TypeScript, please include its version (`npm list typescript`) as well.
|
||||
placeholder: Node.js version 16.9+ is required for version 14.0.0+
|
||||
placeholder: Node.js version 16.6+ is required for version 13.0.0+
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
@@ -90,15 +89,13 @@ body:
|
||||
|
||||
Tip: you can select multiple items
|
||||
options:
|
||||
- Not applicable (subpackage bug)
|
||||
- No Partials
|
||||
- User
|
||||
- Channel
|
||||
- GuildMember
|
||||
- Message
|
||||
- Reaction
|
||||
- GuildScheduledEvent
|
||||
- ThreadMember
|
||||
- USER
|
||||
- CHANNEL
|
||||
- GUILD_MEMBER
|
||||
- MESSAGE
|
||||
- REACTION
|
||||
- GUILD_SCHEDULED_EVENT
|
||||
multiple: true
|
||||
validations:
|
||||
required: true
|
||||
@@ -107,29 +104,26 @@ body:
|
||||
attributes:
|
||||
label: Which gateway intents are you subscribing to?
|
||||
description: |
|
||||
Check your Client constructor options for the `intents` key.
|
||||
Check your Client constructor for the `intents` key.
|
||||
|
||||
Tip: you can select multiple items
|
||||
options:
|
||||
- Not applicable (subpackage bug)
|
||||
- No Intents
|
||||
- Guilds
|
||||
- GuildMembers
|
||||
- GuildBans
|
||||
- GuildEmojisAndStickers
|
||||
- GuildIntegrations
|
||||
- GuildWebhooks
|
||||
- GuildInvites
|
||||
- GuildVoiceStates
|
||||
- GuildPresences
|
||||
- GuildMessages
|
||||
- GuildMessageReactions
|
||||
- GuildMessageTyping
|
||||
- DirectMessages
|
||||
- DirectMessageReactions
|
||||
- DirectMessageTyping
|
||||
- MessageContent
|
||||
- GuildScheduledEvents
|
||||
- GUILDS
|
||||
- GUILD_MEMBERS
|
||||
- GUILD_BANS
|
||||
- GUILD_EMOJIS_AND_STICKERS
|
||||
- GUILD_INTEGRATIONS
|
||||
- GUILD_WEBHOOKS
|
||||
- GUILD_INVITES
|
||||
- GUILD_VOICE_STATES
|
||||
- GUILD_PRESENCES
|
||||
- GUILD_MESSAGES
|
||||
- GUILD_MESSAGE_REACTIONS
|
||||
- GUILD_MESSAGE_TYPING
|
||||
- DIRECT_MESSAGES
|
||||
- DIRECT_MESSAGE_REACTIONS
|
||||
- DIRECT_MESSAGE_TYPING
|
||||
- GUILD_SCHEDULED_EVENTS
|
||||
multiple: true
|
||||
validations:
|
||||
required: true
|
||||
@@ -137,8 +131,8 @@ body:
|
||||
id: dev-release
|
||||
attributes:
|
||||
label: I have tested this issue on a development release
|
||||
placeholder: d23280c (commit hash)
|
||||
placeholder: d23280c
|
||||
description: |
|
||||
The issue might already be fixed in a development release or main. This is not required, but helps us greatly.
|
||||
[discord.js only] To install the latest development release run `npm i discord.js@dev` in your project directory.
|
||||
The issue might already be fixed in a development release. This is not required, but helps us greatly.
|
||||
To install the latest development release run `npm i discord.js@dev` in your project directory.
|
||||
Run `npm list discord.js` and use the last part of the printed information (`d23280c` for `discord.js@xx.x.x-dev.1530234593.d23280c`)
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
16
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,5 +1,5 @@
|
||||
name: Feature request
|
||||
description: Request a new feature (discord.js accepts documented features of the official Discord developer API only!)
|
||||
description: Request a new feature (documented features of the official Discord developer API only!)
|
||||
labels: [feature request]
|
||||
body:
|
||||
- type: markdown
|
||||
@@ -8,20 +8,6 @@ body:
|
||||
We can only implement features that Discord publishes, documents and merges into the Discord API documentation.
|
||||
We do not implement unreleased features.
|
||||
Use Discord for questions: https://discord.gg/djs
|
||||
- type: dropdown
|
||||
id: package
|
||||
attributes:
|
||||
label: Which package is the feature request for?
|
||||
options:
|
||||
- discord.js
|
||||
- builders
|
||||
- collection
|
||||
- rest
|
||||
- proxy
|
||||
- proxy-container
|
||||
- voice
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,5 +1,7 @@
|
||||
**Please describe the changes this PR makes and why it should be merged:**
|
||||
|
||||
|
||||
|
||||
**Status and versioning classification:**
|
||||
|
||||
<!--
|
||||
|
||||
13
.github/check_deploy_branch.sh
vendored
Executable file
13
.github/check_deploy_branch.sh
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
git diff HEAD^ HEAD --quiet .
|
||||
|
||||
if [[ "$VERCEL_GIT_COMMIT_REF" == "main" && $? -eq 1 ]]; then
|
||||
# Proceed with the build
|
||||
echo "✅ - Proceed"
|
||||
exit 1;
|
||||
else
|
||||
# Don't build
|
||||
echo "🛑 - Build cancelled"
|
||||
exit 0;
|
||||
fi
|
||||
58
.github/labeler.yml
vendored
58
.github/labeler.yml
vendored
@@ -1,43 +1,15 @@
|
||||
chore:
|
||||
- any: ['*']
|
||||
all: ['!packages/*', '!packages/**/*']
|
||||
|
||||
'packages:builders':
|
||||
- packages/builders/*
|
||||
- packages/builders/**/*
|
||||
|
||||
'packages:collection':
|
||||
- packages/collection/*
|
||||
- packages/collection/**/*
|
||||
|
||||
'packages:discord.js':
|
||||
- packages/discord.js/*
|
||||
- packages/discord.js/**/*
|
||||
|
||||
'packages:docgen':
|
||||
- packages/docgen/*
|
||||
- packages/docgen/**/*
|
||||
|
||||
'packages:proxy':
|
||||
- packages/proxy/*
|
||||
- packages/proxy/**/*
|
||||
|
||||
'packages:proxy-container':
|
||||
- packages/proxy-container/*
|
||||
- packages/proxy-container/**/*
|
||||
|
||||
'packages:rest':
|
||||
- packages/rest/*
|
||||
- packages/rest/**/*
|
||||
|
||||
'packages:voice':
|
||||
- packages/voice/*
|
||||
- packages/voice/**/*
|
||||
|
||||
'packages:website':
|
||||
- packages/website/*
|
||||
- packages/website/**/*
|
||||
|
||||
'packages:ws':
|
||||
- packages/ws/*
|
||||
- packages/ws/**/*
|
||||
apps:guide:
|
||||
- apps/guide/*
|
||||
- apps/guide/**/*
|
||||
apps:website:
|
||||
- apps/website/*
|
||||
- apps/website/**/*
|
||||
packages:discord.js:
|
||||
- scripts/*
|
||||
- scripts/**/*
|
||||
- src/*
|
||||
- src/**/*
|
||||
- test/*
|
||||
- test/**/*
|
||||
- typings/*
|
||||
- typings/**/*
|
||||
|
||||
22
.github/labels.yml
vendored
22
.github/labels.yml
vendored
@@ -4,8 +4,6 @@
|
||||
color: '5663e9'
|
||||
- name: 'backlog'
|
||||
color: '7ef7ef'
|
||||
- name: 'blocked'
|
||||
color: 'fc1423'
|
||||
- name: 'bug'
|
||||
color: 'd73a4a'
|
||||
- name: 'caching'
|
||||
@@ -46,26 +44,6 @@
|
||||
color: 'e4e669'
|
||||
- name: 'need repro'
|
||||
color: 'c66037'
|
||||
- name: 'packages:builders'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:collection'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:discord.js'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:docgen'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:proxy'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:proxy-container'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:rest'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:voice'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:ws'
|
||||
color: 'fbca04'
|
||||
- name: 'packages:website'
|
||||
color: 'fbca04'
|
||||
- name: 'performance'
|
||||
color: '80c042'
|
||||
- name: 'permissions'
|
||||
|
||||
32
.github/tsc.json
vendored
32
.github/tsc.json
vendored
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "tsc",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(?:\\s+\\d+\\>)?([^\\s].*)\\((\\d+),(\\d+)\\)\\s*:\\s+(error|warning|info)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"code": 5,
|
||||
"message": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "tsc",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(?:\\s+\\d+\\>)?([^\\s].*)\\((\\d+),(\\d+)\\)\\s*:\\s+(error|warning|info)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"code": 5,
|
||||
"message": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
14
.github/workflows/auto-deprecate.yml
vendored
14
.github/workflows/auto-deprecate.yml
vendored
@@ -7,22 +7,20 @@ jobs:
|
||||
auto-deprecate:
|
||||
name: npm auto deprecate
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install node.js v16
|
||||
uses: actions/setup-node@v3
|
||||
- name: Install Node v16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: yarn.lock
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --immutable
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Deprecate versions
|
||||
run: 'yarn npm-deprecate --name "*dev*" --package @discordjs/builders @discordjs/collection discord.js @discordjs/rest @discordjs/voice'
|
||||
run: 'npm exec --no npm-deprecate -- --name "*dev*" --package "discord.js"'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
|
||||
89
.github/workflows/documentation.yml
vendored
89
.github/workflows/documentation.yml
vendored
@@ -2,8 +2,7 @@ name: Documentation
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'stable'
|
||||
- 'v13'
|
||||
- '!docs'
|
||||
tags:
|
||||
- '**'
|
||||
@@ -31,38 +30,20 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: yarn.lock
|
||||
|
||||
- name: Turbo cache
|
||||
id: turbo-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .turbo
|
||||
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
turbo-${{ github.job }}-${{ github.ref_name }}-
|
||||
cache: 'npm'
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --immutable
|
||||
|
||||
- name: Build dependencies
|
||||
run: yarn build --cache-dir=".turbo"
|
||||
run: npm ci
|
||||
|
||||
- name: Build docs
|
||||
run: yarn docs --cache-dir=".turbo"
|
||||
run: npm run docs
|
||||
|
||||
- name: Upload docgen artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docgen
|
||||
path: packages/*/docs/docs.json
|
||||
|
||||
- name: Upload api-extractor artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: api-extractor
|
||||
path: packages/*/docs/docs.api.json
|
||||
path: docs/docs.json
|
||||
|
||||
- name: Set outputs for upload job
|
||||
id: env
|
||||
@@ -74,11 +55,6 @@ jobs:
|
||||
upload:
|
||||
name: Upload Documentation
|
||||
needs: build
|
||||
strategy:
|
||||
max-parallel: 1
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'voice']
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.event.inputs.ref || needs.build.outputs.BRANCH_NAME }}
|
||||
@@ -92,23 +68,11 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: yarn.lock
|
||||
|
||||
- name: Turbo cache
|
||||
id: turbo-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .turbo
|
||||
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
turbo-${{ github.job }}-${{ github.ref_name }}-
|
||||
cache: 'npm'
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --immutable
|
||||
|
||||
- name: Build actions
|
||||
run: yarn build --cache-dir=".turbo"
|
||||
run: npm ci
|
||||
|
||||
- name: Download docgen artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
@@ -116,12 +80,6 @@ jobs:
|
||||
name: docgen
|
||||
path: docs
|
||||
|
||||
- name: Download api-extractor artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: api-extractor
|
||||
path: docs
|
||||
|
||||
- name: Checkout docs repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -129,35 +87,10 @@ jobs:
|
||||
token: ${{ secrets.DJS_DOCS }}
|
||||
path: 'out'
|
||||
|
||||
- name: Extract package and semver from tag
|
||||
if: ${{ github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag' }}
|
||||
id: extract-tag
|
||||
uses: ./packages/actions/src/formatTag
|
||||
with:
|
||||
tag: ${{ env.BRANCH_NAME }}
|
||||
|
||||
- name: Move docs to correct directory
|
||||
if: ${{ (github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag') && matrix.package == steps.extract-tag.outputs.package }}
|
||||
env:
|
||||
PACKAGE: ${{ steps.extract-tag.outputs.package }}
|
||||
SEMVER: ${{ steps.extract-tag.outputs.semver }}
|
||||
run: |
|
||||
mkdir -p out/${PACKAGE}
|
||||
mv docs/${PACKAGE}/docs/docs.json out/${PACKAGE}/${SEMVER}.json
|
||||
if [[ $PACKAGE != "discord.js" ]]; then
|
||||
mv docs/${PACKAGE}/docs/docs.api.json out/${PACKAGE}/${SEMVER}.api.json
|
||||
fi
|
||||
|
||||
- name: Move docs to correct directory
|
||||
if: ${{ !github.event.inputs.ref && env.BRANCH_OR_TAG == 'branch' }}
|
||||
env:
|
||||
PACKAGE: ${{ matrix.package }}
|
||||
run: |
|
||||
mkdir -p out/${PACKAGE}
|
||||
mv docs/${PACKAGE}/docs/docs.json out/${PACKAGE}/${BRANCH_NAME}.json
|
||||
if [[ $PACKAGE != "discord.js" ]]; then
|
||||
mv docs/${PACKAGE}/docs/docs.api.json out/${PACKAGE}/${BRANCH_NAME}.api.json
|
||||
fi
|
||||
mkdir -p out/discord.js
|
||||
mv docs/docs.json out/discord.js/${BRANCH_NAME}.json
|
||||
|
||||
- name: Commit and push
|
||||
run: |
|
||||
|
||||
10
.github/workflows/labelsync.yml
vendored
10
.github/workflows/labelsync.yml
vendored
@@ -9,14 +9,14 @@ on:
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
jobs:
|
||||
labelsync:
|
||||
name: Label sync
|
||||
labeler:
|
||||
name: Labeler
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Label sync
|
||||
uses: crazy-max/ghaction-github-labeler@v4
|
||||
- name: Run Label Sync
|
||||
uses: crazy-max/ghaction-github-labeler@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
name: 'PR Automation'
|
||||
name: 'PR Triage'
|
||||
on:
|
||||
pull_request_target:
|
||||
jobs:
|
||||
triage:
|
||||
pr-triage:
|
||||
name: PR Triage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Automatically label PR
|
||||
@@ -13,4 +14,4 @@ jobs:
|
||||
|
||||
- name: Automatically assign reviewers
|
||||
if: github.event.action == 'opened'
|
||||
uses: kentaro-m/auto-assign-action@v1.2.1
|
||||
uses: kentaro-m/auto-assign-action@v1.2.4
|
||||
26
.github/workflows/publish-dev-docker.yml
vendored
26
.github/workflows/publish-dev-docker.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Publish dev Docker Images
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 */12 * * *'
|
||||
jobs:
|
||||
docker:
|
||||
name: Docker
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'discordjs'
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
run: echo ${{ secrets.DOCKER_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
|
||||
|
||||
- name: Build the image
|
||||
run: docker build -t discordjs/proxy:latest -f packages/proxy-container/Dockerfile .
|
||||
|
||||
- name: Push image to DockerHub
|
||||
run: docker push discordjs/proxy:latest
|
||||
51
.github/workflows/publish-dev.yml
vendored
51
.github/workflows/publish-dev.yml
vendored
@@ -6,70 +6,39 @@ on:
|
||||
jobs:
|
||||
npm:
|
||||
name: npm
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- package: '@discordjs/builders'
|
||||
folder: 'builders'
|
||||
- package: '@discordjs/collection'
|
||||
folder: 'collection'
|
||||
- package: 'discord.js'
|
||||
folder: 'discord.js'
|
||||
- package: '@discordjs/proxy'
|
||||
folder: 'proxy'
|
||||
- package: '@discordjs/rest'
|
||||
folder: 'rest'
|
||||
- package: '@discordjs/voice'
|
||||
folder: 'voice'
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install node.js v16
|
||||
uses: actions/setup-node@v3
|
||||
- name: Install Node v16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: yarn.lock
|
||||
|
||||
- name: Turbo cache
|
||||
id: turbo-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .turbo
|
||||
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
turbo-${{ github.job }}-${{ github.ref_name }}-
|
||||
cache: npm
|
||||
|
||||
- name: Check previous released version
|
||||
id: pre-release
|
||||
run: |
|
||||
if [[ $(npm view ${{ matrix.package }}@dev version | grep -e "$(jq --raw-output '.version' packages/${{ matrix.folder }}/package.json)\..*-$(git rev-parse --short HEAD)") ]]; \
|
||||
if [[ $(npm view discord.js@dev version | grep -e "$(jq --raw-output '.version' package.json).*.$(git rev-parse --short HEAD | cut -b1-3)") ]]; \
|
||||
then echo '::set-output name=release::false'; \
|
||||
else echo '::set-output name=release::true'; fi
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.pre-release.outputs.release == 'true'
|
||||
run: yarn --immutable
|
||||
|
||||
- name: Build dependencies
|
||||
if: steps.pre-release.outputs.release == 'true'
|
||||
run: yarn build --cache-dir=".turbo"
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Deprecate old versions
|
||||
if: steps.pre-release.outputs.release == 'true'
|
||||
run: npm deprecate ${{ matrix.package }}@"~$(jq --raw-output '.version' packages/${{ matrix.folder }}/package.json)" "no longer supported" || true
|
||||
run: npm deprecate discord.js@"~$(jq --raw-output '.version' package.json)" "no longer supported" || true
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
|
||||
- name: Publish
|
||||
if: steps.pre-release.outputs.release == 'true'
|
||||
run: |
|
||||
yarn workspace ${{ matrix.package }} version $(jq --raw-output '.version' packages/${{ matrix.folder }}/package.json).$(date +%s)-$(git rev-parse --short HEAD)
|
||||
yarn workspace ${{ matrix.package }} npm publish --tag dev || true
|
||||
npm version --git-tag-version=false $(jq --raw-output '.version' package.json).$(date +%s).$(git rev-parse --short HEAD)
|
||||
npm publish --tag dev || true
|
||||
env:
|
||||
YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
|
||||
26
.github/workflows/publish-docker.yml
vendored
26
.github/workflows/publish-docker.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Publish Docker Images
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
docker:
|
||||
name: Docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
run: echo ${{ secrets.DOCKER_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
|
||||
|
||||
- name: Build the image
|
||||
run: docker build -t discordjs/proxy:latest -f packages/proxy-container/Dockerfile .
|
||||
|
||||
- name: Tag the image with major
|
||||
run: docker tag discordjs/proxy discordjs/proxy:$(cut -d '.' -f1 <<< $(jq --raw-output '.version' packages/proxy-container/package.json))
|
||||
|
||||
- name: Push image to DockerHub
|
||||
run: docker push --all-tags discordjs/proxy
|
||||
30
.github/workflows/publish-release.yml
vendored
Normal file
30
.github/workflows/publish-release.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Publish Release
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
jobs:
|
||||
npm-publish:
|
||||
name: npm publish
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
if: github.repository_owner == 'discordjs'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install node.js v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Publish package (v13)
|
||||
run: npm publish --tag v13-lts
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
88
.github/workflows/test.yml
vendored
88
.github/workflows/test.yml
vendored
@@ -6,36 +6,76 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install node.js v16
|
||||
uses: actions/setup-node@v3
|
||||
- name: Install Node v16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: yarn.lock
|
||||
|
||||
- name: Turbo cache
|
||||
id: turbo-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .turbo
|
||||
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
turbo-${{ github.job }}-${{ github.ref_name }}-
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn --immutable
|
||||
run: npm ci
|
||||
|
||||
- name: ESLint
|
||||
run: yarn lint --cache-dir=".turbo"
|
||||
- name: Run Prettier and ESLint
|
||||
run: npm run lint
|
||||
|
||||
- name: Tests
|
||||
run: yarn test
|
||||
typings:
|
||||
name: TSLint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Upload Coverage
|
||||
uses: ./packages/actions/src/uploadCoverage
|
||||
if: github.repository_owner == 'discordjs'
|
||||
- name: Install Node v16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
|
||||
- name: Build
|
||||
run: yarn build --cache-dir=".turbo"
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run TSLint
|
||||
run: npm run lint:typings
|
||||
|
||||
typescript:
|
||||
name: TypeScript
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node v16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Register Problem Matcher
|
||||
run: echo "##[add-matcher].github/tsc.json"
|
||||
|
||||
- name: Run Type Tests
|
||||
run: npm run test:typescript
|
||||
|
||||
docs:
|
||||
name: Documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node v16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Test documentation
|
||||
run: npm run docs:test
|
||||
|
||||
29
.gitignore
vendored
29
.gitignore
vendored
@@ -13,30 +13,21 @@ pids
|
||||
|
||||
# Env
|
||||
.env
|
||||
test/auth.json
|
||||
test/auth.js
|
||||
docs/deploy/deploy_key
|
||||
docs/deploy/deploy_key.pub
|
||||
deploy/deploy_key
|
||||
deploy/deploy_key.pub
|
||||
|
||||
# Dist
|
||||
dist/
|
||||
docs/docs.json
|
||||
|
||||
# Miscellaneous
|
||||
.tmp/
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
.idea/
|
||||
.DS_Store
|
||||
.turbo
|
||||
tsconfig.tsbuildinfo
|
||||
coverage/
|
||||
|
||||
# yarn
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
# Cache
|
||||
.prettiercache
|
||||
.eslintcache
|
||||
.yarn/
|
||||
.turbo/
|
||||
.vercel/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn commitlint --edit $1
|
||||
npx --no-install commitlint --edit $1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn build && yarn lint && yarn test
|
||||
npx --no-install lint-staged
|
||||
|
||||
4
.lintstagedrc.json
Normal file
4
.lintstagedrc.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"*.{mjs,js}": "eslint --fix --ext mjs,js,ts",
|
||||
"*.{ts,json,yml,yaml}": "prettier --write"
|
||||
}
|
||||
5
.npmrc
Normal file
5
.npmrc
Normal file
@@ -0,0 +1,5 @@
|
||||
audit=false
|
||||
fund=false
|
||||
legacy-peer-deps=true
|
||||
tag-version-prefix=""
|
||||
message="chore(Release): %s"
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "as-needed",
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "lf"
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"trailingComma": "all",
|
||||
"endOfLine": "lf",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
14
.tern-project
Normal file
14
.tern-project
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ecmaVersion": 7,
|
||||
"libs": [],
|
||||
"loadEagerly": ["./src/*.js"],
|
||||
"dontLoad": ["node_modules/**"],
|
||||
"plugins": {
|
||||
"es_modules": {},
|
||||
"node": {},
|
||||
"doc_comment": {
|
||||
"fullDocs": true,
|
||||
"strong": true
|
||||
},
|
||||
}
|
||||
}
|
||||
13
.vscode/extensions.json
vendored
13
.vscode/extensions.json
vendored
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"tamasfe.even-better-toml",
|
||||
"github.vscode-pull-request-github",
|
||||
"codezombiech.gitignore",
|
||||
"eamodio.gitlens",
|
||||
"christian-kohler.npm-intellisense",
|
||||
"christian-kohler.path-intellisense",
|
||||
"antfu.unocss"
|
||||
]
|
||||
}
|
||||
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"eslint.workingDirectories": [{ "pattern": "./packages/*" }],
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": true,
|
||||
"source.organizeImports": false
|
||||
},
|
||||
"unocss.root": "./packages/website"
|
||||
}
|
||||
363
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
363
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
File diff suppressed because one or more lines are too long
550
.yarn/plugins/@yarnpkg/plugin-version.cjs
vendored
550
.yarn/plugins/@yarnpkg/plugin-version.cjs
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
786
.yarn/releases/yarn-3.2.1.cjs
vendored
786
.yarn/releases/yarn-3.2.1.cjs
vendored
File diff suppressed because one or more lines are too long
11
.yarnrc.yml
11
.yarnrc.yml
@@ -1,11 +0,0 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||
spec: "@yarnpkg/plugin-interactive-tools"
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
||||
spec: "@yarnpkg/plugin-workspace-tools"
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
|
||||
spec: "@yarnpkg/plugin-version"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.2.1.cjs
|
||||
9127
CHANGELOG.md
Normal file
9127
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -175,7 +175,8 @@
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2022 Noel Buechler
|
||||
Copyright 2015 - 2021 Noel Buechler
|
||||
Copyright 2015 - 2021 Amish Shah
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
71
README.md
71
README.md
@@ -9,7 +9,6 @@
|
||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/v/discord.js.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/discord.js"><img src="https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Tests status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2" alt="Code coverage" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +24,7 @@ discord.js is a powerful [Node.js](https://nodejs.org) module that allows you to
|
||||
|
||||
## Installation
|
||||
|
||||
**Node.js 16.9.0 or newer is required.**
|
||||
**Node.js 16.6.0 or newer is required.**
|
||||
|
||||
```sh-session
|
||||
npm install discord.js
|
||||
@@ -39,62 +38,60 @@ pnpm add discord.js
|
||||
- [erlpack](https://github.com/discord/erlpack) for significantly faster WebSocket data (de)serialisation (`npm install discord/erlpack`)
|
||||
- [bufferutil](https://www.npmjs.com/package/bufferutil) for a much faster WebSocket connection (`npm install bufferutil`)
|
||||
- [utf-8-validate](https://www.npmjs.com/package/utf-8-validate) in combination with `bufferutil` for much faster WebSocket processing (`npm install utf-8-validate`)
|
||||
- [@discordjs/voice](https://www.npmjs.com/package/@discordjs/voice) for interacting with the Discord Voice API (`npm install @discordjs/voice`)
|
||||
- [@discordjs/voice](https://github.com/discordjs/voice) for interacting with the Discord Voice API (`npm install @discordjs/voice`)
|
||||
|
||||
## Example usage
|
||||
|
||||
Install all required dependencies:
|
||||
|
||||
```sh-session
|
||||
npm install discord.js @discordjs/rest
|
||||
yarn add discord.js @discordjs/rest
|
||||
pnpm add discord.js @discordjs/rest
|
||||
npm install discord.js @discordjs/rest discord-api-types
|
||||
yarn add discord.js @discordjs/rest discord-api-types
|
||||
pnpm add discord.js @discordjs/rest discord-api-types
|
||||
```
|
||||
|
||||
Register a slash command against the Discord API:
|
||||
|
||||
```js
|
||||
const { REST } = require('@discordjs/rest');
|
||||
const { Routes } = require('discord.js');
|
||||
const { Routes } = require('discord-api-types/v9');
|
||||
|
||||
const commands = [
|
||||
{
|
||||
name: 'ping',
|
||||
description: 'Replies with Pong!',
|
||||
},
|
||||
];
|
||||
const commands = [{
|
||||
name: 'ping',
|
||||
description: 'Replies with Pong!'
|
||||
}];
|
||||
|
||||
const rest = new REST({ version: '10' }).setToken('token');
|
||||
const rest = new REST({ version: '9' }).setToken('token');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log('Started refreshing application (/) commands.');
|
||||
try {
|
||||
console.log('Started refreshing application (/) commands.');
|
||||
|
||||
await rest.put(Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID), { body: commands });
|
||||
await rest.put(
|
||||
Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID),
|
||||
{ body: commands },
|
||||
);
|
||||
|
||||
console.log('Successfully reloaded application (/) commands.');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
console.log('Successfully reloaded application (/) commands.');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
Afterwards we can create a quite simple example bot:
|
||||
|
||||
```js
|
||||
const { Client, GatewayIntentBits } = require('discord.js');
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
const { Client, Intents } = require('discord.js');
|
||||
const client = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
||||
|
||||
client.on('ready', () => {
|
||||
console.log(`Logged in as ${client.user.tag}!`);
|
||||
console.log(`Logged in as ${client.user.tag}!`);
|
||||
});
|
||||
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
client.on('interactionCreate', async interaction => {
|
||||
if (!interaction.isCommand()) return;
|
||||
|
||||
if (interaction.commandName === 'ping') {
|
||||
await interaction.reply('Pong!');
|
||||
}
|
||||
if (interaction.commandName === 'ping') {
|
||||
await interaction.reply('Pong!');
|
||||
}
|
||||
});
|
||||
|
||||
client.login('token');
|
||||
@@ -102,10 +99,10 @@ client.login('token');
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/discord.js/tree/main/packages/website))
|
||||
- [Documentation](https://discord.js.org/#/docs)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
|
||||
- [Documentation](https://old.discordjs.dev/#/docs)
|
||||
- [Guide](https://v13.discordjs.guide) ([source](https://github.com/discordjs/guide/tree/v13))
|
||||
See also the [Update Guide](https://v13.discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js)
|
||||
@@ -119,7 +116,7 @@ client.login('token');
|
||||
## Contributing
|
||||
|
||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||
[documentation](https://discord.js.org/#/docs).
|
||||
[documentation](https://old.discordjs.dev/#/docs).
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
0
apps/website/.gitkeep
Normal file
0
apps/website/.gitkeep
Normal file
@@ -58,7 +58,7 @@ commit_parsers = [
|
||||
]
|
||||
filter_commits = true
|
||||
tag_pattern = "[0-9]*"
|
||||
skip_tags = "v[0-9]*|11|12|@discordjs"
|
||||
skip_tags = "v[0-9]*|@discordjs"
|
||||
ignore_tags = ""
|
||||
topo_order = false
|
||||
topo_order = true
|
||||
sort_commits = "newest"
|
||||
26
codecov.yml
26
codecov.yml
@@ -1,26 +0,0 @@
|
||||
codecov:
|
||||
notify:
|
||||
after_n_builds: 6
|
||||
strict_yaml_branch: main
|
||||
|
||||
coverage:
|
||||
range: '50...90'
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 5%
|
||||
informational: true
|
||||
patch: off
|
||||
|
||||
flag_management:
|
||||
default_rules:
|
||||
statuses:
|
||||
- type: project
|
||||
target: auto
|
||||
threshold: 2%
|
||||
informational: true
|
||||
|
||||
comment:
|
||||
require_changes: true
|
||||
after_n_builds: 6
|
||||
1
docs/README.md
Normal file
1
docs/README.md
Normal file
@@ -0,0 +1 @@
|
||||
## [View the documentation here.](https://old.discordjs.dev/#/docs)
|
||||
5
docs/index.yml
Normal file
5
docs/index.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- name: General
|
||||
files:
|
||||
- name: Welcome
|
||||
id: welcome
|
||||
path: ../../README.md
|
||||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
11775
package-lock.json
generated
Normal file
11775
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
152
package.json
152
package.json
@@ -1,66 +1,90 @@
|
||||
{
|
||||
"name": "@discordjs/discord.js",
|
||||
"version": "0.0.0",
|
||||
"description": "A powerful library for interacting with the Discord API",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"test": "turbo run test",
|
||||
"lint": "turbo run lint",
|
||||
"format": "turbo run format",
|
||||
"fmt": "turbo run format",
|
||||
"postinstall": "is-ci || husky install",
|
||||
"docs": "turbo run docs",
|
||||
"changelog": "turbo run changelog",
|
||||
"update": "yarn upgrade-interactive"
|
||||
},
|
||||
"contributors": [
|
||||
"Crawl <icrawltogo@gmail.com>",
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>"
|
||||
],
|
||||
"keywords": [
|
||||
"discord",
|
||||
"api",
|
||||
"bot",
|
||||
"client",
|
||||
"node",
|
||||
"discordapp"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/discordjs/discord.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/discord.js/issues"
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.3",
|
||||
"@commitlint/config-angular": "^17.0.3",
|
||||
"@favware/cliff-jumper": "^1.8.5",
|
||||
"@favware/npm-deprecate": "^1.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||
"@typescript-eslint/parser": "^5.30.6",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"eslint": "^8.20.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-typescript": "^3.2.7",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"husky": "^8.0.1",
|
||||
"is-ci": "^3.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
"turbo": "^1.3.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"packageManager": "yarn@3.2.1"
|
||||
"name": "discord.js",
|
||||
"version": "13.17.1",
|
||||
"description": "A powerful library for interacting with the Discord API",
|
||||
"scripts": {
|
||||
"test": "npm run lint && npm run docs:test && npm run lint:typings && npm run test:typescript",
|
||||
"test:typescript": "tsc --noEmit && tsd",
|
||||
"lint": "prettier --check src/**/*.js typings/**/*.ts && eslint src",
|
||||
"lint:fix": "npm run format && eslint src --fix",
|
||||
"lint:typings": "tslint typings/index.d.ts",
|
||||
"format": "prettier --write src/**/*.js typings/**/*.ts",
|
||||
"prepare": "is-ci || husky install",
|
||||
"docs": "docgen --source src --custom docs/index.yml --output docs/docs.json",
|
||||
"docs:test": "docgen --source src --custom docs/index.yml",
|
||||
"prepublishOnly": "npm run test",
|
||||
"changelog": "git cliff --prepend CHANGELOG.md -u",
|
||||
"release": "cliff-jumper"
|
||||
},
|
||||
"main": "./src/index.js",
|
||||
"types": "./typings/index.d.ts",
|
||||
"files": [
|
||||
"src",
|
||||
"typings"
|
||||
],
|
||||
"directories": {
|
||||
"lib": "src",
|
||||
"test": "test"
|
||||
},
|
||||
"contributors": [
|
||||
"Crawl <icrawltogo@gmail.com>",
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
"discord",
|
||||
"api",
|
||||
"bot",
|
||||
"client",
|
||||
"node",
|
||||
"discordapp"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/discordjs/discord.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/discord.js/issues"
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^0.16.0",
|
||||
"@discordjs/collection": "^0.7.0",
|
||||
"@sapphire/async-queue": "^1.5.0",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
"@types/ws": "^8.5.4",
|
||||
"discord-api-types": "^0.33.5",
|
||||
"form-data": "^4.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"ws": "^8.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.5.1",
|
||||
"@commitlint/config-angular": "^17.4.4",
|
||||
"@discordjs/docgen": "^0.11.1",
|
||||
"@favware/cliff-jumper": "^2.0.0",
|
||||
"@favware/npm-deprecate": "^1.0.7",
|
||||
"@types/node": "^16.11.45",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"dtslint": "^4.2.1",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"husky": "^8.0.3",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest": "^29.5.0",
|
||||
"lint-staged": "^13.2.0",
|
||||
"prettier": "^2.8.7",
|
||||
"tsd": "^0.28.1",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "^5.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.6.0",
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
29
packages/actions/.gitignore
vendored
29
packages/actions/.gitignore
vendored
@@ -1,29 +0,0 @@
|
||||
# Packages
|
||||
node_modules/
|
||||
|
||||
# Log files
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Dist
|
||||
dist/
|
||||
typings/
|
||||
|
||||
docs/**/*
|
||||
!docs/index.yml
|
||||
!docs/README.md
|
||||
!docs/examples/
|
||||
!docs/examples/*.md
|
||||
|
||||
# Miscellaneous
|
||||
.tmp/
|
||||
coverage/
|
||||
@@ -1,9 +0,0 @@
|
||||
# Autogenerated
|
||||
CHANGELOG.md
|
||||
.turbo
|
||||
dist/
|
||||
docs/**/*
|
||||
!docs/index.yml
|
||||
!docs/README.md
|
||||
coverage/
|
||||
tsup.config.*.mjs
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
@@ -1,31 +0,0 @@
|
||||
<div align="center">
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/discord.js/tree/main/packages/website))
|
||||
- [Documentation](https://discord.js.org/#/docs)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/scripts)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
## Contributing
|
||||
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||
nudge in the right direction, please don't hesitate to join our official [discord.js Server](https://discord.gg/djs).
|
||||
@@ -1,22 +0,0 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { formatTag } from '../src';
|
||||
|
||||
describe('Format Tag', () => {
|
||||
test('GIVEN tag with a prefix THEN format tag to not contain the prefix', () => {
|
||||
expect(formatTag('@discordjs/rest@0.4.0')).toEqual({ package: 'rest', semver: '0.4.0' });
|
||||
expect(formatTag('@discordjs/collection@0.6.0')).toEqual({ package: 'collection', semver: '0.6.0' });
|
||||
expect(formatTag('@discordjs/proxy@0.1.0')).toEqual({ package: 'proxy', semver: '0.1.0' });
|
||||
expect(formatTag('@discordjs/builders@0.13.0')).toEqual({ package: 'builders', semver: '0.13.0' });
|
||||
expect(formatTag('@discordjs/voice@0.9.0')).toEqual({ package: 'voice', semver: '0.9.0' });
|
||||
});
|
||||
|
||||
test('GIVEN tag with no prefix THEN return tag', () => {
|
||||
expect(formatTag('13.5.1')).toEqual({ semver: '13.5.1' });
|
||||
expect(formatTag('13.7.0')).toEqual({ package: undefined, semver: '13.7.0' });
|
||||
});
|
||||
|
||||
test('GIVEN no or invalid tag THEN return null', () => {
|
||||
expect(formatTag('')).toEqual(null);
|
||||
expect(formatTag('abc')).toEqual(null);
|
||||
});
|
||||
});
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"name": "@discordjs/actions",
|
||||
"version": "0.1.0-dev",
|
||||
"description": "A set of actions that we use for our workflows",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "src",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"contributors": [
|
||||
"Crawl <icrawltogo@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
"api",
|
||||
"bot",
|
||||
"client",
|
||||
"node",
|
||||
"discordjs"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/discordjs/discord.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/discord.js/issues"
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.0",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.45",
|
||||
"c8": "^7.11.3",
|
||||
"eslint": "^8.20.0",
|
||||
"prettier": "^2.7.1",
|
||||
"tsup": "^6.1.3",
|
||||
"typescript": "^4.7.4",
|
||||
"vitest": "^0.18.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
name: 'Format Tag'
|
||||
description: 'Formats a git tag to remove potentially prefixes'
|
||||
inputs:
|
||||
tag:
|
||||
description: 'The input tag'
|
||||
required: true
|
||||
outputs:
|
||||
package:
|
||||
description: 'The package string that was extracted from this tag'
|
||||
semver:
|
||||
description: 'The semver string that was extracted from this tag'
|
||||
runs:
|
||||
using: node16
|
||||
main: ../../dist/formatTag/index.js
|
||||
@@ -1,9 +0,0 @@
|
||||
export function formatTag(tag: string) {
|
||||
const parsed = /(^@.*\/(?<package>.*)@v?)?(?<semver>\d+.\d+.\d+)-?.*/.exec(tag);
|
||||
|
||||
if (parsed?.groups) {
|
||||
return parsed.groups;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { getInput, setOutput } from '@actions/core';
|
||||
import { formatTag } from './formatTag';
|
||||
|
||||
const tag = getInput('tag', { required: true });
|
||||
const parsed = formatTag(tag);
|
||||
|
||||
if (parsed) {
|
||||
setOutput('package', parsed.package);
|
||||
setOutput('semver', parsed.semver);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from './formatTag/formatTag';
|
||||
@@ -1,52 +0,0 @@
|
||||
name: 'Upload Coverage'
|
||||
description: 'Uploads code coverage reports to codecov with separate flags for separate packages'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Upload Builders Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/builders/coverage/cobertura-coverage.xml
|
||||
flags: builders
|
||||
|
||||
- name: Upload Collection Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/collection/coverage/cobertura-coverage.xml
|
||||
flags: collection
|
||||
|
||||
- name: Upload Discord.js Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/discord.js/coverage/cobertura-coverage.xml
|
||||
flags: discord.js
|
||||
|
||||
- name: Upload Proxy Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/proxy/coverage/cobertura-coverage.xml
|
||||
flags: proxy
|
||||
|
||||
- name: Upload Rest Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/rest/coverage/cobertura-coverage.xml
|
||||
flags: rest
|
||||
|
||||
- name: Upload Voice Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/voice/coverage/cobertura-coverage.xml
|
||||
flags: voice
|
||||
|
||||
- name: Upload Website Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/website/coverage/cobertura-coverage.xml
|
||||
flags: website
|
||||
|
||||
- name: Upload Utilities Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/actions/coverage/cobertura-coverage.xml, ./packages/scripts/coverage/cobertura-coverage.xml
|
||||
flags: utilities
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js",
|
||||
"**/*.mjs",
|
||||
"**/*.jsx",
|
||||
"**/*.test.ts",
|
||||
"**/*.test.js",
|
||||
"**/*.test.mjs",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.mjs"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { createTsupConfig } from '../../tsup.config';
|
||||
|
||||
export default createTsupConfig({
|
||||
entry: ['src/index.ts', 'src/formatTag/index.ts'],
|
||||
format: ['cjs'],
|
||||
skipNodeModulesBundle: false,
|
||||
noExternal: ['@actions/core'],
|
||||
minify: true,
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "builders",
|
||||
"org": "discordjs",
|
||||
"packagePath": "packages/builders"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
29
packages/builders/.gitignore
vendored
29
packages/builders/.gitignore
vendored
@@ -1,29 +0,0 @@
|
||||
# Packages
|
||||
node_modules/
|
||||
|
||||
# Log files
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Dist
|
||||
dist/
|
||||
typings/
|
||||
|
||||
docs/**/*
|
||||
!docs/index.json
|
||||
!docs/README.md
|
||||
!docs/examples/
|
||||
!docs/examples/*.md
|
||||
|
||||
# Miscellaneous
|
||||
.tmp/
|
||||
coverage/
|
||||
@@ -1,9 +0,0 @@
|
||||
# Autogenerated
|
||||
CHANGELOG.md
|
||||
.turbo
|
||||
dist/
|
||||
docs/**/*
|
||||
!docs/index.yml
|
||||
!docs/README.md
|
||||
coverage/
|
||||
tsup.config.*.mjs
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('../../.prettierrc.json');
|
||||
@@ -1,246 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
# [@discordjs/builders@0.16.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.15.0...@discordjs/builders@0.16.0) - (2022-07-17)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Slash command name regex (#8265) ([32f9056](https://github.com/discordjs/discord.js/commit/32f9056b15edede3bab07de96afb4b56d3a9ecca))
|
||||
- **TextInputBuilder:** Parse `custom_id`, `label`, and `style` (#8216) ([2d9dfa3](https://github.com/discordjs/discord.js/commit/2d9dfa3c6ea4bb972da2f7e088d148b798c866d9))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))
|
||||
|
||||
## Features
|
||||
|
||||
- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25))
|
||||
- Codecov (#8219) ([f10f4cd](https://github.com/discordjs/discord.js/commit/f10f4cdcd88ca6be7ec735ed3a415ba13da83db0))
|
||||
- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))
|
||||
- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))
|
||||
- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))
|
||||
- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))
|
||||
|
||||
## Refactor
|
||||
|
||||
- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b))
|
||||
- Remove @sindresorhus/is as it's now esm only (#8133) ([c6f285b](https://github.com/discordjs/discord.js/commit/c6f285b7b089b004776fbeb444fe973a68d158d8))
|
||||
- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))
|
||||
|
||||
## Typings
|
||||
|
||||
- Remove expect error (#8242) ([7e6dbaa](https://github.com/discordjs/discord.js/commit/7e6dbaaed900c07d1a04e23bbbf9cd0d1b0501c5))
|
||||
- **builder:** Remove casting (#8241) ([8198da5](https://github.com/discordjs/discord.js/commit/8198da5cd0898e06954615a2287853321e7ebbd4))
|
||||
|
||||
# [@discordjs/builders@0.15.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.14.0...@discordjs/builders@0.15.0) - (2022-06-06)
|
||||
|
||||
## Features
|
||||
|
||||
- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f))
|
||||
- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))
|
||||
- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))
|
||||
|
||||
# [@discordjs/builders@0.15.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.14.0...@discordjs/builders@0.15.0) - (2022-06-05)
|
||||
|
||||
## Features
|
||||
|
||||
- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f))
|
||||
- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))
|
||||
- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))
|
||||
|
||||
# [@discordjs/builders@0.14.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.13.0...@discordjs/builders@0.14.0) - (2022-06-04)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **builders:** Leftover invalid null type ([8a7cd10](https://github.com/discordjs/discord.js/commit/8a7cd10554a2a71cd2fe7f6a177b5f4f43464348))
|
||||
- **SlashCommandBuilder:** Import `Permissions` correctly (#7921) ([7ce641d](https://github.com/discordjs/discord.js/commit/7ce641d33a4af6586d5e7beffbe7d38619dcf1a2))
|
||||
- Add localizations for subcommand builders and option choices (#7862) ([c1b5e73](https://github.com/discordjs/discord.js/commit/c1b5e731daa9cbbfca03a046e47cb1221ee1ed7c))
|
||||
|
||||
## Features
|
||||
|
||||
- Export types from `interactions/slashCommands/mixins` (#7942) ([68d5169](https://github.com/discordjs/discord.js/commit/68d5169f66c96f8fe5be17a1c01cdd5155607ab2))
|
||||
- **builders:** Add new command permissions v2 (#7861) ([de3f157](https://github.com/discordjs/discord.js/commit/de3f1573f07dda294cc0fbb1ca4b659eb2388a12))
|
||||
- **builders:** Improve embed errors and predicates (#7795) ([ec8d87f](https://github.com/discordjs/discord.js/commit/ec8d87f93272cc9987f9613735c0361680c4ed1e))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Use arrays instead of rest parameters for builders (#7759) ([29293d7](https://github.com/discordjs/discord.js/commit/29293d7bbb5ed463e52e5a5853817e5a09cf265b))
|
||||
|
||||
## Styling
|
||||
|
||||
- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))
|
||||
|
||||
# [@discordjs/builders@0.13.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.12.0...@discordjs/builders@0.13.0) - (2022-04-17)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- Validate select menu options (#7566) ([b1d63d9](https://github.com/discordjs/discord.js/commit/b1d63d919a61f309ac89f27016b0f148678dac2b))
|
||||
- **SelectMenu:** Set `placeholder` max to 150 (#7538) ([dcd4797](https://github.com/discordjs/discord.js/commit/dcd479767b6ec980a373f2ea1f22754f41661c1e))
|
||||
- Only check `instanceof Component` once (#7546) ([0aa4851](https://github.com/discordjs/discord.js/commit/0aa48516a4e33497e8e8dc50da164a57cdee09d3))
|
||||
- **builders:** Allow negative min/max value of number/integer option (#7484) ([3baa340](https://github.com/discordjs/discord.js/commit/3baa340821b8ecf8a16253bc0917a1033250d7c9))
|
||||
- **components:** SetX should take rest parameters (#7461) ([3617359](https://github.com/discordjs/discord.js/commit/36173590a712f041b087b7882054805a8bd42dae))
|
||||
- Unsafe embed builder field normalization (#7418) ([b936103](https://github.com/discordjs/discord.js/commit/b936103395121cb21a8c616f669ddab1d2efb0f1))
|
||||
- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7))
|
||||
- **builders:** Make type optional in constructor (#7391) ([4abb28c](https://github.com/discordjs/discord.js/commit/4abb28c0a1256c57a60369a6b8ec9e98c265b489))
|
||||
- Don't create new instances of builders classes (#7343) ([d6b56d0](https://github.com/discordjs/discord.js/commit/d6b56d0080c4c5f8ace731f1e8bcae0c9d3fb5a5))
|
||||
|
||||
## Documentation
|
||||
|
||||
- Completely fix builders example link (#7543) ([1a14c0c](https://github.com/discordjs/discord.js/commit/1a14c0ca562ea173d363a770a0437209f461fd23))
|
||||
- Add slash command builders example, fixes #7338 (#7339) ([3ae6f3c](https://github.com/discordjs/discord.js/commit/3ae6f3c313091151245d6e6b52337b459ecfc765))
|
||||
|
||||
## Features
|
||||
|
||||
- Slash command localization for builders (#7683) ([40b9a1d](https://github.com/discordjs/discord.js/commit/40b9a1d67d0b508ec593e030913acd8161cd17f8))
|
||||
- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3))
|
||||
- Add support for module: NodeNext in TS and ESM (#7598) ([8f1986a](https://github.com/discordjs/discord.js/commit/8f1986a6aa98365e09b00e84ad5f9f354ab61f3d))
|
||||
- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c))
|
||||
- Add missing `v13` component methods (#7466) ([f7257f0](https://github.com/discordjs/discord.js/commit/f7257f07655076eabfe355cb6a53260b39ca9670))
|
||||
- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb))
|
||||
- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f))
|
||||
- **embed:** Add setFields (#7322) ([bcc5cda](https://github.com/discordjs/discord.js/commit/bcc5cda8a902ddb28c7e3578e0f29b4272832624))
|
||||
|
||||
## Refactor
|
||||
|
||||
- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3))
|
||||
- Replace zod with shapeshift (#7547) ([3c0bbac](https://github.com/discordjs/discord.js/commit/3c0bbac82fa9988af4a62ff00c66d149fbe6b921))
|
||||
- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36))
|
||||
- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15))
|
||||
- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a))
|
||||
- Remove obsolete builder methods (#7590) ([10607db](https://github.com/discordjs/discord.js/commit/10607dbdafe257c5cbf5b952b7eecec4919e8b4a))
|
||||
- **Embed:** Remove add field (#7522) ([8478d2f](https://github.com/discordjs/discord.js/commit/8478d2f4de9ac013733850cbbc67902f7c5abc55))
|
||||
- Make `data` public in builders (#7486) ([ba31203](https://github.com/discordjs/discord.js/commit/ba31203a0ad96e0a00f8312c397889351e4c5cfd))
|
||||
- **embed:** Remove array support in favor of rest params (#7498) ([b3fa2ec](https://github.com/discordjs/discord.js/commit/b3fa2ece402839008738ad3adce3db958445838d))
|
||||
- **components:** Default set boolean methods to true (#7502) ([b122149](https://github.com/discordjs/discord.js/commit/b12214922cea2f43afbe6b1555a74a3c8e16f798))
|
||||
- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e))
|
||||
- **builders-methods:** Make methods consistent (#7395) ([f495364](https://github.com/discordjs/discord.js/commit/f4953647ff9f39127978c73bf8a62c08462802ca))
|
||||
- Remove conditional autocomplete option return types (#7396) ([0909824](https://github.com/discordjs/discord.js/commit/09098240bfb13b8afafa4ab549f06d236e0ff1c9))
|
||||
- **embed:** Mark properties as readonly (#7332) ([31768fc](https://github.com/discordjs/discord.js/commit/31768fcd69ed5b4566a340bda89ce881418e8272))
|
||||
|
||||
## Typings
|
||||
|
||||
- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664))
|
||||
|
||||
# [@discordjs/builders@0.12.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.11.0...@discordjs/builders@0.12.0) - (2022-01-24)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **builders:** Dont export `Button` component stuff twice (#7289) ([86d9d06](https://github.com/discordjs/discord.js/commit/86d9d0674347c08d056cd054cb4ce4253195bf94))
|
||||
|
||||
## Documentation
|
||||
|
||||
- **SlashCommandSubcommands:** Updating old links from Discord developer portal (#7224) ([bd7a6f2](https://github.com/discordjs/discord.js/commit/bd7a6f265212624199fb0b2ddc8ece39759c63de))
|
||||
|
||||
## Features
|
||||
|
||||
- Add components to /builders (#7195) ([2bb40fd](https://github.com/discordjs/discord.js/commit/2bb40fd767cf5918e3ba422ff73082734bfa05b0))
|
||||
|
||||
## Typings
|
||||
|
||||
- Make `required` a boolean (#7307) ([c10afea](https://github.com/discordjs/discord.js/commit/c10afeadc702ab98bec5e077b3b92494a9596f9c))
|
||||
|
||||
# [0.11.0](https://github.com/discordjs/builders/compare/v0.10.0...v0.11.0) (2021-12-29)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ApplicationCommandOptions:** clean up code for builder options ([#68](https://github.com/discordjs/builders/issues/68)) ([b5d0b15](https://github.com/discordjs/builders/commit/b5d0b157b1262bd01fa011f8e0cf33adb82776e7))
|
||||
|
||||
# [0.10.0](https://github.com/discordjs/builders/compare/v0.9.0...v0.10.0) (2021-12-24)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- use zod instead of ow for max/min option validation ([#66](https://github.com/discordjs/builders/issues/66)) ([beb35fb](https://github.com/discordjs/builders/commit/beb35fb1f65bd6be2321e17cc792f67e8615fd48))
|
||||
|
||||
## Features
|
||||
|
||||
- add max/min option for int and number builder options ([#47](https://github.com/discordjs/builders/issues/47)) ([2e1e860](https://github.com/discordjs/builders/commit/2e1e860b46e3453398b20df63dabb6d4325e32d1))
|
||||
|
||||
# [0.9.0](https://github.com/discordjs/builders/compare/v0.8.2...v0.9.0) (2021-12-02)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- replace ow with zod ([#58](https://github.com/discordjs/builders/issues/58)) ([0b6fb81](https://github.com/discordjs/builders/commit/0b6fb8161b858e42781855fb73aaa873fec58160))
|
||||
|
||||
## Features
|
||||
|
||||
- **SlashCommandBuilder:** add autocomplete ([#53](https://github.com/discordjs/builders/issues/53)) ([05b07a7](https://github.com/discordjs/builders/commit/05b07a7e88848188c27d7380d9f948cba25ef778))
|
||||
|
||||
## [0.8.2](https://github.com/discordjs/builders/compare/v0.8.1...v0.8.2) (2021-10-30)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- downgrade ow because of esm issues ([#55](https://github.com/discordjs/builders/issues/55)) ([3722d2c](https://github.com/discordjs/builders/commit/3722d2c1109a7a5c0abad63c1a7eb944df6e46c8))
|
||||
|
||||
## [0.8.1](https://github.com/discordjs/builders/compare/v0.8.0...v0.8.1) (2021-10-29)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- documentation ([e33ec8d](https://github.com/discordjs/builders/commit/e33ec8dfd5785312f82e0afb017a3dac614fd71d))
|
||||
|
||||
# [0.7.0](https://github.com/discordjs/builders/compare/v0.6.0...v0.7.0) (2021-10-18)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- properly type `toJSON` methods ([#34](https://github.com/discordjs/builders/issues/34)) ([7723ad0](https://github.com/discordjs/builders/commit/7723ad0da169386e638188de220451a97513bc25))
|
||||
|
||||
## Features
|
||||
|
||||
- **ContextMenus:** add context menu command builder ([#29](https://github.com/discordjs/builders/issues/29)) ([f0641e5](https://github.com/discordjs/builders/commit/f0641e55733de8992600f3082bcf054e6f815cf7))
|
||||
- add support for channel types on channel options ([#41](https://github.com/discordjs/builders/issues/41)) ([f6c187e](https://github.com/discordjs/builders/commit/f6c187e0ad6ebe03e65186ece3e95cb1db5aeb50))
|
||||
|
||||
# [0.6.0](https://github.com/discordjs/builders/compare/v0.5.0...v0.6.0) (2021-08-24)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **SlashCommandBuilder:** allow subcommands and groups to coexist at the root level ([#26](https://github.com/discordjs/builders/issues/26)) ([0be4daf](https://github.com/discordjs/builders/commit/0be4dafdfc0b5747c880be0078c00ada913eb4fb))
|
||||
|
||||
## Features
|
||||
|
||||
- create `Embed` builder ([#11](https://github.com/discordjs/builders/issues/11)) ([eb942a4](https://github.com/discordjs/builders/commit/eb942a4d1f3bcec9a4e370b6af602a713ad8f9b7))
|
||||
- **SlashCommandBuilder:** create setDefaultPermission function ([#19](https://github.com/discordjs/builders/issues/19)) ([5d53759](https://github.com/discordjs/builders/commit/5d537593937a8da330153ce4711b7d093a80330e))
|
||||
- **SlashCommands:** add number option type ([#23](https://github.com/discordjs/builders/issues/23)) ([1563991](https://github.com/discordjs/builders/commit/1563991d421bb07bf7a412c87e7613692d770f04))
|
||||
|
||||
# [0.5.0](https://github.com/discordjs/builders/compare/v0.3.0...v0.5.0) (2021-08-10)
|
||||
|
||||
## Features
|
||||
|
||||
- **Formatters:** add `formatEmoji` ([#20](https://github.com/discordjs/builders/issues/20)) ([c3d8bb5](https://github.com/discordjs/builders/commit/c3d8bb5363a1d46b45c0def4277da6921e2ba209))
|
||||
|
||||
# [0.4.0](https://github.com/discordjs/builders/compare/v0.3.0...v0.4.0) (2021-08-05)
|
||||
|
||||
## Features
|
||||
|
||||
- `sub command` => `subcommand` ([#18](https://github.com/discordjs/builders/pull/18)) ([95599c5](https://github.com/discordjs/builders/commit/95599c5b5366ebd054c4c277c52f1a44cda1209d))
|
||||
|
||||
# [0.3.0](https://github.com/discordjs/builders/compare/v0.2.0...v0.3.0) (2021-08-01)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **Shrug:** Update comment ([#14](https://github.com/discordjs/builders/issues/14)) ([6fa6c40](https://github.com/discordjs/builders/commit/6fa6c405f2ea733811677d3d1bfb1e2806d504d5))
|
||||
- shrug face rendering ([#13](https://github.com/discordjs/builders/issues/13)) ([6ad24ec](https://github.com/discordjs/builders/commit/6ad24ecd96c82b0f576e78e9e53fc7bf9c36ef5d))
|
||||
|
||||
## Features
|
||||
|
||||
- **formatters:** mentions ([#9](https://github.com/discordjs/builders/issues/9)) ([f83fe99](https://github.com/discordjs/builders/commit/f83fe99b83188ed999845751ffb005c687dbd60a))
|
||||
- **Formatters:** Add a spoiler function ([#16](https://github.com/discordjs/builders/issues/16)) ([c213a6a](https://github.com/discordjs/builders/commit/c213a6abb114f65653017a4edec4bdba2162d771))
|
||||
- **SlashCommands:** add slash command builders ([#3](https://github.com/discordjs/builders/issues/3)) ([6aa3af0](https://github.com/discordjs/builders/commit/6aa3af07b0ee342fff91f080914bb12b3ab773f8))
|
||||
- shrug, tableflip and unflip strings ([#5](https://github.com/discordjs/builders/issues/5)) ([de5fa82](https://github.com/discordjs/builders/commit/de5fa823cd6f1feba5b2d0a63b2cb1761dfd1814))
|
||||
|
||||
# [0.2.0](https://github.com/discordjs/builders/compare/v0.1.1...v0.2.0) (2021-07-03)
|
||||
|
||||
## Features
|
||||
|
||||
- **Formatters:** added `hyperlink` and `hideLinkEmbed` ([#4](https://github.com/discordjs/builders/issues/4)) ([c532daf](https://github.com/discordjs/builders/commit/c532daf2ba2feae75bf9668f63462e96a5314cff))
|
||||
|
||||
# [0.1.1](https://github.com/discordjs/builders/compare/v0.1.0...v0.1.1) (2021-06-30)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **Deps:** added `tslib` as dependency ([#2](https://github.com/discordjs/builders/issues/2)) ([5576ff3](https://github.com/discordjs/builders/commit/5576ff3b67136b957bed0ab8a4c655d5de322813))
|
||||
|
||||
# 0.1.0 (2021-06-30)
|
||||
|
||||
## Features
|
||||
|
||||
- added message formatters ([#1](https://github.com/discordjs/builders/issues/1)) ([765e46d](https://github.com/discordjs/builders/commit/765e46dac96c4e49d350243e5fad34c2bc738a7c))
|
||||
@@ -1,191 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2021 Noel Buechler
|
||||
Copyright 2021 Vlad Frangu
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,53 +0,0 @@
|
||||
<div align="center">
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/dt/@discordjs/builders.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js" ><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders" alt="Code coverage" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## Installation
|
||||
|
||||
**Node.js 16.9.0 or newer is required.**
|
||||
|
||||
```sh-session
|
||||
npm install @discordjs/builders
|
||||
yarn add @discordjs/builders
|
||||
pnpm add @discordjs/builders
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Here are some examples for the builders and utilities you can find in this package:
|
||||
|
||||
- [Slash Command Builders](https://github.com/discordjs/discord.js/blob/main/packages/builders/docs/examples/Slash%20Command%20Builders.md)
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/discord.js/tree/main/packages/website))
|
||||
- [Documentation](https://discord.js.org/#/docs/builders)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v13.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/builders)
|
||||
- [npm](https://www.npmjs.com/package/@discordjs/builders)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
## Contributing
|
||||
|
||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||
[documentation](https://discord.js.org/#/docs/builders).
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||
nudge in the right direction, please don't hesitate to join our official [discord.js Server](https://discord.gg/djs).
|
||||
@@ -1,151 +0,0 @@
|
||||
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
createComponentBuilder,
|
||||
SelectMenuBuilder,
|
||||
SelectMenuOptionBuilder,
|
||||
} from '../../src';
|
||||
|
||||
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.Button,
|
||||
label: 'test',
|
||||
custom_id: '123',
|
||||
style: ButtonStyle.Primary,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
custom_id: '1234',
|
||||
options: [
|
||||
{
|
||||
label: 'one',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'two',
|
||||
value: 'two',
|
||||
},
|
||||
],
|
||||
max_values: 10,
|
||||
min_values: 12,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('Action Row Components', () => {
|
||||
describe('Assertion Tests', () => {
|
||||
test('GIVEN valid components THEN do not throw', () => {
|
||||
expect(() => new ActionRowBuilder().addComponents(new ButtonBuilder())).not.toThrowError();
|
||||
expect(() => new ActionRowBuilder().setComponents(new ButtonBuilder())).not.toThrowError();
|
||||
expect(() => new ActionRowBuilder().addComponents([new ButtonBuilder()])).not.toThrowError();
|
||||
expect(() => new ActionRowBuilder().setComponents([new ButtonBuilder()])).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
|
||||
const actionRowData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.Button,
|
||||
label: 'button',
|
||||
style: ButtonStyle.Primary,
|
||||
custom_id: 'test',
|
||||
},
|
||||
{
|
||||
type: ComponentType.Button,
|
||||
label: 'link',
|
||||
style: ButtonStyle.Link,
|
||||
url: 'https://google.com',
|
||||
},
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
placeholder: 'test',
|
||||
custom_id: 'test',
|
||||
options: [
|
||||
{
|
||||
label: 'option',
|
||||
value: 'option',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(new ActionRowBuilder(actionRowData).toJSON()).toEqual(actionRowData);
|
||||
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
||||
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder options THEN valid JSON output is given', () => {
|
||||
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.Button,
|
||||
label: 'test',
|
||||
custom_id: '123',
|
||||
style: ButtonStyle.Primary,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
custom_id: '1234',
|
||||
options: [
|
||||
{
|
||||
label: 'one',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'two',
|
||||
value: 'two',
|
||||
},
|
||||
],
|
||||
max_values: 10,
|
||||
min_values: 12,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(new ActionRowBuilder(rowWithButtonData).toJSON()).toEqual(rowWithButtonData);
|
||||
expect(new ActionRowBuilder(rowWithSelectMenuData).toJSON()).toEqual(rowWithSelectMenuData);
|
||||
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
|
||||
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder options THEN valid JSON output is given 2', () => {
|
||||
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
||||
const selectMenu = new SelectMenuBuilder()
|
||||
.setCustomId('1234')
|
||||
.setMaxValues(10)
|
||||
.setMinValues(12)
|
||||
.setOptions(
|
||||
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
)
|
||||
.setOptions([
|
||||
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
]);
|
||||
|
||||
expect(new ActionRowBuilder().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
||||
expect(new ActionRowBuilder().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
|
||||
expect(new ActionRowBuilder().addComponents([button]).toJSON()).toEqual(rowWithButtonData);
|
||||
expect(new ActionRowBuilder().addComponents([selectMenu]).toJSON()).toEqual(rowWithSelectMenuData);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,147 +0,0 @@
|
||||
import {
|
||||
APIButtonComponentWithCustomId,
|
||||
APIButtonComponentWithURL,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
|
||||
import { ButtonBuilder } from '../../src/components/button/Button';
|
||||
|
||||
const buttonComponent = () => new ButtonBuilder();
|
||||
|
||||
const longStr =
|
||||
'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';
|
||||
|
||||
describe('Button Components', () => {
|
||||
describe('Assertion Tests', () => {
|
||||
test('GIVEN valid label THEN validator does not throw', () => {
|
||||
expect(() => buttonLabelValidator.parse('foobar')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid label THEN validator does throw', () => {
|
||||
expect(() => buttonLabelValidator.parse(null)).toThrowError();
|
||||
expect(() => buttonLabelValidator.parse('')).toThrowError();
|
||||
|
||||
expect(() => buttonLabelValidator.parse(longStr)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid style THEN validator does not throw', () => {
|
||||
expect(() => buttonStyleValidator.parse(3)).not.toThrowError();
|
||||
expect(() => buttonStyleValidator.parse(ButtonStyle.Secondary)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid style THEN validator does not throw', () => {
|
||||
expect(() => buttonStyleValidator.parse(7)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid fields THEN builder does not throw', () => {
|
||||
expect(() =>
|
||||
buttonComponent().setCustomId('custom').setStyle(ButtonStyle.Primary).setLabel('test'),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent()
|
||||
.setCustomId('custom')
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(true)
|
||||
.setEmoji({ name: 'test' });
|
||||
|
||||
button.toJSON();
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(() => buttonComponent().setURL('https://google.com')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid fields THEN build does throw', () => {
|
||||
expect(() => {
|
||||
buttonComponent().setCustomId(longStr);
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent()
|
||||
.setCustomId('custom')
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(true)
|
||||
.setLabel('test')
|
||||
.setURL('https://google.com')
|
||||
.setEmoji({ name: 'test' });
|
||||
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
const button = buttonComponent().setEmoji('test');
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setStyle(ButtonStyle.Primary);
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setStyle(ButtonStyle.Primary).setCustomId('test');
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setStyle(ButtonStyle.Link);
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setStyle(ButtonStyle.Primary).setLabel('test').setURL('https://google.com');
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const button = buttonComponent().setStyle(ButtonStyle.Link).setLabel('test');
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => buttonComponent().setStyle(24)).toThrowError();
|
||||
expect(() => buttonComponent().setLabel(longStr)).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => buttonComponent().setDisabled(0)).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => buttonComponent().setEmoji('foo')).toThrowError();
|
||||
|
||||
expect(() => buttonComponent().setURL('foobar')).toThrowError();
|
||||
});
|
||||
|
||||
test('GiVEN valid input THEN valid JSON outputs are given', () => {
|
||||
const interactionData: APIButtonComponentWithCustomId = {
|
||||
type: ComponentType.Button,
|
||||
custom_id: 'test',
|
||||
label: 'test',
|
||||
style: ButtonStyle.Primary,
|
||||
disabled: true,
|
||||
};
|
||||
|
||||
expect(new ButtonBuilder(interactionData).toJSON()).toEqual(interactionData);
|
||||
|
||||
expect(
|
||||
buttonComponent()
|
||||
.setCustomId(interactionData.custom_id)
|
||||
.setLabel(interactionData.label!)
|
||||
.setStyle(interactionData.style)
|
||||
.setDisabled(interactionData.disabled)
|
||||
.toJSON(),
|
||||
).toEqual(interactionData);
|
||||
|
||||
const linkData: APIButtonComponentWithURL = {
|
||||
type: ComponentType.Button,
|
||||
label: 'test',
|
||||
style: ButtonStyle.Link,
|
||||
disabled: true,
|
||||
url: 'https://google.com',
|
||||
};
|
||||
|
||||
expect(new ButtonBuilder(linkData).toJSON()).toEqual(linkData);
|
||||
|
||||
expect(buttonComponent().setLabel(linkData.label!).setDisabled(true).setURL(linkData.url));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,73 +0,0 @@
|
||||
import {
|
||||
APIActionRowComponent,
|
||||
APIButtonComponent,
|
||||
APIMessageActionRowComponent,
|
||||
APISelectMenuComponent,
|
||||
APITextInputComponent,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
TextInputStyle,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
createComponentBuilder,
|
||||
SelectMenuBuilder,
|
||||
TextInputBuilder,
|
||||
} from '../../src/index';
|
||||
|
||||
describe('createComponentBuilder', () => {
|
||||
test.each([ButtonBuilder, SelectMenuBuilder, TextInputBuilder])(
|
||||
'passing an instance of %j should return itself',
|
||||
(Builder) => {
|
||||
const builder = new Builder();
|
||||
expect(createComponentBuilder(builder)).toBe(builder);
|
||||
},
|
||||
);
|
||||
|
||||
test('GIVEN an action row component THEN returns a ActionRowBuilder', () => {
|
||||
const actionRow: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
components: [],
|
||||
type: ComponentType.ActionRow,
|
||||
};
|
||||
|
||||
expect(createComponentBuilder(actionRow)).toBeInstanceOf(ActionRowBuilder);
|
||||
});
|
||||
|
||||
test('GIVEN a button component THEN returns a ButtonBuilder', () => {
|
||||
const button: APIButtonComponent = {
|
||||
custom_id: 'abc',
|
||||
style: ButtonStyle.Primary,
|
||||
type: ComponentType.Button,
|
||||
};
|
||||
|
||||
expect(createComponentBuilder(button)).toBeInstanceOf(ButtonBuilder);
|
||||
});
|
||||
|
||||
test('GIVEN a select menu component THEN returns a SelectMenuBuilder', () => {
|
||||
const selectMenu: APISelectMenuComponent = {
|
||||
custom_id: 'abc',
|
||||
options: [],
|
||||
type: ComponentType.SelectMenu,
|
||||
};
|
||||
|
||||
expect(createComponentBuilder(selectMenu)).toBeInstanceOf(SelectMenuBuilder);
|
||||
});
|
||||
|
||||
test('GIVEN a text input component THEN returns a TextInputBuilder', () => {
|
||||
const textInput: APITextInputComponent = {
|
||||
custom_id: 'abc',
|
||||
label: 'abc',
|
||||
style: TextInputStyle.Short,
|
||||
type: ComponentType.TextInput,
|
||||
};
|
||||
|
||||
expect(createComponentBuilder(textInput)).toBeInstanceOf(TextInputBuilder);
|
||||
});
|
||||
|
||||
test('GIVEN an unknown component type THEN throws error', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => createComponentBuilder({ type: 'invalid' })).toThrowError();
|
||||
});
|
||||
});
|
||||
@@ -1,166 +0,0 @@
|
||||
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index';
|
||||
|
||||
const selectMenu = () => new SelectMenuBuilder();
|
||||
const selectMenuOption = () => new SelectMenuOptionBuilder();
|
||||
|
||||
const longStr = 'a'.repeat(256);
|
||||
|
||||
const selectMenuOptionData: APISelectMenuOption = {
|
||||
label: 'test',
|
||||
value: 'test',
|
||||
emoji: { name: 'test' },
|
||||
default: true,
|
||||
description: 'test',
|
||||
};
|
||||
|
||||
const selectMenuDataWithoutOptions = {
|
||||
type: ComponentType.SelectMenu,
|
||||
custom_id: 'test',
|
||||
max_values: 10,
|
||||
min_values: 3,
|
||||
disabled: true,
|
||||
placeholder: 'test',
|
||||
} as const;
|
||||
|
||||
const selectMenuData: APISelectMenuComponent = {
|
||||
...selectMenuDataWithoutOptions,
|
||||
options: [selectMenuOptionData],
|
||||
};
|
||||
|
||||
describe('Select Menu Components', () => {
|
||||
describe('Assertion Tests', () => {
|
||||
test('GIVEN valid inputs THEN Select Menu does not throw', () => {
|
||||
expect(() => selectMenu().setCustomId('foo')).not.toThrowError();
|
||||
expect(() => selectMenu().setMaxValues(10)).not.toThrowError();
|
||||
expect(() => selectMenu().setMinValues(3)).not.toThrowError();
|
||||
expect(() => selectMenu().setDisabled(true)).not.toThrowError();
|
||||
expect(() => selectMenu().setDisabled()).not.toThrowError();
|
||||
expect(() => selectMenu().setPlaceholder('description')).not.toThrowError();
|
||||
const option = selectMenuOption()
|
||||
.setLabel('test')
|
||||
.setValue('test')
|
||||
.setDefault(true)
|
||||
.setEmoji({ name: 'test' })
|
||||
.setDescription('description');
|
||||
expect(() => selectMenu().addOptions(option)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(option)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions({ label: 'test', value: 'test' })).not.toThrowError();
|
||||
expect(() => selectMenu().addOptions([option])).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions([option])).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions([{ label: 'test', value: 'test' }])).not.toThrowError();
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions({
|
||||
label: 'test',
|
||||
value: 'test',
|
||||
emoji: {
|
||||
id: '123',
|
||||
name: 'test',
|
||||
animated: true,
|
||||
},
|
||||
})
|
||||
.addOptions([
|
||||
{
|
||||
label: 'test',
|
||||
value: 'test',
|
||||
emoji: {
|
||||
id: '123',
|
||||
name: 'test',
|
||||
animated: true,
|
||||
},
|
||||
},
|
||||
]),
|
||||
).not.toThrowError();
|
||||
|
||||
const options = new Array<APISelectMenuOption>(25).fill({ label: 'test', value: 'test' });
|
||||
expect(() => selectMenu().addOptions(...options)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(...options)).not.toThrowError();
|
||||
expect(() => selectMenu().addOptions(options)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(options)).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions({ label: 'test', value: 'test' })
|
||||
.addOptions(...new Array<APISelectMenuOption>(24).fill({ label: 'test', value: 'test' })),
|
||||
).not.toThrowError();
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions([{ label: 'test', value: 'test' }])
|
||||
.addOptions(new Array<APISelectMenuOption>(24).fill({ label: 'test', value: 'test' })),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid inputs THEN Select Menu does throw', () => {
|
||||
expect(() => selectMenu().setCustomId(longStr)).toThrowError();
|
||||
expect(() => selectMenu().setMaxValues(30)).toThrowError();
|
||||
expect(() => selectMenu().setMinValues(-20)).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().setDisabled(0)).toThrowError();
|
||||
expect(() => selectMenu().setPlaceholder(longStr)).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ label: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ label: longStr, value: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ value: longStr, label: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', description: longStr })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', default: 100 })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ value: 'test' })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions({ default: true })).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions([{ label: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ label: longStr, value: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ value: longStr, label: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ label: 'test', value: 'test', description: longStr }])).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions([{ label: 'test', value: 'test', default: 100 }])).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions([{ value: 'test' }])).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => selectMenu().addOptions([{ default: true }])).toThrowError();
|
||||
|
||||
const tooManyOptions = new Array<APISelectMenuOption>(26).fill({ label: 'test', value: 'test' });
|
||||
expect(() => selectMenu().setOptions(...tooManyOptions)).toThrowError();
|
||||
expect(() => selectMenu().setOptions(tooManyOptions)).toThrowError();
|
||||
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions({ label: 'test', value: 'test' })
|
||||
.addOptions(...tooManyOptions),
|
||||
).toThrowError();
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions([{ label: 'test', value: 'test' }])
|
||||
.addOptions(tooManyOptions),
|
||||
).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
selectMenuOption()
|
||||
.setLabel(longStr)
|
||||
.setValue(longStr)
|
||||
// @ts-expect-error
|
||||
.setDefault(-1)
|
||||
// @ts-expect-error
|
||||
.setEmoji({ name: 1 })
|
||||
.setDescription(longStr);
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
|
||||
expect(
|
||||
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions(new SelectMenuOptionBuilder(selectMenuOptionData))
|
||||
.toJSON(),
|
||||
).toEqual(selectMenuData);
|
||||
expect(
|
||||
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions([new SelectMenuOptionBuilder(selectMenuOptionData)])
|
||||
.toJSON(),
|
||||
).toEqual(selectMenuData);
|
||||
expect(new SelectMenuOptionBuilder(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,133 +0,0 @@
|
||||
import { APITextInputComponent, ComponentType, TextInputStyle } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
labelValidator,
|
||||
maxLengthValidator,
|
||||
minLengthValidator,
|
||||
placeholderValidator,
|
||||
valueValidator,
|
||||
textInputStyleValidator,
|
||||
} from '../../src/components/textInput/Assertions';
|
||||
import { TextInputBuilder } from '../../src/components/textInput/TextInput';
|
||||
|
||||
const superLongStr = 'a'.repeat(5000);
|
||||
|
||||
const textInputComponent = () => new TextInputBuilder();
|
||||
|
||||
describe('Text Input Components', () => {
|
||||
describe('Assertion Tests', () => {
|
||||
test('GIVEN valid label THEN validator does not throw', () => {
|
||||
expect(() => labelValidator.parse('foobar')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid label THEN validator does throw', () => {
|
||||
expect(() => labelValidator.parse(24)).toThrowError();
|
||||
expect(() => labelValidator.parse(undefined)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid style THEN validator does not throw', () => {
|
||||
expect(() => textInputStyleValidator.parse(TextInputStyle.Paragraph)).not.toThrowError();
|
||||
expect(() => textInputStyleValidator.parse(TextInputStyle.Short)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid style THEN validator does throw', () => {
|
||||
expect(() => textInputStyleValidator.parse(24)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid min length THEN validator does not throw', () => {
|
||||
expect(() => minLengthValidator.parse(10)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid min length THEN validator does throw', () => {
|
||||
expect(() => minLengthValidator.parse(-1)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid max length THEN validator does not throw', () => {
|
||||
expect(() => maxLengthValidator.parse(10)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid min length THEN validator does throw 2', () => {
|
||||
expect(() => maxLengthValidator.parse(4001)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid value THEN validator does not throw', () => {
|
||||
expect(() => valueValidator.parse('foobar')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid value THEN validator does throw', () => {
|
||||
expect(() => valueValidator.parse(superLongStr)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid placeholder THEN validator does not throw', () => {
|
||||
expect(() => placeholderValidator.parse('foobar')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid value THEN validator does throw 2', () => {
|
||||
expect(() => placeholderValidator.parse(superLongStr)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid fields THEN builder does not throw', () => {
|
||||
expect(() => {
|
||||
textInputComponent().setCustomId('foobar').setLabel('test').setStyle(TextInputStyle.Paragraph).toJSON();
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(() => {
|
||||
textInputComponent()
|
||||
.setCustomId('foobar')
|
||||
.setLabel('test')
|
||||
.setMaxLength(100)
|
||||
.setMinLength(1)
|
||||
.setPlaceholder('bar')
|
||||
.setRequired(true)
|
||||
.setStyle(TextInputStyle.Paragraph)
|
||||
.toJSON();
|
||||
}).not.toThrowError();
|
||||
|
||||
expect(() => {
|
||||
// Issue #8107
|
||||
// @ts-expect-error: shapeshift maps the enum key to the value when parsing
|
||||
textInputComponent().setCustomId('Custom').setLabel('Guess').setStyle('Short').toJSON();
|
||||
}).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN invalid fields THEN builder throws', () => {
|
||||
expect(() => textInputComponent().toJSON()).toThrowError();
|
||||
expect(() => {
|
||||
textInputComponent()
|
||||
.setCustomId('test')
|
||||
.setMaxLength(100)
|
||||
.setPlaceholder('hello')
|
||||
.setStyle(TextInputStyle.Paragraph)
|
||||
.toJSON();
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid input THEN valid JSON outputs are given', () => {
|
||||
const textInputData: APITextInputComponent = {
|
||||
type: ComponentType.TextInput,
|
||||
label: 'label',
|
||||
custom_id: 'custom id',
|
||||
placeholder: 'placeholder',
|
||||
max_length: 100,
|
||||
min_length: 10,
|
||||
value: 'value',
|
||||
required: false,
|
||||
style: TextInputStyle.Paragraph,
|
||||
};
|
||||
|
||||
expect(new TextInputBuilder(textInputData).toJSON()).toEqual(textInputData);
|
||||
expect(
|
||||
textInputComponent()
|
||||
.setCustomId(textInputData.custom_id)
|
||||
.setLabel(textInputData.label)
|
||||
.setPlaceholder(textInputData.placeholder!)
|
||||
.setMaxLength(textInputData.max_length!)
|
||||
.setMinLength(textInputData.min_length!)
|
||||
.setValue(textInputData.value!)
|
||||
.setRequired(textInputData.required)
|
||||
.setStyle(textInputData.style)
|
||||
.toJSON(),
|
||||
).toEqual(textInputData);
|
||||
});
|
||||
});
|
||||
@@ -1,148 +0,0 @@
|
||||
import { PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index';
|
||||
|
||||
const getBuilder = () => new ContextMenuCommandBuilder();
|
||||
|
||||
describe('Context Menu Commands', () => {
|
||||
describe('Assertions tests', () => {
|
||||
test('GIVEN valid name THEN does not throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateName('ping')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid name THEN throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateName(null)).toThrowError();
|
||||
|
||||
// Too short of a name
|
||||
expect(() => ContextMenuCommandAssertions.validateName('')).toThrowError();
|
||||
|
||||
// Invalid characters used
|
||||
expect(() => ContextMenuCommandAssertions.validateName('ABC123$%^&')).toThrowError();
|
||||
|
||||
// Too long of a name
|
||||
expect(() =>
|
||||
ContextMenuCommandAssertions.validateName('qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid type THEN does not throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateType(3)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid type THEN throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateType(null)).toThrowError();
|
||||
|
||||
// Out of range
|
||||
expect(() => ContextMenuCommandAssertions.validateType(1)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid required parameters THEN does not throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateRequiredParameters('owo', 2)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid default_permission THEN does not throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateDefaultPermission(true)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid default_permission THEN throw error', () => {
|
||||
expect(() => ContextMenuCommandAssertions.validateDefaultPermission(null)).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ContextMenuCommandBuilder', () => {
|
||||
describe('Builder tests', () => {
|
||||
test('GIVEN empty builder THEN throw error when calling toJSON', () => {
|
||||
expect(() => getBuilder().toJSON()).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('example').setType(3).toJSON()).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid name THEN throw error', () => {
|
||||
expect(() => getBuilder().setName('$$$')).toThrowError();
|
||||
|
||||
expect(() => getBuilder().setName(' ')).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid names THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('hi_there')).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().setName('A COMMAND')).not.toThrowError();
|
||||
|
||||
// Translation: a_command
|
||||
expect(() => getBuilder().setName('o_comandă')).not.toThrowError();
|
||||
|
||||
// Translation: thx (according to GTranslate)
|
||||
expect(() => getBuilder().setName('どうも')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid types THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setType(2)).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().setType(3)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder with defaultPermission false THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('foo').setDefaultPermission(false)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder with dmPermission false THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('foo').setDMPermission(false)).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Context menu command localizations', () => {
|
||||
const expectedSingleLocale = { 'en-US': 'foobar' };
|
||||
const expectedMultipleLocales = {
|
||||
...expectedSingleLocale,
|
||||
bg: 'test',
|
||||
};
|
||||
|
||||
test('GIVEN valid name localizations THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setNameLocalization('en-US', 'foobar')).not.toThrowError();
|
||||
expect(() => getBuilder().setNameLocalizations({ 'en-US': 'foobar' })).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid name localizations THEN does throw error', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' })).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid name localizations THEN valid data is stored', () => {
|
||||
expect(getBuilder().setNameLocalization('en-US', 'foobar').name_localizations).toEqual(expectedSingleLocale);
|
||||
expect(getBuilder().setNameLocalizations({ 'en-US': 'foobar', bg: 'test' }).name_localizations).toEqual(
|
||||
expectedMultipleLocales,
|
||||
);
|
||||
expect(getBuilder().setNameLocalizations(null).name_localizations).toBeNull();
|
||||
expect(getBuilder().setNameLocalization('en-US', null).name_localizations).toEqual({
|
||||
'en-US': null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('permissions', () => {
|
||||
test('GIVEN valid permission string THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions('1')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid permission bitfield THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setDefaultMemberPermissions(PermissionFlagsBits.AddReactions | PermissionFlagsBits.AttachFiles),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN null permissions THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions(null)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid inputs THEN does throw error', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions('1.1')).toThrowError();
|
||||
|
||||
expect(() => getBuilder().setDefaultMemberPermissions(1.1)).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,222 +0,0 @@
|
||||
import {
|
||||
APIApplicationCommandAttachmentOption,
|
||||
APIApplicationCommandBooleanOption,
|
||||
APIApplicationCommandChannelOption,
|
||||
APIApplicationCommandIntegerOption,
|
||||
APIApplicationCommandMentionableOption,
|
||||
APIApplicationCommandNumberOption,
|
||||
APIApplicationCommandRoleOption,
|
||||
APIApplicationCommandStringOption,
|
||||
APIApplicationCommandUserOption,
|
||||
ApplicationCommandOptionType,
|
||||
ChannelType,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
SlashCommandAttachmentOption,
|
||||
SlashCommandBooleanOption,
|
||||
SlashCommandChannelOption,
|
||||
SlashCommandIntegerOption,
|
||||
SlashCommandMentionableOption,
|
||||
SlashCommandNumberOption,
|
||||
SlashCommandRoleOption,
|
||||
SlashCommandStringOption,
|
||||
SlashCommandUserOption,
|
||||
} from '../../../src/index';
|
||||
|
||||
const getBooleanOption = () =>
|
||||
new SlashCommandBooleanOption().setName('owo').setDescription('Testing 123').setRequired(true);
|
||||
|
||||
const getChannelOption = () =>
|
||||
new SlashCommandChannelOption()
|
||||
.setName('owo')
|
||||
.setDescription('Testing 123')
|
||||
.setRequired(true)
|
||||
.addChannelTypes(ChannelType.GuildText);
|
||||
|
||||
const getStringOption = () =>
|
||||
new SlashCommandStringOption().setName('owo').setDescription('Testing 123').setRequired(true);
|
||||
|
||||
const getIntegerOption = () =>
|
||||
new SlashCommandIntegerOption()
|
||||
.setName('owo')
|
||||
.setDescription('Testing 123')
|
||||
.setRequired(true)
|
||||
.setMinValue(-1)
|
||||
.setMaxValue(10);
|
||||
|
||||
const getNumberOption = () =>
|
||||
new SlashCommandNumberOption()
|
||||
.setName('owo')
|
||||
.setDescription('Testing 123')
|
||||
.setRequired(true)
|
||||
.setMinValue(-1.23)
|
||||
.setMaxValue(10);
|
||||
|
||||
const getUserOption = () => new SlashCommandUserOption().setName('owo').setDescription('Testing 123').setRequired(true);
|
||||
|
||||
const getRoleOption = () => new SlashCommandRoleOption().setName('owo').setDescription('Testing 123').setRequired(true);
|
||||
|
||||
const getMentionableOption = () =>
|
||||
new SlashCommandMentionableOption().setName('owo').setDescription('Testing 123').setRequired(true);
|
||||
|
||||
const getAttachmentOption = () =>
|
||||
new SlashCommandAttachmentOption().setName('attachment').setDescription('attachment').setRequired(true);
|
||||
|
||||
describe('Application Command toJSON() results', () => {
|
||||
test('GIVEN a boolean option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getBooleanOption().toJSON()).toEqual<APIApplicationCommandBooleanOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Boolean,
|
||||
required: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN a channel option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getChannelOption().toJSON()).toEqual<APIApplicationCommandChannelOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Channel,
|
||||
required: true,
|
||||
channel_types: [ChannelType.GuildText],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN a integer option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getIntegerOption().toJSON()).toEqual<APIApplicationCommandIntegerOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Integer,
|
||||
required: true,
|
||||
max_value: 10,
|
||||
min_value: -1,
|
||||
});
|
||||
|
||||
expect(getIntegerOption().setAutocomplete(true).setChoices().toJSON()).toEqual<APIApplicationCommandIntegerOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Integer,
|
||||
required: true,
|
||||
max_value: 10,
|
||||
min_value: -1,
|
||||
autocomplete: true,
|
||||
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
choices: [],
|
||||
});
|
||||
|
||||
expect(
|
||||
getIntegerOption().addChoices({ name: 'uwu', value: 1 }).toJSON(),
|
||||
).toEqual<APIApplicationCommandIntegerOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Integer,
|
||||
required: true,
|
||||
max_value: 10,
|
||||
min_value: -1,
|
||||
choices: [{ name: 'uwu', value: 1 }],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN a mentionable option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getMentionableOption().toJSON()).toEqual<APIApplicationCommandMentionableOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Mentionable,
|
||||
required: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN a number option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getNumberOption().toJSON()).toEqual<APIApplicationCommandNumberOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Number,
|
||||
required: true,
|
||||
max_value: 10,
|
||||
min_value: -1.23,
|
||||
});
|
||||
|
||||
expect(getNumberOption().setAutocomplete(true).setChoices().toJSON()).toEqual<APIApplicationCommandNumberOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Number,
|
||||
required: true,
|
||||
max_value: 10,
|
||||
min_value: -1.23,
|
||||
autocomplete: true,
|
||||
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
choices: [],
|
||||
});
|
||||
|
||||
expect(getNumberOption().addChoices({ name: 'uwu', value: 1 }).toJSON()).toEqual<APIApplicationCommandNumberOption>(
|
||||
{
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Number,
|
||||
required: true,
|
||||
max_value: 10,
|
||||
min_value: -1.23,
|
||||
choices: [{ name: 'uwu', value: 1 }],
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN a role option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getRoleOption().toJSON()).toEqual<APIApplicationCommandRoleOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.Role,
|
||||
required: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN a string option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getStringOption().setMinLength(1).setMaxLength(10).toJSON()).toEqual<APIApplicationCommandStringOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
max_length: 10,
|
||||
min_length: 1,
|
||||
});
|
||||
|
||||
expect(getStringOption().setAutocomplete(true).setChoices().toJSON()).toEqual<APIApplicationCommandStringOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
choices: [],
|
||||
});
|
||||
|
||||
expect(
|
||||
getStringOption().addChoices({ name: 'uwu', value: '1' }).toJSON(),
|
||||
).toEqual<APIApplicationCommandStringOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
choices: [{ name: 'uwu', value: '1' }],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN a user option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getUserOption().toJSON()).toEqual<APIApplicationCommandUserOption>({
|
||||
name: 'owo',
|
||||
description: 'Testing 123',
|
||||
type: ApplicationCommandOptionType.User,
|
||||
required: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an attachment option THEN calling toJSON should return a valid JSON', () => {
|
||||
expect(getAttachmentOption().toJSON()).toEqual<APIApplicationCommandAttachmentOption>({
|
||||
name: 'attachment',
|
||||
description: 'attachment',
|
||||
type: ApplicationCommandOptionType.Attachment,
|
||||
required: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,512 +0,0 @@
|
||||
import { APIApplicationCommandOptionChoice, ChannelType, PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
SlashCommandAssertions,
|
||||
SlashCommandBooleanOption,
|
||||
SlashCommandBuilder,
|
||||
SlashCommandChannelOption,
|
||||
SlashCommandIntegerOption,
|
||||
SlashCommandMentionableOption,
|
||||
SlashCommandNumberOption,
|
||||
SlashCommandRoleOption,
|
||||
SlashCommandAttachmentOption,
|
||||
SlashCommandStringOption,
|
||||
SlashCommandSubcommandBuilder,
|
||||
SlashCommandSubcommandGroupBuilder,
|
||||
SlashCommandUserOption,
|
||||
} from '../../../src/index';
|
||||
|
||||
const largeArray = Array.from({ length: 26 }, () => 1 as unknown as APIApplicationCommandOptionChoice);
|
||||
|
||||
const getBuilder = () => new SlashCommandBuilder();
|
||||
const getNamedBuilder = () => getBuilder().setName('example').setDescription('Example command');
|
||||
const getStringOption = () => new SlashCommandStringOption().setName('owo').setDescription('Testing 123');
|
||||
const getIntegerOption = () => new SlashCommandIntegerOption().setName('owo').setDescription('Testing 123');
|
||||
const getNumberOption = () => new SlashCommandNumberOption().setName('owo').setDescription('Testing 123');
|
||||
const getBooleanOption = () => new SlashCommandBooleanOption().setName('owo').setDescription('Testing 123');
|
||||
const getUserOption = () => new SlashCommandUserOption().setName('owo').setDescription('Testing 123');
|
||||
const getChannelOption = () => new SlashCommandChannelOption().setName('owo').setDescription('Testing 123');
|
||||
const getRoleOption = () => new SlashCommandRoleOption().setName('owo').setDescription('Testing 123');
|
||||
const getAttachmentOption = () => new SlashCommandAttachmentOption().setName('owo').setDescription('Testing 123');
|
||||
const getMentionableOption = () => new SlashCommandMentionableOption().setName('owo').setDescription('Testing 123');
|
||||
const getSubcommandGroup = () => new SlashCommandSubcommandGroupBuilder().setName('owo').setDescription('Testing 123');
|
||||
const getSubcommand = () => new SlashCommandSubcommandBuilder().setName('owo').setDescription('Testing 123');
|
||||
|
||||
class Collection {
|
||||
public get [Symbol.toStringTag]() {
|
||||
return 'Map';
|
||||
}
|
||||
}
|
||||
|
||||
describe('Slash Commands', () => {
|
||||
describe('Assertions tests', () => {
|
||||
test('GIVEN valid name THEN does not throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateName('ping')).not.toThrowError();
|
||||
expect(() => SlashCommandAssertions.validateName('hello-world_command')).not.toThrowError();
|
||||
expect(() => SlashCommandAssertions.validateName('aˇ㐆1٢〣²अก')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid name THEN throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateName(null)).toThrowError();
|
||||
|
||||
// Too short of a name
|
||||
expect(() => SlashCommandAssertions.validateName('')).toThrowError();
|
||||
|
||||
// Invalid characters used
|
||||
expect(() => SlashCommandAssertions.validateName('ABC')).toThrowError();
|
||||
expect(() => SlashCommandAssertions.validateName('ABC123$%^&')).toThrowError();
|
||||
expect(() => SlashCommandAssertions.validateName('help ping')).toThrowError();
|
||||
expect(() => SlashCommandAssertions.validateName('🦦')).toThrowError();
|
||||
|
||||
// Too long of a name
|
||||
expect(() =>
|
||||
SlashCommandAssertions.validateName('qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid description THEN does not throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateDescription('This is an OwO moment fur sure!~')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid description THEN throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateDescription(null)).toThrowError();
|
||||
|
||||
// Too short of a description
|
||||
expect(() => SlashCommandAssertions.validateDescription('')).toThrowError();
|
||||
|
||||
// Too long of a description
|
||||
expect(() =>
|
||||
SlashCommandAssertions.validateDescription(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magnam autem libero expedita vitae accusamus nostrum ipsam tempore repudiandae deserunt ipsum facilis, velit fugiat facere accusantium, explicabo corporis aliquam non quos.',
|
||||
),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid default_permission THEN does not throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateDefaultPermission(true)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid default_permission THEN throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateDefaultPermission(null)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid array of options or choices THEN does not throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateMaxOptionsLength([])).not.toThrowError();
|
||||
|
||||
expect(() => SlashCommandAssertions.validateChoicesLength(25)).not.toThrowError();
|
||||
expect(() => SlashCommandAssertions.validateChoicesLength(25, [])).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid options or choices THEN throw error', () => {
|
||||
expect(() => SlashCommandAssertions.validateMaxOptionsLength(null)).toThrowError();
|
||||
|
||||
// Given an array that's too big
|
||||
expect(() => SlashCommandAssertions.validateMaxOptionsLength(largeArray)).toThrowError();
|
||||
|
||||
expect(() => SlashCommandAssertions.validateChoicesLength(1, largeArray)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid required parameters THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
SlashCommandAssertions.validateRequiredParameters(
|
||||
'owo',
|
||||
'My fancy command that totally exists, to test assertions',
|
||||
[],
|
||||
),
|
||||
).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('SlashCommandBuilder', () => {
|
||||
describe('Builder with no options', () => {
|
||||
test('GIVEN empty builder THEN throw error when calling toJSON', () => {
|
||||
expect(() => getBuilder().toJSON()).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('example').setDescription('Example command').toJSON()).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Builder with simple options', () => {
|
||||
test('GIVEN valid builder with options THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
getBuilder()
|
||||
.setName('example')
|
||||
.setDescription('Example command')
|
||||
.setDMPermission(false)
|
||||
.addBooleanOption((boolean) =>
|
||||
boolean.setName('iscool').setDescription('Are we cool or what?').setRequired(true),
|
||||
)
|
||||
.addChannelOption((channel) => channel.setName('iscool').setDescription('Are we cool or what?'))
|
||||
.addMentionableOption((mentionable) => mentionable.setName('iscool').setDescription('Are we cool or what?'))
|
||||
.addRoleOption((role) => role.setName('iscool').setDescription('Are we cool or what?'))
|
||||
.addUserOption((user) => user.setName('iscool').setDescription('Are we cool or what?'))
|
||||
.addIntegerOption((integer) =>
|
||||
integer
|
||||
.setName('iscool')
|
||||
.setDescription('Are we cool or what?')
|
||||
.addChoices({ name: 'Very cool', value: 1_000 }),
|
||||
)
|
||||
.addNumberOption((number) =>
|
||||
number
|
||||
.setName('iscool')
|
||||
.setDescription('Are we cool or what?')
|
||||
.addChoices({ name: 'Very cool', value: 1.5 }),
|
||||
)
|
||||
.addStringOption((string) =>
|
||||
string
|
||||
.setName('iscool')
|
||||
.setDescription('Are we cool or what?')
|
||||
.addChoices(
|
||||
{ name: 'Fancy Pants', value: 'fp_1' },
|
||||
{ name: 'Fancy Shoes', value: 'fs_1' },
|
||||
{ name: 'The Whole shebang', value: 'all' },
|
||||
),
|
||||
)
|
||||
.addIntegerOption((integer) =>
|
||||
integer.setName('iscool').setDescription('Are we cool or what?').setAutocomplete(true),
|
||||
)
|
||||
.addNumberOption((number) =>
|
||||
number.setName('iscool').setDescription('Are we cool or what?').setAutocomplete(true),
|
||||
)
|
||||
.addStringOption((string) =>
|
||||
string.setName('iscool').setDescription('Are we cool or what?').setAutocomplete(true),
|
||||
)
|
||||
.toJSON(),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid autocomplete THEN does throw an error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addStringOption(getStringOption().setAutocomplete('not a boolean'))).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with both choices and autocomplete THEN does throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().addStringOption(
|
||||
getStringOption().setAutocomplete(true).addChoices({ name: 'Fancy Pants', value: 'fp_1' }),
|
||||
),
|
||||
).toThrowError();
|
||||
|
||||
expect(() =>
|
||||
getBuilder().addStringOption(
|
||||
getStringOption()
|
||||
.setAutocomplete(true)
|
||||
.addChoices(
|
||||
{ name: 'Fancy Pants', value: 'fp_1' },
|
||||
{ name: 'Fancy Shoes', value: 'fs_1' },
|
||||
{ name: 'The Whole shebang', value: 'all' },
|
||||
),
|
||||
),
|
||||
).toThrowError();
|
||||
|
||||
expect(() =>
|
||||
getBuilder().addStringOption(
|
||||
getStringOption().addChoices({ name: 'Fancy Pants', value: 'fp_1' }).setAutocomplete(true),
|
||||
),
|
||||
).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const option = getStringOption();
|
||||
Reflect.set(option, 'autocomplete', true);
|
||||
Reflect.set(option, 'choices', [{ name: 'Fancy Pants', value: 'fp_1' }]);
|
||||
return option.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const option = getNumberOption();
|
||||
Reflect.set(option, 'autocomplete', true);
|
||||
Reflect.set(option, 'choices', [{ name: 'Fancy Pants', value: 'fp_1' }]);
|
||||
return option.toJSON();
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
const option = getIntegerOption();
|
||||
Reflect.set(option, 'autocomplete', true);
|
||||
Reflect.set(option, 'choices', [{ name: 'Fancy Pants', value: 'fp_1' }]);
|
||||
return option.toJSON();
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with valid channel options and channel_types THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().addChannelOption(getChannelOption().addChannelTypes(ChannelType.GuildText)),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() => {
|
||||
getBuilder().addChannelOption(
|
||||
getChannelOption().addChannelTypes(ChannelType.GuildNews, ChannelType.GuildText),
|
||||
);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with valid channel options and channel_types THEN does throw an error', () => {
|
||||
expect(() => getBuilder().addChannelOption(getChannelOption().addChannelTypes(100))).toThrowError();
|
||||
|
||||
expect(() => getBuilder().addChannelOption(getChannelOption().addChannelTypes(100, 200))).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid number min/max options THEN does throw an error', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption().setMaxValue('test'))).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMaxValue('test'))).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption().setMinValue('test'))).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue('test'))).toThrowError();
|
||||
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue(1.5))).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a builder with valid number min/max options THEN does not throw an error', () => {
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue(1))).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption().setMinValue(1.5))).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMaxValue(1))).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption().setMaxValue(1.5))).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an already built builder THEN does not throw an error', () => {
|
||||
expect(() => getBuilder().addStringOption(getStringOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addBooleanOption(getBooleanOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addUserOption(getUserOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addChannelOption(getChannelOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addRoleOption(getRoleOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addAttachmentOption(getAttachmentOption())).not.toThrowError();
|
||||
|
||||
expect(() => getBuilder().addMentionableOption(getMentionableOption())).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN no valid return for an addOption method THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(getRoleOption())).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid name THEN throw error', () => {
|
||||
expect(() => getBuilder().setName('TEST_COMMAND')).toThrowError();
|
||||
|
||||
expect(() => getBuilder().setName('ĂĂĂĂĂĂ')).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid names THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('hi_there')).not.toThrowError();
|
||||
|
||||
// Translation: a_command
|
||||
expect(() => getBuilder().setName('o_comandă')).not.toThrowError();
|
||||
|
||||
// Translation: thx (according to GTranslate)
|
||||
expect(() => getBuilder().setName('どうも')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid returns for builder THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(true)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(null)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(undefined)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(() => SlashCommandStringOption)).toThrowError();
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(() => new Collection())).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid builder with defaultPermission false THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setName('foo').setDescription('foo').setDefaultPermission(false)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an option that is autocompletable and has choices, THEN passing nothing to setChoices should not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().addStringOption(getStringOption().setAutocomplete(true).setChoices()),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an option that is autocompletable, THEN setting choices should throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().addStringOption(
|
||||
getStringOption().setAutocomplete(true).setChoices({ name: 'owo', value: 'uwu' }),
|
||||
),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an option, THEN setting choices should not throw an error', () => {
|
||||
expect(() =>
|
||||
getBuilder().addStringOption(getStringOption().setChoices({ name: 'owo', value: 'uwu' })),
|
||||
).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Builder with subcommand (group) options', () => {
|
||||
test('GIVEN builder with subcommand group THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
getNamedBuilder().addSubcommandGroup((group) => group.setName('group').setDescription('Group us together!')),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with subcommand THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
getNamedBuilder().addSubcommand((subcommand) =>
|
||||
subcommand.setName('boop').setDescription('Boops a fellow nerd (you)'),
|
||||
),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with already built subcommand group THEN does not throw error', () => {
|
||||
expect(() => getNamedBuilder().addSubcommandGroup(getSubcommandGroup())).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with already built subcommand THEN does not throw error', () => {
|
||||
expect(() => getNamedBuilder().addSubcommand(getSubcommand())).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with already built subcommand with options THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
getNamedBuilder().addSubcommand(getSubcommand().addBooleanOption(getBooleanOption())),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with a subcommand that tries to add an invalid result THEN throw error', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error Checking if check works JS-side too
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
|
||||
getNamedBuilder().addSubcommand(getSubcommand()).addInteger(getInteger()),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN no valid return for an addSubcommand(Group) method THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addSubcommandGroup()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addSubcommand()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addSubcommand(getSubcommandGroup())).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Subcommand group builder', () => {
|
||||
test('GIVEN no valid subcommand THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getSubcommandGroup().addSubcommand()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getSubcommandGroup().addSubcommand(getSubcommandGroup())).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN a valid subcommand THEN does not throw an error', () => {
|
||||
expect(() =>
|
||||
getSubcommandGroup()
|
||||
.addSubcommand((sub) => sub.setName('sub').setDescription('Testing 123'))
|
||||
.toJSON(),
|
||||
).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Subcommand builder', () => {
|
||||
test('GIVEN a valid subcommand with options THEN does not throw error', () => {
|
||||
expect(() => getSubcommand().addBooleanOption(getBooleanOption()).toJSON()).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Slash command localizations', () => {
|
||||
const expectedSingleLocale = { 'en-US': 'foobar' };
|
||||
const expectedMultipleLocales = {
|
||||
...expectedSingleLocale,
|
||||
bg: 'test',
|
||||
};
|
||||
|
||||
test('GIVEN valid name localizations THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setNameLocalization('en-US', 'foobar')).not.toThrowError();
|
||||
expect(() => getBuilder().setNameLocalizations({ 'en-US': 'foobar' })).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid name localizations THEN does throw error', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' })).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid name localizations THEN valid data is stored', () => {
|
||||
expect(getBuilder().setNameLocalization('en-US', 'foobar').name_localizations).toEqual(expectedSingleLocale);
|
||||
expect(getBuilder().setNameLocalizations({ 'en-US': 'foobar', bg: 'test' }).name_localizations).toEqual(
|
||||
expectedMultipleLocales,
|
||||
);
|
||||
expect(getBuilder().setNameLocalizations(null).name_localizations).toBeNull();
|
||||
expect(getBuilder().setNameLocalization('en-US', null).name_localizations).toEqual({
|
||||
'en-US': null,
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN valid description localizations THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setDescriptionLocalization('en-US', 'foobar')).not.toThrowError();
|
||||
expect(() => getBuilder().setDescriptionLocalizations({ 'en-US': 'foobar' })).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid description localizations THEN does throw error', () => {
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().setDescriptionLocalization('en-U', 'foobar')).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => getBuilder().setDescriptionLocalizations({ 'en-U': 'foobar' })).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid description localizations THEN valid data is stored', () => {
|
||||
expect(getBuilder().setDescriptionLocalization('en-US', 'foobar').description_localizations).toEqual(
|
||||
expectedSingleLocale,
|
||||
);
|
||||
expect(
|
||||
getBuilder().setDescriptionLocalizations({ 'en-US': 'foobar', bg: 'test' }).description_localizations,
|
||||
).toEqual(expectedMultipleLocales);
|
||||
expect(getBuilder().setDescriptionLocalizations(null).description_localizations).toBeNull();
|
||||
expect(getBuilder().setDescriptionLocalization('en-US', null).description_localizations).toEqual({
|
||||
'en-US': null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('permissions', () => {
|
||||
test('GIVEN valid permission string THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions('1')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid permission bitfield THEN does not throw error', () => {
|
||||
expect(() =>
|
||||
getBuilder().setDefaultMemberPermissions(PermissionFlagsBits.AddReactions | PermissionFlagsBits.AttachFiles),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN null permissions THEN does not throw error', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions(null)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid inputs THEN does throw error', () => {
|
||||
expect(() => getBuilder().setDefaultMemberPermissions('1.1')).toThrowError();
|
||||
|
||||
expect(() => getBuilder().setDefaultMemberPermissions(1.1)).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,173 +0,0 @@
|
||||
import {
|
||||
APIModalInteractionResponseCallbackData,
|
||||
APITextInputComponent,
|
||||
ComponentType,
|
||||
TextInputStyle,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ModalBuilder,
|
||||
ModalActionRowComponentBuilder,
|
||||
TextInputBuilder,
|
||||
} from '../../src';
|
||||
import {
|
||||
componentsValidator,
|
||||
titleValidator,
|
||||
validateRequiredParameters,
|
||||
} from '../../src/interactions/modals/Assertions';
|
||||
|
||||
const modal = () => new ModalBuilder();
|
||||
|
||||
describe('Modals', () => {
|
||||
describe('Assertion Tests', () => {
|
||||
test('GIVEN valid title THEN validator does not throw', () => {
|
||||
expect(() => titleValidator.parse('foobar')).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid title THEN validator does throw', () => {
|
||||
expect(() => titleValidator.parse(42)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid components THEN validator does not throw', () => {
|
||||
expect(() => componentsValidator.parse([new ActionRowBuilder(), new ActionRowBuilder()])).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid components THEN validator does throw', () => {
|
||||
expect(() => componentsValidator.parse([new ButtonBuilder(), new TextInputBuilder()])).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid required parameters THEN validator does not throw', () => {
|
||||
expect(() =>
|
||||
validateRequiredParameters('123', 'title', [new ActionRowBuilder(), new ActionRowBuilder()]),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid required parameters THEN validator does throw', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error
|
||||
validateRequiredParameters('123', undefined, [new ActionRowBuilder(), new ButtonBuilder()]),
|
||||
).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN valid fields THEN builder does not throw', () => {
|
||||
expect(() =>
|
||||
modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRowBuilder()),
|
||||
).not.toThrowError();
|
||||
|
||||
expect(() =>
|
||||
// @ts-expect-error: You can pass a TextInputBuilder and it will add it to an action row
|
||||
modal().setTitle('test').setCustomId('foobar').addComponents(new TextInputBuilder()),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid fields THEN builder does throw', () => {
|
||||
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid input THEN valid JSON outputs are given', () => {
|
||||
const modalData: APIModalInteractionResponseCallbackData = {
|
||||
title: 'title',
|
||||
custom_id: 'custom id',
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.TextInput,
|
||||
label: 'label',
|
||||
style: TextInputStyle.Paragraph,
|
||||
custom_id: 'custom id',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.TextInput,
|
||||
label: 'label',
|
||||
style: TextInputStyle.Paragraph,
|
||||
custom_id: 'custom id',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(new ModalBuilder(modalData).toJSON()).toEqual(modalData);
|
||||
|
||||
expect(
|
||||
modal()
|
||||
.setTitle(modalData.title)
|
||||
.setCustomId('custom id')
|
||||
.setComponents(
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
|
||||
),
|
||||
)
|
||||
.addComponents([
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
|
||||
),
|
||||
])
|
||||
.toJSON(),
|
||||
).toEqual(modalData);
|
||||
});
|
||||
|
||||
describe('equals()', () => {
|
||||
const textInput1 = new TextInputBuilder()
|
||||
.setCustomId('custom id')
|
||||
.setLabel('label')
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
|
||||
const textInput2: APITextInputComponent = {
|
||||
type: ComponentType.TextInput,
|
||||
custom_id: 'custom id',
|
||||
label: 'label',
|
||||
style: TextInputStyle.Paragraph,
|
||||
};
|
||||
|
||||
test('GIVEN equal builders THEN returns true', () => {
|
||||
const equalTextInput = new TextInputBuilder()
|
||||
.setCustomId('custom id')
|
||||
.setLabel('label')
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
|
||||
expect(textInput1.equals(equalTextInput)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('GIVEN the same builder THEN returns true', () => {
|
||||
expect(textInput1.equals(textInput1)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('GIVEN equal builder and data THEN returns true', () => {
|
||||
expect(textInput1.equals(textInput2)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('GIVEN different builders THEN returns false', () => {
|
||||
const diffTextInput = new TextInputBuilder()
|
||||
.setCustomId('custom id')
|
||||
.setLabel('label 2')
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
|
||||
expect(textInput1.equals(diffTextInput)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('GIVEN different text input builder and data THEN returns false', () => {
|
||||
const diffTextInputData: APITextInputComponent = {
|
||||
type: ComponentType.TextInput,
|
||||
custom_id: 'custom id',
|
||||
label: 'label 2',
|
||||
style: TextInputStyle.Short,
|
||||
};
|
||||
|
||||
expect(textInput1.equals(diffTextInputData)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,418 +0,0 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { EmbedBuilder, embedLength } from '../../src';
|
||||
|
||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
describe('Embed', () => {
|
||||
describe('Embed getters', () => {
|
||||
test('GIVEN an embed with specific amount of characters THEN returns amount of characters', () => {
|
||||
const embed = new EmbedBuilder({
|
||||
title: alpha,
|
||||
description: alpha,
|
||||
fields: [{ name: alpha, value: alpha }],
|
||||
author: { name: alpha },
|
||||
footer: { text: alpha },
|
||||
});
|
||||
|
||||
expect(embedLength(embed.data)).toEqual(alpha.length * 6);
|
||||
});
|
||||
|
||||
test('GIVEN an embed with zero characters THEN returns amount of characters', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(embedLength(embed.data)).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed title', () => {
|
||||
test('GIVEN an embed with a pre-defined title THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ title: 'foo' });
|
||||
expect(embed.toJSON()).toStrictEqual({ title: 'foo' });
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setTitle THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setTitle('foo');
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ title: 'foo' });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ title: 'foo' });
|
||||
embed.setTitle(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ title: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with an invalid title THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setTitle('a'.repeat(257))).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed description', () => {
|
||||
test('GIVEN an embed with a pre-defined description THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ description: 'foo' });
|
||||
expect(embed.toJSON()).toStrictEqual({ description: 'foo' });
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setDescription THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setDescription('foo');
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ description: 'foo' });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined description THEN unset description THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ description: 'foo' });
|
||||
embed.setDescription(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ description: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with an invalid description THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setDescription('a'.repeat(4097))).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed URL', () => {
|
||||
test('GIVEN an embed with a pre-defined url THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ url: 'https://discord.js.org/' });
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
url: 'https://discord.js.org/',
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setURL THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setURL('https://discord.js.org/');
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
url: 'https://discord.js.org/',
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ url: 'https://discord.js.org' });
|
||||
embed.setURL(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ url: undefined });
|
||||
});
|
||||
|
||||
test.each(['owo', 'discord://user'])('GIVEN an embed with an invalid URL THEN throws error', (input) => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setURL(input)).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Color', () => {
|
||||
test('GIVEN an embed with a pre-defined color THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ color: 0xff0000 });
|
||||
expect(embed.toJSON()).toStrictEqual({ color: 0xff0000 });
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setColor THEN returns valid toJSON data', () => {
|
||||
expect(new EmbedBuilder().setColor(0xff0000).toJSON()).toStrictEqual({ color: 0xff0000 });
|
||||
expect(new EmbedBuilder().setColor([242, 66, 245]).toJSON()).toStrictEqual({ color: 0xf242f5 });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined color THEN unset color THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ color: 0xff0000 });
|
||||
embed.setColor(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ color: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with an invalid color THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => embed.setColor('RED')).toThrowError();
|
||||
// @ts-expect-error
|
||||
expect(() => embed.setColor([42, 36])).toThrowError();
|
||||
expect(() => embed.setColor([42, 36, 1000])).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Timestamp', () => {
|
||||
const now = new Date();
|
||||
|
||||
test('GIVEN an embed with a pre-defined timestamp THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ timestamp: now.toISOString() });
|
||||
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
||||
});
|
||||
|
||||
test('given an embed using Embed#setTimestamp (with Date) THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setTimestamp(now);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setTimestamp (with int) THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setTimestamp(now.getTime());
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ timestamp: now.toISOString() });
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setTimestamp (default) THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setTimestamp();
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ timestamp: embed.data.timestamp });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined timestamp THEN unset timestamp THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ timestamp: now.toISOString() });
|
||||
embed.setTimestamp(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ timestamp: undefined });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Thumbnail', () => {
|
||||
test('GIVEN an embed with a pre-defined thumbnail THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setThumbnail THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setThumbnail('https://discord.js.org/static/logo.svg');
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
thumbnail: { url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined thumbnail THEN unset thumbnail THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||
embed.setThumbnail(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ thumbnail: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with an invalid thumbnail THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setThumbnail('owo')).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Image', () => {
|
||||
test('GIVEN an embed with a pre-defined image THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ image: { url: 'https://discord.js.org/static/logo.svg' } });
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
image: { url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setImage THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setImage('https://discord.js.org/static/logo.svg');
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
image: { url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined image THEN unset image THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({ image: { url: 'https://discord.js/org/static/logo.svg' } });
|
||||
embed.setImage(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ image: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with an invalid image THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setImage('owo')).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Author', () => {
|
||||
test('GIVEN an embed with a pre-defined author THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({
|
||||
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
||||
});
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setAuthor({
|
||||
name: 'Wumpus',
|
||||
iconURL: 'https://discord.js.org/static/logo.svg',
|
||||
url: 'https://discord.js.org',
|
||||
});
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined author THEN unset author THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({
|
||||
author: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },
|
||||
});
|
||||
embed.setAuthor(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ author: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with an invalid author name THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setAuthor({ name: 'a'.repeat(257) })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Footer', () => {
|
||||
test('GIVEN an embed with a pre-defined footer THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({
|
||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setFooter({ text: 'Wumpus', iconURL: 'https://discord.js.org/static/logo.svg' });
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed with a pre-defined footer THEN unset footer THEN return valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({
|
||||
footer: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },
|
||||
});
|
||||
embed.setFooter(null);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({ footer: undefined });
|
||||
});
|
||||
|
||||
test('GIVEN an embed with invalid footer text THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setFooter({ text: 'a'.repeat(2049) })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Embed Fields', () => {
|
||||
test('GIVEN an embed with a pre-defined field THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder({
|
||||
fields: [{ name: 'foo', value: 'bar' }],
|
||||
});
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
fields: [{ name: 'foo', value: 'bar' }],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields({ name: 'foo', value: 'bar' });
|
||||
embed.addFields([{ name: 'foo', value: 'bar' }]);
|
||||
|
||||
expect(embed.toJSON()).toStrictEqual({
|
||||
fields: [
|
||||
{ name: 'foo', value: 'bar' },
|
||||
{ name: 'foo', value: 'bar' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
|
||||
|
||||
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
|
||||
fields: [{ name: 'foo', value: 'baz' }],
|
||||
});
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data 2', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||
|
||||
expect(() =>
|
||||
embed.spliceFields(0, 3, ...Array.from({ length: 5 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#spliceFields that adds additional fields resulting in fields > 25 THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
embed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));
|
||||
|
||||
expect(() =>
|
||||
embed.spliceFields(0, 3, ...Array.from({ length: 8 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setFields THEN returns valid toJSON data', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() =>
|
||||
embed.setFields(...Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).not.toThrowError();
|
||||
expect(() =>
|
||||
embed.setFields(Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN an embed using Embed#setFields that sets more than 25 fields THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() =>
|
||||
embed.setFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).toThrowError();
|
||||
expect(() => embed.setFields(Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })))).toThrowError();
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field amount THEN throws error', () => {
|
||||
test('1', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() =>
|
||||
embed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' }))),
|
||||
).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field name THEN throws error', () => {
|
||||
test('2', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields({ name: '', value: 'bar' })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field name length THEN throws error', () => {
|
||||
test('3', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GIVEN invalid field value length THEN throws error', () => {
|
||||
test('4', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,203 +0,0 @@
|
||||
import { URL } from 'node:url';
|
||||
import { describe, test, expect, vitest } from 'vitest';
|
||||
import {
|
||||
blockQuote,
|
||||
bold,
|
||||
channelMention,
|
||||
codeBlock,
|
||||
Faces,
|
||||
formatEmoji,
|
||||
hideLinkEmbed,
|
||||
hyperlink,
|
||||
inlineCode,
|
||||
italic,
|
||||
quote,
|
||||
roleMention,
|
||||
spoiler,
|
||||
strikethrough,
|
||||
time,
|
||||
TimestampStyles,
|
||||
underscore,
|
||||
userMention,
|
||||
} from '../../src';
|
||||
|
||||
describe('Message formatters', () => {
|
||||
describe('codeBlock', () => {
|
||||
test('GIVEN "discord.js" with no language THEN returns "```\\ndiscord.js```"', () => {
|
||||
expect<'```\ndiscord.js```'>(codeBlock('discord.js')).toEqual('```\ndiscord.js```');
|
||||
});
|
||||
|
||||
test('GIVEN "discord.js" with "js" as language THEN returns "```js\\ndiscord.js```"', () => {
|
||||
expect<'```js\ndiscord.js```'>(codeBlock('js', 'discord.js')).toEqual('```js\ndiscord.js```');
|
||||
});
|
||||
});
|
||||
|
||||
describe('inlineCode', () => {
|
||||
test('GIVEN "discord.js" THEN returns "`discord.js`"', () => {
|
||||
expect<'`discord.js`'>(inlineCode('discord.js')).toEqual('`discord.js`');
|
||||
});
|
||||
});
|
||||
|
||||
describe('italic', () => {
|
||||
test('GIVEN "discord.js" THEN returns "_discord.js_"', () => {
|
||||
expect<'_discord.js_'>(italic('discord.js')).toEqual('_discord.js_');
|
||||
});
|
||||
});
|
||||
|
||||
describe('bold', () => {
|
||||
test('GIVEN "discord.js" THEN returns "**discord.js**"', () => {
|
||||
expect<'**discord.js**'>(bold('discord.js')).toEqual('**discord.js**');
|
||||
});
|
||||
});
|
||||
|
||||
describe('underscore', () => {
|
||||
test('GIVEN "discord.js" THEN returns "__discord.js__"', () => {
|
||||
expect<'__discord.js__'>(underscore('discord.js')).toEqual('__discord.js__');
|
||||
});
|
||||
});
|
||||
|
||||
describe('strikethrough', () => {
|
||||
test('GIVEN "discord.js" THEN returns "~~discord.js~~"', () => {
|
||||
expect<'~~discord.js~~'>(strikethrough('discord.js')).toEqual('~~discord.js~~');
|
||||
});
|
||||
});
|
||||
|
||||
describe('quote', () => {
|
||||
test('GIVEN "discord.js" THEN returns "> discord.js"', () => {
|
||||
expect<'> discord.js'>(quote('discord.js')).toEqual('> discord.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('blockQuote', () => {
|
||||
test('GIVEN "discord.js" THEN returns ">>> discord.js"', () => {
|
||||
expect<'>>> discord.js'>(blockQuote('discord.js')).toEqual('>>> discord.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hideLinkEmbed', () => {
|
||||
test('GIVEN "https://discord.js.org" THEN returns "<https://discord.js.org>"', () => {
|
||||
expect<'<https://discord.js.org>'>(hideLinkEmbed('https://discord.js.org')).toEqual('<https://discord.js.org>');
|
||||
});
|
||||
|
||||
test('GIVEN new URL("https://discord.js.org") THEN returns "<https://discord.js.org>"', () => {
|
||||
expect<`<${string}>`>(hideLinkEmbed(new URL('https://discord.js.org/'))).toEqual('<https://discord.js.org/>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hyperlink', () => {
|
||||
test('GIVEN content and string URL THEN returns "[content](url)"', () => {
|
||||
expect<'[discord.js](https://discord.js.org)'>(hyperlink('discord.js', 'https://discord.js.org')).toEqual(
|
||||
'[discord.js](https://discord.js.org)',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN content and URL THEN returns "[content](url)"', () => {
|
||||
expect<`[discord.js](${string})`>(hyperlink('discord.js', new URL('https://discord.js.org'))).toEqual(
|
||||
'[discord.js](https://discord.js.org/)',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN content, string URL, and title THEN returns "[content](url "title")"', () => {
|
||||
expect<'[discord.js](https://discord.js.org "Official Documentation")'>(
|
||||
hyperlink('discord.js', 'https://discord.js.org', 'Official Documentation'),
|
||||
).toEqual('[discord.js](https://discord.js.org "Official Documentation")');
|
||||
});
|
||||
|
||||
test('GIVEN content, URL, and title THEN returns "[content](url "title")"', () => {
|
||||
expect<`[discord.js](${string} "Official Documentation")`>(
|
||||
hyperlink('discord.js', new URL('https://discord.js.org'), 'Official Documentation'),
|
||||
).toEqual('[discord.js](https://discord.js.org/ "Official Documentation")');
|
||||
});
|
||||
});
|
||||
|
||||
describe('spoiler', () => {
|
||||
test('GIVEN "discord.js" THEN returns "||discord.js||"', () => {
|
||||
expect<'||discord.js||'>(spoiler('discord.js')).toEqual('||discord.js||');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mentions', () => {
|
||||
describe('userMention', () => {
|
||||
test('GIVEN userId THEN returns "<@[userId]>"', () => {
|
||||
expect(userMention('139836912335716352')).toEqual('<@139836912335716352>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('channelMention', () => {
|
||||
test('GIVEN channelId THEN returns "<#[channelId]>"', () => {
|
||||
expect(channelMention('829924760309334087')).toEqual('<#829924760309334087>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('roleMention', () => {
|
||||
test('GIVEN roleId THEN returns "<&[roleId]>"', () => {
|
||||
expect(roleMention('815434166602170409')).toEqual('<@&815434166602170409>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatEmoji', () => {
|
||||
test('GIVEN static emojiId THEN returns "<:_:${emojiId}>"', () => {
|
||||
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952')).toEqual('<:_:851461487498493952>');
|
||||
});
|
||||
|
||||
test('GIVEN static emojiId WITH animated explicitly false THEN returns "<:_:[emojiId]>"', () => {
|
||||
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952', false)).toEqual('<:_:851461487498493952>');
|
||||
});
|
||||
|
||||
test('GIVEN animated emojiId THEN returns "<a:_:${emojiId}>"', () => {
|
||||
expect<`<a:_:827220205352255549>`>(formatEmoji('827220205352255549', true)).toEqual('<a:_:827220205352255549>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('time', () => {
|
||||
test('GIVEN no arguments THEN returns "<t:${bigint}>"', () => {
|
||||
vitest.useFakeTimers();
|
||||
vitest.setSystemTime(1566424897579);
|
||||
|
||||
expect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');
|
||||
|
||||
vitest.useRealTimers();
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${bigint}>"', () => {
|
||||
expect<`<t:${bigint}>`>(time(new Date(1867424897579))).toEqual('<t:1867424897>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a style from string THEN returns "<t:${bigint}:${style}>"', () => {
|
||||
expect<`<t:${bigint}:d>`>(time(new Date(1867424897579), 'd')).toEqual('<t:1867424897:d>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a format from enum THEN returns "<t:${bigint}:${style}>"', () => {
|
||||
expect<`<t:${bigint}:R>`>(time(new Date(1867424897579), TimestampStyles.RelativeTime)).toEqual(
|
||||
'<t:1867424897:R>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${time}>"', () => {
|
||||
expect<'<t:1867424897>'>(time(1867424897)).toEqual('<t:1867424897>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a style from string THEN returns "<t:${time}:${style}>"', () => {
|
||||
expect<'<t:1867424897:d>'>(time(1867424897, 'd')).toEqual('<t:1867424897:d>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a format from enum THEN returns "<t:${time}:${style}>"', () => {
|
||||
expect<'<t:1867424897:R>'>(time(1867424897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Faces', () => {
|
||||
test('GIVEN Faces.Shrug THEN returns "¯\\_(ツ)\\_/¯"', () => {
|
||||
expect<'¯\\_(ツ)\\_/¯'>(Faces.Shrug).toEqual('¯\\_(ツ)\\_/¯');
|
||||
});
|
||||
|
||||
test('GIVEN Faces.Tableflip THEN returns "(╯°□°)╯︵ ┻━┻"', () => {
|
||||
expect<'(╯°□°)╯︵ ┻━┻'>(Faces.Tableflip).toEqual('(╯°□°)╯︵ ┻━┻');
|
||||
});
|
||||
|
||||
test('GIVEN Faces.Unflip THEN returns "┬─┬ ノ( ゜-゜ノ)"', () => {
|
||||
expect<'┬─┬ ノ( ゜-゜ノ)'>(Faces.Unflip).toEqual('┬─┬ ノ( ゜-゜ノ)');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
isJSONEncodable,
|
||||
isEquatable,
|
||||
ActionRowBuilder,
|
||||
enableValidators,
|
||||
disableValidators,
|
||||
isValidationEnabled,
|
||||
} from '../src/index';
|
||||
|
||||
describe('isEquatable', () => {
|
||||
test('returns true if the object is equatable', () => {
|
||||
expect(isEquatable({ equals: () => true })).toBeTruthy();
|
||||
});
|
||||
|
||||
test('returns false if the object is not equatable', () => {
|
||||
expect(isEquatable({})).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isJSONEncodable', () => {
|
||||
test('returns true if the object is JSON encodable', () => {
|
||||
expect(isJSONEncodable({ toJSON: () => ({}) })).toBeTruthy();
|
||||
expect(isJSONEncodable(new ActionRowBuilder())).toBeTruthy();
|
||||
});
|
||||
|
||||
test('returns false if the object is not JSON encodable', () => {
|
||||
expect(isJSONEncodable({})).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('validation', () => {
|
||||
test('enables validation', () => {
|
||||
enableValidators();
|
||||
expect(isValidationEnabled()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('disables validation', () => {
|
||||
disableValidators();
|
||||
expect(isValidationEnabled()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -1,376 +0,0 @@
|
||||
/**
|
||||
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
|
||||
/**
|
||||
* Optionally specifies another JSON config file that this file extends from. This provides a way for
|
||||
* standard settings to be shared across multiple projects.
|
||||
*
|
||||
* If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
|
||||
* the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
|
||||
* resolved using NodeJS require().
|
||||
*
|
||||
* SUPPORTED TOKENS: none
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "extends": "./shared/api-extractor-base.json"
|
||||
// "extends": "my-package/include/api-extractor-base.json"
|
||||
|
||||
/**
|
||||
* Determines the "<projectFolder>" token that can be used with other config file settings. The project folder
|
||||
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting.
|
||||
*
|
||||
* The default value for "projectFolder" is the token "<lookup>", which means the folder is determined by traversing
|
||||
* parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
|
||||
* that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
|
||||
* will be reported.
|
||||
*
|
||||
* SUPPORTED TOKENS: <lookup>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "projectFolder": "..",
|
||||
|
||||
/**
|
||||
* (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
|
||||
* analyzes the symbols exported by this module.
|
||||
*
|
||||
* The file extension must be ".d.ts" and not ".ts".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
*/
|
||||
"mainEntryPointFilePath": "<projectFolder>/dist/index.d.ts",
|
||||
|
||||
/**
|
||||
* A list of NPM package names whose exports should be treated as part of this package.
|
||||
*
|
||||
* For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
|
||||
* and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
|
||||
* of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
|
||||
* imports library2. To avoid this, we can specify:
|
||||
*
|
||||
* "bundledPackages": [ "library2" ],
|
||||
*
|
||||
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
|
||||
* local files for library1.
|
||||
*/
|
||||
"bundledPackages": [],
|
||||
|
||||
/**
|
||||
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
|
||||
*/
|
||||
"compiler": {
|
||||
/**
|
||||
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* Note: This setting will be ignored if "overrideTsconfig" is used.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/tsconfig.json"
|
||||
*/
|
||||
// "tsconfigFilePath": "<projectFolder>/tsconfig.json",
|
||||
/**
|
||||
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
|
||||
* The object must conform to the TypeScript tsconfig schema:
|
||||
*
|
||||
* http://json.schemastore.org/tsconfig
|
||||
*
|
||||
* If omitted, then the tsconfig.json file will be read from the "projectFolder".
|
||||
*
|
||||
* DEFAULT VALUE: no overrideTsconfig section
|
||||
*/
|
||||
// "overrideTsconfig": {
|
||||
// . . .
|
||||
// }
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
|
||||
* and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
|
||||
* dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
|
||||
* for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "skipLibCheck": true,
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the API report file (*.api.md) will be generated.
|
||||
*/
|
||||
"apiReport": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate an API report.
|
||||
*/
|
||||
"enabled": false
|
||||
|
||||
/**
|
||||
* The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
|
||||
* a full file path.
|
||||
*
|
||||
* The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
|
||||
*
|
||||
* SUPPORTED TOKENS: <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<unscopedPackageName>.api.md"
|
||||
*/
|
||||
// "reportFileName": "<unscopedPackageName>.api.md",
|
||||
|
||||
/**
|
||||
* Specifies the folder where the API report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
|
||||
* e.g. for an API review.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/"
|
||||
*/
|
||||
// "reportFolder": "<projectFolder>/temp/",
|
||||
|
||||
/**
|
||||
* Specifies the folder where the temporary report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* After the temporary file is written to disk, it is compared with the file in the "reportFolder".
|
||||
* If they are different, a production build will fail.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/"
|
||||
*/
|
||||
// "reportTempFolder": "<projectFolder>/temp/"
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the doc model file (*.api.json) will be generated.
|
||||
*/
|
||||
"docModel": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate a doc model file.
|
||||
*/
|
||||
"enabled": true,
|
||||
|
||||
/**
|
||||
* The output path for the doc model file. The file extension should be ".api.json".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
*/
|
||||
"apiJsonFilePath": "<projectFolder>/docs/docs.api.json"
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the .d.ts rollup file will be generated.
|
||||
*/
|
||||
"dtsRollup": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate the .d.ts rollup file.
|
||||
*/
|
||||
"enabled": false
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
|
||||
* This file will include all declarations that are exported by the main entry point.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/dist/<unscopedPackageName>.d.ts"
|
||||
*/
|
||||
// "untrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release.
|
||||
* This file will include only declarations that are marked as "@public", "@beta", or "@alpha".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "alphaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-alpha.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
|
||||
* This file will include only declarations that are marked as "@public" or "@beta".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-beta.d.ts",
|
||||
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
|
||||
* This file will include only declarations that are marked as "@public".
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-public.d.ts",
|
||||
|
||||
/**
|
||||
* When a declaration is trimmed, by default it will be replaced by a code comment such as
|
||||
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
|
||||
* declaration completely.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "omitTrimmingComments": true
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures how the tsdoc-metadata.json file will be generated.
|
||||
*/
|
||||
"tsdocMetadata": {
|
||||
/**
|
||||
* Whether to generate the tsdoc-metadata.json file.
|
||||
*
|
||||
* DEFAULT VALUE: true
|
||||
*/
|
||||
// "enabled": true,
|
||||
/**
|
||||
* Specifies where the TSDoc metadata file should be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* The default value is "<lookup>", which causes the path to be automatically inferred from the "tsdocMetadata",
|
||||
* "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
|
||||
* falls back to "tsdoc-metadata.json" in the package folder.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
|
||||
},
|
||||
|
||||
/**
|
||||
* Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
|
||||
* will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
|
||||
* To use the OS's default newline kind, specify "os".
|
||||
*
|
||||
* DEFAULT VALUE: "crlf"
|
||||
*/
|
||||
"newlineKind": "lf",
|
||||
|
||||
/**
|
||||
* Configures how API Extractor reports error and warning messages produced during analysis.
|
||||
*
|
||||
* There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
|
||||
*/
|
||||
"messages": {
|
||||
/**
|
||||
* Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
|
||||
* the input .d.ts files.
|
||||
*
|
||||
* TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"compilerMessageReporting": {
|
||||
/**
|
||||
* Configures the default routing for messages that don't match an explicit rule in this table.
|
||||
*/
|
||||
"default": {
|
||||
/**
|
||||
* Specifies whether the message should be written to the the tool's output log. Note that
|
||||
* the "addToApiReportFile" property may supersede this option.
|
||||
*
|
||||
* Possible values: "error", "warning", "none"
|
||||
*
|
||||
* Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
|
||||
* and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
|
||||
* the "--local" option), the warning is displayed but the build will not fail.
|
||||
*
|
||||
* DEFAULT VALUE: "warning"
|
||||
*/
|
||||
"logLevel": "warning"
|
||||
|
||||
/**
|
||||
* When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
|
||||
* then the message will be written inside that file; otherwise, the message is instead logged according to
|
||||
* the "logLevel" option.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "TS2551": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by API Extractor during its analysis.
|
||||
*
|
||||
* API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
|
||||
*
|
||||
* DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
|
||||
*/
|
||||
"extractorMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "ae-extra-release-tag": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
|
||||
/**
|
||||
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
|
||||
*
|
||||
* TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"tsdocMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
|
||||
// "tsdoc-link-tag-unescaped-text": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
[changelog]
|
||||
header = """
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
body = """
|
||||
{% if version %}\
|
||||
# [{{ version | trim_start_matches(pat="v") }}]\
|
||||
{% if previous %}\
|
||||
{% if previous.version %}\
|
||||
(https://github.com/discordjs/discord.js/compare/{{ previous.version }}...{{ version }})\
|
||||
{% else %}\
|
||||
(https://github.com/discordjs/discord.js/tree/{{ version }})\
|
||||
{% endif %}\
|
||||
{% endif %} \
|
||||
- ({{ timestamp | date(format="%Y-%m-%d") }})
|
||||
{% else %}\
|
||||
# [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
## {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.scope %}\
|
||||
**{{commit.scope}}:** \
|
||||
{% endif %}\
|
||||
{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/discordjs/discord.js/commit/{{ commit.id }}))\
|
||||
{% if commit.breaking %}\
|
||||
{% for breakingChange in commit.footers %}\
|
||||
\n{% raw %} {% endraw %}- **{{ breakingChange.token }}{{ breakingChange.separator }}** {{ breakingChange.value }}\
|
||||
{% endfor %}\
|
||||
{% endif %}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
trim = true
|
||||
footer = ""
|
||||
|
||||
[git]
|
||||
conventional_commits = true
|
||||
filter_unconventional = true
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Features"},
|
||||
{ message = "^fix", group = "Bug Fixes"},
|
||||
{ message = "^docs", group = "Documentation"},
|
||||
{ message = "^perf", group = "Performance"},
|
||||
{ message = "^refactor", group = "Refactor"},
|
||||
{ message = "^typings", group = "Typings"},
|
||||
{ message = "^types", group = "Typings"},
|
||||
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation"},
|
||||
{ message = "^revert", skip = true},
|
||||
{ message = "^style", group = "Styling"},
|
||||
{ message = "^test", group = "Testing"},
|
||||
{ message = "^chore", skip = true},
|
||||
{ message = "^ci", skip = true},
|
||||
{ message = "^build", skip = true},
|
||||
{ body = ".*security", group = "Security"},
|
||||
]
|
||||
filter_commits = true
|
||||
tag_pattern = "@discordjs/builders@[0-9]*"
|
||||
ignore_tags = ""
|
||||
topo_order = false
|
||||
sort_commits = "newest"
|
||||
@@ -1 +0,0 @@
|
||||
## [View the documentation here.](https://discord.js.org/#/docs/builders)
|
||||
@@ -1,99 +0,0 @@
|
||||
# Slash Command Builders
|
||||
|
||||
## Ping command
|
||||
|
||||
```ts
|
||||
import { SlashCommandBuilder } from '@discordjs/builders';
|
||||
|
||||
// Create a slash command builder
|
||||
const pingCommand = new SlashCommandBuilder().setName('ping').setDescription('Check if this interaction is responsive');
|
||||
|
||||
// Get the raw data that can be sent to Discord
|
||||
const rawData = pingCommand.toJSON();
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
```ts
|
||||
import { SlashCommandBuilder } from '@discordjs/builders';
|
||||
|
||||
// Creates a boop command
|
||||
const boopCommand = new SlashCommandBuilder()
|
||||
.setName('boop')
|
||||
.setDescription('Boops the specified user, as many times as you want')
|
||||
.addUserOption((option) => option.setName('user').setDescription('The user to boop').setRequired(true))
|
||||
|
||||
// Adds an integer option
|
||||
.addIntegerOption((option) =>
|
||||
option.setName('boop_amount').setDescription('How many times should the user be booped (defaults to 1)'),
|
||||
)
|
||||
|
||||
// Supports choices too!
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName('boop_reminder')
|
||||
.setDescription('How often should we remind you to boop the user')
|
||||
.addChoices({ name: 'Every day', value: 1 }, { name: 'Weekly', value: 7 }),
|
||||
);
|
||||
|
||||
// Get the final raw data that can be sent to Discord
|
||||
const rawData = boopCommand.toJSON();
|
||||
```
|
||||
|
||||
## Subcommands and subcommand groups
|
||||
|
||||
```ts
|
||||
import { SlashCommandBuilder } from '@discordjs/builders';
|
||||
|
||||
const pointsCommand = new SlashCommandBuilder()
|
||||
.setName('points')
|
||||
.setDescription('Lists or manages user points')
|
||||
|
||||
// Add a manage group
|
||||
.addSubcommandGroup((group) =>
|
||||
group
|
||||
.setName('manage')
|
||||
.setDescription('Shows or manages points in the server')
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('user_points')
|
||||
.setDescription("Alters a user's points")
|
||||
.addUserOption((option) =>
|
||||
option.setName('user').setDescription('The user whose points to alter').setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('action')
|
||||
.setDescription('What action should be taken with the users points?')
|
||||
.addChoices(
|
||||
{ name: 'Add points', value: 'add' },
|
||||
{ name: 'Remove points', value: 'remove' },
|
||||
{ name: 'Reset points', value: 'reset' },
|
||||
)
|
||||
.setRequired(true),
|
||||
)
|
||||
.addIntegerOption((option) => option.setName('points').setDescription('Points to add or remove')),
|
||||
),
|
||||
)
|
||||
|
||||
// Add an information group
|
||||
.addSubcommandGroup((group) =>
|
||||
group
|
||||
.setName('info')
|
||||
.setDescription('Shows information about points in the guild')
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand.setName('total').setDescription('Tells you the total amount of points given in the guild'),
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('user')
|
||||
.setDescription("Lists a user's points")
|
||||
.addUserOption((option) =>
|
||||
option.setName('user').setDescription('The user whose points to list').setRequired(true),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Get the final raw data that can be sent to Discord
|
||||
const rawData = pointsCommand.toJSON();
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
[{ "name": "General", "files": [{ "name": "Welcome", "id": "welcome", "path": "../../README.md" }] }]
|
||||
@@ -1,81 +0,0 @@
|
||||
{
|
||||
"name": "@discordjs/builders",
|
||||
"version": "0.17.0-dev",
|
||||
"description": "A set of builders that you can use when creating your bot",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"docs": "docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn build && yarn lint",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'",
|
||||
"release": "cliff-jumper"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "src",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"contributors": [
|
||||
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
||||
"Crawl <icrawltogo@gmail.com>",
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
"discord",
|
||||
"api",
|
||||
"bot",
|
||||
"client",
|
||||
"node",
|
||||
"discordapp",
|
||||
"discordjs"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/discordjs/discord.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/discord.js/issues"
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@sapphire/shapeshift": "^3.5.1",
|
||||
"discord-api-types": "^0.36.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discordjs/docgen": "workspace:^",
|
||||
"@discordjs/scripts": "workspace:^",
|
||||
"@favware/cliff-jumper": "^1.8.5",
|
||||
"@microsoft/api-extractor": "^7.28.4",
|
||||
"@types/node": "^16.11.45",
|
||||
"c8": "^7.11.3",
|
||||
"eslint": "^8.20.0",
|
||||
"prettier": "^2.7.1",
|
||||
"tsup": "^6.1.3",
|
||||
"typescript": "^4.7.4",
|
||||
"vitest": "^0.18.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import {
|
||||
type APIActionRowComponent,
|
||||
ComponentType,
|
||||
APIMessageActionRowComponent,
|
||||
APIModalActionRowComponent,
|
||||
APIActionRowComponentTypes,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ComponentBuilder } from './Component';
|
||||
import { createComponentBuilder } from './Components';
|
||||
import type { ButtonBuilder } from './button/Button';
|
||||
import type { SelectMenuBuilder } from './selectMenu/SelectMenu';
|
||||
import type { TextInputBuilder } from './textInput/TextInput';
|
||||
import { normalizeArray, type RestOrArray } from '../util/normalizeArray';
|
||||
|
||||
export type MessageComponentBuilder =
|
||||
| MessageActionRowComponentBuilder
|
||||
| ActionRowBuilder<MessageActionRowComponentBuilder>;
|
||||
export type ModalComponentBuilder = ModalActionRowComponentBuilder | ActionRowBuilder<ModalActionRowComponentBuilder>;
|
||||
export type MessageActionRowComponentBuilder = ButtonBuilder | SelectMenuBuilder;
|
||||
export type ModalActionRowComponentBuilder = TextInputBuilder;
|
||||
export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder;
|
||||
|
||||
/**
|
||||
* Represents an action row component
|
||||
*/
|
||||
export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBuilder<
|
||||
APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>
|
||||
> {
|
||||
/**
|
||||
* The components within this action row
|
||||
*/
|
||||
public readonly components: T[];
|
||||
|
||||
public constructor({ components, ...data }: Partial<APIActionRowComponent<APIActionRowComponentTypes>> = {}) {
|
||||
super({ type: ComponentType.ActionRow, ...data });
|
||||
this.components = (components?.map((c) => createComponentBuilder(c)) ?? []) as T[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds components to this action row.
|
||||
*
|
||||
* @param components - The components to add to this action row.
|
||||
*/
|
||||
public addComponents(...components: RestOrArray<T>) {
|
||||
this.components.push(...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the components in this action row
|
||||
*
|
||||
* @param components - The components to set this row to
|
||||
*/
|
||||
public setComponents(...components: RestOrArray<T>) {
|
||||
this.components.splice(0, this.components.length, ...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
public toJSON(): APIActionRowComponent<ReturnType<T['toJSON']>> {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
...this.data,
|
||||
components: this.components.map((component) => component.toJSON()),
|
||||
} as APIActionRowComponent<ReturnType<T['toJSON']>>;
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v10';
|
||||
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
|
||||
import { isValidationEnabled } from '../util/validation';
|
||||
|
||||
export const customIdValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(100)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const emojiValidator = s
|
||||
.object({
|
||||
id: s.string,
|
||||
name: s.string,
|
||||
animated: s.boolean,
|
||||
})
|
||||
.partial.strict.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const disabledValidator = s.boolean;
|
||||
|
||||
export const buttonLabelValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(80)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const buttonStyleValidator = s.nativeEnum(ButtonStyle);
|
||||
|
||||
export const placeholderValidator = s.string.lengthLessThanOrEqual(150).setValidationEnabled(isValidationEnabled);
|
||||
export const minMaxValidator = s.number.int
|
||||
.greaterThanOrEqual(0)
|
||||
.lessThanOrEqual(25)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const labelValueDescriptionValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(100)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const optionValidator = s
|
||||
.union(
|
||||
s.object({
|
||||
label: labelValueDescriptionValidator,
|
||||
value: labelValueDescriptionValidator,
|
||||
description: labelValueDescriptionValidator.optional,
|
||||
emoji: emojiValidator.optional,
|
||||
default: s.boolean.optional,
|
||||
}),
|
||||
s.instance(SelectMenuOptionBuilder),
|
||||
)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const optionsValidator = optionValidator.array
|
||||
.lengthGreaterThanOrEqual(0)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const optionsLengthValidator = s.number.int
|
||||
.greaterThanOrEqual(0)
|
||||
.lessThanOrEqual(25)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export function validateRequiredSelectMenuParameters(options: SelectMenuOptionBuilder[], customId?: string) {
|
||||
customIdValidator.parse(customId);
|
||||
optionsValidator.parse(options);
|
||||
}
|
||||
|
||||
export const defaultValidator = s.boolean;
|
||||
|
||||
export function validateRequiredSelectMenuOptionParameters(label?: string, value?: string) {
|
||||
labelValueDescriptionValidator.parse(label);
|
||||
labelValueDescriptionValidator.parse(value);
|
||||
}
|
||||
|
||||
export const urlValidator = s.string
|
||||
.url({
|
||||
allowedProtocols: ['http:', 'https:', 'discord:'],
|
||||
})
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export function validateRequiredButtonParameters(
|
||||
style?: ButtonStyle,
|
||||
label?: string,
|
||||
emoji?: APIMessageComponentEmoji,
|
||||
customId?: string,
|
||||
url?: string,
|
||||
) {
|
||||
if (url && customId) {
|
||||
throw new RangeError('URL and custom id are mutually exclusive');
|
||||
}
|
||||
|
||||
if (!label && !emoji) {
|
||||
throw new RangeError('Buttons must have a label and/or an emoji');
|
||||
}
|
||||
|
||||
if (style === ButtonStyle.Link) {
|
||||
if (!url) {
|
||||
throw new RangeError('Link buttons must have a url');
|
||||
}
|
||||
} else if (url) {
|
||||
throw new RangeError('Non-link buttons cannot have a url');
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import type {
|
||||
APIActionRowComponent,
|
||||
APIActionRowComponentTypes,
|
||||
APIBaseComponent,
|
||||
ComponentType,
|
||||
} from 'discord-api-types/v10';
|
||||
import type { JSONEncodable } from '../util/jsonEncodable';
|
||||
|
||||
export type AnyAPIActionRowComponent = APIActionRowComponentTypes | APIActionRowComponent<APIActionRowComponentTypes>;
|
||||
|
||||
/**
|
||||
* Represents a discord component
|
||||
*/
|
||||
export abstract class ComponentBuilder<
|
||||
DataType extends Partial<APIBaseComponent<ComponentType>> = APIBaseComponent<ComponentType>,
|
||||
> implements JSONEncodable<AnyAPIActionRowComponent>
|
||||
{
|
||||
/**
|
||||
* The API data associated with this component
|
||||
*/
|
||||
public readonly data: Partial<DataType>;
|
||||
|
||||
public abstract toJSON(): AnyAPIActionRowComponent;
|
||||
|
||||
public constructor(data: Partial<DataType>) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v10';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
type AnyComponentBuilder,
|
||||
type MessageComponentBuilder,
|
||||
type ModalComponentBuilder,
|
||||
} from './ActionRow';
|
||||
import { ComponentBuilder } from './Component';
|
||||
import { ButtonBuilder } from './button/Button';
|
||||
import { SelectMenuBuilder } from './selectMenu/SelectMenu';
|
||||
import { TextInputBuilder } from './textInput/TextInput';
|
||||
|
||||
export interface MappedComponentTypes {
|
||||
[ComponentType.ActionRow]: ActionRowBuilder<AnyComponentBuilder>;
|
||||
[ComponentType.Button]: ButtonBuilder;
|
||||
[ComponentType.SelectMenu]: SelectMenuBuilder;
|
||||
[ComponentType.TextInput]: TextInputBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating components from API data
|
||||
*
|
||||
* @param data - The api data to transform to a component class
|
||||
*/
|
||||
export function createComponentBuilder<T extends keyof MappedComponentTypes>(
|
||||
data: (APIMessageComponent | APIModalComponent) & { type: T },
|
||||
): MappedComponentTypes[T];
|
||||
export function createComponentBuilder<C extends MessageComponentBuilder | ModalComponentBuilder>(data: C): C;
|
||||
export function createComponentBuilder(
|
||||
data: APIMessageComponent | APIModalComponent | MessageComponentBuilder,
|
||||
): ComponentBuilder {
|
||||
if (data instanceof ComponentBuilder) {
|
||||
return data;
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case ComponentType.ActionRow:
|
||||
return new ActionRowBuilder(data);
|
||||
case ComponentType.Button:
|
||||
return new ButtonBuilder(data);
|
||||
case ComponentType.SelectMenu:
|
||||
return new SelectMenuBuilder(data);
|
||||
case ComponentType.TextInput:
|
||||
return new TextInputBuilder(data);
|
||||
default:
|
||||
// @ts-expect-error
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
throw new Error(`Cannot properly serialize component type: ${data.type}`);
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import {
|
||||
ComponentType,
|
||||
ButtonStyle,
|
||||
type APIMessageComponentEmoji,
|
||||
type APIButtonComponent,
|
||||
type APIButtonComponentWithURL,
|
||||
type APIButtonComponentWithCustomId,
|
||||
} from 'discord-api-types/v10';
|
||||
import {
|
||||
buttonLabelValidator,
|
||||
buttonStyleValidator,
|
||||
customIdValidator,
|
||||
disabledValidator,
|
||||
emojiValidator,
|
||||
urlValidator,
|
||||
validateRequiredButtonParameters,
|
||||
} from '../Assertions';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
|
||||
/**
|
||||
* Represents a button component
|
||||
*/
|
||||
export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
public constructor(data?: Partial<APIButtonComponent>) {
|
||||
super({ type: ComponentType.Button, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the style of this button
|
||||
*
|
||||
* @param style - The style of the button
|
||||
*/
|
||||
public setStyle(style: ButtonStyle) {
|
||||
this.data.style = buttonStyleValidator.parse(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL for this button
|
||||
*
|
||||
* @param url - The URL to open when this button is clicked
|
||||
*/
|
||||
public setURL(url: string) {
|
||||
(this.data as APIButtonComponentWithURL).url = urlValidator.parse(url);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id for this button
|
||||
*
|
||||
* @param customId - The custom id to use for this button
|
||||
*/
|
||||
public setCustomId(customId: string) {
|
||||
(this.data as APIButtonComponentWithCustomId).custom_id = customIdValidator.parse(customId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the emoji to display on this button
|
||||
*
|
||||
* @param emoji - The emoji to display on this button
|
||||
*/
|
||||
public setEmoji(emoji: APIMessageComponentEmoji) {
|
||||
this.data.emoji = emojiValidator.parse(emoji);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this button is disabled
|
||||
*
|
||||
* @param disabled - Whether to disable this button
|
||||
*/
|
||||
public setDisabled(disabled = true) {
|
||||
this.data.disabled = disabledValidator.parse(disabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label for this button
|
||||
*
|
||||
* @param label - The label to display on this button
|
||||
*/
|
||||
public setLabel(label: string) {
|
||||
this.data.label = buttonLabelValidator.parse(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
public toJSON(): APIButtonComponent {
|
||||
validateRequiredButtonParameters(
|
||||
this.data.style,
|
||||
this.data.label,
|
||||
this.data.emoji,
|
||||
(this.data as APIButtonComponentWithCustomId).custom_id,
|
||||
(this.data as APIButtonComponentWithURL).url,
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
...this.data,
|
||||
} as APIButtonComponent;
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
|
||||
import { SelectMenuOptionBuilder } from './SelectMenuOption';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import {
|
||||
customIdValidator,
|
||||
disabledValidator,
|
||||
minMaxValidator,
|
||||
optionsLengthValidator,
|
||||
optionValidator,
|
||||
placeholderValidator,
|
||||
validateRequiredSelectMenuParameters,
|
||||
} from '../Assertions';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
|
||||
/**
|
||||
* Represents a select menu component
|
||||
*/
|
||||
export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent> {
|
||||
/**
|
||||
* The options within this select menu
|
||||
*/
|
||||
public readonly options: SelectMenuOptionBuilder[];
|
||||
|
||||
public constructor(data?: Partial<APISelectMenuComponent>) {
|
||||
const { options, ...initData } = data ?? {};
|
||||
super({ type: ComponentType.SelectMenu, ...initData });
|
||||
this.options = options?.map((o) => new SelectMenuOptionBuilder(o)) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the placeholder for this select menu
|
||||
*
|
||||
* @param placeholder - The placeholder to use for this select menu
|
||||
*/
|
||||
public setPlaceholder(placeholder: string) {
|
||||
this.data.placeholder = placeholderValidator.parse(placeholder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum values that must be selected in the select menu
|
||||
*
|
||||
* @param minValues - The minimum values that must be selected
|
||||
*/
|
||||
public setMinValues(minValues: number) {
|
||||
this.data.min_values = minMaxValidator.parse(minValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum values that must be selected in the select menu
|
||||
*
|
||||
* @param maxValues - The maximum values that must be selected
|
||||
*/
|
||||
public setMaxValues(maxValues: number) {
|
||||
this.data.max_values = minMaxValidator.parse(maxValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id for this select menu
|
||||
*
|
||||
* @param customId - The custom id to use for this select menu
|
||||
*/
|
||||
public setCustomId(customId: string) {
|
||||
this.data.custom_id = customIdValidator.parse(customId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this select menu is disabled
|
||||
*
|
||||
* @param disabled - Whether this select menu is disabled
|
||||
*/
|
||||
public setDisabled(disabled = true) {
|
||||
this.data.disabled = disabledValidator.parse(disabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options to this select menu
|
||||
*
|
||||
* @param options - The options to add to this select menu
|
||||
* @returns
|
||||
*/
|
||||
public addOptions(...options: RestOrArray<SelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(this.options.length + options.length);
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
option instanceof SelectMenuOptionBuilder
|
||||
? option
|
||||
: new SelectMenuOptionBuilder(optionValidator.parse<APISelectMenuOption>(option)),
|
||||
),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options on this select menu
|
||||
*
|
||||
* @param options - The options to set on this select menu
|
||||
*/
|
||||
public setOptions(...options: RestOrArray<SelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(options.length);
|
||||
this.options.splice(
|
||||
0,
|
||||
this.options.length,
|
||||
...options.map((option) =>
|
||||
option instanceof SelectMenuOptionBuilder
|
||||
? option
|
||||
: new SelectMenuOptionBuilder(optionValidator.parse<APISelectMenuOption>(option)),
|
||||
),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
public toJSON(): APISelectMenuComponent {
|
||||
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
...this.data,
|
||||
options: this.options.map((o) => o.toJSON()),
|
||||
} as APISelectMenuComponent;
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';
|
||||
|
||||
import {
|
||||
defaultValidator,
|
||||
emojiValidator,
|
||||
labelValueDescriptionValidator,
|
||||
validateRequiredSelectMenuOptionParameters,
|
||||
} from '../Assertions';
|
||||
|
||||
/**
|
||||
* Represents a option within a select menu component
|
||||
*/
|
||||
export class SelectMenuOptionBuilder {
|
||||
public constructor(public data: Partial<APISelectMenuOption> = {}) {}
|
||||
|
||||
/**
|
||||
* Sets the label of this option
|
||||
*
|
||||
* @param label - The label to show on this option
|
||||
*/
|
||||
public setLabel(label: string) {
|
||||
this.data.label = labelValueDescriptionValidator.parse(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this option
|
||||
*
|
||||
* @param value - The value of this option
|
||||
*/
|
||||
public setValue(value: string) {
|
||||
this.data.value = labelValueDescriptionValidator.parse(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description of this option
|
||||
*
|
||||
* @param description - The description of this option
|
||||
*/
|
||||
public setDescription(description: string) {
|
||||
this.data.description = labelValueDescriptionValidator.parse(description);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this option is selected by default
|
||||
*
|
||||
* @param isDefault - Whether this option is selected by default
|
||||
*/
|
||||
public setDefault(isDefault = true) {
|
||||
this.data.default = defaultValidator.parse(isDefault);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the emoji to display on this option
|
||||
*
|
||||
* @param emoji - The emoji to display on this option
|
||||
*/
|
||||
public setEmoji(emoji: APIMessageComponentEmoji) {
|
||||
this.data.emoji = emojiValidator.parse(emoji);
|
||||
return this;
|
||||
}
|
||||
|
||||
public toJSON(): APISelectMenuOption {
|
||||
validateRequiredSelectMenuOptionParameters(this.data.label, this.data.value);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
...this.data,
|
||||
} as APISelectMenuOption;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { TextInputStyle } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation';
|
||||
import { customIdValidator } from '../Assertions';
|
||||
|
||||
export const textInputStyleValidator = s.nativeEnum(TextInputStyle);
|
||||
export const minLengthValidator = s.number.int
|
||||
.greaterThanOrEqual(0)
|
||||
.lessThanOrEqual(4000)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const maxLengthValidator = s.number.int
|
||||
.greaterThanOrEqual(1)
|
||||
.lessThanOrEqual(4000)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const requiredValidator = s.boolean;
|
||||
export const valueValidator = s.string.lengthLessThanOrEqual(4000).setValidationEnabled(isValidationEnabled);
|
||||
export const placeholderValidator = s.string.lengthLessThanOrEqual(100).setValidationEnabled(isValidationEnabled);
|
||||
export const labelValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(45)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export function validateRequiredParameters(customId?: string, style?: TextInputStyle, label?: string) {
|
||||
customIdValidator.parse(customId);
|
||||
textInputStyleValidator.parse(style);
|
||||
labelValidator.parse(label);
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import {
|
||||
maxLengthValidator,
|
||||
minLengthValidator,
|
||||
placeholderValidator,
|
||||
requiredValidator,
|
||||
valueValidator,
|
||||
validateRequiredParameters,
|
||||
labelValidator,
|
||||
textInputStyleValidator,
|
||||
} from './Assertions';
|
||||
import { isJSONEncodable, type JSONEncodable } from '../../util/jsonEncodable';
|
||||
import { customIdValidator } from '../Assertions';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
|
||||
export class TextInputBuilder extends ComponentBuilder<APITextInputComponent> {
|
||||
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
|
||||
super({ type: ComponentType.TextInput, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id for this text input
|
||||
*
|
||||
* @param customId - The custom id of this text input
|
||||
*/
|
||||
public setCustomId(customId: string) {
|
||||
this.data.custom_id = customIdValidator.parse(customId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label for this text input
|
||||
*
|
||||
* @param label - The label for this text input
|
||||
*/
|
||||
public setLabel(label: string) {
|
||||
this.data.label = labelValidator.parse(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the style for this text input
|
||||
*
|
||||
* @param style - The style for this text input
|
||||
*/
|
||||
public setStyle(style: TextInputStyle) {
|
||||
this.data.style = textInputStyleValidator.parse(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum length of text for this text input
|
||||
*
|
||||
* @param minLength - The minimum length of text for this text input
|
||||
*/
|
||||
public setMinLength(minLength: number) {
|
||||
this.data.min_length = minLengthValidator.parse(minLength);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum length of text for this text input
|
||||
*
|
||||
* @param maxLength - The maximum length of text for this text input
|
||||
*/
|
||||
public setMaxLength(maxLength: number) {
|
||||
this.data.max_length = maxLengthValidator.parse(maxLength);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the placeholder of this text input
|
||||
*
|
||||
* @param placeholder - The placeholder of this text input
|
||||
*/
|
||||
public setPlaceholder(placeholder: string) {
|
||||
this.data.placeholder = placeholderValidator.parse(placeholder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this text input
|
||||
*
|
||||
* @param value - The value for this text input
|
||||
*/
|
||||
public setValue(value: string) {
|
||||
this.data.value = valueValidator.parse(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this text input is required
|
||||
*
|
||||
* @param required - Whether this text input is required
|
||||
*/
|
||||
public setRequired(required = true) {
|
||||
this.data.required = requiredValidator.parse(required);
|
||||
return this;
|
||||
}
|
||||
|
||||
public toJSON(): APITextInputComponent {
|
||||
validateRequiredParameters(this.data.custom_id, this.data.style, this.data.label);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
...this.data,
|
||||
} as APITextInputComponent;
|
||||
}
|
||||
|
||||
public equals(other: JSONEncodable<APITextInputComponent> | APITextInputComponent): boolean {
|
||||
if (isJSONEncodable(other)) {
|
||||
return isEqual(other.toJSON(), this.data);
|
||||
}
|
||||
|
||||
return isEqual(other, this.data);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user