Compare commits

..

391 Commits

Author SHA1 Message Date
iCrawl
b45b99f92b chore(ws): release @discordjs/ws@0.2.0 2022-07-30 20:42:46 +02:00
DD
5137bfc17d fix(WebSocketShard): account code 1000 with no prior indication (#8399) 2022-07-30 20:37:46 +02:00
Jiralite
fca3dada2a docs(Embed): Ensure height and width are numbers (#8396) 2022-07-30 11:39:15 +02:00
Parbez
d070de6da7 chore: fix file path (#8391)
* chore: fix file path

* chore: emit only mjs
2022-07-29 18:43:57 +02:00
iCrawl
a3183cfad4 chore(discord.js): release discord.js@14.1.1 2022-07-29 13:47:21 +02:00
iCrawl
aba307341d chore(builders): release @discordjs/builders@1.1.0 2022-07-29 13:42:55 +02:00
Parbez
c479d39a6b chore: build only actions (#8383) 2022-07-29 11:19:54 +02:00
Parbez
52c2818b25 feat(website): add implements for class (#8388)
Co-authored-by: Noel <buechler.noel@outlook.com>
2022-07-29 11:19:32 +02:00
iCrawl
d03cf6176c chore(discord.js): release discord.js@14.1.0 2022-07-29 11:04:08 +02:00
iCrawl
11e77f7f86 chore: deps 2022-07-29 11:00:45 +02:00
iCrawl
2b1e88b5fa chore: update changelog 2022-07-29 10:59:35 +02:00
Synbulat Biishev
e5bfe2c7c2 chore: reexport rest (#8372) 2022-07-29 10:47:30 +02:00
Jiralite
a7deb8f898 feat: Add channel & message URL formatters (#8371) 2022-07-29 10:47:23 +02:00
Almeida
b4e2c0c4d5 fix(MessageMentions): ignoreRepliedUser option in has() (#8202) 2022-07-29 10:47:05 +02:00
Suneet Tipirneni
33113614e0 feat(website): parse tsdoc comments (#8386) 2022-07-29 10:46:17 +02:00
Suneet Tipirneni
26556390a3 fix: use proper format for @link text (#8384)
fix(collection): use proper format for link text
2022-07-28 20:24:07 +02:00
Parbez
5494791313 docs: use link tags (#8382) 2022-07-28 19:18:42 +02:00
Parbez
c258bdf083 chore: cleanup tsup configs (#8381) 2022-07-28 18:57:57 +02:00
Parbez
ff5dd1fcb4 docs: hide sections with no members (#8380) 2022-07-28 17:55:46 +02:00
iCrawl
a38c58dbd0 feat: tertiary sidebar 2022-07-28 17:46:41 +02:00
Suneet Tipirneni
ec43c184fe feat(website): add icons for sections (#8377)
* feat(website): add icons for sections

* chore: make requested changes

* fix: add icon for function parameters
2022-07-28 16:26:06 +02:00
iCrawl
c25e8ad78b chore: use date order instead of topological for changelog 2022-07-27 14:36:09 +02:00
iCrawl
3f17ff23bf chore: fix changelog 2022-07-27 14:22:13 +02:00
iCrawl
a7dc588d9f chore(proxy): release @discordjs/proxy@1.0.1 2022-07-27 14:16:56 +02:00
iCrawl
2291429d30 chore(ws): release @discordjs/ws@0.1.0 2022-07-27 14:15:59 +02:00
iCrawl
bf7326729d chore(rest): release @discordjs/rest@1.0.1 2022-07-27 14:12:23 +02:00
iCrawl
124d8123b8 chore(collection): release @discordjs/collection@1.0.1 2022-07-27 14:10:17 +02:00
Jiralite
0b61dbf720 docs(InteractionResponses): Add showModal() return type (#8376) 2022-07-27 13:59:26 +02:00
Jiralite
ba6797e742 docs(WebhookClient): Document working options (#8375) 2022-07-27 13:05:47 +02:00
Jiralite
7fd9ed8f13 refactor: Deprecate Formatter class (#8373) 2022-07-27 13:05:31 +02:00
iCrawl
b6bba9901b chore: deps 2022-07-27 12:23:07 +02:00
Jiralite
2130aae321 docs(Message): Document gateway intent for content (#8364) 2022-07-27 12:10:05 +02:00
Jiralite
80b9738957 docs: Use info blocks for requirements (#8361) 2022-07-27 12:09:50 +02:00
A. Román
5d8bd030d6 fix(Formatters): add newline in codeBlock (#8369) 2022-07-27 12:09:34 +02:00
Jiralite
e9920a9c98 docs(WebhookClient): Make constructor a union (#8370)
Co-authored-by: muchnameless <12682826+muchnameless@users.noreply.github.com>
2022-07-27 12:09:18 +02:00
Jiralite
6d248051cf refactor(PermissionOverwriteManager): Use OverwriteType (#8374) 2022-07-27 12:06:59 +02:00
iCrawl
798466a696 fix: various css for the sidebar 2022-07-26 09:48:40 +02:00
Suneet Tipirneni
1275918ca8 feat(website): group items by symbol kind (#8360)
* feat(website): group items by symbol kind

* chore: make requested changes

* chore: fix darkmode colors

* chore: make requested changes

* Update packages/website/src/components/ListSidebar.tsx

Co-authored-by: Almeida <almeidx@pm.me>

Co-authored-by: Almeida <almeidx@pm.me>
2022-07-26 09:30:57 +02:00
SpaceEEC
a7d49e56fc fix(GuildChannelManager): allow unsetting rtcRegion (#8359) 2022-07-26 09:29:30 +02:00
Ryan Munro
34ba9d1c4c docs: update docs and examples to PascalCase links (#8305)
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2022-07-25 11:13:09 +02:00
Ryan Munro
77ed407f6a feat: restore missing typeguards (#8328) 2022-07-25 11:12:48 +02:00
Rodry
4fc2c60a3b feat(GuildMember): add dmChannel getter (#8281) 2022-07-25 11:12:00 +02:00
Jiralite
9f4446b10f chore: Update update guide link (#8358)
chore: update update guide
2022-07-25 11:09:58 +02:00
Jiralite
78d4295a40 fix(WebSocketShard): Use correct import (#8357) 2022-07-25 11:09:27 +02:00
iCrawl
5a3c9996e0 fix(enums): dark theme colors 2022-07-25 01:38:17 +02:00
iCrawl
4fff6076e7 refactor: cleanup css 2022-07-25 00:55:40 +02:00
Suneet Tipirneni
4bda24678a refactor(website): add typography improvements (#8355)
* refactor(website): add typography improvements

* chore: bold on hover
2022-07-24 21:56:50 +02:00
iCrawl
9ae461d84d chore: rename docker publish 2022-07-24 18:51:26 +02:00
iCrawl
160487d866 chore: fix dockerbuild and add ws props everywhere 2022-07-24 18:49:06 +02:00
iCrawl
41e4e10b48 fix(Layout): refactor to sidebar layout component 2022-07-24 18:28:32 +02:00
Jiralite
200ab91f52 types(GuildAuditLogsEntryExtraField): Use AuditLogOptionsType (#8349) 2022-07-24 17:26:55 +02:00
Jiralite
3839958e3f fix(ThreadChannel): Omit webhook fetching (#8351) 2022-07-24 17:18:08 +02:00
thehairy
58c1b51c5c fix(GuildAuditLogsEntry): replace OverwriteType with AuditLogOptionsType (#8345) 2022-07-24 16:15:51 +02:00
Suneet Tipirneni
6a2d0d8e96 fix(selectMenu): allow json to be used for select menu options (#8322) 2022-07-24 15:14:33 +02:00
Suneet Tipirneni
335695c698 refactor: use next links (#8344)
* chore(website): use next links

* chore: fix deploy check

* chore: use ligher syntax highlighter
2022-07-24 15:14:18 +02:00
DD
8e520f946a fix(ShardClientUtil#_respond): construct global error (#8348) 2022-07-24 15:13:13 +02:00
Jiralite
59a7e52224 fix: Ensure returns for function type definitions (#8346) 2022-07-24 13:44:46 +02:00
Jiralite
af837debe3 chore: Use raw GitHub link to show Vercel logo on website (#8343)
chore: use raw GitHub link to show on docs
2022-07-23 23:38:49 +02:00
Jiralite
df42fdfc42 fix(Presence): Do not return NaN for activity timestamp (#8340) 2022-07-23 18:21:47 +02:00
iCrawl
5f667c0c82 fix: correctly configure middleware 2022-07-23 04:13:16 +02:00
iCrawl
90cbd2bbd5 fix: move middleware into source directory
This needs to be on the same level as the pages directory, sometimes the documentation mentioned "root", but that obviously is not true if you use a src directory
2022-07-23 02:49:24 +02:00
iCrawl
f50382e1ce feat: add middleware for path rewriting 2022-07-23 02:35:21 +02:00
iCrawl
1b03631205 chore: patch all versions of tsdoc-config 2022-07-23 01:57:47 +02:00
iCrawl
a490adfe36 chore: remove hoist and install normally 2022-07-23 01:41:12 +02:00
iCrawl
f097f0bc1f chore: create patch for tsdoc-config 2022-07-23 01:38:21 +02:00
iCrawl
1d63d3ce1c build: explicitly add deps 2022-07-23 01:24:45 +02:00
iCrawl
6d25fb8856 fix(yarn): don't hoist packages for website 2022-07-23 00:36:00 +02:00
iCrawl
86a9be7d33 fix(IRS): also generate index routes 2022-07-23 00:11:19 +02:00
iCrawl
82165d4f80 feat(IRS): next IRS 2022-07-22 23:39:48 +02:00
iCrawl
ee455c812e refactor: switch to next.js 2022-07-22 21:47:06 +02:00
iCrawl
0d687b5606 chore: deps 2022-07-22 19:25:24 +02:00
DD
748d7271c4 feat: @discordjs/ws (#8260)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
2022-07-22 19:13:47 +02:00
SpaceEEC
830c670c61 fix(Client): omit private properties from toJSON (#8337) 2022-07-22 17:11:54 +02:00
iCrawl
74ec7be346 chore: add lint-staged 2022-07-22 01:32:19 +02:00
iCrawl
96b62b6539 ci: rename files to match better naming 2022-07-20 22:33:23 +02:00
iCrawl
8a6ee906a7 ci: better naming for ci 2022-07-20 20:24:09 +02:00
Almeida
1fb7b30963 fix(ApplicationCommandManager): allow passing 0n to defaultMemberPermissions (#8311)
* fix(ApplicationCommandManager): allow passing 0n to defaultMemberPermissions

* fix(ApplicationCommand): equals()
2022-07-20 20:12:58 +02:00
iCrawl
45c9659080 ci: fix vercel deploy check 2022-07-20 19:03:48 +02:00
iCrawl
07a5cd7048 ci: check deploy branch vercel 2022-07-20 18:49:24 +02:00
iCrawl
d0e3c972b4 chore: reorder release steps 2022-07-20 18:44:44 +02:00
iCrawl
a05386a46c ci: fix docs and dev publishes 2022-07-20 17:22:57 +02:00
Noel
3b0197bd8e build: refactor build system (#8324) 2022-07-20 16:36:42 +02:00
iCrawl
d1245418f9 chore: add license to root 2022-07-19 20:11:23 +02:00
iCrawl
e7d4d41640 chore: use full link for vercel banner in readmes 2022-07-19 19:43:14 +02:00
iCrawl
ce1807dc80 fix(landing): vercel banner not wrapped in a tag 2022-07-19 19:41:14 +02:00
iCrawl
34d3917a28 chore: spacing on vercel logo 2022-07-19 19:38:11 +02:00
iCrawl
9e624abf1a chore(discord.js): release discord.js 2022-07-19 18:40:01 +02:00
iCrawl
8c4b9865e1 fix(landing): vercel banner 2022-07-19 18:33:50 +02:00
iCrawl
dbad1c468b chore: fix root vercel banner 2022-07-19 18:29:41 +02:00
iCrawl
4ffd7f9f80 chore: vercel banner 2022-07-19 18:26:03 +02:00
advaith
660e212e83 fix(Components): support emoji id strings (#8310) 2022-07-19 14:56:21 +02:00
iCrawl
70dd757ec3 refactor(theme): switch theme detection to use class 2022-07-18 19:53:07 +02:00
Suneet Tipirneni
b5d4b2d78b feat(website): add basic landing page (#8313)
Co-authored-by: Noel <buechler.noel@outlook.com>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2022-07-18 19:11:18 +02:00
iCrawl
78d013f87c ci: fix building before linting/testing 2022-07-18 14:20:11 +02:00
iCrawl
21d61ca260 chore: remove parallel execution 2022-07-18 14:09:45 +02:00
iCrawl
b316ac7cc4 ci: remove turbo cache 2022-07-18 13:16:16 +02:00
iCrawl
ed94b3d9ec chore: change versions 2022-07-18 12:52:15 +02:00
iCrawl
dcbbecfed2 chore: dev version 2022-07-18 12:28:39 +02:00
iCrawl
0c5e37d515 chore(discord.js): release discord.js 2022-07-18 12:26:49 +02:00
iCrawl
656e9550db fix: default package to discord.js 2022-07-18 12:21:48 +02:00
DD
3a7e93df57 fix(DataResolver#resolveImage): adjust to updated resolveFile (#8308) 2022-07-18 12:17:46 +02:00
iCrawl
66092cad8b feat(theme): dark theme detection 2022-07-18 02:57:29 +02:00
iCrawl
ec230faa4d feat(theme): better dark theme 2022-07-18 02:35:34 +02:00
iCrawl
cd13a4a902 fix(sidebar): styling issues 2022-07-18 02:14:38 +02:00
iCrawl
dda2895bfb chore: release bump 2022-07-17 22:37:01 +02:00
iCrawl
f0b77348d3 chore: bump dev version 2022-07-17 22:18:45 +02:00
iCrawl
b0a9131b1c chore(discord.js): release discord.js 2022-07-17 22:15:00 +02:00
iCrawl
29be5b570b chore: deps 2022-07-17 22:06:54 +02:00
iCrawl
d677c31161 chore: update dev versions 2022-07-17 22:05:32 +02:00
iCrawl
f6ef92ad6a chore: release @discordjs/builders, @discordjs/collection, @discordjs/proxy, @discordjs/rest 2022-07-17 22:02:32 +02:00
Jiralite
52a9e213c2 fix(GuildMemberManager): Allow setting own nickname (#8066) 2022-07-17 21:47:02 +02:00
Almeida
b7e62380f2 test(builders): improve coverage (#8274) 2022-07-17 21:20:26 +02:00
Lo
cafde77d73 refactor(Util)!: rename fetchRecommendedShards (#8298) 2022-07-17 21:17:49 +02:00
Rodry
b7d4e55419 types(GuildFeature): allow feature strings to be passed (#8264)
Co-authored-by: Synbulat Biishev <syjalo.dev@gmail.com>
2022-07-17 21:14:54 +02:00
Almeida
5aeed99350 docs: align webhook method return types with implementation (#8253) 2022-07-17 21:14:25 +02:00
Jiralite
452dec57ca docs: Remove @private constructor documentation (#8255) 2022-07-17 21:13:54 +02:00
Jiralite
64f814066c refactor(Embed): Add all the types (#8254) 2022-07-17 21:13:40 +02:00
Rodry
33a7a5cbdc types(CategoryChannelChildManager): fix Holds type (#8288) 2022-07-17 21:12:22 +02:00
iCrawl
edf83f02ea chore: bump dev versions 2022-07-17 21:05:21 +02:00
iCrawl
25bd771559 chore(voice): release @discordjs/voice@0.11.0 2022-07-17 21:04:18 +02:00
iCrawl
f2ca0ca6f9 chore(rest): release @discordjs/rest@0.6.0 2022-07-17 21:03:35 +02:00
iCrawl
6712de9752 chore(collection): release @discordjs/collection@0.8.0 2022-07-17 20:59:54 +02:00
iCrawl
28cd293f14 chore: update changelog 2022-07-17 19:42:10 +02:00
iCrawl
3f5690afe1 chore(builders): bump dev version 2022-07-17 19:31:32 +02:00
iCrawl
015ab69956 chore(builders): release @discordjs/builders@0.16.0 2022-07-17 19:28:12 +02:00
iCrawl
caecc574f0 chore: deps 2022-07-17 19:20:40 +02:00
BattleEye
3bf30b1e6d fix(PermissionOverwriteManager): mutates user (#8283) 2022-07-17 18:59:10 +02:00
DD
103a3584c9 refactor(rest): add content-type(s) to uploads (#8290) 2022-07-17 18:55:25 +02:00
Almeida
bf65b37d1a types: remove MemberMention (#8292) 2022-07-17 18:54:44 +02:00
Parbez
7e6dbaaed9 types: remove expect error (#8242) 2022-07-17 18:53:40 +02:00
CallMe AsYouFeel
1a6ddbbe7b fix(VoiceReceiver): parsePacket correctly (#8277) 2022-07-17 18:52:35 +02:00
Tiemen
32f9056b15 fix: slash command name regex (#8265) 2022-07-17 18:52:18 +02:00
Jiralite
3648f6d567 fix(GuildChannelManager): Access resolveId correctly (#8296) 2022-07-17 18:51:25 +02:00
Almeida
bddb6a461c chore: ignore index files in coverage (#8293)
Co-authored-by: ckohen <chaikohen@gmail.com>
2022-07-17 18:51:03 +02:00
Jiralite
fe34f48efb chore: Remove --cache (#8279) 2022-07-13 16:58:40 +02:00
Jeroen Claassens
30a8d3231f chore: update Git Cliff TOMLs (#8276) 2022-07-13 09:49:17 +02:00
Suneet Tipirneni
1ed605eaa4 feat(website): add extends clauses, enum members and automatic -types links (#8270)
* feat(website): add extends clauses, enum members and automatic -types links

* chore: remove vscode settings

* refactor: remove util file
2022-07-12 22:42:32 +02:00
muchnameless
787654816d fix(GuildChannelManager): edit lockPermissions (#8269) 2022-07-12 22:34:14 +02:00
Eejit
f0b68d5736 refactor: make GuildAuditLogsEntry.action return an AuditLogEvent (#8256) 2022-07-09 19:55:24 +02:00
Jiralite
75256153a9 types(GuildMemberManager): Fix placement for fetchMe() (#8258) 2022-07-09 19:43:02 +02:00
Suneet Tipirneni
33ae7df000 feat(website): add detailed property and method documentation (#8252)
Co-authored-by: Noel <buechler.noel@outlook.com>
2022-07-08 22:03:18 +02:00
Tyler Resch
feb3bdda0a types: convert Events to an enum (#8246) 2022-07-08 16:02:48 +02:00
Suneet Tipirneni
e78c9c9ee9 feat(website): show package members in a sidebar (#8245)
* feat(website): show package members in a sidebar

* fix: put response instead of loader

* Apply suggestions from code review

Co-authored-by: Noel <buechler.noel@outlook.com>

* chore: make requested changes

* refactor: make only package list scrollable

* feat: make sidebar mobile responsive

* fix: breakpoints for sidebar

Co-authored-by: Noel <buechler.noel@outlook.com>
2022-07-07 22:09:19 +02:00
MateoDeveloper
43f62bb667 docs(ApplicationCommand): add min_length and max_length to ApplicationCommandOptionData (#8239) 2022-07-07 20:46:06 +02:00
Parbez
96c8d21f95 feat(builder): add max min length in string option (#8214) 2022-07-07 20:45:32 +02:00
Anton Istomin
10ba0080cc fix(recorder-example): bump dependencies (#8123) 2022-07-06 22:25:10 +02:00
iCrawl
0b979b04f2 chore: add blocked label 2022-07-06 21:17:07 +02:00
Parbez
a4d1862982 refactor(builder): remove unsafe*Builders (#8074) 2022-07-06 20:42:51 +02:00
Suneet Tipirneni
34531c45e3 feat(website): add support for type parameter documentation (#8237) 2022-07-06 17:37:33 +02:00
Parbez
8198da5cd0 types(builder): remove casting (#8241) 2022-07-06 12:28:00 +02:00
iCrawl
ba10637529 chore: deps 2022-07-06 10:43:06 +02:00
iCrawl
68c3d8743e refactor(createApiModel): reusable function for api model creation 2022-07-05 17:00:44 +02:00
Almeida
a51f7215ec test(collection): improve coverage (#8222) 2022-07-05 16:10:42 +02:00
Jiralite
c271e05223 fix(SpeakingMap): Allow docgen to detect event name (#8236) 2022-07-05 16:10:23 +02:00
Almeida
d2e74003d5 chore: remove docgen test stuff (#8231) 2022-07-05 14:13:11 +02:00
ckohen
fd1c24036f fix(codecov): use cobertura (#8235) 2022-07-05 12:32:05 +02:00
ckohen
eb9ad46d4f fix(coverage): upload lcov instead of clover (#8234) 2022-07-05 10:52:38 +02:00
Almeida
5bd6b28b3e fix(Collection): make error messages consistent (#8224) 2022-07-04 17:40:33 +02:00
ckohen
f6db285c07 docs: add codecov coverage badge to readmes (#8226)
* docs: add codecov coverage badge to readmes

* docs: fix tab-space consistency
2022-07-04 14:00:27 +02:00
Almeida
68ade870f8 chore: upgrade vitest and add it as dep on each workspace (#8223) 2022-07-04 11:51:48 +02:00
Jiralite
c7a205f7b9 types(GuildMemberManager): Non-void return of edit() (#8186) 2022-07-03 18:04:29 +02:00
Almeida
c5750d59f5 refactor: make ShardEvents the events of Shard (#8185) 2022-07-03 18:04:19 +02:00
Suneet Tipirneni
31d5930464 fix(SelectMenuBuilder): properly accept SelectMenuOptionBuilders (#8174) 2022-07-03 18:04:08 +02:00
Jiralite
cdd9214212 fix: Remove global flag on regular expressions (#8177) 2022-07-03 15:36:53 +02:00
A. Román
fa010b5162 fix(MessagePayload): guard against repliedUser property (#8211) 2022-07-03 15:36:32 +02:00
A. Román
6b20645740 refactor(Util): make single replace call in cleanContent (#8210)
Co-authored-by: Almeida <almeidx@pm.me>
2022-07-03 15:36:20 +02:00
Almeida
50d55bd6b8 fix(ApplicationCommandManager): explicitly allow passing builders to methods (#8209) 2022-07-03 15:35:59 +02:00
Almeida
2d9dfa3c6e fix(TextInputBuilder): parse custom_id, label, and style (#8216) 2022-07-03 15:35:19 +02:00
Tyler Resch
ab238a9046 docs(MessageInteraction#commandName): updated description (#8212)
Co-authored-by: A. Román <kyradiscord@gmail.com>
2022-07-03 15:34:47 +02:00
Parbez
94ee60d3d4 feat(applicationCommand): add max min length in string option (#8215) 2022-07-03 15:34:04 +02:00
ckohen
f10f4cdcd8 feat: codecov (#8219) 2022-07-03 15:33:18 +02:00
Suneet Tipirneni
d95197cc78 feat: add website documentation early mvp (#8183)
Co-authored-by: iCrawl <buechler.noel@outlook.com>
2022-07-01 20:54:15 +02:00
Jiralite
e0c8282490 docs: Add missing @extends (#8205) 2022-07-01 17:48:11 +02:00
tnfAngel
741b3c8e27 docs: Remove Music bot in voice examples (#8203) 2022-07-01 10:54:11 +02:00
iCrawl
819a1fdf7d ci: check for main package before moving api-extractor docs 2022-06-30 16:17:52 +02:00
iCrawl
ce9afbb8e4 ci: fix building before generating docs 2022-06-30 15:56:07 +02:00
iCrawl
b2776c22d4 ci: api-extractor support for docs 2022-06-30 15:46:14 +02:00
DD
525bf031a5 chore: revert pre-commit hook to not change state (#8200) 2022-06-30 11:47:27 +02:00
CarelessInternet
27d8deb471 types: add missing shard types (#8180) 2022-06-30 00:37:55 +02:00
Xaliks
11b1739319 fix(GuildMemberRemove): remove member's presence (#8181) 2022-06-30 00:37:47 +02:00
Jiralite
b83e0c0caf types: Implement GuildChannelEditOptions (#8184) 2022-06-30 00:37:38 +02:00
Almeida
8421f9203b types(Status): add missing members (#8179) 2022-06-30 00:37:31 +02:00
A. Román
cb3dca4ae0 refactor(ApplicationCommandManager): use makeURLSearchParams (#8196) 2022-06-30 00:36:47 +02:00
MateoDeveloper
002d6a5aed feat(BaseInteraction): add support for app_permissions (#8194)
Co-authored-by: Almeida <almeidx@pm.me>
2022-06-30 00:36:32 +02:00
DD
c4653f97b1 feat(util): parseWebhookURL (#8166)
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2022-06-25 11:02:11 +02:00
Suneet Tipirneni
e24970e3c3 refactor: Use Base prefix for channel and interaction base classes (#8099) 2022-06-24 10:42:50 +02:00
Tyler Resch
65dc8d677e types(GuildScheduledEvent#scheduledStartAt): should be nullish (#8111) 2022-06-24 10:42:39 +02:00
Almeida
0ffbef506a fix: edit() data can be partial and defaultMemberPermissions can be null (#8163) 2022-06-24 10:42:20 +02:00
iCrawl
5d3dd55a26 chore(changelog): add v13 changelog 2022-06-23 18:28:32 +02:00
Skick
70b42bb64a types(voice): bring back typed events (#8109) 2022-06-23 12:39:36 +02:00
Jan
af04992ed3 docs(Constants): fix SweeperKeys type (#8157) 2022-06-23 12:37:12 +02:00
ckohen
bbdb5d980b revert: refactor: move eslint.tsconfig.json to root (#8159) 2022-06-23 12:36:42 +02:00
Suneet Tipirneni
7279f9c31b types: fix modal builder constructor data type (#8143) 2022-06-22 20:37:46 +02:00
Jiralite
5e5853a4e8 docs(Channels): internally document channel creation (#8154) 2022-06-22 20:37:24 +02:00
Jiralite
cd17aad720 refactor(Constants): Remove leftover code (#8156)
* refactor(Constants): tidy up file

* docs(Constants): add type definition
2022-06-22 20:36:58 +02:00
Jiralite
ee36d60dc6 docs: Update threads to use ThreadAutoArchiveDuration (#8153) 2022-06-22 20:34:41 +02:00
SpaceEEC
c34c02ab8d fix(WebSocketShard): keep an error handler on connections (#8150) 2022-06-22 20:34:11 +02:00
Almeida
31f658247f fix(DJSError): error code validation (#8149) 2022-06-22 20:33:47 +02:00
Jiralite
a3799f9ebb types: Use ThreadAutoArchiveDuration from discord-api-types (#8145) 2022-06-22 11:23:39 +02:00
Jiralite
a061233510 docs(APITypes): Remove duplicate type definition (#8144) 2022-06-22 11:23:17 +02:00
Jiralite
203bc4a2cf docs: Document missing type definitions (#8130)
Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
2022-06-22 11:23:03 +02:00
Parbez
65d1879c0a chore: move deps to root and some miscellaneous changes (#8129) 2022-06-21 15:15:38 +02:00
Parbez
c6f285b7b0 refactor: remove @sindresorhus/is as it's now esm only (#8133) 2022-06-21 14:41:33 +02:00
pat
2eeaad6f27 fix(vcs): nsfw property (#8132) 2022-06-21 14:35:42 +02:00
pat
f1ac17c961 docs(InteractionResponse): fix return (#8141) 2022-06-21 14:35:33 +02:00
Jiralite
db2b0333d9 fix(WebSocketManager): Correct error name (#8138) 2022-06-21 14:35:17 +02:00
DD
94f7ca9474 chore: update proxy-container README (#8122)
Co-authored-by: Almeida <almeidx@pm.me>
2022-06-20 14:47:19 +02:00
DD
e68effa822 refactor: errors (#8068)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
Co-authored-by: A. Román <kyradiscord@gmail.com>
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
2022-06-20 14:46:35 +02:00
iCrawl
358c3f4a46 chore: upgrade deps 2022-06-19 13:19:24 +02:00
DD
268a9b4be5 fix: vitest recursion (#8121) 2022-06-19 13:18:36 +02:00
KinectTheUnknown
95e6d6ede0 types(Shard#reconnecting): fix event name (#8118) 2022-06-19 12:24:04 +02:00
DD
17867f9154 fix(proxy-container): proper deps (#8120) 2022-06-19 12:17:47 +02:00
Jiralite
3a77ce0b18 docs(PermissionsBitField): Fix @name of bitfield (#8115)
docs(PermissionsBitField): `Permission` -> `PermissionsBitField`
2022-06-18 18:42:47 +02:00
Jiralite
23e183a9ac fix(WebSocketShard): Disconnected casing (#8117) 2022-06-18 18:42:30 +02:00
Parbez
b3c3a94d5d ci: don't run publish workflow on forks (#8116) 2022-06-18 18:42:09 +02:00
DD
8610700c87 fix(ci): log into dockerhub properly (#8114) 2022-06-18 13:59:05 +02:00
Jiralite
db663a55c2 docs: TextBasedChannel -> TextBasedChannels typos (#8110) 2022-06-18 13:02:41 +02:00
DD
0673ea377a fix(proxy-container): add @discordjs/rest to deps (#8113) 2022-06-18 13:02:12 +02:00
DD
2681929e42 feat: proxy container (#8000) 2022-06-17 23:29:50 +02:00
Jiralite
0a138dab95 docs: Remove numbers from enums (#8098) 2022-06-17 23:28:30 +02:00
Jiralite
415513696c docs(GuildAuditLogs): Fix and reimplement type definitions (#8108) 2022-06-17 23:27:54 +02:00
Almeida
90a98fee16 refactor(ClientOptions): remove $ prefix from ws.properties keys (#8094) 2022-06-17 23:26:42 +02:00
advaith
386c41f24f docs(WebSocketOptions): add version to docs and typings (#8050) 2022-06-17 23:26:08 +02:00
pat
d54bf5d286 fix(webhooks): revert webhook caching (and returning Message) (#8038) 2022-06-17 23:25:46 +02:00
Jiralite
e5ec1c4dbc refactor: Use GuildFeature enum (#8101) 2022-06-17 23:25:29 +02:00
Jiralite
ad9ab2b177 chore: Add MessageContent to issue form (#8106) 2022-06-17 23:24:26 +02:00
Rodry
4df491ce85 types(ApplicationCommand): fix typo in setDMPermission (#8097) 2022-06-16 09:59:46 +02:00
Jiralite
0a44b05db8 fix(ApplicationCommand): Remove autocomplete check at the top level and correctly check for dmPermission (#8100) 2022-06-16 09:58:54 +02:00
Almeida
b4e28a8ff6 types: fix setType() parameter and ChannelData.type (#8089) 2022-06-13 23:43:10 +02:00
Jiralite
9c0f190de1 docs(BaseGuildTextChannel): Update setType()'s parameter type (#8088) 2022-06-13 22:09:00 +02:00
BaumianerNiklas
093117d938 chore: remove -types import in readme example (#8085) 2022-06-13 21:42:28 +02:00
Suneet Tipirneni
e53d162198 refactor(util): make utility functions top level (#8052)
* refactor(util): make functions top level

* types: make channel typeguards more strict

* chore: make requested changes
2022-06-13 20:04:53 +02:00
Almeida
51eadf3737 docs: update outdated examples (#8081) 2022-06-13 18:18:15 +02:00
Jiralite
552ec72542 docs(ThreadMemberManager): Require member in FetchThreadMemberOptions (#8079) 2022-06-13 18:17:44 +02:00
Ben
ac7bf692bf docs(AutocompleteInteraction): change useless log in responds example (#8077) 2022-06-13 18:16:54 +02:00
n1ck_pro
9964454c29 types: fix ApplicationCommandPermissionsUpdate event typings (#8071) 2022-06-13 18:16:07 +02:00
Rodry
476b7d519c types(AutocompleteOption): fix and improve types (#8069) 2022-06-13 18:15:31 +02:00
Jiralite
10a6c4287d feat(AutocompleteInteraction): Add commandGuildId (#8086) 2022-06-13 18:14:01 +02:00
Jiralite
a2eebf6c66 docs: Description and missing @typedef fixes (#8087) 2022-06-13 18:12:08 +02:00
CodeGoat
96053babe1 fix(ApplicationCommand): fix default member permissions assignment (#8067) 2022-06-11 11:05:43 +02:00
ckohen
f527dea36e fix(scripts): read directory and rerun (#8065) 2022-06-11 11:04:53 +02:00
ckohen
c7391db11b refactor(ApplicationCommand): permissions v2 (#7857)
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
2022-06-10 21:34:17 +02:00
Suneet Tipirneni
c5176be14b feat(guild): add support for setting MFA level (#8024) 2022-06-10 21:26:11 +02:00
Parbez
fbe67e1025 fix: select menu options to accept both rest and array (#8032)
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
2022-06-10 21:22:04 +02:00
Parbez
3bb9c0e5c3 fix: check for function type (#8064) 2022-06-10 21:21:45 +02:00
DD
9c8b3102ce refactor(*): include name/reason/etc fields into options/data params (#8026) 2022-06-10 21:20:59 +02:00
Jiralite
2392a6f5de types(ThreadMemberManager): Fix return type of fetching members with no arguments (#8060)
* types(ThreadMemberManager): non-optional first overload for fetching

* test: organisation
2022-06-10 21:20:00 +02:00
Parbez
c0f079d232 typings: remove isAutocomplete typeguard from typings (#8063) 2022-06-10 21:19:44 +02:00
Jiralite
d8077c6839 fix(CommandInteractionOptionResolver): Handle autocompletion interactions (#8058) 2022-06-10 21:19:27 +02:00
iCrawl
d4b41dd081 feat(docgen): proper event parsing for typescript 2022-06-10 16:22:11 +02:00
pat
0415300243 feat(vcs): add missing property and methods (#8002) 2022-06-10 13:42:53 +02:00
Jeroen Claassens
caee94897f build: fix git cliff config files (#8057) 2022-06-10 13:37:24 +02:00
iCrawl
b3346f4b9b feat(docgen): update typedoc 2022-06-10 12:59:46 +02:00
iCrawl
2791c86cdf chore: remove unneeded tsc build 2022-06-09 21:27:06 +02:00
Almeida
c8f1690896 refactor(collection): remove default property (#8055) 2022-06-09 20:53:23 +02:00
Jiralite
da9107c007 refactor(ThreadMemberManager): Consistent thread member fetching (#8021) 2022-06-09 20:52:56 +02:00
Suneet Tipirneni
f57d6768ad refactor(interactions): remove redundant interaction typeguards (#8027) 2022-06-09 20:52:44 +02:00
iCrawl
d7b8357dcb fix(docgen): strip dots from return types 2022-06-09 20:47:51 +02:00
A. Román
16810f3e41 refactor(collection): remove default export (#8053) 2022-06-09 16:53:01 +02:00
A. Román
598f61b992 fix(scripts): add quotes around blob arguments (#8054) 2022-06-09 16:52:18 +02:00
iCrawl
50401453e7 fix(docgen): shorten output for path info 2022-06-09 16:14:37 +02:00
Almeida
94bdcaca62 docs: ignore docs of unexported functions (#8051) 2022-06-09 13:58:42 +02:00
iCrawl
eea139b346 feat(docgen): support for ignore tag 2022-06-09 13:54:35 +02:00
iCrawl
50822f5254 fix(docgen): parsing constructor 2022-06-09 11:37:22 +02:00
muchnameless
f2b267c079 fix(Message): force fetching (#8047) 2022-06-09 10:35:52 +02:00
advaith
b2eea1c900 docs(ClientOptions): fix closeTimeout default (#8049) 2022-06-09 10:35:27 +02:00
iCrawl
3ae2633c3f feat(website): add some styling 2022-06-08 23:40:03 +02:00
iCrawl
3937b402c0 fix(website): don't build concurrently 2022-06-08 22:26:39 +02:00
iCrawl
256c4f955c feat(website): unocss 2022-06-08 21:45:16 +02:00
iCrawl
33cdcdbb7a fix: vercel deployment 2022-06-08 20:09:23 +02:00
iCrawl
bc466a5997 fix(website): deployment 2022-06-08 19:36:09 +02:00
Noel
127931d1df feat: website (#8043) 2022-06-08 19:13:31 +02:00
iCrawl
5259639c2c fix: doc generation for return types 2022-06-08 19:12:42 +02:00
iCrawl
5de9b80814 fix: returns for typescript parsing 2022-06-08 18:41:22 +02:00
iCrawl
bc4fbcef2e fix(serializer): properly serialize data 2022-06-08 18:11:25 +02:00
iCrawl
3279b40912 feat(docgen): typescript support 2022-06-08 17:26:54 +02:00
Synbulat Biishev
1afae909d7 fix(Attachment): do not destructure data (#8041) 2022-06-08 13:30:06 +02:00
iCrawl
65cb36166f fix(VarType): parsing type names 2022-06-08 13:27:41 +02:00
Superchupu
ecc6600df2 refactor(docgen): use the node: protocol (#8034)
Co-authored-by: Synbulat Biishev <syjalo.dev@gmail.com>
2022-06-08 00:17:48 +02:00
iCrawl
314d76e907 fix(docgen): fix up method return types 2022-06-07 15:19:42 +02:00
Parbez
769ea0bfe7 refactor: move all the config files to root (#8033) 2022-06-07 12:35:19 +02:00
Noel
8b979c0245 feat: docgen package (#8029) 2022-06-07 10:51:33 +02:00
Noel
5475767c2c build: use cliff-jumper for releases (#8030) 2022-06-07 00:59:21 +02:00
Jiralite
86d8fbc023 fix(DirectoryChannel): Type name and handle url (#8023) 2022-06-06 15:47:13 +02:00
iCrawl
fba9710fc9 chore(builders): dev version 2022-06-06 14:45:46 +02:00
iCrawl
5ca3974301 chore(release): version 2022-06-06 14:44:25 +02:00
iCrawl
3202c91c5a chore: properly adapt changelog script 2022-06-06 14:43:15 +02:00
Jiralite
f3f34f07b3 docs(DirectoryChannel): Extend Channel (#8022) 2022-06-06 14:24:35 +02:00
Parbez
f8ed71bfca fix: readd isThread type guard (#8019) 2022-06-06 14:24:03 +02:00
Voxelli
e1176faa27 feat: backport handle zombie connection (#7626)
* feat: backport zombie connection fixes

* fix: enums

* fix: prettier

* feat: add zombie connection event to shard events

* Apply suggestions from code review

Co-authored-by: muchnameless <12682826+muchnameless@users.noreply.github.com>

* fix: prettier

* fix: handleZombieConnection

* feat: backport new logic of handling zombie connection

Co-authored-by: muchnameless <12682826+muchnameless@users.noreply.github.com>
2022-06-06 12:21:35 +02:00
Caleb Lam
aa59a409b3 feat(CommandInteraction): add 'commandGuildId' (#8018) 2022-06-06 10:07:37 +02:00
Rodry
7fa698d23e types(AttachmentBuilder): fix data type (#8016)
* types(AttachmentBuilder): fix data type

* types(MessageOptions): add AttachmentPayload
2022-06-06 10:07:15 +02:00
markisha64
b9df37a89f refact: Sticker's tags property (#8010) 2022-06-05 23:29:31 +02:00
Rodry
ad75be9a9c feat: allow builders to accept rest params and arrays (#7874)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
Co-authored-by: Khafra <42794878+KhafraDev@users.noreply.github.com>
2022-06-05 23:29:16 +02:00
Suneet Tipirneni
70c733bb9a refactor(channel): remove redundant channel type guards (#8012) 2022-06-05 23:29:05 +02:00
Rodry
a3287782b5 feat(MessageReaction): add react method (#7810) 2022-06-05 23:28:44 +02:00
Suneet Tipirneni
0ccc243c8f types(modal): fix showModal() typings (#8014) 2022-06-05 23:28:28 +02:00
Almeida
0a7953e463 docs(Attachment): remove constructor doc (#8009) 2022-06-05 23:28:18 +02:00
Parbez
6aa623240e types: fix some attachment related typings (#8013) 2022-06-05 22:37:56 +02:00
n1ck_pro
6266b0c1e3 types(AttachmentBuilder): remove name parameter from constructor (#8008) 2022-06-05 22:37:01 +02:00
Suneet Tipirneni
9720e55534 refactor: always return Message instances in interactions (#7917)
Co-authored-by: Almeida <almeidx@pm.me>
2022-06-05 19:00:35 +02:00
Parbez
ad36c0be77 fix: add static method from in builders (#7990) 2022-06-05 18:33:19 +02:00
SpaceEEC
5987dbe5cf docs(VoiceChannel): annotate that it is implementing TextBasedChannel (#8007) 2022-06-05 18:30:14 +02:00
Rodry
5244fe3c1c feat(Collector): add ignore event (#7644)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
2022-06-05 18:29:13 +02:00
Synbulat Biishev
349766dd69 feat(GuildMemberManager): add GuildMemberManager#fetchMe() (#7526) 2022-06-05 18:29:00 +02:00
markisha64
7a1095b66b fix: typings (#7965)
Co-authored-by: Almeida <almeidx@pm.me>
2022-06-05 09:36:59 +02:00
iCrawl
10009a43ee ci: remove cache-dir from test 2022-06-05 01:14:39 +02:00
iCrawl
8d8e6c03de feat: use vitest instead of jest for more speed 2022-06-05 01:07:10 +02:00
Suneet Tipirneni
dfadcbc2fd refactor(attachment): don't return attachment builders from API (#7852)
Co-authored-by: Almeida <almeidx@pm.me>
Co-authored-by: A. Román <kyradiscord@gmail.com>
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
2022-06-04 22:33:13 +02:00
n1ck_pro
546d48655f docs: add missing discord-api-types external types (#8001) 2022-06-04 22:27:01 +02:00
iCrawl
f8739bd9c0 fix(voice): re-add accidental removal of postbuild script 2022-06-04 19:15:28 +02:00
iCrawl
f2ae1f9348 feat: add scripts package for locally used scripts 2022-06-04 19:07:50 +02:00
iCrawl
3401fd4eb6 chore: remove leftover files from pre-monorepo era 2022-06-04 18:41:37 +02:00
iCrawl
fdbd229832 ci: equality check on tag and package name 2022-06-04 17:57:07 +02:00
iCrawl
9e8e2411c1 ci: check for the correct prop to be defined 2022-06-04 17:51:31 +02:00
iCrawl
c02ced9a22 ci: fix if checks for branch/tag when using workflow dispatch 2022-06-04 17:37:00 +02:00
iCrawl
8c5a7f80ef ci: fix inputs for workflow dispatches 2022-06-04 17:15:08 +02:00
iCrawl
14018b0118 ci: allow workflow dispatches 2022-06-04 17:13:40 +02:00
iCrawl
8095723604 chore: only build cjs for actions 2022-06-04 17:08:26 +02:00
iCrawl
e17bb54c85 chore: update dev versions 2022-06-04 17:01:47 +02:00
iCrawl
e92d937bcc chore: release packages 2022-06-04 16:59:00 +02:00
iCrawl
091f1bd170 chore: deps 2022-06-04 16:49:47 +02:00
iCrawl
bd2cf20ecb chore: re-generate changelogs 2022-06-04 16:42:00 +02:00
iCrawl
8af916dba0 chore: remove accidental changelog for voice 2022-06-04 16:22:31 +02:00
iCrawl
781a6e013c chore: fix changelogs 2022-06-04 16:20:33 +02:00
iCrawl
2172a00c50 chore: remove unneeded actions dep 2022-06-04 15:45:18 +02:00
iCrawl
271b1c8e5d feat: actions for workflows 2022-06-04 15:34:40 +02:00
iCrawl
6b8ef20cb3 style: cleanup tests and tsup configs 2022-06-04 15:21:57 +02:00
iCrawl
a45bef4cad fix(proxy): add docs script 2022-06-04 13:34:57 +02:00
DD
1ba2d2a898 feat: @discordjs/proxy (#7925)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
2022-06-04 13:26:25 +02:00
iCrawl
e518c8a137 chore: update yarn 2022-06-04 13:13:52 +02:00
iCrawl
80cd4a4a43 ci: run assigning reviewers also on drafts 2022-06-04 12:59:54 +02:00
iCrawl
8a7cd10554 fix(builders): leftover invalid null type 2022-06-04 12:59:26 +02:00
iCrawl
251862ea57 chore: deps 2022-06-04 12:58:09 +02:00
Jiralite
2f03f9ad3f fix(GuildAuditLogs): Cache guild scheduled events (#7951) 2022-06-04 09:04:08 +02:00
Suneet Tipirneni
db81127886 chore: add external links for dapi-types (#7966) 2022-06-04 09:03:05 +02:00
Suneet Tipirneni
cdd2ba036a feat(guildChannelManager): add videoQualityMode option for create() (#7980)
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
2022-06-04 09:02:21 +02:00
Suneet Tipirneni
97eaab35d7 feat(rest): add guild member banner cdn url (#7973) 2022-06-04 09:00:39 +02:00
Suneet Tipirneni
d60c464e61 types: add types to EventEmitter static methods (#7986) 2022-06-04 08:58:15 +02:00
Suneet Tipirneni
643dab3b1b refactor: clean up modal submissions (#7994)
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2022-06-04 08:57:19 +02:00
Azarias B
68d5169f66 feat: Export types from interactions/slashCommands/mixins (#7942) 2022-05-25 10:04:20 +02:00
Suneet Tipirneni
7f4d411e73 chore: reexport all dapi-types (#7909) 2022-05-25 10:03:51 +02:00
Jeroen Claassens
636d4f263b chore: fix git cliff configs (#7948)
Co-authored-by: Vlad <kingdgrizzle@gmail.com>
2022-05-25 10:02:17 +02:00
Jiralite
fdeac9d9fb types: nullify guildScheduledEventUpdate's old parameter (#7955) 2022-05-21 02:02:57 +02:00
Suneet Tipirneni
adf461baf4 fix: make sure action row builders create djs builders (#7945) 2022-05-18 21:56:56 +02:00
DD
191510b7f8 fix(TextBasedChannel#bulkDelete): return deleted message (#7943) 2022-05-18 19:58:39 +02:00
DD
e2f5a4a494 chore: enable noUncheckedIndexAccess (#7931) 2022-05-18 19:56:42 +02:00
A. Román
993eb74475 chore(deps): update discord-api-types and /voice (#7934) 2022-05-18 19:54:35 +02:00
DD
dfe449c253 feat: REST#raw (#7929) 2022-05-17 16:31:19 +02:00
Jiralite
5e9b757a37 fix: Remove trailing invites on channel deletion (#7932) 2022-05-16 12:13:02 +02:00
Sam
28172ca7b5 fix(DataResolver): fix check for readable streams (#7928) 2022-05-16 12:12:34 +02:00
Vlad Frangu
7ce641d33a fix(SlashCommandBuilder): import Permissions correctly (#7921) 2022-05-14 22:47:26 +02:00
Khafra
e92b17d855 fix(REST): remove dom types (#7922) 2022-05-14 18:39:12 +02:00
Khafra
d1504f2ae1 fix: ok statusCode can be 200..299 (#7919) 2022-05-14 18:38:05 +02:00
Jiralite
b1a3aa97ea chore: bump discord-api-types (#7923) 2022-05-14 18:37:01 +02:00
iCrawl
d522320aa4 chore: update v13 changelog 2022-05-13 12:11:36 +02:00
Khafra
76694c1497 feat(EnumResolvers): remove Enumresolvers (#7876) 2022-05-13 11:35:08 +02:00
Vlad Frangu
de3f1573f0 feat(builders): add new command permissions v2 (#7861) 2022-05-13 11:33:40 +02:00
Synbulat Biishev
aed687b09f feat: move me to GuildMemberManager manager (#7669)
Co-authored-by: muchnameless <12682826+muchnameless@users.noreply.github.com>
Co-authored-by: Almeida <almeidx@pm.me>
2022-05-12 22:51:28 +02:00
n1ck_pro
e07b910e68 types: make CacheType generic more accurate for return values (#7868) 2022-05-12 22:50:31 +02:00
Khafra
d1ec8c37ff feat(rest): use undici (#7747)
Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
Co-authored-by: ckohen <chaikohen@gmail.com>
2022-05-12 22:49:15 +02:00
Parbez
4515a1ea80 chore: bump shapeshift for faster object validation (#7914) 2022-05-12 12:09:50 +02:00
Vlad Frangu
c1b5e731da fix: add localizations for subcommand builders and option choices (#7862) 2022-05-12 10:32:27 +02:00
Suneet Tipirneni
64bdf53116 types(guildScheduledEvent): Mark entityMetadata as nullable (#7908) 2022-05-12 10:30:26 +02:00
Ben
d308c66eec docs(InteractionResponses): replace outdated Embed example for reply (#7875) 2022-05-12 10:29:44 +02:00
Jiralite
dfd9eb20b2 refactor(ThreadChannel): Remove MAX helper from threads (#7846) 2022-05-12 10:29:21 +02:00
Ryan Munro
19eaed6390 fix(AuditLog): default changes to empty array (#7880) 2022-05-12 10:26:07 +02:00
SpaceEEC
4ba0f56b6a feat(VoiceChannel): add support for text in voice (#6921) 2022-05-02 09:39:14 +02:00
advaith
5eeef3f708 types(discord.js): export missing enums (#7864) 2022-05-02 09:37:46 +02:00
with-heart
679dcda970 feat(REST): enable setting default authPrefix (#7853) 2022-04-28 13:08:02 +02:00
newracket
df64d3ea38 fix(Util): flatten ignoring certain fields (#7773) 2022-04-26 00:45:52 +02:00
Jiralite
6239d83c4d fix: possibly missing (#7829) 2022-04-26 00:31:21 +02:00
Khafra
0c18dab128 fix: endReason not being properly set in base Collector (#7833)
* fix: `endReason` not being properly set in base Collector

* types: add _endReason type
2022-04-26 00:31:12 +02:00
Almeida
ece628986c types: fix return type of toString() on channels (#7836)
* types(DMChannel): `toString()` returns a `UserMention`

* test: add more tests
2022-04-26 00:31:05 +02:00
Jiralite
f4ccc6772c docs: require parameter (#7838) 2022-04-26 00:30:58 +02:00
Almeida
5ba7740fcf refactor(Activity): remove undocumented properties (#7844) 2022-04-26 00:30:45 +02:00
Almeida
bfeaf856f7 types(Message#activity): make partyId optional and use enum for type (#7845) 2022-04-26 00:30:13 +02:00
FIRE
361709332b fix(SelectMenuBuilder): options array (#7826) 2022-04-22 20:50:36 +02:00
Rodry
61a44c509c docs(ApplicationCommand): fix and improve localization docs (#7804) 2022-04-21 19:07:49 +02:00
Hyro
4ac91c61d0 fix(Activity): platform type (#7805) 2022-04-21 19:07:18 +02:00
Hyro
4972bd87c1 fix(ApplicationCommand): equal nameLocalizations and descriptionLocalizations (#7802) 2022-04-21 19:06:42 +02:00
Euan Caskie
a1b145e0ce makeContent should accept empty strings (#7764) 2022-04-21 18:57:00 +02:00
Suneet Tipirneni
29293d7bbb refactor: use arrays instead of rest parameters for builders (#7759) 2022-04-21 18:56:10 +02:00
Rodry
f22245e9d0 feat(SelectMenu): allow emojis in options and option constructors (#7797) 2022-04-21 18:55:51 +02:00
Suneet Tipirneni
585169f2f0 types: cleanup *Data type definitions (#7716) 2022-04-19 16:00:55 +02:00
Ryan Munro
ec8d87f932 feat(builders): improve embed errors and predicates (#7795)
* feat(builders): improve embed errors

* fix: use imageURLPredicates

Co-authored-by: Synbulat Biishev <arziksin@gmail.com>

Co-authored-by: Synbulat Biishev <arziksin@gmail.com>
2022-04-19 15:58:47 +02:00
n1ck_pro
440ac243ca types: fix BooleanCache never resolving to true (#7809)
* types: fix BooleanCache never resolving to true

* fix: broke other types by accident
2022-04-19 15:57:44 +02:00
Ryan Munro
c5fb548529 fix(InteractionResponses): use optional chaining on nullable property (#7812)
* fix(InteractionResponses): use optional chaining on nullable property

* fix: one more spot
2022-04-19 15:56:45 +02:00
Almeida
a6d9ce57c6 types(CommandInteraction): add awaitModalSubmit (#7811) 2022-04-19 15:56:22 +02:00
Rodry
08574763eb types(ThreadChannel): fix autoArchiveDuration types (#7816) 2022-04-19 15:54:54 +02:00
iCrawl
9ef7ffdc6d ci: use proper regex escapes 2022-04-17 20:07:19 +02:00
619 changed files with 32897 additions and 13601 deletions

38
.dockerignore Normal file
View File

@@ -0,0 +1,38 @@
# 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

11
.eslintrc.json Normal file
View File

@@ -0,0 +1,11 @@
{
"root": true,
"extends": "marine/prettier/node",
"parserOptions": {
"project": "./tsconfig.eslint.json"
},
"ignorePatterns": ["**/dist/*"],
"env": {
"jest": true
}
}

View File

@@ -15,7 +15,10 @@ body:
- builders
- collection
- rest
- proxy
- proxy-container
- voice
- ws
validations:
required: true
- type: textarea
@@ -126,6 +129,7 @@ body:
- DirectMessages
- DirectMessageReactions
- DirectMessageTyping
- MessageContent
- GuildScheduledEvents
multiple: true
validations:

View File

@@ -17,7 +17,10 @@ body:
- builders
- collection
- rest
- proxy
- proxy-container
- voice
- ws
validations:
required: true
- type: textarea

View File

@@ -5,3 +5,4 @@ reviewers:
- kyranet
- vladfrangu
numberOfReviewers: 0
runOnDraft: true

13
.github/check_deploy_branch.sh vendored Executable file
View 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

16
.github/labeler.yml vendored
View File

@@ -14,6 +14,18 @@ chore:
- 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/**/*
@@ -22,6 +34,10 @@ chore:
- packages/voice/*
- packages/voice/**/*
'packages:website':
- packages/website/*
- packages/website/**/*
'packages:ws':
- packages/ws/*
- packages/ws/**/*

10
.github/labels.yml vendored
View File

@@ -4,6 +4,8 @@
color: '5663e9'
- name: 'backlog'
color: '7ef7ef'
- name: 'blocked'
color: 'fc1423'
- name: 'bug'
color: 'd73a4a'
- name: 'caching'
@@ -50,10 +52,18 @@
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:website'
color: 'fbca04'
- name: 'packages:ws'
color: 'fbca04'
- name: 'performance'

6
.github/powered-by-vercel.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -7,6 +7,11 @@ on:
- '!docs'
tags:
- '**'
workflow_dispatch:
inputs:
ref:
description: 'The branch, tag or SHA to checkout'
required: true
jobs:
build:
name: Build documentation
@@ -18,36 +23,38 @@ jobs:
SHA: ${{ steps.env.outputs.SHA }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.ref || '' }}
- name: Install node.js v16
uses: actions/setup-node@v2
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@v2
with:
path: .turbo
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
turbo-${{ github.job }}-${{ github.ref_name }}-
- name: Install dependencies
run: yarn --immutable
- name: Build docs
run: yarn docs --cache-dir=".turbo"
- name: Build dependencies
run: yarn build
- name: Upload artifacts
uses: actions/upload-artifact@v2
- name: Build docs
run: yarn docs
- name: Upload docgen artifacts
uses: actions/upload-artifact@v3
with:
name: docs
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
- name: Set outputs for upload job
id: env
run: |
@@ -62,60 +69,77 @@ jobs:
max-parallel: 1
fail-fast: false
matrix:
package: ['builders', 'collection', 'discord.js', 'rest', 'voice']
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'voice', 'ws']
runs-on: ubuntu-latest
env:
BRANCH_NAME: ${{ needs.build.outputs.BRANCH_NAME }}
BRANCH_NAME: ${{ github.event.inputs.ref || needs.build.outputs.BRANCH_NAME }}
BRANCH_OR_TAG: ${{ needs.build.outputs.BRANCH_OR_TAG }}
SHA: ${{ needs.build.outputs.SHA }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v2
- name: Checkout repository
uses: actions/checkout@v3
- name: Install node.js v16
uses: actions/setup-node@v3
with:
name: docs
node-version: 16
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable
- name: Build actions
run: yarn workspace @discordjs/actions build
- name: Download docgen artifacts
uses: actions/download-artifact@v3
with:
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@v2
uses: actions/checkout@v3
with:
repository: 'discordjs/docs'
token: ${{ secrets.DJS_DOCS }}
path: 'out'
- name: 'Extract package from tag'
if: env.BRANCH_OR_TAG == 'tag'
id: package-name
uses: frabert/replace-string-action@v2.0
- 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:
pattern: '(^@.*\\/(?<package>.*)@v?)?(?<semver>\d+.\d+.\d+)-?.*'
string: ${{ env.BRANCH_NAME }}
replace-with: '$<package>'
- name: 'Extract semver from tag'
if: env.BRANCH_OR_TAG == 'tag'
id: semver
uses: frabert/replace-string-action@v2.0
with:
pattern: '(^@.*\\/(?<package>.*)@v?)?(?<semver>\d+.\d+.\d+)-?.*'
string: ${{ env.BRANCH_NAME }}
replace-with: '$<semver>'
tag: ${{ env.BRANCH_NAME }}
- name: Move docs to correct directory
if: env.BRANCH_OR_TAG == 'tag'
if: ${{ (github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag') && matrix.package == steps.extract-tag.outputs.package }}
env:
PACKAGE: ${{ steps.package-name.outputs.replaced }}
SEMVER: ${{ steps.semver.outputs.replaced }}
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: env.BRANCH_OR_TAG == 'branch'
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
- name: Commit and push
run: |

View File

@@ -1,4 +1,4 @@
name: Label Sync
name: Label sync
on:
schedule:
- cron: '0 0 * * *'
@@ -9,14 +9,15 @@ on:
paths:
- '.github/labels.yml'
jobs:
labelsync:
label-sync:
name: Label sync
runs-on: ubuntu-latest
if: github.repository_owner == 'discordjs'
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Label sync
uses: crazy-max/ghaction-github-labeler@v3
uses: crazy-max/ghaction-github-labeler@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -4,16 +4,16 @@ on:
schedule:
- cron: '0 1 * * *'
jobs:
auto-deprecate:
npm-auto-deprecate:
name: npm auto deprecate
runs-on: ubuntu-latest
if: github.repository_owner == 'discordjs'
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install node.js v16
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
@@ -23,6 +23,6 @@ jobs:
run: yarn --immutable
- name: Deprecate versions
run: 'yarn npm-deprecate --name "*dev*" --package @discordjs/builders @discordjs/collection discord.js @discordjs/rest @discordjs/voice'
run: 'yarn npm-deprecate --name "*dev*" --package @discordjs/builders @discordjs/collection discord.js @discordjs/proxy @discordjs/rest @discordjs/voice'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

View File

@@ -1,16 +1,17 @@
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
uses: actions/labeler@v3
uses: actions/labeler@v4
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
sync-labels: true
- name: Automatically assign reviewers
if: ${{ github.event.action == 'opened' }}
uses: kentaro-m/auto-assign-action@v1.1.2
if: github.event.action == 'opened'
uses: kentaro-m/auto-assign-action@v1.2.1

View File

@@ -0,0 +1,25 @@
name: Publish dev docker images
on:
workflow_dispatch:
schedule:
- cron: '0 */12 * * *'
jobs:
docker-publish:
name: Docker publish
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

View File

@@ -4,8 +4,8 @@ on:
schedule:
- cron: '0 */12 * * *'
jobs:
npm:
name: npm
npm-publish:
name: npm publish
strategy:
fail-fast: false
matrix:
@@ -16,58 +16,37 @@ jobs:
folder: 'collection'
- package: 'discord.js'
folder: 'discord.js'
- package: '@discordjs/proxy'
folder: 'proxy'
- package: '@discordjs/rest'
folder: 'rest'
- package: '@discordjs/voice'
folder: 'voice'
- package: '@discordjs/ws'
folder: 'ws'
runs-on: ubuntu-latest
if: github.repository_owner == 'discordjs'
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install node.js v16
uses: actions/setup-node@v2
uses: actions/setup-node@v3
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@v2
with:
path: .turbo
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
turbo-${{ github.job }}-${{ github.ref_name }}-
- 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)") ]]; \
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: yarn build
- 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
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
- name: Publish
if: steps.pre-release.outputs.release == 'true'
- name: Publish package
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 }} release --preid "dev.$(date +%s)-$(git rev-parse --short HEAD)"
yarn workspace ${{ matrix.package }} npm publish --tag dev || true
env:
YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

25
.github/workflows/publish-docker.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Publish docker images
on:
workflow_dispatch:
jobs:
docker-publish:
name: Docker publish
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 docker image
run: docker build -t discordjs/proxy:latest -f packages/proxy-container/Dockerfile .
- name: Tag 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

View File

@@ -1,37 +0,0 @@
name: Tests
on: [push, pull_request]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install node.js 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@v2
with:
path: .turbo
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
turbo-${{ github.job }}-${{ github.ref_name }}-
- name: Install dependencies
run: yarn --immutable
- name: ESLint
run: yarn lint --cache-dir=".turbo"
- name: Tests
run: yarn test --cache-dir=".turbo"
- name: Build
run: yarn build --cache-dir=".turbo"

32
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Tests
on: [push, pull_request]
jobs:
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install node.js v16
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable
- name: Build dependencies
run: yarn build
- name: ESLint
run: yarn lint
- name: Tests
run: yarn test
- name: Upload Coverage
uses: ./packages/actions/src/uploadCoverage
if: github.repository_owner == 'discordjs'

5
.gitignore vendored
View File

@@ -26,6 +26,7 @@ dist/
.DS_Store
.turbo
tsconfig.tsbuildinfo
coverage/
# yarn
.pnp.*
@@ -35,3 +36,7 @@ tsconfig.tsbuildinfo
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Cache
.prettiercache
.eslintcache

View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn format
yarn build && yarn lint-staged

5
.lintstagedrc.json Normal file
View File

@@ -0,0 +1,5 @@
{
"*": "prettier --ignore-unknown --write",
"{src/**,__tests__/**}.{mjs,js,ts}": "eslint --ext mjs,js,ts --fix",
"src/**.ts": "vitest related"
}

View File

@@ -7,6 +7,7 @@
"codezombiech.gitignore",
"eamodio.gitlens",
"christian-kohler.npm-intellisense",
"christian-kohler.path-intellisense"
"christian-kohler.path-intellisense",
"antfu.unocss"
]
}

View File

@@ -5,5 +5,7 @@
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": false
}
},
"unocss.root": "./packages/website",
"typescript.tsdk": "node_modules/typescript/lib"
}

View File

@@ -0,0 +1,14 @@
diff --git a/lib/TSDocConfigFile.js b/lib/TSDocConfigFile.js
index caf3515d60fd386c5909db5a0aa8b4180b10d602..6fa4f1984b6ba6b3a7aecd05e54477ebf141af94 100644
--- a/lib/TSDocConfigFile.js
+++ b/lib/TSDocConfigFile.js
@@ -31,8 +31,7 @@ const ajv_1 = __importDefault(require("ajv"));
const jju = __importStar(require("jju"));
const ajv = new ajv_1.default({ verbose: true });
function initializeSchemaValidator() {
- const jsonSchemaPath = resolve.sync('@microsoft/tsdoc/schemas/tsdoc.schema.json', { basedir: __dirname });
- const jsonSchemaContent = fs.readFileSync(jsonSchemaPath).toString();
+ const jsonSchemaContent = "{\"title\":\"TSDoc Configuration\",\"description\":\"Describes the TSDoc configuration for a TypeScript project\",\"type\":\"object\",\"properties\":{\"$schema\":{\"description\":\"Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.\",\"type\":\"string\"},\"extends\":{\"description\":\"Optionally specifies one or more JSON config files that will be combined with this file. This provides a way for standard settings to be shared across multiple projects. Important: The \\\"extends\\\" paths are resolved using NodeJS module resolution, so a path to a local file MUST be prefixed with \\\"./\\\".\",\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"noStandardTags\":{\"description\":\"By default, the config file loader will predefine all of the standardized TSDoc tags. To disable this and start with a completely empty configuration, set \\\"noStandardTags\\\"=true.\",\"type\":\"boolean\"},\"tagDefinitions\":{\"description\":\"Additional tags to support when parsing documentation comments with TSDoc.\",\"type\":\"array\",\"items\":{\"$ref\":\"#/definitions/tsdocTagDefinition\"}},\"supportedHtmlElements\":{\"description\":\"The HTML element names that are supported in this configuration. Used in conjunction with the \\\"reportUnsupportedHtmlElements\\\" setting.\",\"type\":\"array\",\"items\":{\"type\":\"string\",\"pattern\":\"^[a-zA-Z0-9-]+$\"}},\"reportUnsupportedHtmlElements\":{\"description\":\"Whether an error should be reported when an unsupported HTML element is encountered in a doc comment. Defaults to \\\"true\\\" if the \\\"supportedHtmlElements\\\" field is present in this file, \\\"false\\\" if not.\",\"type\":\"boolean\"},\"supportForTags\":{\"description\":\"A collection of key/value pairs. The key is a TSDoc tag name (e.g. \\\"@myTag\\\") that must be defined in this configuration. The value is a boolean indicating whether the tag is supported. The TSDoc parser may report warnings when unsupported tags are encountered. If \\\"supportForTags\\\" is specified for at least one tag, then the \\\"reportUnsupportedTags\\\" validation check is enabled by default.\",\"type\":\"object\",\"patternProperties\":{\"@[a-zA-Z][a-zA-Z0-9]*$\":{\"type\":\"boolean\"}},\"additionalItems\":false}},\"required\":[\"$schema\"],\"additionalProperties\":false,\"definitions\":{\"tsdocTagDefinition\":{\"description\":\"Configuration for a custom supported TSDoc tag.\",\"type\":\"object\",\"properties\":{\"tagName\":{\"description\":\"Name of the custom tag. TSDoc tag names start with an at-sign (@) followed by ASCII letters using camelCase capitalization.\",\"type\":\"string\"},\"syntaxKind\":{\"description\":\"Syntax kind of the custom tag. \\\"inline\\\" means that this tag can appear inside other documentation sections (example: {@link}). \\\"block\\\" means that this tag starts a new documentation section (example: @remarks). \\\"modifier\\\" means that this tag's presence indicates an aspect of the associated API item (example: @internal).\",\"type\":\"string\",\"enum\":[\"inline\",\"block\",\"modifier\"]},\"allowMultiple\":{\"description\":\"If true, then this tag may appear multiple times in a doc comment. By default, a tag may only appear once.\",\"type\":\"boolean\"}},\"required\":[\"tagName\",\"syntaxKind\"],\"additionalProperties\":false}}}";
const jsonSchema = jju.parse(jsonSchemaContent, { mode: 'cjson' });
return ajv.compile(jsonSchema);
}

View File

@@ -0,0 +1,36 @@
diff --git a/dist/rollup-plugin-typescript2.cjs.js b/dist/rollup-plugin-typescript2.cjs.js
index 9ab972b041cc76f8f786d6a20f3efb53c364cad6..13e056a3c0971eb18b307d91fad096a9f3b9de79 100644
--- a/dist/rollup-plugin-typescript2.cjs.js
+++ b/dist/rollup-plugin-typescript2.cjs.js
@@ -29799,6 +29799,13 @@ const typescript = (options) => {
declarations[key] = { type: result.dts, map: result.dtsmap };
context.debug(() => `${safe.exports.blue("generated declarations")} for '${key}'`);
}
+ // if a user sets this compilerOption, they probably want another plugin (e.g. Babel, ESBuild) to transform their TS instead, while rpt2 just type-checks and/or outputs declarations
+ // note that result.code is non-existent if emitDeclarationOnly per https://github.com/ezolenko/rollup-plugin-typescript2/issues/268
+ if (parsedConfig.options.emitDeclarationOnly)
+ {
+ context.debug(() => `${blue("emitDeclarationOnly")} enabled, not transforming TS'`);
+ return undefined;
+ }
const transformResult = { code: result.code, map: { mappings: "" } };
if (result.map) {
if (pluginOptions.sourceMapCallback)
diff --git a/dist/rollup-plugin-typescript2.es.js b/dist/rollup-plugin-typescript2.es.js
index e43bf8f03bc6792b61d8352e04bb6466712426c2..420e8f0d0d109076bc72e9d60240077235a9ba11 100644
--- a/dist/rollup-plugin-typescript2.es.js
+++ b/dist/rollup-plugin-typescript2.es.js
@@ -29770,6 +29770,13 @@ const typescript = (options) => {
declarations[key] = { type: result.dts, map: result.dtsmap };
context.debug(() => `${safe.exports.blue("generated declarations")} for '${key}'`);
}
+ // if a user sets this compilerOption, they probably want another plugin (e.g. Babel, ESBuild) to transform their TS instead, while rpt2 just type-checks and/or outputs declarations
+ // note that result.code is non-existent if emitDeclarationOnly per https://github.com/ezolenko/rollup-plugin-typescript2/issues/268
+ if (parsedConfig.options.emitDeclarationOnly)
+ {
+ context.debug(() => `${blue("emitDeclarationOnly")} enabled, not transforming TS'`);
+ return undefined;
+ }
const transformResult = { code: result.code, map: { mappings: "" } };
if (result.map) {
if (pluginOptions.sourceMapCallback)

File diff suppressed because one or more lines are too long

786
.yarn/releases/yarn-3.2.1.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -8,4 +8,4 @@ plugins:
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
spec: "@yarnpkg/plugin-version"
yarnPath: .yarn/releases/yarn-3.1.1.cjs
yarnPath: .yarn/releases/yarn-3.2.1.cjs

191
LICENSE Normal file
View File

@@ -0,0 +1,191 @@
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 2015 Amish Shah
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.

View File

@@ -1,15 +1,19 @@
<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/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>
</p>
<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/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>
<p>
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
</p>
</div>
## About
@@ -42,19 +46,18 @@ pnpm add discord.js
## Example usage
Install all required dependencies:
Install discord.js:
```sh-session
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
npm install discord.js
yarn add discord.js
pnpm add discord.js
```
Register a slash command against the Discord API:
```js
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v10');
const { REST, Routes } = require('discord.js');
const commands = [
{
@@ -89,7 +92,7 @@ client.on('ready', () => {
});
client.on('interactionCreate', async (interaction) => {
if (!interaction.isCommand()) return;
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'ping') {
await interaction.reply('Pong!');
@@ -101,10 +104,10 @@ client.login('token');
## Links
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
- [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.
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v14.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)

93
build.config.ts Normal file
View File

@@ -0,0 +1,93 @@
import { relative, resolve } from 'node:path';
import glob from 'fast-glob';
import typescript from 'rollup-plugin-typescript2';
import { defineBuildConfig, BuildEntry } from 'unbuild';
interface ConfigOptions {
entries: (BuildEntry | string)[];
minify: boolean;
emitCJS: boolean;
externals: string[];
cjsBridge: boolean;
sourcemap: boolean;
preserveModules: boolean;
preserveModulesRoot: string;
declaration: boolean;
typeCheck: boolean;
}
export function createUnbuildConfig({
entries = [{ builder: 'rollup', input: 'src/index' }],
minify = false,
emitCJS = true,
cjsBridge = true,
externals = [],
sourcemap = true,
preserveModules = true,
preserveModulesRoot = 'src',
declaration = true,
typeCheck = false,
}: Partial<ConfigOptions> = {}) {
const files = glob
.sync('**', { cwd: 'src' })
.map((file) => [`${file.slice(0, -2)}cjs`, `${file.slice(0, -2)}mjs`])
.flat();
return defineBuildConfig({
entries,
clean: true,
rollup: {
esbuild: {
minify,
minifyIdentifiers: false,
},
emitCJS,
cjsBridge,
json: {
namedExports: false,
},
},
externals: [...files, ...externals],
hooks: {
'rollup:options': (_, options) => {
// @ts-expect-error: This will always be an array
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
options.output![0] = {
// @ts-expect-error: This will always be an array
...options.output![0],
sourcemap,
preserveModules,
preserveModulesRoot,
};
if (emitCJS) {
// @ts-expect-error: This will always be an array
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
options.output![1] = {
// @ts-expect-error: This will always be an array
...options.output![1],
sourcemap,
preserveModules,
preserveModulesRoot,
};
}
if (declaration) {
options.plugins?.unshift(
typescript({
check: typeCheck,
tsconfig: relative(__dirname, resolve(process.cwd(), 'tsconfig.json')),
tsconfigOverride: {
compilerOptions: {
emitDeclarationOnly: true,
},
},
}),
);
}
},
},
});
}

26
codecov.yml Normal file
View File

@@ -0,0 +1,26 @@
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

View File

@@ -4,14 +4,13 @@
"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",
"build": "yarn workspaces foreach --parallel --topological run build",
"test": "yarn workspaces foreach --parallel --topological run test",
"lint": "yarn workspaces foreach --parallel --topological run lint",
"format": "yarn workspaces foreach --parallel --topological run format",
"fmt": "yarn format",
"postinstall": "is-ci || husky install",
"docs": "turbo run docs",
"changelog": "turbo run changelog",
"docs": "yarn workspaces foreach --parallel --topological run docs",
"update": "yarn upgrade-interactive"
},
"contributors": [
@@ -38,13 +37,28 @@
},
"homepage": "https://discord.js.org",
"devDependencies": {
"@commitlint/cli": "^16.2.3",
"@commitlint/config-angular": "^16.2.3",
"@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.31.0",
"@typescript-eslint/parser": "^5.31.0",
"conventional-changelog-cli": "^2.2.2",
"husky": "^7.0.4",
"prettier": "^2.6.2",
"turbo": "^1.2.4"
"eslint": "^8.20.0",
"eslint-config-marine": "^9.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.3.0",
"eslint-plugin-import": "^2.26.0",
"fast-glob": "^3.2.11",
"husky": "^8.0.1",
"is-ci": "^3.0.1",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
},
"resolutions": {
"rollup-plugin-typescript2@0.32.1": "patch:rollup-plugin-typescript2@npm:0.32.1#.yarn/patches/rollup-plugin-typescript2-npm-0.32.1-b5887420f2.patch",
"@microsoft/tsdoc-config": "patch:@microsoft/tsdoc-config@npm:0.16.1#.yarn/patches/@microsoft-tsdoc-config-npm-0.16.1-81031b1bbf.patch"
},
"engines": {
"node": ">=16.9.0"
@@ -52,5 +66,5 @@
"workspaces": [
"packages/*"
],
"packageManager": "yarn@3.1.1"
"packageManager": "yarn@3.2.1"
}

View File

@@ -0,0 +1,3 @@
{
"extends": "../../.eslintrc.json"
}

29
packages/actions/.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
# 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/

View File

@@ -0,0 +1 @@
module.exports = require('../../.lintstagedrc.json');

View File

@@ -0,0 +1,8 @@
# Autogenerated
CHANGELOG.md
.turbo
dist/
docs/**/*
!docs/index.yml
!docs/README.md
coverage/

View File

@@ -0,0 +1 @@
module.exports = require('../../.prettierrc.json');

190
packages/actions/LICENSE Normal file
View File

@@ -0,0 +1,190 @@
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 2022 Noel Buechler
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.

View File

@@ -0,0 +1,34 @@
<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>
<p>
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></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-v14.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).

View File

@@ -0,0 +1,22 @@
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({ package: 'discord.js', semver: '13.5.1' });
expect(formatTag('13.7.0')).toEqual({ package: 'discord.js', semver: '13.7.0' });
});
test('GIVEN no or invalid tag THEN return null', () => {
expect(formatTag('')).toEqual(null);
expect(formatTag('abc')).toEqual(null);
});
});

View File

@@ -0,0 +1,3 @@
import { createUnbuildConfig } from '../../build.config';
export default createUnbuildConfig({ minify: true, emitCJS: false });

View File

@@ -0,0 +1,58 @@
{
"name": "@discordjs/actions",
"version": "0.1.0",
"description": "A set of actions that we use for our workflows",
"private": true,
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"fmt": "yarn format"
},
"main": "./dist/index.mjs",
"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.46",
"c8": "^7.12.0",
"eslint": "^8.20.0",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"typescript": "^4.7.4",
"unbuild": "^0.7.6",
"vitest": "^0.19.1"
},
"engines": {
"node": ">=16.9.0"
}
}

View File

@@ -0,0 +1,14 @@
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.mjs

View File

@@ -0,0 +1,12 @@
export function formatTag(tag: string) {
const parsed = /(^@.*\/(?<package>.*)@v?)?(?<semver>\d+.\d+.\d+)-?.*/.exec(tag);
if (parsed?.groups) {
return {
package: parsed.groups.package ?? 'discord.js',
semver: parsed.groups.semver,
};
}
return null;
}

View File

@@ -0,0 +1,10 @@
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);
}

View File

@@ -0,0 +1 @@
export * from './formatTag/formatTag';

View File

@@ -0,0 +1,58 @@
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 WS Coverage
uses: codecov/codecov-action@v3
with:
files: ./packages/ws/coverage/cobertura-coverage.xml
flags: ws
- 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

View File

@@ -0,0 +1,20 @@
{
"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": []
}

View File

@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*.ts"]
}

View File

@@ -0,0 +1,5 @@
{
"name": "builders",
"org": "discordjs",
"packagePath": "packages/builders"
}

View File

@@ -1,12 +1,3 @@
{
"root": true,
"extends": "marine/prettier/node",
"parserOptions": {
"project": "./tsconfig.eslint.json",
"extraFileExtensions": [".mjs"]
},
"ignorePatterns": ["**/dist/*"],
"env": {
"jest": true
}
"extends": "../../.eslintrc.json"
}

View File

@@ -19,7 +19,7 @@ dist/
typings/
docs/**/*
!docs/index.yml
!docs/index.json
!docs/README.md
!docs/examples/
!docs/examples/*.md

View File

@@ -0,0 +1 @@
module.exports = require('../../.lintstagedrc.json');

View File

@@ -5,4 +5,4 @@ dist/
docs/**/*
!docs/index.yml
!docs/README.md
coverage/
coverage/

View File

@@ -0,0 +1 @@
module.exports = require('../../.prettierrc.json');

View File

@@ -1,8 +0,0 @@
{
"printWidth": 120,
"useTabs": true,
"singleQuote": true,
"quoteProps": "as-needed",
"trailingComma": "all",
"endOfLine": "lf"
}

View File

@@ -1,3 +0,0 @@
{
"releaseCommitMessageFormat": "chore(Release): publish"
}

View File

@@ -2,7 +2,98 @@
All notable changes to this project will be documented in this file.
# [0.13.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.12.0...@discordjs/builders@0.13.0) (2022-04-17)
# [@discordjs/builders@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.0.0...@discordjs/builders@1.1.0) - (2022-07-29)
## Bug Fixes
- Use proper format for `@link` text (#8384) ([2655639](https://github.com/discordjs/discord.js/commit/26556390a3800e954974a00c1328ff47d3e67e9a))
- **Formatters:** Add newline in `codeBlock` (#8369) ([5d8bd03](https://github.com/discordjs/discord.js/commit/5d8bd030d60ef364de3ef5f9963da8bda5c4efd4))
- **selectMenu:** Allow json to be used for select menu options (#8322) ([6a2d0d8](https://github.com/discordjs/discord.js/commit/6a2d0d8e96d157d5b85cee7f17bffdfff4240074))
## Documentation
- Use link tags (#8382) ([5494791](https://github.com/discordjs/discord.js/commit/549479131318c659f86f0eb18578d597e22522d3))
## Features
- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1))
# [@discordjs/builders@1.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.16.0...@discordjs/builders@1.0.0) - (2022-07-17)
## Info
- 1.0.0 release bump, no new features.
# [@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
@@ -15,13 +106,11 @@ All notable changes to this project will be documented in this file.
- 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))
- **builders:** Dont export `Button` component stuff twice (#7289) ([86d9d06](https://github.com/discordjs/discord.js/commit/86d9d0674347c08d056cd054cb4ce4253195bf94))
## 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))
- **SlashCommandSubcommands:** Updating old links from Discord developer portal (#7224) ([bd7a6f2](https://github.com/discordjs/discord.js/commit/bd7a6f265212624199fb0b2ddc8ece39759c63de))
## Features
@@ -33,7 +122,6 @@ All notable changes to this project will be documented in this file.
- **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))
- Add components to /builders (#7195) ([2bb40fd](https://github.com/discordjs/discord.js/commit/2bb40fd767cf5918e3ba422ff73082734bfa05b0))
## Refactor
@@ -55,9 +143,8 @@ All notable changes to this project will be documented in this file.
## Typings
- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664))
- Make `required` a boolean (#7307) ([c10afea](https://github.com/discordjs/discord.js/commit/c10afeadc702ab98bec5e077b3b92494a9596f9c))
# [0.12.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.11.0...@discordjs/builders@0.12.0) (2021-12-08)
# [@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

View File

@@ -4,12 +4,15 @@
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
</p>
<br />
<p>
<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/builders"><img src="https://codecov.io/gh/discordjs/builders/branch/main/graph/badge.svg" alt="Code coverage" /></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>
<p>
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
</p>
</div>
@@ -31,10 +34,10 @@ Here are some examples for the builders and utilities you can find in this packa
## Links
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/website))
- [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.
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v14.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)

View File

@@ -1,4 +1,5 @@
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
ActionRowBuilder,
ButtonBuilder,
@@ -46,6 +47,8 @@ describe('Action Row Components', () => {
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', () => {
@@ -82,6 +85,7 @@ describe('Action Row Components', () => {
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,
@@ -122,7 +126,8 @@ describe('Action Row Components', () => {
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', () => {
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')
@@ -131,10 +136,16 @@ describe('Action Row Components', () => {
.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);
});
});
});

View File

@@ -4,6 +4,7 @@ import {
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';
@@ -124,7 +125,7 @@ describe('Button Components', () => {
expect(
buttonComponent()
.setCustomId(interactionData.custom_id)
.setLabel(interactionData.label)
.setLabel(interactionData.label!)
.setStyle(interactionData.style)
.setDisabled(interactionData.disabled)
.toJSON(),
@@ -140,7 +141,7 @@ describe('Button Components', () => {
expect(new ButtonBuilder(linkData).toJSON()).toEqual(linkData);
expect(buttonComponent().setLabel(linkData.label).setDisabled(true).setURL(linkData.url));
expect(buttonComponent().setLabel(linkData.label!).setDisabled(true).setURL(linkData.url));
});
});
});

View File

@@ -0,0 +1,73 @@
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();
});
});

View File

@@ -1,4 +1,5 @@
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();
@@ -46,27 +47,49 @@ describe('Select Menu Components', () => {
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,
},
}),
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', () => {
@@ -87,15 +110,32 @@ describe('Select Menu Components', () => {
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()
@@ -109,12 +149,28 @@ describe('Select Menu Components', () => {
}).toThrowError();
});
test('GIVEN valid option types THEN does not throw', () => {
expect(() =>
selectMenu().addOptions({
label: 'test',
value: 'test',
}),
).not.toThrowError();
expect(() => selectMenu().addOptions(selectMenuOption().setLabel('test').setValue('test'))).not.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);
});
});

View File

@@ -1,4 +1,5 @@
import { APITextInputComponent, ComponentType, TextInputStyle } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
labelValidator,
maxLengthValidator,
@@ -45,7 +46,7 @@ describe('Text Input Components', () => {
expect(() => maxLengthValidator.parse(10)).not.toThrowError();
});
test('GIVEN invalid min length THEN validator does throw', () => {
test('GIVEN invalid min length THEN validator does throw 2', () => {
expect(() => maxLengthValidator.parse(4001)).toThrowError();
});
@@ -61,7 +62,7 @@ describe('Text Input Components', () => {
expect(() => placeholderValidator.parse('foobar')).not.toThrowError();
});
test('GIVEN invalid value THEN validator does throw', () => {
test('GIVEN invalid value THEN validator does throw 2', () => {
expect(() => placeholderValidator.parse(superLongStr)).toThrowError();
});
@@ -81,6 +82,12 @@ describe('Text Input Components', () => {
.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();
});
});
@@ -114,10 +121,10 @@ describe('Text Input Components', () => {
textInputComponent()
.setCustomId(textInputData.custom_id)
.setLabel(textInputData.label)
.setPlaceholder(textInputData.placeholder)
.setMaxLength(textInputData.max_length)
.setMinLength(textInputData.min_length)
.setValue(textInputData.value)
.setPlaceholder(textInputData.placeholder!)
.setMaxLength(textInputData.max_length!)
.setMinLength(textInputData.min_length!)
.setValue(textInputData.value!)
.setRequired(textInputData.required)
.setStyle(textInputData.style)
.toJSON(),

View File

@@ -1,3 +1,5 @@
import { PermissionFlagsBits } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index';
const getBuilder = () => new ContextMenuCommandBuilder();
@@ -84,6 +86,63 @@ describe('Context Menu Commands', () => {
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();
});
});
});
});

View File

@@ -1,4 +1,5 @@
import {
APIApplicationCommandAttachmentOption,
APIApplicationCommandBooleanOption,
APIApplicationCommandChannelOption,
APIApplicationCommandIntegerOption,
@@ -10,7 +11,9 @@ import {
ApplicationCommandOptionType,
ChannelType,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
SlashCommandAttachmentOption,
SlashCommandBooleanOption,
SlashCommandChannelOption,
SlashCommandIntegerOption,
@@ -57,6 +60,9 @@ const getRoleOption = () => new SlashCommandRoleOption().setName('owo').setDescr
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>({
@@ -166,11 +172,13 @@ describe('Application Command toJSON() results', () => {
});
test('GIVEN a string option THEN calling toJSON should return a valid JSON', () => {
expect(getStringOption().toJSON()).toEqual<APIApplicationCommandStringOption>({
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>({
@@ -202,4 +210,13 @@ describe('Application Command toJSON() results', () => {
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,
});
});
});

View File

@@ -1,4 +1,5 @@
import { APIApplicationCommandOptionChoice, ChannelType } from 'discord-api-types/v10';
import { APIApplicationCommandOptionChoice, ChannelType, PermissionFlagsBits } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
SlashCommandAssertions,
SlashCommandBooleanOption,
@@ -41,6 +42,8 @@ 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', () => {
@@ -50,7 +53,10 @@ describe('Slash Commands', () => {
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(() =>
@@ -87,6 +93,7 @@ describe('Slash Commands', () => {
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();
});
@@ -127,6 +134,7 @@ describe('Slash Commands', () => {
getBuilder()
.setName('example')
.setDescription('Example command')
.setDMPermission(false)
.addBooleanOption((boolean) =>
boolean.setName('iscool').setDescription('Are we cool or what?').setRequired(true),
)
@@ -313,8 +321,10 @@ describe('Slash Commands', () => {
// @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
@@ -433,7 +443,7 @@ describe('Slash Commands', () => {
expect(() => getBuilder().setNameLocalizations({ 'en-US': 'foobar' })).not.toThrowError();
});
test('GIVEN valid name localizations THEN does not throw error', () => {
test('GIVEN invalid name localizations THEN does throw error', () => {
// @ts-expect-error
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
// @ts-expect-error
@@ -456,7 +466,7 @@ describe('Slash Commands', () => {
expect(() => getBuilder().setDescriptionLocalizations({ 'en-US': 'foobar' })).not.toThrowError();
});
test('GIVEN valid description localizations THEN does not throw error', () => {
test('GIVEN invalid description localizations THEN does throw error', () => {
// @ts-expect-error
expect(() => getBuilder().setDescriptionLocalization('en-U', 'foobar')).toThrowError();
// @ts-expect-error
@@ -476,5 +486,27 @@ describe('Slash Commands', () => {
});
});
});
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();
});
});
});
});

View File

@@ -1,4 +1,10 @@
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v10';
import {
APIModalInteractionResponseCallbackData,
APITextInputComponent,
ComponentType,
TextInputStyle,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
ActionRowBuilder,
ButtonBuilder,
@@ -50,14 +56,16 @@ describe('Modals', () => {
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(() =>
// @ts-expect-error
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRowBuilder()]).toJSON(),
).toThrowError();
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
// @ts-expect-error
expect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError();
});
@@ -78,6 +86,17 @@ describe('Modals', () => {
},
],
},
{
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.TextInput,
label: 'label',
style: TextInputStyle.Paragraph,
custom_id: 'custom id',
},
],
},
],
};
@@ -92,7 +111,63 @@ describe('Modals', () => {
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();
});
});
});

View File

@@ -1,3 +1,4 @@
import { describe, test, expect } from 'vitest';
import { EmbedBuilder, embedLength } from '../../src';
const alpha = 'abcdefghijklmnopqrstuvwxyz';
@@ -13,13 +14,13 @@ describe('Embed', () => {
footer: { text: alpha },
});
expect(embedLength(embed.data)).toBe(alpha.length * 6);
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)).toBe(0);
expect(embedLength(embed.data)).toEqual(0);
});
});
@@ -323,9 +324,13 @@ describe('Embed', () => {
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', inline: undefined }],
fields: [
{ name: 'foo', value: 'bar' },
{ name: 'foo', value: 'bar' },
],
});
});
@@ -334,11 +339,11 @@ describe('Embed', () => {
embed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });
expect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({
fields: [{ name: 'foo', value: 'baz', inline: undefined }],
fields: [{ name: 'foo', value: 'baz' }],
});
});
test('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {
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' })));
@@ -362,6 +367,9 @@ describe('Embed', () => {
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', () => {
@@ -370,10 +378,11 @@ describe('Embed', () => {
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('', () => {
test('1', () => {
const embed = new EmbedBuilder();
expect(() =>
@@ -383,7 +392,7 @@ describe('Embed', () => {
});
describe('GIVEN invalid field name THEN throws error', () => {
test('', () => {
test('2', () => {
const embed = new EmbedBuilder();
expect(() => embed.addFields({ name: '', value: 'bar' })).toThrowError();
@@ -391,7 +400,7 @@ describe('Embed', () => {
});
describe('GIVEN invalid field name length THEN throws error', () => {
test('', () => {
test('3', () => {
const embed = new EmbedBuilder();
expect(() => embed.addFields({ name: 'a'.repeat(257), value: 'bar' })).toThrowError();
@@ -399,7 +408,7 @@ describe('Embed', () => {
});
describe('GIVEN invalid field value length THEN throws error', () => {
test('', () => {
test('4', () => {
const embed = new EmbedBuilder();
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();

View File

@@ -1,6 +1,9 @@
import { URL } from 'node:url';
import { describe, test, expect, vitest } from 'vitest';
import {
blockQuote,
bold,
channelLink,
channelMention,
codeBlock,
Faces,
@@ -9,6 +12,7 @@ import {
hyperlink,
inlineCode,
italic,
messageLink,
quote,
roleMention,
spoiler,
@@ -22,75 +26,75 @@ import {
describe('Message formatters', () => {
describe('codeBlock', () => {
test('GIVEN "discord.js" with no language THEN returns "```\\ndiscord.js```"', () => {
expect<'```\ndiscord.js```'>(codeBlock('discord.js')).toBe('```\ndiscord.js```');
expect<'```\ndiscord.js\n```'>(codeBlock('discord.js')).toEqual('```\ndiscord.js\n```');
});
test('GIVEN "discord.js" with "js" as language THEN returns "```js\\ndiscord.js```"', () => {
expect<'```js\ndiscord.js```'>(codeBlock('js', 'discord.js')).toBe('```js\ndiscord.js```');
expect<'```js\ndiscord.js\n```'>(codeBlock('js', 'discord.js')).toEqual('```js\ndiscord.js\n```');
});
});
describe('inlineCode', () => {
test('GIVEN "discord.js" THEN returns "`discord.js`"', () => {
expect<'`discord.js`'>(inlineCode('discord.js')).toBe('`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')).toBe('_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')).toBe('**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')).toBe('__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')).toBe('~~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')).toBe('> 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')).toBe('>>> 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')).toBe('<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/'))).toBe('<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')).toBe(
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'))).toBe(
expect<`[discord.js](${string})`>(hyperlink('discord.js', new URL('https://discord.js.org'))).toEqual(
'[discord.js](https://discord.js.org/)',
);
});
@@ -98,102 +102,132 @@ describe('Message formatters', () => {
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'),
).toBe('[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'),
).toBe('[discord.js](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')).toBe('||discord.js||');
expect<'||discord.js||'>(spoiler('discord.js')).toEqual('||discord.js||');
});
});
describe('Mentions', () => {
describe('userMention', () => {
test('GIVEN userId THEN returns "<@[userId]>"', () => {
expect(userMention('139836912335716352')).toBe('<@139836912335716352>');
expect(userMention('139836912335716352')).toEqual('<@139836912335716352>');
});
});
describe('channelMention', () => {
test('GIVEN channelId THEN returns "<#[channelId]>"', () => {
expect(channelMention('829924760309334087')).toBe('<#829924760309334087>');
expect(channelMention('829924760309334087')).toEqual('<#829924760309334087>');
});
});
describe('roleMention', () => {
test('GIVEN roleId THEN returns "<&[roleId]>"', () => {
expect(roleMention('815434166602170409')).toBe('<@&815434166602170409>');
expect(roleMention('815434166602170409')).toEqual('<@&815434166602170409>');
});
});
});
describe('formatEmoji', () => {
test('GIVEN static emojiId THEN returns "<:_:${emojiId}>"', () => {
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952')).toBe('<:_:851461487498493952>');
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952')).toEqual('<:_:851461487498493952>');
});
test('GIVEN static emojiId WITH animated explicitly false THEN returns "<:_:[emojiId]>"', () => {
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952', false)).toBe('<:_:851461487498493952>');
expect<`<:_:851461487498493952>`>(formatEmoji('851461487498493952', false)).toEqual('<:_:851461487498493952>');
});
test('GIVEN animated emojiId THEN returns "<a:_:${emojiId}>"', () => {
expect<`<a:_:827220205352255549>`>(formatEmoji('827220205352255549', true)).toBe('<a:_:827220205352255549>');
expect<`<a:_:827220205352255549>`>(formatEmoji('827220205352255549', true)).toEqual('<a:_:827220205352255549>');
});
});
describe('channelLink', () => {
test('GIVEN channelId THEN returns "https://discord.com/channels/@me/${channelId}"', () => {
expect<'https://discord.com/channels/@me/123456789012345678'>(channelLink('123456789012345678')).toEqual(
'https://discord.com/channels/@me/123456789012345678',
);
});
test('GIVEN channelId WITH guildId THEN returns "https://discord.com/channels/${guildId}/${channelId}"', () => {
expect<'https://discord.com/channels/987654321987654/123456789012345678'>(
channelLink('123456789012345678', '987654321987654'),
).toEqual('https://discord.com/channels/987654321987654/123456789012345678');
});
});
describe('messageLink', () => {
test('GIVEN channelId AND messageId THEN returns "https://discord.com/channels/@me/${channelId}/${messageId}"', () => {
expect<'https://discord.com/channels/@me/123456789012345678/102938475657483'>(
messageLink('123456789012345678', '102938475657483'),
).toEqual('https://discord.com/channels/@me/123456789012345678/102938475657483');
});
test('GIVEN channelId AND messageId WITH guildId THEN returns "https://discord.com/channels/${guildId}/${channelId}/${messageId}"', () => {
expect<'https://discord.com/channels/987654321987654/123456789012345678/102938475657483'>(
messageLink('123456789012345678', '102938475657483', '987654321987654'),
).toEqual('https://discord.com/channels/987654321987654/123456789012345678/102938475657483');
});
});
describe('time', () => {
test('GIVEN no arguments THEN returns "<t:${bigint}>"', () => {
jest.useFakeTimers('modern');
jest.setSystemTime(1566424897579);
vitest.useFakeTimers();
vitest.setSystemTime(1566424897579);
expect<`<t:${bigint}>`>(time()).toBe('<t:1566424897>');
expect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');
jest.useRealTimers();
vitest.useRealTimers();
});
test('GIVEN a date THEN returns "<t:${bigint}>"', () => {
expect<`<t:${bigint}>`>(time(new Date(1867424897579))).toBe('<t:1867424897>');
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')).toBe('<t:1867424897:d>');
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)).toBe('<t:1867424897:R>');
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)).toBe('<t:1867424897>');
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')).toBe('<t:1867424897:d>');
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)).toBe('<t:1867424897:R>');
expect<'<t:1867424897:R>'>(time(1867424897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
});
});
describe('Faces', () => {
test('GIVEN Faces.Shrug THEN returns "¯\\_(ツ)\\_/¯"', () => {
expect<'¯\\_(ツ)\\_/¯'>(Faces.Shrug).toBe('¯\\_(ツ)\\_/¯');
expect<'¯\\_(ツ)\\_/¯'>(Faces.Shrug).toEqual('¯\\_(ツ)\\_/¯');
});
test('GIVEN Faces.Tableflip THEN returns "(╯°□°)╯︵ ┻━┻"', () => {
expect<'(╯°□°)╯︵ ┻━┻'>(Faces.Tableflip).toBe('(╯°□°)╯︵ ┻━┻');
expect<'(╯°□°)╯︵ ┻━┻'>(Faces.Tableflip).toEqual('(╯°□°)╯︵ ┻━┻');
});
test('GIVEN Faces.Unflip THEN returns "┬─┬ ( ゜-゜ノ)"', () => {
expect<'┬─┬ ( ゜-゜ノ)'>(Faces.Unflip).toBe('┬─┬ ( ゜-゜ノ)');
expect<'┬─┬ ( ゜-゜ノ)'>(Faces.Unflip).toEqual('┬─┬ ( ゜-゜ノ)');
});
});
});

View File

@@ -0,0 +1,42 @@
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();
});
});

View File

@@ -0,0 +1,376 @@
/**
* 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>/docs/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
// },
//
// . . .
}
}
}

View File

@@ -1,18 +0,0 @@
/**
* @type {import('@babel/core').TransformOptions}
*/
module.exports = {
parserOpts: { strictMode: true },
sourceMaps: 'inline',
presets: [
[
'@babel/preset-env',
{
targets: { node: 'current' },
modules: 'commonjs',
},
],
'@babel/preset-typescript',
],
plugins: ['babel-plugin-transform-typescript-metadata', ['@babel/plugin-proposal-decorators', { legacy: true }]],
};

View File

@@ -0,0 +1,3 @@
import { createUnbuildConfig } from '../../build.config';
export default createUnbuildConfig();

View File

@@ -6,29 +6,31 @@ 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") }})
# [{{ 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]
# [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
## {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}\
[**breaking**] \
{% endif %}\
{% 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 }}))\
{% endfor %}
## {{ 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
@@ -38,25 +40,24 @@ footer = ""
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"},
{ 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@.*"
skip_tags = "v[0-9]*|11|12"
tag_pattern = "@discordjs/builders@[0-9]*"
ignore_tags = ""
topo_order = false
date_order = true
sort_commits = "newest"

View File

@@ -1,10 +0,0 @@
coverage:
status:
project:
default:
target: 70%
threshold: 5%
patch:
default:
target: 70%
threshold: 5%

View File

@@ -0,0 +1 @@
[{ "name": "General", "files": [{ "name": "Welcome", "id": "welcome", "path": "../../README.md" }] }]

View File

@@ -1,5 +0,0 @@
- name: General
files:
- name: Welcome
id: welcome
path: ../../README.md

View File

@@ -1,19 +0,0 @@
/**
* @type {import('@jest/types').Config.InitialOptions}
*/
module.exports = {
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
testEnvironment: 'node',
collectCoverage: true,
collectCoverageFrom: ['src/**/*.ts'],
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'clover'],
coverageThreshold: {
global: {
branches: 70,
lines: 70,
statements: 70,
},
},
coveragePathIgnorePatterns: ['src/index.ts'],
};

View File

@@ -1,22 +1,24 @@
{
"name": "@discordjs/builders",
"version": "0.14.0-dev",
"version": "1.1.0",
"description": "A set of builders that you can use when creating your bot",
"scripts": {
"build": "tsup",
"test": "jest --pass-with-no-tests",
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"docs": "typedoc --json docs/typedoc-out.json src/index.ts && node scripts/docs.mjs",
"prepublishOnly": "yarn build && yarn lint && yarn test",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'"
"fmt": "yarn format",
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
"prepack": "yarn lint && yarn test && yarn build",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'",
"release": "cliff-jumper"
},
"main": "./dist/index.js",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"directories": {
@@ -52,33 +54,25 @@
},
"homepage": "https://discord.js.org",
"dependencies": {
"@sapphire/shapeshift": "^2.0.0",
"@sindresorhus/is": "^4.6.0",
"discord-api-types": "^0.31.1",
"@sapphire/shapeshift": "^3.5.1",
"discord-api-types": "^0.36.3",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.1",
"tslib": "^2.3.1"
"tslib": "^2.4.0"
},
"devDependencies": {
"@babel/core": "^7.17.9",
"@babel/plugin-proposal-decorators": "^7.17.9",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"@discordjs/ts-docgen": "^0.4.1",
"@types/jest": "^27.4.1",
"@types/node": "^16.11.27",
"@typescript-eslint/eslint-plugin": "^5.19.0",
"@typescript-eslint/parser": "^5.19.0",
"babel-plugin-transform-typescript-metadata": "^0.3.2",
"eslint": "^8.13.0",
"eslint-config-marine": "^9.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"jest": "^27.5.1",
"prettier": "^2.6.2",
"tsup": "^5.12.5",
"typedoc": "^0.22.15",
"typescript": "^4.6.3"
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.5",
"@microsoft/api-extractor": "^7.28.6",
"@types/node": "^16.11.46",
"c8": "^7.12.0",
"downlevel-dts": "^0.10.0",
"eslint": "^8.20.0",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"typescript": "^4.7.4",
"unbuild": "^0.7.6",
"vitest": "^0.19.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -1,7 +0,0 @@
import { runGenerator } from '@discordjs/ts-docgen';
runGenerator({
existingOutput: 'docs/typedoc-out.json',
custom: 'docs/index.yml',
output: 'docs/docs.json',
});

View File

@@ -7,7 +7,10 @@ import {
} from 'discord-api-types/v10';
import { ComponentBuilder } from './Component';
import { createComponentBuilder } from './Components';
import type { ButtonBuilder, SelectMenuBuilder, TextInputBuilder } from '..';
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
@@ -35,20 +38,21 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
/**
* Adds components to this action row.
* @param components The components to add to this action row.
* @returns
*
* @param components - The components to add to this action row.
*/
public addComponents(...components: T[]) {
this.components.push(...components);
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
*
* @param components - The components to set this row to
*/
public setComponents(...components: T[]) {
this.components.splice(0, this.components.length, ...components);
public setComponents(...components: RestOrArray<T>) {
this.components.splice(0, this.components.length, ...normalizeArray(components));
return this;
}

View File

@@ -1,55 +1,78 @@
import { s } from '@sapphire/shapeshift';
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v10';
import type { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
import { UnsafeSelectMenuOptionBuilder } from './selectMenu/UnsafeSelectMenuOption';
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
import { isValidationEnabled } from '../util/validation';
export const customIdValidator = s.string.lengthGe(1).lengthLe(100);
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;
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.lengthGe(1).lengthLe(80);
export const buttonLabelValidator = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(80)
.setValidationEnabled(isValidationEnabled);
export const buttonStyleValidator = s.nativeEnum(ButtonStyle);
export const placeholderValidator = s.string.lengthLe(150);
export const minMaxValidator = s.number.int.ge(0).le(25);
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.lengthGe(1).lengthLe(100);
export const optionValidator = s.union(
s.object({
export const labelValueDescriptionValidator = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(100)
.setValidationEnabled(isValidationEnabled);
export const jsonOptionValidator = s
.object({
label: labelValueDescriptionValidator,
value: labelValueDescriptionValidator,
description: labelValueDescriptionValidator.optional,
emoji: emojiValidator.optional,
default: s.boolean.optional,
}),
s.instance(UnsafeSelectMenuOptionBuilder),
);
export const optionsValidator = optionValidator.array.lengthGe(0);
export const optionsLengthValidator = s.number.int.ge(0).le(25);
})
.setValidationEnabled(isValidationEnabled);
export const optionValidator = 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 labelValueValidator = s.string.lengthGe(1).lengthLe(100);
export const defaultValidator = s.boolean;
export function validateRequiredSelectMenuOptionParameters(label?: string, value?: string) {
labelValueValidator.parse(label);
labelValueValidator.parse(value);
labelValueDescriptionValidator.parse(label);
labelValueDescriptionValidator.parse(value);
}
export const urlValidator = s.string.url({
allowedProtocols: ['http:', 'https:', 'discord:'],
});
export const urlValidator = s.string
.url({
allowedProtocols: ['http:', 'https:', 'discord:'],
})
.setValidationEnabled(isValidationEnabled);
export function validateRequiredButtonParameters(
style?: ButtonStyle,

View File

@@ -1,6 +1,14 @@
import { APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v10';
import type { AnyComponentBuilder, MessageComponentBuilder, ModalComponentBuilder } from './ActionRow';
import { ActionRowBuilder, ButtonBuilder, ComponentBuilder, SelectMenuBuilder, TextInputBuilder } from '../index';
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>;
@@ -11,7 +19,8 @@ export interface MappedComponentTypes {
/**
* Factory for creating components from API data
* @param data The api data to transform to a component class
*
* @param data - The api data to transform to a component class
*/
export function createComponentBuilder<T extends keyof MappedComponentTypes>(
data: (APIMessageComponent | APIModalComponent) & { type: T },

View File

@@ -1,11 +1,11 @@
import type {
import {
ComponentType,
ButtonStyle,
APIMessageComponentEmoji,
APIButtonComponent,
APIButtonComponentWithCustomId,
APIButtonComponentWithURL,
type APIMessageComponentEmoji,
type APIButtonComponent,
type APIButtonComponentWithURL,
type APIButtonComponentWithCustomId,
} from 'discord-api-types/v10';
import { UnsafeButtonBuilder } from './UnsafeButton';
import {
buttonLabelValidator,
buttonStyleValidator,
@@ -15,36 +15,77 @@ import {
urlValidator,
validateRequiredButtonParameters,
} from '../Assertions';
import { ComponentBuilder } from '../Component';
/**
* Represents a validated button component
* Represents a button component
*/
export class ButtonBuilder extends UnsafeButtonBuilder {
public override setStyle(style: ButtonStyle) {
return super.setStyle(buttonStyleValidator.parse(style));
export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
public constructor(data?: Partial<APIButtonComponent>) {
super({ type: ComponentType.Button, ...data });
}
public override setURL(url: string) {
return super.setURL(urlValidator.parse(url));
/**
* 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;
}
public override setCustomId(customId: string) {
return super.setCustomId(customIdValidator.parse(customId));
/**
* 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;
}
public override setEmoji(emoji: APIMessageComponentEmoji) {
return super.setEmoji(emojiValidator.parse(emoji));
/**
* 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;
}
public override setDisabled(disabled = true) {
return super.setDisabled(disabledValidator.parse(disabled));
/**
* 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;
}
public override setLabel(label: string) {
return super.setLabel(buttonLabelValidator.parse(label));
/**
* 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;
}
public override toJSON(): APIButtonComponent {
/**
* 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,
@@ -52,6 +93,9 @@ export class ButtonBuilder extends UnsafeButtonBuilder {
(this.data as APIButtonComponentWithCustomId).custom_id,
(this.data as APIButtonComponentWithURL).url,
);
return super.toJSON();
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APIButtonComponent;
}
}

View File

@@ -1,79 +0,0 @@
import {
ComponentType,
ButtonStyle,
type APIMessageComponentEmoji,
type APIButtonComponent,
type APIButtonComponentWithURL,
type APIButtonComponentWithCustomId,
} from 'discord-api-types/v10';
import { ComponentBuilder } from '../Component';
/**
* Represents a non-validated button component
*/
export class UnsafeButtonBuilder 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 = 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 = 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 = 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 = emoji;
return this;
}
/**
* Sets whether this button is disable or not
* @param disabled Whether or not to disable this button or not
*/
public setDisabled(disabled = true) {
this.data.disabled = 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 = label;
return this;
}
public toJSON(): APIButtonComponent {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APIButtonComponent;
}
}

View File

@@ -1,68 +1,127 @@
import type { APISelectMenuComponent, APISelectMenuOption } from 'discord-api-types/v10';
import { UnsafeSelectMenuBuilder } from './UnsafeSelectMenu';
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
import { SelectMenuOptionBuilder } from './SelectMenuOption';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
import {
customIdValidator,
disabledValidator,
jsonOptionValidator,
minMaxValidator,
optionsLengthValidator,
optionValidator,
placeholderValidator,
validateRequiredSelectMenuParameters,
} from '../Assertions';
import { ComponentBuilder } from '../Component';
/**
* Represents a validated select menu component
* Represents a select menu component
*/
export class SelectMenuBuilder extends UnsafeSelectMenuBuilder {
public override setPlaceholder(placeholder: string) {
return super.setPlaceholder(placeholderValidator.parse(placeholder));
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)) ?? [];
}
public override setMinValues(minValues: number) {
return super.setMinValues(minMaxValidator.parse(minValues));
/**
* 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;
}
public override setMaxValues(maxValues: number) {
return super.setMaxValues(minMaxValidator.parse(maxValues));
/**
* 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;
}
public override setCustomId(customId: string) {
return super.setCustomId(customIdValidator.parse(customId));
/**
* 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;
}
public override setDisabled(disabled = true) {
return super.setDisabled(disabledValidator.parse(disabled));
/**
* 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;
}
public override addOptions(...options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
/**
* 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 UnsafeSelectMenuOptionBuilder
option instanceof SelectMenuOptionBuilder
? option
: new UnsafeSelectMenuOptionBuilder(optionValidator.parse(option) as APISelectMenuOption),
: new SelectMenuOptionBuilder(jsonOptionValidator.parse(option)),
),
);
return this;
}
public override setOptions(...options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
/**
* 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 UnsafeSelectMenuOptionBuilder
option instanceof SelectMenuOptionBuilder
? option
: new UnsafeSelectMenuOptionBuilder(optionValidator.parse(option) as APISelectMenuOption),
: new SelectMenuOptionBuilder(jsonOptionValidator.parse(option)),
),
);
return this;
}
public override toJSON(): APISelectMenuComponent {
public toJSON(): APISelectMenuComponent {
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
return super.toJSON();
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
options: this.options.map((o) => o.toJSON()),
} as APISelectMenuComponent;
}
}

View File

@@ -1,30 +1,73 @@
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
import {
defaultValidator,
emojiValidator,
labelValueValidator,
labelValueDescriptionValidator,
validateRequiredSelectMenuOptionParameters,
} from '../Assertions';
/**
* Represents a validated option within a select menu component
* Represents a option within a select menu component
*/
export class SelectMenuOptionBuilder extends UnsafeSelectMenuOptionBuilder {
public override setDescription(description: string) {
return super.setDescription(labelValueValidator.parse(description));
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;
}
public override setDefault(isDefault = true) {
return super.setDefault(defaultValidator.parse(isDefault));
/**
* 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;
}
public override setEmoji(emoji: APIMessageComponentEmoji) {
return super.setEmoji(emojiValidator.parse(emoji));
/**
* 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;
}
public override toJSON(): APISelectMenuOption {
/**
* 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);
return super.toJSON();
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APISelectMenuOption;
}
}

View File

@@ -1,101 +0,0 @@
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
import { ComponentBuilder } from '../Component';
/**
* Represents a non-validated select menu component
*/
export class UnsafeSelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent> {
/**
* The options within this select menu
*/
public readonly options: UnsafeSelectMenuOptionBuilder[];
public constructor(data?: Partial<APISelectMenuComponent>) {
const { options, ...initData } = data ?? {};
super({ type: ComponentType.SelectMenu, ...initData });
this.options = options?.map((o) => new UnsafeSelectMenuOptionBuilder(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 = 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 = minValues;
return this;
}
/**
* Sets the maximum values that must be selected in the select menu
* @param minValues The maximum values that must be selected
*/
public setMaxValues(maxValues: number) {
this.data.max_values = 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 = customId;
return this;
}
/**
* Sets whether or not this select menu is disabled
* @param disabled Whether or not this select menu is disabled
*/
public setDisabled(disabled = true) {
this.data.disabled = disabled;
return this;
}
/**
* Adds options to this select menu
* @param options The options to add to this select menu
* @returns
*/
public addOptions(...options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
this.options.push(
...options.map((option) =>
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
),
);
return this;
}
/**
* Sets the options on this select menu
* @param options The options to set on this select menu
*/
public setOptions(...options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
this.options.splice(
0,
this.options.length,
...options.map((option) =>
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
),
);
return this;
}
public toJSON(): APISelectMenuComponent {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
options: this.options.map((o) => o.toJSON()),
} as APISelectMenuComponent;
}
}

View File

@@ -1,60 +0,0 @@
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';
/**
* Represents a non-validated option within a select menu component
*/
export class UnsafeSelectMenuOptionBuilder {
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 = label;
return this;
}
/**
* Sets the value of this option
* @param value The value of this option
*/
public setValue(value: string) {
this.data.value = value;
return this;
}
/**
* Sets the description of this option.
* @param description The description of this option
*/
public setDescription(description: string) {
this.data.description = 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 = 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 = emoji;
return this;
}
public toJSON(): APISelectMenuOption {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APISelectMenuOption;
}
}

View File

@@ -1,14 +1,24 @@
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.ge(0).le(4000);
export const maxLengthValidator = s.number.int.ge(1).le(4000);
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.lengthLe(4000);
export const placeholderValidator = s.string.lengthLe(100);
export const labelValidator = s.string.lengthGe(1).lengthLe(45);
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);

View File

@@ -1,4 +1,5 @@
import type { APITextInputComponent } from 'discord-api-types/v10';
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
import isEqual from 'fast-deep-equal';
import {
maxLengthValidator,
minLengthValidator,
@@ -6,32 +7,111 @@ import {
requiredValidator,
valueValidator,
validateRequiredParameters,
labelValidator,
textInputStyleValidator,
} from './Assertions';
import { UnsafeTextInputBuilder } from './UnsafeTextInput';
import { isJSONEncodable, type JSONEncodable } from '../../util/jsonEncodable';
import { customIdValidator } from '../Assertions';
import { ComponentBuilder } from '../Component';
export class TextInputBuilder extends UnsafeTextInputBuilder {
public override setMinLength(minLength: number) {
return super.setMinLength(minLengthValidator.parse(minLength));
export class TextInputBuilder extends ComponentBuilder<APITextInputComponent> {
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
super({ type: ComponentType.TextInput, ...data });
}
public override setMaxLength(maxLength: number) {
return super.setMaxLength(maxLengthValidator.parse(maxLength));
/**
* 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;
}
public override setRequired(required = true) {
return super.setRequired(requiredValidator.parse(required));
/**
* 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;
}
public override setValue(value: string) {
return super.setValue(valueValidator.parse(value));
/**
* 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;
}
public override setPlaceholder(placeholder: string) {
return super.setPlaceholder(placeholderValidator.parse(placeholder));
/**
* 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;
}
public override toJSON(): APITextInputComponent {
/**
* 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);
return super.toJSON();
// 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);
}
}

View File

@@ -1,96 +0,0 @@
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
import isEqual from 'fast-deep-equal';
import { ComponentBuilder } from '../../index';
export class UnsafeTextInputBuilder 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 = 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 = 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 = 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 = 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 = 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 = 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 = value;
return this;
}
/**
* Sets whether this text input is required or not
* @param required Whether this text input is required or not
*/
public setRequired(required = true) {
this.data.required = required;
return this;
}
public toJSON(): APITextInputComponent {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APITextInputComponent;
}
public equals(other: UnsafeTextInputBuilder | APITextInputComponent): boolean {
if (other instanceof UnsafeTextInputBuilder) {
return isEqual(other.data, this.data);
}
return isEqual(other, this.data);
}
}

View File

@@ -1,7 +1,6 @@
export * as EmbedAssertions from './messages/embed/Assertions';
export * from './messages/embed/Embed';
export * from './messages/formatters';
export * from './messages/embed/UnsafeEmbed';
export * as ComponentAssertions from './components/Assertions';
export * from './components/ActionRow';
@@ -10,15 +9,10 @@ export * from './components/Component';
export * from './components/Components';
export * from './components/textInput/TextInput';
export * as TextInputAssertions from './components/textInput/Assertions';
export * from './components/textInput/UnsafeTextInput';
export * from './interactions/modals/UnsafeModal';
export * from './interactions/modals/Modal';
export * as ModalAssertions from './interactions/modals/Assertions';
export * from './components/selectMenu/SelectMenu';
export * from './components/selectMenu/SelectMenuOption';
export * from './components/button/UnsafeButton';
export * from './components/selectMenu/UnsafeSelectMenu';
export * from './components/selectMenu/UnsafeSelectMenuOption';
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions';
export * from './interactions/slashCommands/SlashCommandBuilder';
@@ -32,6 +26,12 @@ export * from './interactions/slashCommands/options/role';
export * from './interactions/slashCommands/options/attachment';
export * from './interactions/slashCommands/options/string';
export * from './interactions/slashCommands/options/user';
export * from './interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionBase';
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin';
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
export * from './interactions/slashCommands/mixins/NameAndDescription';
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions';
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions';
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
@@ -39,3 +39,5 @@ export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
export * from './util/jsonEncodable';
export * from './util/equatable';
export * from './util/componentUtil';
export * from './util/normalizeArray';
export * from './util/validation';

View File

@@ -1,14 +1,16 @@
import { s } from '@sapphire/shapeshift';
import { ApplicationCommandType } from 'discord-api-types/v10';
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder';
import { isValidationEnabled } from '../../util/validation';
const namePredicate = s.string
.lengthGe(1)
.lengthLe(32)
.regex(/^( *[\p{L}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+ *)+$/u);
const typePredicate = s.union(s.literal(ApplicationCommandType.User), s.literal(ApplicationCommandType.Message));
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(32)
.regex(/^( *[\p{L}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+ *)+$/u)
.setValidationEnabled(isValidationEnabled);
const typePredicate = s
.union(s.literal(ApplicationCommandType.User), s.literal(ApplicationCommandType.Message))
.setValidationEnabled(isValidationEnabled);
const booleanPredicate = s.boolean;
export function validateDefaultPermission(value: unknown): asserts value is boolean {
@@ -30,3 +32,19 @@ export function validateRequiredParameters(name: string, type: number) {
// Assert type is valid
validateType(type);
}
const dmPermissionPredicate = s.boolean.nullish;
export function validateDMPermission(value: unknown): asserts value is boolean | null | undefined {
dmPermissionPredicate.parse(value);
}
const memberPermissionPredicate = s.union(
s.bigint.transform((value) => value.toString()),
s.number.safeInt.transform((value) => value.toString()),
s.string.regex(/^\d+$/),
).nullish;
export function validateDefaultMemberPermissions(permissions: unknown) {
return memberPermissionPredicate.parse(permissions);
}

View File

@@ -1,5 +1,19 @@
import type { ApplicationCommandType, RESTPostAPIApplicationCommandsJSONBody } from 'discord-api-types/v10';
import { validateRequiredParameters, validateName, validateType, validateDefaultPermission } from './Assertions';
import type {
ApplicationCommandType,
LocaleString,
LocalizationMap,
Permissions,
RESTPostAPIApplicationCommandsJSONBody,
} from 'discord-api-types/v10';
import {
validateRequiredParameters,
validateName,
validateType,
validateDefaultPermission,
validateDefaultMemberPermissions,
validateDMPermission,
} from './Assertions';
import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions';
export class ContextMenuCommandBuilder {
/**
@@ -7,6 +21,11 @@ export class ContextMenuCommandBuilder {
*/
public readonly name: string = undefined!;
/**
* The localized names for this command
*/
public readonly name_localizations?: LocalizationMap;
/**
* The type of this context menu command
*/
@@ -15,14 +34,26 @@ export class ContextMenuCommandBuilder {
/**
* Whether the command is enabled by default when the app is added to a guild
*
* @default true
* @deprecated This property is deprecated and will be removed in the future.
* You should use `setDefaultMemberPermissions` or `setDMPermission` instead.
*/
public readonly defaultPermission: boolean | undefined = undefined;
public readonly default_permission: boolean | undefined = undefined;
/**
* Set of permissions represented as a bit set for the command
*/
public readonly default_member_permissions: Permissions | null | undefined = undefined;
/**
* Indicates whether the command is available in DMs with the application, only for globally-scoped commands.
* By default, commands are visible.
*/
public readonly dm_permission: boolean | undefined = undefined;
/**
* Sets the name
*
* @param name The name
* @param name - The name
*/
public setName(name: string) {
// Assert the name matches the conditions
@@ -36,7 +67,7 @@ export class ContextMenuCommandBuilder {
/**
* Sets the type
*
* @param type The type
* @param type - The type
*/
public setType(type: ContextMenuCommandType) {
// Assert the type is valid
@@ -52,19 +83,98 @@ export class ContextMenuCommandBuilder {
*
* **Note**: If set to `false`, you will have to later `PUT` the permissions for this command.
*
* @param value Whether or not to enable this command by default
* @param value - Whether or not to enable this command by default
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
* @deprecated Use `setDefaultMemberPermissions` or `setDMPermission` instead.
*/
public setDefaultPermission(value: boolean) {
// Assert the value matches the conditions
validateDefaultPermission(value);
Reflect.set(this, 'defaultPermission', value);
Reflect.set(this, 'default_permission', value);
return this;
}
/**
* Sets the default permissions a member should have in order to run the command.
*
* **Note:** You can set this to `'0'` to disable the command by default.
*
* @param permissions - The permissions bit field to set
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
*/
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
// Assert the value and parse it
const permissionValue = validateDefaultMemberPermissions(permissions);
Reflect.set(this, 'default_member_permissions', permissionValue);
return this;
}
/**
* Sets if the command is available in DMs with the application, only for globally-scoped commands.
* By default, commands are visible.
*
* @param enabled - If the command should be enabled in DMs
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
*/
public setDMPermission(enabled: boolean | null | undefined) {
// Assert the value matches the conditions
validateDMPermission(enabled);
Reflect.set(this, 'dm_permission', enabled);
return this;
}
/**
* Sets a name localization
*
* @param locale - The locale to set a description for
* @param localizedName - The localized description for the given locale
*/
public setNameLocalization(locale: LocaleString, localizedName: string | null) {
if (!this.name_localizations) {
Reflect.set(this, 'name_localizations', {});
}
const parsedLocale = validateLocale(locale);
if (localizedName === null) {
this.name_localizations![parsedLocale] = null;
return this;
}
validateName(localizedName);
this.name_localizations![parsedLocale] = localizedName;
return this;
}
/**
* Sets the name localizations
*
* @param localizedNames - The dictionary of localized descriptions to set
*/
public setNameLocalizations(localizedNames: LocalizationMap | null) {
if (localizedNames === null) {
Reflect.set(this, 'name_localizations', null);
return this;
}
Reflect.set(this, 'name_localizations', {});
Object.entries(localizedNames).forEach((args) =>
this.setNameLocalization(...(args as [LocaleString, string | null])),
);
return this;
}
/**
* Returns the final data that should be sent to Discord.
*
@@ -72,11 +182,10 @@ export class ContextMenuCommandBuilder {
*/
public toJSON(): RESTPostAPIApplicationCommandsJSONBody {
validateRequiredParameters(this.name, this.type);
return {
name: this.name,
type: this.type,
default_permission: this.defaultPermission,
};
validateLocalizationMap(this.name_localizations);
return { ...this };
}
}

View File

@@ -1,9 +1,16 @@
import { s } from '@sapphire/shapeshift';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../..';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow';
import { customIdValidator } from '../../components/Assertions';
import { isValidationEnabled } from '../../util/validation';
export const titleValidator = s.string.lengthGe(1).lengthLe(45);
export const componentsValidator = s.instance(ActionRowBuilder).array.lengthGe(1);
export const titleValidator = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(45)
.setValidationEnabled(isValidationEnabled);
export const componentsValidator = s
.instance(ActionRowBuilder)
.array.lengthGreaterThanOrEqual(1)
.setValidationEnabled(isValidationEnabled);
export function validateRequiredParameters(
customId?: string,

View File

@@ -1,19 +1,81 @@
import type { APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';
import type {
APIActionRowComponent,
APIModalActionRowComponent,
APIModalInteractionResponseCallbackData,
} from 'discord-api-types/v10';
import { titleValidator, validateRequiredParameters } from './Assertions';
import { UnsafeModalBuilder } from './UnsafeModal';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow';
import { customIdValidator } from '../../components/Assertions';
import { createComponentBuilder } from '../../components/Components';
import type { JSONEncodable } from '../../util/jsonEncodable';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
export class ModalBuilder extends UnsafeModalBuilder {
public override setCustomId(customId: string): this {
return super.setCustomId(customIdValidator.parse(customId));
export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {
public readonly data: Partial<APIModalInteractionResponseCallbackData>;
public readonly components: ActionRowBuilder<ModalActionRowComponentBuilder>[] = [];
public constructor({ components, ...data }: Partial<APIModalInteractionResponseCallbackData> = {}) {
this.data = { ...data };
this.components = (components?.map((c) => createComponentBuilder(c)) ??
[]) as ActionRowBuilder<ModalActionRowComponentBuilder>[];
}
public override setTitle(title: string) {
return super.setTitle(titleValidator.parse(title));
/**
* Sets the title of the modal
*
* @param title - The title of the modal
*/
public setTitle(title: string) {
this.data.title = titleValidator.parse(title);
return this;
}
public override toJSON(): APIModalInteractionResponseCallbackData {
/**
* Sets the custom id of the modal
*
* @param customId - The custom id of this modal
*/
public setCustomId(customId: string) {
this.data.custom_id = customIdValidator.parse(customId);
return this;
}
/**
* Adds components to this modal
*
* @param components - The components to add to this modal
*/
public addComponents(
...components: RestOrArray<
ActionRowBuilder<ModalActionRowComponentBuilder> | APIActionRowComponent<APIModalActionRowComponent>
>
) {
this.components.push(
...normalizeArray(components).map((component) =>
component instanceof ActionRowBuilder
? component
: new ActionRowBuilder<ModalActionRowComponentBuilder>(component),
),
);
return this;
}
/**
* Sets the components in this modal
*
* @param components - The components to set this modal to
*/
public setComponents(...components: RestOrArray<ActionRowBuilder<ModalActionRowComponentBuilder>>) {
this.components.splice(0, this.components.length, ...normalizeArray(components));
return this;
}
public toJSON(): APIModalInteractionResponseCallbackData {
validateRequiredParameters(this.data.custom_id, this.data.title, this.components);
return super.toJSON();
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
components: this.components.map((component) => component.toJSON()),
} as APIModalInteractionResponseCallbackData;
}
}

View File

@@ -1,72 +0,0 @@
import type {
APIActionRowComponent,
APIModalActionRowComponent,
APIModalInteractionResponseCallbackData,
} from 'discord-api-types/v10';
import { ActionRowBuilder, createComponentBuilder, JSONEncodable, ModalActionRowComponentBuilder } from '../../index';
export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {
public readonly data: Partial<APIModalInteractionResponseCallbackData>;
public readonly components: ActionRowBuilder<ModalActionRowComponentBuilder>[] = [];
public constructor({ components, ...data }: Partial<APIModalInteractionResponseCallbackData> = {}) {
this.data = { ...data };
this.components = (components?.map((c) => createComponentBuilder(c)) ??
[]) as ActionRowBuilder<ModalActionRowComponentBuilder>[];
}
/**
* Sets the title of the modal
* @param title The title of the modal
*/
public setTitle(title: string) {
this.data.title = title;
return this;
}
/**
* Sets the custom id of the modal
* @param customId The custom id of this modal
*/
public setCustomId(customId: string) {
this.data.custom_id = customId;
return this;
}
/**
* Adds components to this modal
* @param components The components to add to this modal
*/
public addComponents(
...components: (
| ActionRowBuilder<ModalActionRowComponentBuilder>
| APIActionRowComponent<APIModalActionRowComponent>
)[]
) {
this.components.push(
...components.map((component) =>
component instanceof ActionRowBuilder
? component
: new ActionRowBuilder<ModalActionRowComponentBuilder>(component),
),
);
return this;
}
/**
* Sets the components in this modal
* @param components The components to set this modal to
*/
public setComponents(...components: ActionRowBuilder<ModalActionRowComponentBuilder>[]) {
this.components.splice(0, this.components.length, ...components);
return this;
}
public toJSON(): APIModalInteractionResponseCallbackData {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
components: this.components.map((component) => component.toJSON()),
} as APIModalInteractionResponseCallbackData;
}
}

Some files were not shown because too many files have changed in this diff Show More